Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Jan 2012 20:26:23 +0000 (12:26 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Jan 2012 20:26:23 +0000 (12:26 -0800)
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc: Fix unpaired __trace_hcall_entry and __trace_hcall_exit
  powerpc: Fix RCU idle and hcall tracing

1884 files changed:
Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration [new file with mode: 0644]
Documentation/ABI/testing/sysfs-kernel-slab
Documentation/DocBook/writing-an-alsa-driver.tmpl
Documentation/cgroups/memory.txt
Documentation/devicetree/bindings/c6x/clocks.txt [new file with mode: 0644]
Documentation/devicetree/bindings/c6x/dscr.txt [new file with mode: 0644]
Documentation/devicetree/bindings/c6x/emifa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/c6x/interrupt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/c6x/soc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/c6x/timer64.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/mc13xxx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/twl-familly.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power_supply/olpc_battery.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/twl-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tegra20-das.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tegra20-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wm8903.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/wm8994.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/digsig.txt [new file with mode: 0644]
Documentation/dma-buf-sharing.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ceph.txt
Documentation/filesystems/ext4.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/squashfs.txt
Documentation/kernel-parameters.txt
Documentation/mmc/mmc-dev-attrs.txt
Documentation/mmc/mmc-dev-parts.txt
Documentation/power/charger-manager.txt [new file with mode: 0644]
Documentation/security/00-INDEX
Documentation/security/LSM.txt [new file with mode: 0644]
Documentation/security/credentials.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sound/alsa/compress_offload.txt [new file with mode: 0644]
Documentation/sysctl/kernel.txt
Documentation/trace/events-kmem.txt
Documentation/trace/postprocess/trace-pagealloc-postprocess.pl
Documentation/trace/tracepoint-analysis.txt
Documentation/virtual/lguest/.gitignore [deleted file]
Documentation/virtual/lguest/Makefile [deleted file]
Documentation/virtual/lguest/extract [deleted file]
Documentation/virtual/lguest/lguest.c [deleted file]
Documentation/virtual/lguest/lguest.txt [deleted file]
Documentation/vm/slub.txt
MAINTAINERS
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/kernel/pci-noop.c
arch/alpha/kernel/pci.c
arch/arm/Kconfig
arch/arm/common/it8152.c
arch/arm/common/via82c505.c
arch/arm/configs/bonito_defconfig [new file with mode: 0644]
arch/arm/configs/kota2_defconfig [new file with mode: 0644]
arch/arm/configs/marzen_defconfig [new file with mode: 0644]
arch/arm/include/asm/io.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/pci.h
arch/arm/kernel/bios32.c
arch/arm/mach-cns3xxx/pcie.c
arch/arm/mach-dove/pcie.c
arch/arm/mach-exynos/include/mach/cpufreq.h [new file with mode: 0644]
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-integrator/pci_v3.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/pci.c
arch/arm/mach-ixp23xx/pci.c
arch/arm/mach-ixp4xx/common-pci.c
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/pci.c
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-orion5x/pci.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/eseries.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/generic.c
arch/arm/mach-sa1100/include/mach/mcp.h
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-bonito.c [new file with mode: 0644]
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/board-marzen.c [new file with mode: 0644]
arch/arm/mach-shmobile/clock-r8a7740.c [new file with mode: 0644]
arch/arm/mach-shmobile/clock-r8a7779.c [new file with mode: 0644]
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/headsmp.S
arch/arm/mach-shmobile/hotplug.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/r8a7740.h [new file with mode: 0644]
arch/arm/mach-shmobile/include/mach/r8a7779.h [new file with mode: 0644]
arch/arm/mach-shmobile/intc-r8a7740.c [new file with mode: 0644]
arch/arm/mach-shmobile/intc-r8a7779.c [new file with mode: 0644]
arch/arm/mach-shmobile/pfc-r8a7740.c [new file with mode: 0644]
arch/arm/mach-shmobile/pfc-r8a7779.c [new file with mode: 0644]
arch/arm/mach-shmobile/platsmp.c
arch/arm/mach-shmobile/pm-r8a7779.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-r8a7740.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-r8a7779.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/smp-r8a7779.c [new file with mode: 0644]
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/pcie.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
arch/arm/mach-versatile/pci.c
arch/arm/mm/iomap.c
arch/arm/plat-iop/pci.c
arch/arm/plat-omap/cpu-omap.c [deleted file]
arch/arm/plat-samsung/include/plat/sdhci.h
arch/arm/plat-samsung/platformdata.c
arch/avr32/include/asm/system.h
arch/avr32/kernel/traps.c
arch/blackfin/configs/BF518F-EZBRD_defconfig
arch/blackfin/configs/BF526-EZBRD_defconfig
arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF548-EZKIT_defconfig
arch/blackfin/configs/BF561-ACVILON_defconfig
arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
arch/blackfin/configs/BF561-EZKIT_defconfig
arch/blackfin/configs/BlackStamp_defconfig
arch/blackfin/configs/CM-BF527_defconfig
arch/blackfin/configs/CM-BF533_defconfig
arch/blackfin/configs/CM-BF537E_defconfig
arch/blackfin/configs/CM-BF537U_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/configs/CM-BF561_defconfig
arch/blackfin/configs/DNP5370_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/IP0X_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/SRV1_defconfig
arch/blackfin/configs/TCM-BF518_defconfig
arch/blackfin/configs/TCM-BF537_defconfig
arch/blackfin/include/asm/bfin_serial.h
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/pci.h
arch/blackfin/include/asm/smp.h
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/time-ts.c
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf518/boards/tcm-bf518.c
arch/blackfin/mach-bf527/boards/ad7160eval.c
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/boards/tll6527m.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/ip0x.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537e.c
arch/blackfin/mach-bf537/boards/cm_bf537u.c
arch/blackfin/mach-bf537/boards/dnp5370.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf538/boards/ezkit.c
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/acvilon.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/include/mach/pll.h
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/smp.c
arch/c6x/Kconfig [new file with mode: 0644]
arch/c6x/Makefile [new file with mode: 0644]
arch/c6x/boot/Makefile [new file with mode: 0644]
arch/c6x/boot/dts/dsk6455.dts [new file with mode: 0644]
arch/c6x/boot/dts/evmc6457.dts [new file with mode: 0644]
arch/c6x/boot/dts/evmc6472.dts [new file with mode: 0644]
arch/c6x/boot/dts/evmc6474.dts [new file with mode: 0644]
arch/c6x/boot/dts/tms320c6455.dtsi [new file with mode: 0644]
arch/c6x/boot/dts/tms320c6457.dtsi [new file with mode: 0644]
arch/c6x/boot/dts/tms320c6472.dtsi [new file with mode: 0644]
arch/c6x/boot/dts/tms320c6474.dtsi [new file with mode: 0644]
arch/c6x/boot/linked_dtb.S [new file with mode: 0644]
arch/c6x/configs/dsk6455_defconfig [new file with mode: 0644]
arch/c6x/configs/evmc6457_defconfig [new file with mode: 0644]
arch/c6x/configs/evmc6472_defconfig [new file with mode: 0644]
arch/c6x/configs/evmc6474_defconfig [new file with mode: 0644]
arch/c6x/include/asm/Kbuild [new file with mode: 0644]
arch/c6x/include/asm/asm-offsets.h [new file with mode: 0644]
arch/c6x/include/asm/bitops.h [new file with mode: 0644]
arch/c6x/include/asm/byteorder.h [new file with mode: 0644]
arch/c6x/include/asm/cache.h [new file with mode: 0644]
arch/c6x/include/asm/cacheflush.h [new file with mode: 0644]
arch/c6x/include/asm/checksum.h [new file with mode: 0644]
arch/c6x/include/asm/clkdev.h [new file with mode: 0644]
arch/c6x/include/asm/clock.h [new file with mode: 0644]
arch/c6x/include/asm/delay.h [new file with mode: 0644]
arch/c6x/include/asm/dma-mapping.h [new file with mode: 0644]
arch/c6x/include/asm/dscr.h [new file with mode: 0644]
arch/c6x/include/asm/elf.h [new file with mode: 0644]
arch/c6x/include/asm/ftrace.h [new file with mode: 0644]
arch/c6x/include/asm/hardirq.h [new file with mode: 0644]
arch/c6x/include/asm/irq.h [new file with mode: 0644]
arch/c6x/include/asm/irqflags.h [new file with mode: 0644]
arch/c6x/include/asm/linkage.h [new file with mode: 0644]
arch/c6x/include/asm/megamod-pic.h [new file with mode: 0644]
arch/c6x/include/asm/mmu.h [new file with mode: 0644]
arch/c6x/include/asm/module.h [new file with mode: 0644]
arch/c6x/include/asm/mutex.h [new file with mode: 0644]
arch/c6x/include/asm/page.h [new file with mode: 0644]
arch/c6x/include/asm/pgtable.h [new file with mode: 0644]
arch/c6x/include/asm/processor.h [new file with mode: 0644]
arch/c6x/include/asm/procinfo.h [new file with mode: 0644]
arch/c6x/include/asm/prom.h [new file with mode: 0644]
arch/c6x/include/asm/ptrace.h [new file with mode: 0644]
arch/c6x/include/asm/sections.h [new file with mode: 0644]
arch/c6x/include/asm/setup.h [new file with mode: 0644]
arch/c6x/include/asm/sigcontext.h [new file with mode: 0644]
arch/c6x/include/asm/signal.h [new file with mode: 0644]
arch/c6x/include/asm/soc.h [new file with mode: 0644]
arch/c6x/include/asm/string.h [new file with mode: 0644]
arch/c6x/include/asm/swab.h [new file with mode: 0644]
arch/c6x/include/asm/syscall.h [new file with mode: 0644]
arch/c6x/include/asm/syscalls.h [new file with mode: 0644]
arch/c6x/include/asm/system.h [new file with mode: 0644]
arch/c6x/include/asm/thread_info.h [new file with mode: 0644]
arch/c6x/include/asm/timer64.h [new file with mode: 0644]
arch/c6x/include/asm/timex.h [new file with mode: 0644]
arch/c6x/include/asm/tlb.h [new file with mode: 0644]
arch/c6x/include/asm/traps.h [new file with mode: 0644]
arch/c6x/include/asm/uaccess.h [new file with mode: 0644]
arch/c6x/include/asm/unaligned.h [new file with mode: 0644]
arch/c6x/include/asm/unistd.h [new file with mode: 0644]
arch/c6x/kernel/Makefile [new file with mode: 0644]
arch/c6x/kernel/asm-offsets.c [new file with mode: 0644]
arch/c6x/kernel/c6x_ksyms.c [new file with mode: 0644]
arch/c6x/kernel/devicetree.c [new file with mode: 0644]
arch/c6x/kernel/dma.c [new file with mode: 0644]
arch/c6x/kernel/entry.S [new file with mode: 0644]
arch/c6x/kernel/head.S [new file with mode: 0644]
arch/c6x/kernel/irq.c [new file with mode: 0644]
arch/c6x/kernel/module.c [new file with mode: 0644]
arch/c6x/kernel/process.c [new file with mode: 0644]
arch/c6x/kernel/ptrace.c [new file with mode: 0644]
arch/c6x/kernel/setup.c [new file with mode: 0644]
arch/c6x/kernel/signal.c [new file with mode: 0644]
arch/c6x/kernel/soc.c [new file with mode: 0644]
arch/c6x/kernel/switch_to.S [new file with mode: 0644]
arch/c6x/kernel/sys_c6x.c [new file with mode: 0644]
arch/c6x/kernel/time.c [new file with mode: 0644]
arch/c6x/kernel/traps.c [new file with mode: 0644]
arch/c6x/kernel/vectors.S [new file with mode: 0644]
arch/c6x/kernel/vmlinux.lds.S [new file with mode: 0644]
arch/c6x/lib/Makefile [new file with mode: 0644]
arch/c6x/lib/checksum.c [new file with mode: 0644]
arch/c6x/lib/csum_64plus.S [new file with mode: 0644]
arch/c6x/lib/divi.S [new file with mode: 0644]
arch/c6x/lib/divremi.S [new file with mode: 0644]
arch/c6x/lib/divremu.S [new file with mode: 0644]
arch/c6x/lib/divu.S [new file with mode: 0644]
arch/c6x/lib/llshl.S [new file with mode: 0644]
arch/c6x/lib/llshr.S [new file with mode: 0644]
arch/c6x/lib/llshru.S [new file with mode: 0644]
arch/c6x/lib/memcpy_64plus.S [new file with mode: 0644]
arch/c6x/lib/mpyll.S [new file with mode: 0644]
arch/c6x/lib/negll.S [new file with mode: 0644]
arch/c6x/lib/pop_rts.S [new file with mode: 0644]
arch/c6x/lib/push_rts.S [new file with mode: 0644]
arch/c6x/lib/remi.S [new file with mode: 0644]
arch/c6x/lib/remu.S [new file with mode: 0644]
arch/c6x/lib/strasgi.S [new file with mode: 0644]
arch/c6x/lib/strasgi_64plus.S [new file with mode: 0644]
arch/c6x/mm/Makefile [new file with mode: 0644]
arch/c6x/mm/dma-coherent.c [new file with mode: 0644]
arch/c6x/mm/init.c [new file with mode: 0644]
arch/c6x/platforms/Kconfig [new file with mode: 0644]
arch/c6x/platforms/Makefile [new file with mode: 0644]
arch/c6x/platforms/cache.c [new file with mode: 0644]
arch/c6x/platforms/dscr.c [new file with mode: 0644]
arch/c6x/platforms/emif.c [new file with mode: 0644]
arch/c6x/platforms/megamod-pic.c [new file with mode: 0644]
arch/c6x/platforms/platform.c [new file with mode: 0644]
arch/c6x/platforms/pll.c [new file with mode: 0644]
arch/c6x/platforms/plldata.c [new file with mode: 0644]
arch/c6x/platforms/timer64.c [new file with mode: 0644]
arch/cris/Kconfig
arch/frv/Kconfig
arch/frv/include/asm/io.h
arch/frv/mb93090-mb00/Makefile
arch/frv/mb93090-mb00/pci-frv.c
arch/frv/mb93090-mb00/pci-frv.h
arch/frv/mb93090-mb00/pci-iomap.c [deleted file]
arch/frv/mb93090-mb00/pci-vdk.c
arch/h8300/Kconfig
arch/h8300/include/asm/pci.h
arch/hexagon/Kconfig
arch/ia64/Kconfig
arch/ia64/include/asm/pci.h
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/entry.S
arch/ia64/kernel/machine_kexec.c
arch/ia64/pci/pci.c
arch/m68k/Kconfig
arch/m68k/amiga/config.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/irq.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pci-bridge.h
arch/microblaze/include/asm/pci.h
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/kernel/early_printk.c
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/irq.c
arch/microblaze/kernel/module.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/syscall_table.S
arch/microblaze/kernel/timer.c
arch/microblaze/lib/Makefile
arch/microblaze/lib/cmpdi2.c [new file with mode: 0644]
arch/microblaze/pci/iomap.c
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/include/asm/ptrace.h
arch/mips/kernel/traps.c
arch/mips/lib/iomap-pci.c
arch/mips/pci/pci.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/exceptions.h
arch/mn10300/include/asm/io.h
arch/mn10300/unit-asb2305/Makefile
arch/mn10300/unit-asb2305/pci-asb2305.c
arch/mn10300/unit-asb2305/pci-asb2305.h
arch/mn10300/unit-asb2305/pci-iomap.c [deleted file]
arch/mn10300/unit-asb2305/pci.c
arch/openrisc/Kconfig
arch/parisc/Kconfig
arch/parisc/include/asm/processor.h
arch/parisc/kernel/process.c
arch/parisc/lib/iomap.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/pci.h
arch/powerpc/kernel/iomap.c
arch/powerpc/kernel/machine_kexec_32.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/pseries/nvram.c
arch/s390/include/asm/processor.h
arch/s390/kernel/nmi.c
arch/score/Kconfig
arch/sh/Kconfig
arch/sh/boards/board-magicpanelr2.c
arch/sh/boards/board-sh7757lcr.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boards/mach-kfr2r09/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-rsk/setup.c
arch/sh/boards/mach-se/7722/setup.c
arch/sh/boards/mach-se/7724/setup.c
arch/sh/drivers/pci/pci.c
arch/sh/include/asm/device.h
arch/sh/include/asm/hwblk.h [deleted file]
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7723.h
arch/sh/include/cpu-sh4/cpu/sh7724.h
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/hwblk.c [deleted file]
arch/sh/kernel/cpu/sh4/sq.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c [deleted file]
arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c [deleted file]
arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c [deleted file]
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/shmobile/Makefile
arch/sh/kernel/cpu/shmobile/cpuidle.c
arch/sh/kernel/cpu/shmobile/pm_runtime.c [deleted file]
arch/sh/kernel/entry-common.S
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/signal_32.c
arch/sh/kernel/signal_64.c
arch/sh/kernel/time.c
arch/sh/mm/cache-sh2a.c
arch/sparc/Kconfig
arch/sparc/include/asm/io_32.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pci_64.h
arch/sparc/include/asm/signal.h
arch/sparc/kernel/leon_pci.c
arch/sparc/kernel/pci.c
arch/sparc/lib/iomap.c
arch/tile/Kconfig
arch/tile/include/asm/io.h
arch/tile/include/asm/pci.h
arch/tile/kernel/machine_kexec.c
arch/tile/kernel/pci.c
arch/um/Kconfig.common
arch/unicore32/Kconfig
arch/unicore32/include/asm/io.h
arch/unicore32/include/asm/pci.h
arch/unicore32/kernel/pci.c
arch/unicore32/kernel/puv3-nb0916.c
arch/unicore32/kernel/setup.c
arch/unicore32/kernel/signal.c
arch/unicore32/kernel/time.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/eboot.c [new file with mode: 0644]
arch/x86/boot/compressed/eboot.h [new file with mode: 0644]
arch/x86/boot/compressed/efi_stub_32.S [new file with mode: 0644]
arch/x86/boot/compressed/efi_stub_64.S [new file with mode: 0644]
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/string.c
arch/x86/boot/header.S
arch/x86/boot/string.c
arch/x86/boot/tools/build.c
arch/x86/crypto/Makefile
arch/x86/crypto/serpent-sse2-i586-asm_32.S [new file with mode: 0644]
arch/x86/crypto/serpent-sse2-x86_64-asm_64.S [new file with mode: 0644]
arch/x86/crypto/serpent_sse2_glue.c [new file with mode: 0644]
arch/x86/crypto/twofish_glue_3way.c
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/init.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/serpent.h [new file with mode: 0644]
arch/x86/include/asm/setup.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/Makefile
arch/x86/kernel/amd_nb.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/e820.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/nmi_selftest.c [new file with mode: 0644]
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
arch/x86/kernel/x86_init.c
arch/x86/lguest/boot.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/mmap.c
arch/x86/mm/numa.c
arch/x86/mm/pageattr.c
arch/x86/pci/Makefile
arch/x86/pci/acpi.c
arch/x86/pci/amd_bus.c
arch/x86/pci/broadcom_bus.c
arch/x86/pci/bus_numa.c
arch/x86/pci/common.c
arch/x86/pci/i386.c
arch/x86/pci/legacy.c
arch/x86/pci/numaq_32.c
arch/x86/platform/mrst/Makefile
arch/x86/platform/mrst/mrst.c
arch/x86/um/Kconfig
arch/xtensa/Kconfig
arch/xtensa/include/asm/pci.h
arch/xtensa/kernel/pci.c
crypto/Kconfig
crypto/Makefile
crypto/algapi.c
crypto/ansi_cprng.c
crypto/crypto_user.c
crypto/lrw.c
crypto/serpent.c [deleted file]
crypto/serpent_generic.c [new file with mode: 0644]
crypto/tcrypt.c
crypto/tcrypt.h
crypto/testmgr.c
crypto/testmgr.h
crypto/twofish_common.c
crypto/xts.c
drivers/Makefile
drivers/acpi/pci_irq.c
drivers/base/Kconfig
drivers/base/base.h
drivers/base/cpu.c
drivers/base/memory.c
drivers/block/rbd.c
drivers/block/virtio_blk.c
drivers/block/xsysace.c
drivers/char/hw_random/atmel-rng.c
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/octeon-rng.c
drivers/char/hw_random/pasemi-rng.c
drivers/char/hw_random/picoxcell-rng.c
drivers/char/hw_random/ppc4xx-rng.c
drivers/char/hw_random/timeriomem-rng.c
drivers/char/hw_random/virtio-rng.c
drivers/char/ramoops.c
drivers/char/tpm/Kconfig
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_tis.c
drivers/char/virtio_console.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_userspace.c
drivers/cpufreq/exynos-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/exynos4210-cpufreq.c
drivers/cpufreq/omap-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/s3c64xx-cpufreq.c
drivers/crypto/amcc/crypto4xx_core.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/compat.h
drivers/crypto/caam/ctrl.c
drivers/crypto/caam/desc.h
drivers/crypto/caam/desc_constr.h
drivers/crypto/caam/regs.h
drivers/crypto/mv_cesa.c
drivers/crypto/picoxcell_crypto.c
drivers/crypto/s5p-sss.c
drivers/crypto/talitos.c
drivers/crypto/talitos.h
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/sigma.c [deleted file]
drivers/gpio/gpio-stmpe.c
drivers/gpu/drm/gma500/cdv_intel_crt.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/gma500/oaktrail_hdmi.c
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/hid/hid-wacom.c
drivers/hid/hid-wiimote-core.c
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-highlander.c
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-intel-mid.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-ixp2000.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-octeon.c
drivers/i2c/busses/i2c-pasemi.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-puv3.c
drivers/i2c/busses/i2c-pxa-pci.c
drivers/i2c/busses/i2c-sh7760.c
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-via.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/i2c-dev.c
drivers/i2c/muxes/gpio-i2cmux.c
drivers/input/keyboard/amikbd.c
drivers/input/keyboard/davinci_keyscan.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/misc/ab8500-ponkey.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/mouse/amimouse.c
drivers/input/mouse/bcm5974.c
drivers/input/serio/at32psif.c
drivers/input/serio/serio_raw.c
drivers/input/serio/xilinx_ps2.c
drivers/input/touchscreen/atmel-wm97xx.c
drivers/input/touchscreen/mc13783_ts.c
drivers/isdn/i4l/Kconfig
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-88pm860x.c
drivers/leds/leds-adp5520.c
drivers/leds/leds-ams-delta.c
drivers/leds/leds-asic3.c
drivers/leds/leds-atmel-pwm.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-cobalt-qube.c
drivers/leds/leds-da903x.c
drivers/leds/leds-dac124s085.c
drivers/leds/leds-fsg.c
drivers/leds/leds-gpio.c
drivers/leds/leds-hp6xx.c
drivers/leds/leds-lm3530.c
drivers/leds/leds-lp3944.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lt3593.c
drivers/leds/leds-max8997.c [new file with mode: 0644]
drivers/leds/leds-mc13783.c
drivers/leds/leds-netxbig.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-pca955x.c
drivers/leds/leds-pwm.c
drivers/leds/leds-rb532.c
drivers/leds/leds-regulator.c
drivers/leds/leds-renesas-tpu.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-tca6507.c [new file with mode: 0644]
drivers/leds/leds-wm831x-status.c
drivers/leds/leds-wm8350.c
drivers/lguest/Makefile
drivers/lguest/lguest_device.c
drivers/lguest/segments.c
drivers/md/md.c
drivers/md/raid1.c
drivers/mfd/88pm860x-i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c
drivers/mfd/ab5500-core.c
drivers/mfd/ab5500-debugfs.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/ab8500-i2c.c
drivers/mfd/ab8500-sysctrl.c
drivers/mfd/cs5535-mfd.c
drivers/mfd/dm355evm_msp.c
drivers/mfd/intel_msic.c
drivers/mfd/jz4740-adc.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8925-core.c
drivers/mfd/max8925-i2c.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/mc13xxx-core.c
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pcf50633-adc.c
drivers/mfd/s5m-core.c [new file with mode: 0644]
drivers/mfd/s5m-irq.c [new file with mode: 0644]
drivers/mfd/sm501.c
drivers/mfd/stmpe-i2c.c [new file with mode: 0644]
drivers/mfd/stmpe-spi.c [new file with mode: 0644]
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/mfd/t7l66xb.c
drivers/mfd/tc6387xb.c
drivers/mfd/ti-ssp.c
drivers/mfd/timberdale.c
drivers/mfd/tps65910-irq.c
drivers/mfd/tps65910.c
drivers/mfd/tps65912-spi.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-audio.c
drivers/mfd/twl4030-irq.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6040-core.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mfd/vx855.c
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-i2c.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-i2c.c
drivers/mfd/wm8400-core.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/mfd/wm8994-regmap.c [new file with mode: 0644]
drivers/mfd/wm8994.h [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/ab8500-pwm.c
drivers/misc/max8997-muic.c [new file with mode: 0644]
drivers/mmc/Makefile
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/Makefile
drivers/mmc/core/bus.c
drivers/mmc/core/cd-gpio.c [new file with mode: 0644]
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_io.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci-data.c [new file with mode: 0644]
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/mtd/mtdoops.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_alb.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/adi/bfin_mac.c
drivers/net/ethernet/amd/au1000_eth.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/freescale/fec.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/s6gmac.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/tundra/tsi108_eth.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/phy/dp83640.c
drivers/net/phy/fixed.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/mdio-octeon.c
drivers/net/phy/mdio_bus.c
drivers/net/ppp/pptp.c
drivers/net/usb/asix.c
drivers/net/virtio_net.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.c
drivers/of/fdt.c
drivers/parisc/dino.c
drivers/parisc/lba_pci.c
drivers/parport/parport_pc.c
drivers/pci/access.c
drivers/pci/ats.c
drivers/pci/bus.c
drivers/pci/iov.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/Kconfig
drivers/pci/probe.c
drivers/pci/remove.c
drivers/pci/setup-res.c
drivers/platform/x86/Kconfig
drivers/pnp/quirks.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/bq20z75.c [deleted file]
drivers/power/bq27x00_battery.c
drivers/power/charger-manager.c [new file with mode: 0644]
drivers/power/collie_battery.c
drivers/power/da9030_battery.c
drivers/power/da9052-battery.c [new file with mode: 0644]
drivers/power/ds2760_battery.c
drivers/power/ds2780_battery.c
drivers/power/gpio-charger.c
drivers/power/intel_mid_battery.c
drivers/power/isp1704_charger.c
drivers/power/jz4740-battery.c
drivers/power/lp8727_charger.c [new file with mode: 0644]
drivers/power/max17042_battery.c
drivers/power/max8903_charger.c
drivers/power/max8925_power.c
drivers/power/max8997_charger.c
drivers/power/max8998_charger.c
drivers/power/olpc_battery.c
drivers/power/pcf50633-charger.c
drivers/power/pda_power.c
drivers/power/power_supply_core.c
drivers/power/power_supply_sysfs.c
drivers/power/s3c_adc_battery.c
drivers/power/sbs-battery.c [new file with mode: 0644]
drivers/power/tosa_battery.c
drivers/power/wm831x_backup.c
drivers/power/wm831x_power.c
drivers/power/wm8350_power.c
drivers/power/wm97xx_battery.c
drivers/power/z2_battery.c
drivers/regulator/ab8500.c
drivers/rtc/Kconfig
drivers/rtc/interface.c
drivers/rtc/rtc-88pm860x.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-bq4802.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-dm355evm.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-m41t93.c
drivers/rtc/rtc-m41t94.c
drivers/rtc/rtc-m48t35.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-max6902.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-max8998.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-puv3.c
drivers/rtc/rtc-rs5c348.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-wm831x.c
drivers/rtc/rtc-wm8350.c
drivers/s390/kvm/kvm_virtio.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/sh/Makefile
drivers/sh/clk/core.c
drivers/sh/clk/cpg.c
drivers/sh/pfc.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
drivers/uio/uio_pci_generic.c
drivers/usb/otg/ab8500-usb.c
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/adp5520_bl.c
drivers/video/backlight/adx_bl.c [deleted file]
drivers/video/backlight/backlight.c
drivers/video/backlight/da903x_bl.c
drivers/video/backlight/ep93xx_bl.c
drivers/video/backlight/generic_bl.c
drivers/video/backlight/jornada720_bl.c
drivers/video/backlight/jornada720_lcd.c
drivers/video/backlight/lcd.c
drivers/video/backlight/ld9040.c
drivers/video/backlight/max8925_bl.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/pcf50633-backlight.c
drivers/video/backlight/platform_lcd.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/wm831x_bl.c
drivers/video/nvidia/nvidia.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
fs/9p/cache.c
fs/9p/fid.c
fs/9p/v9fs.c
fs/9p/vfs_addr.c
fs/9p/vfs_dentry.c
fs/9p/vfs_dir.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/vfs_super.c
fs/9p/xattr.c
fs/Kconfig.binfmt
fs/aio.c
fs/autofs4/autofs_i.h
fs/autofs4/inode.c
fs/autofs4/waitq.c
fs/binfmt_elf.c
fs/block_dev.c
fs/btrfs/disk-io.c
fs/btrfs/file.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/coda/cnode.c
fs/coda/coda_fs_i.h
fs/coda/dir.c
fs/coda/inode.c
fs/dcache.c
fs/direct-io.c
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/debug_fs.c
fs/dlm/dir.c
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lockspace.c
fs/dlm/member.c
fs/dlm/member.h
fs/dlm/rcom.c
fs/dlm/rcom.h
fs/dlm/recover.c
fs/dlm/recoverd.c
fs/dlm/user.c
fs/eventpoll.c
fs/exec.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/xattr_security.c
fs/fs-writeback.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/lock_dlm.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/sys.c
fs/gfs2/sys.h
fs/hfsplus/super.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/jbd2/commit.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/file.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/objlayout/objlayout.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs4callback.c
fs/ocfs2/stack_user.c
fs/pipe.c
fs/proc/array.c
fs/proc/base.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/root.c
fs/reiserfs/bitmap.c
fs/reiserfs/journal.c
fs/reiserfs/super.c
fs/squashfs/cache.c
fs/squashfs/inode.c
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/journal.c
fs/ubifs/lpt.c
fs/ubifs/replay.c
fs/ubifs/tnc.c
fs/ubifs/tnc_misc.c
fs/ubifs/xattr.c
include/asm-generic/io.h
include/asm-generic/iomap.h
include/asm-generic/page.h
include/asm-generic/pci_iomap.h [new file with mode: 0644]
include/asm-generic/tlb.h
include/asm-generic/uaccess.h
include/crypto/algapi.h
include/crypto/lrw.h [new file with mode: 0644]
include/crypto/serpent.h [new file with mode: 0644]
include/crypto/twofish.h
include/crypto/xts.h [new file with mode: 0644]
include/drm/drm_crtc.h
include/linux/amba/mmci.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/crash_dump.h
include/linux/dcache.h
include/linux/digsig.h [new file with mode: 0644]
include/linux/dlm.h
include/linux/efi.h
include/linux/elf-em.h
include/linux/eventpoll.h
include/linux/fs.h
include/linux/fuse.h
include/linux/gfp.h
include/linux/gfs2_ondisk.h
include/linux/huge_mm.h
include/linux/i2c/twl.h
include/linux/inet_diag.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/key-type.h
include/linux/kmsg_dump.h
include/linux/leds-tca6507.h [new file with mode: 0644]
include/linux/linkage.h
include/linux/lp8727.h [new file with mode: 0755]
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mfd/88pm860x.h
include/linux/mfd/ab5500/ab5500.h [deleted file]
include/linux/mfd/ab8500.h [deleted file]
include/linux/mfd/ab8500/gpadc.h [deleted file]
include/linux/mfd/ab8500/gpio.h [deleted file]
include/linux/mfd/ab8500/sysctrl.h [deleted file]
include/linux/mfd/abx500/ab5500.h [new file with mode: 0644]
include/linux/mfd/abx500/ab8500-gpadc.h [new file with mode: 0644]
include/linux/mfd/abx500/ab8500-gpio.h [new file with mode: 0644]
include/linux/mfd/abx500/ab8500-sysctrl.h [new file with mode: 0644]
include/linux/mfd/abx500/ab8500.h [new file with mode: 0644]
include/linux/mfd/max8925.h
include/linux/mfd/max8997.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/mcp.h
include/linux/mfd/s5m87xx/s5m-core.h [new file with mode: 0644]
include/linux/mfd/s5m87xx/s5m-pmic.h [new file with mode: 0644]
include/linux/mfd/s5m87xx/s5m-rtc.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/mfd/ucb1x00.h
include/linux/mfd/wm8994/core.h
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/registers.h
include/linux/migrate.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmc/card.h
include/linux/mmc/cd-gpio.h [new file with mode: 0644]
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci-pci-data.h [new file with mode: 0644]
include/linux/mmc/sdhci.h
include/linux/mmc/sdio.h
include/linux/mmzone.h
include/linux/mod_devicetable.h
include/linux/mpi.h [new file with mode: 0644]
include/linux/nfs_fs_sb.h
include/linux/nfs_idmap.h
include/linux/nfs_xdr.h
include/linux/oom.h
include/linux/page-debug-flags.h
include/linux/page_cgroup.h
include/linux/pagevec.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/pci_regs.h
include/linux/pda_power.h
include/linux/phy.h
include/linux/pid_namespace.h
include/linux/pkt_sched.h
include/linux/power/bq20z75.h [deleted file]
include/linux/power/charger-manager.h [new file with mode: 0644]
include/linux/power/sbs-battery.h [new file with mode: 0644]
include/linux/power_supply.h
include/linux/prctl.h
include/linux/proc_fs.h
include/linux/radix-tree.h
include/linux/rmap.h
include/linux/s3c_adc_battery.h
include/linux/sched.h
include/linux/security.h
include/linux/serial_sci.h
include/linux/sh_clk.h
include/linux/sh_pfc.h
include/linux/sigma.h [deleted file]
include/linux/signal.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/auth_gss.h
include/linux/sunrpc/xdr.h
include/linux/swap.h
include/linux/virtio.h
include/linux/virtio_ring.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/9p/9p.h
include/net/bluetooth/hci_core.h
include/net/red.h
include/sound/Kbuild
include/sound/compress_driver.h [new file with mode: 0644]
include/sound/compress_offload.h [new file with mode: 0644]
include/sound/compress_params.h [new file with mode: 0644]
include/sound/control.h
include/sound/core.h
include/sound/minors.h
include/sound/sh_fsi.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sta32x.h [new file with mode: 0644]
include/sound/wm8903.h
include/trace/events/ext4.h
include/trace/events/kmem.h
include/trace/events/oom.h [new file with mode: 0644]
include/trace/events/task.h [new file with mode: 0644]
include/trace/events/vmscan.h
include/trace/events/writeback.h
init/Kconfig
init/calibrate.c
init/do_mounts.c
init/main.c
ipc/mqueue.c
kernel/exit.c
kernel/fork.c
kernel/kexec.c
kernel/kprobes.c
kernel/panic.c
kernel/pid.c
kernel/pid_namespace.c
kernel/power/snapshot.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/signal.c
kernel/sys.c
kernel/sysctl.c
kernel/workqueue.c
lib/Kconfig
lib/Makefile
lib/btree.c
lib/crc32.c
lib/decompress_unlzo.c
lib/devres.c
lib/digsig.c [new file with mode: 0644]
lib/iomap.c
lib/mpi/Makefile [new file with mode: 0644]
lib/mpi/generic_mpi-asm-defs.h [new file with mode: 0644]
lib/mpi/generic_mpih-add1.c [new file with mode: 0644]
lib/mpi/generic_mpih-lshift.c [new file with mode: 0644]
lib/mpi/generic_mpih-mul1.c [new file with mode: 0644]
lib/mpi/generic_mpih-mul2.c [new file with mode: 0644]
lib/mpi/generic_mpih-mul3.c [new file with mode: 0644]
lib/mpi/generic_mpih-rshift.c [new file with mode: 0644]
lib/mpi/generic_mpih-sub1.c [new file with mode: 0644]
lib/mpi/longlong.h [new file with mode: 0644]
lib/mpi/mpi-add.c [new file with mode: 0644]
lib/mpi/mpi-bit.c [new file with mode: 0644]
lib/mpi/mpi-cmp.c [new file with mode: 0644]
lib/mpi/mpi-div.c [new file with mode: 0644]
lib/mpi/mpi-gcd.c [new file with mode: 0644]
lib/mpi/mpi-inline.c [new file with mode: 0644]
lib/mpi/mpi-inline.h [new file with mode: 0644]
lib/mpi/mpi-internal.h [new file with mode: 0644]
lib/mpi/mpi-inv.c [new file with mode: 0644]
lib/mpi/mpi-mpow.c [new file with mode: 0644]
lib/mpi/mpi-mul.c [new file with mode: 0644]
lib/mpi/mpi-pow.c [new file with mode: 0644]
lib/mpi/mpi-scan.c [new file with mode: 0644]
lib/mpi/mpicoder.c [new file with mode: 0644]
lib/mpi/mpih-cmp.c [new file with mode: 0644]
lib/mpi/mpih-div.c [new file with mode: 0644]
lib/mpi/mpih-mul.c [new file with mode: 0644]
lib/mpi/mpiutil.c [new file with mode: 0644]
lib/pci_iomap.c [new file with mode: 0644]
lib/radix-tree.c
mm/Kconfig.debug
mm/bootmem.c
mm/compaction.c
mm/debug-pagealloc.c
mm/fadvise.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c
mm/mmap.c
mm/mremap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_cgroup.c
mm/rmap.c
mm/slab.c
mm/slub.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/9p/client.c
net/9p/error.c
net/9p/mod.c
net/9p/protocol.c
net/9p/trans_fd.c
net/9p/trans_rdma.c
net/9p/trans_virtio.c
net/9p/util.c
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/ceph/crush/mapper.c
net/ceph/crypto.c
net/ceph/osd_client.c
net/core/net-sysfs.c
net/core/netpoll.c
net/dccp/diag.c
net/decnet/dn_dev.c
net/ipv4/devinet.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/inet_diag.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_memcontrol.c
net/ipv4/udp_diag.c
net/ipv6/addrconf.c
net/ipv6/ip6_tunnel.c
net/ipv6/raw.c
net/ipv6/sit.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/sta_info.c
net/mac80211/wpa.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_log.c
net/netfilter/nf_queue.c
net/netfilter/nfnetlink.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_unlabeled.c
net/phonet/af_phonet.c
net/phonet/pn_dev.c
net/phonet/socket.c
net/rds/iw_rdma.c
net/sched/sch_sfq.c
net/socket.c
net/sunrpc/auth_generic.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/xdr.c
net/wireless/nl80211.c
net/xfrm/xfrm_user.c
scripts/checkpatch.pl
scripts/get_maintainer.pl
scripts/mod/file2alias.c
security/apparmor/audit.c
security/apparmor/lsm.c
security/inode.c
security/integrity/Kconfig
security/integrity/Makefile
security/integrity/digsig.c [new file with mode: 0644]
security/integrity/evm/evm.h
security/integrity/evm/evm_crypto.c
security/integrity/evm/evm_main.c
security/integrity/ima/ima_api.c
security/integrity/ima/ima_queue.c
security/integrity/integrity.h
security/keys/key.c
security/selinux/selinuxfs.c
security/selinux/ss/conditional.c
security/tomoyo/.gitignore [new file with mode: 0644]
security/tomoyo/common.h
sound/arm/pxa2xx-ac97.c
sound/core/Kconfig
sound/core/Makefile
sound/core/compress_offload.c [new file with mode: 0644]
sound/core/ctljack.c [new file with mode: 0644]
sound/core/oss/pcm_oss.c
sound/core/seq/seq_dummy.c
sound/core/sound.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mts64.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl3/opl3_seq.c
sound/drivers/pcsp/pcsp.c
sound/drivers/pcsp/pcsp_lib.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1848/ad1848.c
sound/isa/adlib.c
sound/isa/als100.c
sound/isa/azt2320.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/es18xx.c
sound/isa/galaxy/galaxy.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/msnd/msnd_pinnacle.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/jazz16.c
sound/isa/sb/sb16.c
sound/isa/sb/sb8.c
sound/isa/sc6000.c
sound/isa/wavefront/wavefront.c
sound/mips/hal2.c
sound/mips/sgio2audio.c
sound/oss/ad1848.c
sound/oss/msnd_pinnacle.c
sound/oss/pas2_card.c
sound/oss/pss.c
sound/oss/trix.c
sound/pci/ac97/ac97_codec.c
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpi.h
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6000.h
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpi_internal.h
sound/pci/asihpi/hpi_version.h [new file with mode: 0644]
sound/pci/asihpi/hpicmn.c
sound/pci/asihpi/hpicmn.h
sound/pci/asihpi/hpidebug.c
sound/pci/asihpi/hpidebug.h
sound/pci/asihpi/hpidspcd.c
sound/pci/asihpi/hpidspcd.h
sound/pci/asihpi/hpifunc.c
sound/pci/asihpi/hpimsginit.c
sound/pci/asihpi/hpimsginit.h
sound/pci/asihpi/hpimsgx.c
sound/pci/asihpi/hpimsgx.h
sound/pci/asihpi/hpioctl.c
sound/pci/asihpi/hpioctl.h
sound/pci/asihpi/hpios.c
sound/pci/asihpi/hpios.h
sound/pci/asihpi/hpipcida.h
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/au88x0/au88x0_core.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/au88x0/au88x0_xtalk.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/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/ctsrc.c
sound/pci/ctxfi/cttimer.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.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/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/alc262_quirks.c [deleted file]
sound/pci/hda/alc880_quirks.c
sound/pci/hda/alc882_quirks.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c [new file with mode: 0644]
sound/pci/hda/hda_jack.h [new file with mode: 0644]
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/amp.c
sound/pci/ice1712/envy24ht.h
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/lola/lola.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/virtuoso.c
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_dg.c
sound/pci/oxygen/xonar_wm87x6.c
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.c
sound/pcmcia/vx/vxpocket.c
sound/ppc/powermac.c
sound/sh/aica.c
sound/sh/sh_dac_audio.c
sound/soc/Kconfig
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/atmel/snd-soc-afeb9260.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/db1000.c
sound/soc/au1x/db1200.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/dma.c
sound/soc/au1x/i2sc.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bfin-eval-adau1373.c
sound/soc/blackfin/bfin-eval-adau1701.c
sound/soc/blackfin/bfin-eval-adav80x.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ads117x.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c [new file with mode: 0644]
sound/soc/codecs/alc5632.h [new file with mode: 0644]
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l73.c [new file with mode: 0644]
sound/soc/codecs/cs42l73.h [new file with mode: 0644]
sound/soc/codecs/cx20442.c
sound/soc/codecs/da7210.c
sound/soc/codecs/dfbmcs320.c
sound/soc/codecs/dmic.c
sound/soc/codecs/jz4740.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max9850.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sigmadsp.c [new file with mode: 0644]
sound/soc/codecs/sigmadsp.h [new file with mode: 0644]
sound/soc/codecs/sn95031.c
sound/soc/codecs/spdif_transciever.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/twl6040.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm1250-ev1.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm5100-tables.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5100.h
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8727.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8782.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994-tables.c [deleted file]
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-sffsdr.c
sound/soc/davinci/davinci-vcif.c
sound/soc/ep93xx/edb93xx.c
sound/soc/ep93xx/ep93xx-ac97.c
sound/soc/ep93xx/ep93xx-i2s.c
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/ep93xx/simone.c
sound/soc/ep93xx/snappercl15.c
sound/soc/fsl/efika-audio-fabric.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/p1022_ds.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/imx/eukrea-tlv320.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-pcm-fiq.c
sound/soc/imx/imx-ssi.c
sound/soc/imx/mx27vis-aic32x4.c
sound/soc/imx/phycore-ac97.c
sound/soc/imx/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/jz4740-pcm.c
sound/soc/jz4740/qi_lb60.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/kirkwood/kirkwood-t5325.c
sound/soc/kirkwood/kirkwood.h
sound/soc/mid-x86/Kconfig
sound/soc/mid-x86/mfld_machine.c
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/nuc900/nuc900-audio.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/igep0020.c
sound/soc/omap/n810.c
sound/soc/omap/omap-dmic.c [new file with mode: 0644]
sound/soc/omap/omap-dmic.h [new file with mode: 0644]
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap3evm.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/omap4-hdmi-card.c
sound/soc/omap/osk5912.c
sound/soc/omap/overo.c
sound/soc/omap/rx51.c
sound/soc/omap/sdp3430.c
sound/soc/omap/sdp4430.c
sound/soc/omap/zoom2.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/imote2.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/raumfeld.c
sound/soc/pxa/saarb.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tavorevb3.c
sound/soc/pxa/tosa.c
sound/soc/pxa/z2.c
sound/soc/pxa/zylonite.c
sound/soc/s6000/s6000-i2s.c
sound/soc/s6000/s6000-pcm.c
sound/soc/s6000/s6105-ipcam.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/ac97.c
sound/soc/samsung/dma.c
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/idma.h
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/littlemill.c [new file with mode: 0644]
sound/soc/samsung/ln2440sbc_alc650.c
sound/soc/samsung/lowland.c [new file with mode: 0644]
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/pcm.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/s3c24xx_simtec_hermes.c
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk2443_wm9710.c
sound/soc/samsung/smdk_spdif.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/samsung/smdk_wm9713.c
sound/soc/samsung/spdif.c
sound/soc/samsung/speyside.c
sound/soc/samsung/speyside_wm8962.c [deleted file]
sound/soc/samsung/tobermory.c [new file with mode: 0644]
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi-ak4642.c
sound/soc/sh/fsi-da7210.c
sound/soc/sh/fsi-hdmi.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/migor.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/siu_dai.c
sound/soc/sh/ssi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra_alc5632.c [new file with mode: 0644]
sound/soc/tegra/tegra_das.c
sound/soc/tegra/tegra_i2s.c
sound/soc/tegra/tegra_i2s.h
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_spdif.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/trimslice.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/txx9/txx9aclc-generic.c
sound/soc/txx9/txx9aclc.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/usb/6fire/chip.c
sound/usb/caiaq/device.c
sound/usb/card.c
sound/usb/endpoint.c
sound/usb/format.c
sound/usb/misc/ua101.c
sound/usb/quirks-table.h
sound/usb/usx2y/us122l.c
sound/usb/usx2y/usb_stream.c
sound/usb/usx2y/usbusx2y.c
tools/lguest/.gitignore [new file with mode: 0644]
tools/lguest/Makefile [new file with mode: 0644]
tools/lguest/extract [new file with mode: 0644]
tools/lguest/lguest.c [new file with mode: 0644]
tools/lguest/lguest.txt [new file with mode: 0644]
tools/perf/Documentation/examples.txt
tools/testing/selftests/Makefile [new file with mode: 0644]
tools/testing/selftests/breakpoints/Makefile [new file with mode: 0644]
tools/testing/selftests/breakpoints/breakpoint_test.c [new file with mode: 0644]
tools/testing/selftests/run_tests [new file with mode: 0644]
tools/virtio/linux/virtio.h
tools/virtio/virtio_test.c

diff --git a/Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration b/Documentation/ABI/testing/sysfs-class-rtc-rtc0-device-rtc_calibration
new file mode 100644 (file)
index 0000000..4cf1e72
--- /dev/null
@@ -0,0 +1,12 @@
+What:           Attribute for calibrating ST-Ericsson AB8500 Real Time Clock
+Date:           Oct 2011
+KernelVersion:  3.0
+Contact:        Mark Godfrey <mark.godfrey@stericsson.com>
+Description:    The rtc_calibration attribute allows the userspace to
+                calibrate the AB8500.s 32KHz Real Time Clock.
+                Every 60 seconds the AB8500 will correct the RTC's value
+                by adding to it the value of this attribute.
+                The range of the attribute is -127 to +127 in units of
+                30.5 micro-seconds (half-parts-per-million of the 32KHz clock)
+Users:          The /vendor/st-ericsson/base_utilities/core/rtc_calibration
+                daemon uses this interface.
index 8b093f8222d318e411113735f7e841c4b52e7ae0..91bd6ca5440f32dbe724c994728a2bee18060692 100644 (file)
@@ -346,6 +346,10 @@ Description:
                number of objects per slab.  If a slab cannot be allocated
                because of fragmentation, SLUB will retry with the minimum order
                possible depending on its characteristics.
+               When debug_guardpage_minorder=N (N > 0) parameter is specified
+               (see Documentation/kernel-parameters.txt), the minimum possible
+               order is used and this sysfs entry can not be used to change
+               the order at run time.
 
 What:          /sys/kernel/slab/cache/order_fallback
 Date:          April 2008
index 5de23c00707828100ce750260ec71e727567d828..cab4ec58e46e6570be19d7f343bfc5671804684f 100644 (file)
   /* SNDRV_CARDS: maximum number of cards supported by this module */
   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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
   /* definition of the chip-specific record */
   struct mychip {
index 4d8774f6f48abd7aaf59e48335a1d0b9415832cd..4c95c0034a4bbbffdae12a99ff2ddbd0798ca09c 100644 (file)
@@ -61,7 +61,7 @@ Brief summary of control files.
  memory.failcnt                         # show the number of memory usage hits limits
  memory.memsw.failcnt           # show the number of memory+Swap hits limits
  memory.max_usage_in_bytes      # show max memory usage recorded
- memory.memsw.usage_in_bytes    # show max memory+Swap usage recorded
+ memory.memsw.max_usage_in_bytes # show max memory+Swap usage recorded
  memory.soft_limit_in_bytes     # set/show soft limit of memory usage
  memory.stat                    # show various statistics
  memory.use_hierarchy           # set/show hierarchical account enabled
@@ -410,8 +410,11 @@ memory.stat file includes following statistics
 cache          - # of bytes of page cache memory.
 rss            - # of bytes of anonymous and swap cache memory.
 mapped_file    - # of bytes of mapped file (includes tmpfs/shmem)
-pgpgin         - # of pages paged in (equivalent to # of charging events).
-pgpgout                - # of pages paged out (equivalent to # of uncharging events).
+pgpgin         - # of charging events to the memory cgroup. The charging
+               event happens each time a page is accounted as either mapped
+               anon page(RSS) or cache page(Page Cache) to the cgroup.
+pgpgout                - # of uncharging events to the memory cgroup. The uncharging
+               event happens each time a page is unaccounted from the cgroup.
 swap           - # of bytes of swap usage
 inactive_anon  - # of bytes of anonymous memory and swap cache memory on
                LRU list.
diff --git a/Documentation/devicetree/bindings/c6x/clocks.txt b/Documentation/devicetree/bindings/c6x/clocks.txt
new file mode 100644 (file)
index 0000000..a04f5fd
--- /dev/null
@@ -0,0 +1,40 @@
+C6X PLL Clock Controllers
+-------------------------
+
+This is a first-cut support for the SoC clock controllers. This is still
+under development and will probably change as the common device tree
+clock support is added to the kernel.
+
+Required properties:
+
+- compatible: "ti,c64x+pll"
+    May also have SoC-specific value to support SoC-specific initialization
+    in the driver. One of:
+        "ti,c6455-pll"
+        "ti,c6457-pll"
+        "ti,c6472-pll"
+        "ti,c6474-pll"
+
+- reg: base address and size of register area
+- clock-frequency: input clock frequency in hz
+
+
+Optional properties:
+
+- ti,c64x+pll-bypass-delay: CPU cycles to delay when entering bypass mode
+
+- ti,c64x+pll-reset-delay:  CPU cycles to delay after PLL reset
+
+- ti,c64x+pll-lock-delay:   CPU cycles to delay after PLL frequency change
+
+Example:
+
+       clock-controller@29a0000 {
+               compatible = "ti,c6472-pll", "ti,c64x+pll";
+               reg = <0x029a0000 0x200>;
+               clock-frequency = <25000000>;
+
+               ti,c64x+pll-bypass-delay = <200>;
+               ti,c64x+pll-reset-delay = <12000>;
+               ti,c64x+pll-lock-delay = <80000>;
+       };
diff --git a/Documentation/devicetree/bindings/c6x/dscr.txt b/Documentation/devicetree/bindings/c6x/dscr.txt
new file mode 100644 (file)
index 0000000..d847758
--- /dev/null
@@ -0,0 +1,127 @@
+Device State Configuration Registers
+------------------------------------
+
+TI C6X SoCs contain a region of miscellaneous registers which provide various
+function for SoC control or status. Details vary considerably among from SoC
+to SoC with no two being alike.
+
+In general, the Device State Configuraion Registers (DSCR) will provide one or
+more configuration registers often protected by a lock register where one or
+more key values must be written to a lock register in order to unlock the
+configuration register for writes. These configuration register may be used to
+enable (and disable in some cases) SoC pin drivers, select peripheral clock
+sources (internal or pin), etc. In some cases, a configuration register is
+write once or the individual bits are write once. In addition to device config,
+the DSCR block may provide registers which which are used to reset peripherals,
+provide device ID information, provide ethernet MAC addresses, as well as other
+miscellaneous functions.
+
+For device state control (enable/disable), each device control is assigned an
+id which is used by individual device drivers to control the state as needed.
+
+Required properties:
+
+- compatible: must be "ti,c64x+dscr"
+- reg: register area base and size
+
+Optional properties:
+
+  NOTE: These are optional in that not all SoCs will have all properties. For
+        SoCs which do support a given property, leaving the property out of the
+        device tree will result in reduced functionality or possibly driver
+        failure.
+
+- ti,dscr-devstat
+    offset of the devstat register
+
+- ti,dscr-silicon-rev
+    offset, start bit, and bitsize of silicon revision field
+
+- ti,dscr-rmii-resets
+    offset and bitmask of RMII reset field. May have multiple tuples if more
+    than one ethernet port is available.
+
+- ti,dscr-locked-regs
+    possibly multiple tuples describing registers which are write protected by
+    a lock register. Each tuple consists of the register offset, lock register
+    offsset, and the key value used to unlock the register.
+
+- ti,dscr-kick-regs
+    offset and key values of two "kick" registers used to write protect other
+    registers in DSCR. On SoCs using kick registers, the first key must be
+    written to the first kick register and the second key must be written to
+    the second register before other registers in the area are write-enabled.
+
+- ti,dscr-mac-fuse-regs
+    MAC addresses are contained in two registers. Each element of a MAC address
+    is contained in a single byte. This property has two tuples. Each tuple has
+    a register offset and four cells representing bytes in the register from
+    most significant to least. The value of these four cells is the MAC byte
+    index (1-6) of the byte within the register. A value of 0 means the byte
+    is unused in the MAC address.
+
+- ti,dscr-devstate-ctl-regs
+    This property describes the bitfields used to control the state of devices.
+    Each tuple describes a range of identical bitfields used to control one or
+    more devices (one bitfield per device). The layout of each tuple is:
+
+        start_id num_ids reg enable disable start_bit nbits
+
+    Where:
+        start_id is device id for the first device control in the range
+        num_ids is the number of device controls in the range
+        reg is the offset of the register holding the control bits
+        enable is the value to enable a device
+        disable is the value to disable a device (0xffffffff if cannot disable)
+        start_bit is the bit number of the first bit in the range
+        nbits is the number of bits per device control
+
+- ti,dscr-devstate-stat-regs
+    This property describes the bitfields used to provide device state status
+    for device states controlled by the DSCR. Each tuple describes a range of
+    identical bitfields used to provide status for one or more devices (one
+    bitfield per device). The layout of each tuple is:
+
+        start_id num_ids reg enable disable start_bit nbits
+
+    Where:
+        start_id is device id for the first device status in the range
+        num_ids is the number of devices covered by the range
+        reg is the offset of the register holding the status bits
+        enable is the value indicating device is enabled
+        disable is the value indicating device is disabled
+        start_bit is the bit number of the first bit in the range
+        nbits is the number of bits per device status
+
+- ti,dscr-privperm
+    Offset and default value for register used to set access privilege for
+    some SoC devices.
+
+
+Example:
+
+       device-state-config-regs@2a80000 {
+               compatible = "ti,c64x+dscr";
+               reg = <0x02a80000 0x41000>;
+
+               ti,dscr-devstat = <0>;
+               ti,dscr-silicon-rev = <8 28 0xf>;
+               ti,dscr-rmii-resets = <0x40020 0x00040000>;
+
+               ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
+               ti,dscr-devstate-ctl-regs =
+                        <0 12 0x40008 1 0  0  2
+                         12 1 0x40008 3 0 30  2
+                         13 2 0x4002c 1 0xffffffff 0 1>;
+               ti,dscr-devstate-stat-regs =
+                       <0 10 0x40014 1 0  0  3
+                        10 2 0x40018 1 0  0  3>;
+
+               ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
+                                        0x704 5 6 0 0>;
+
+               ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
+
+               ti,dscr-kick-regs = <0x38 0x83E70B13
+                                    0x3c 0x95A4F1E0>;
+       };
diff --git a/Documentation/devicetree/bindings/c6x/emifa.txt b/Documentation/devicetree/bindings/c6x/emifa.txt
new file mode 100644 (file)
index 0000000..0ff6e9b
--- /dev/null
@@ -0,0 +1,62 @@
+External Memory Interface
+-------------------------
+
+The emifa node describes a simple external bus controller found on some C6X
+SoCs. This interface provides external busses with a number of chip selects.
+
+Required properties:
+
+- compatible: must be "ti,c64x+emifa", "simple-bus"
+- reg: register area base and size
+- #address-cells: must be 2 (chip-select + offset)
+- #size-cells: must be 1
+- ranges: mapping from EMIFA space to parent space
+
+
+Optional properties:
+
+- ti,dscr-dev-enable: Device ID if EMIF is enabled/disabled from DSCR
+
+- ti,emifa-burst-priority:
+      Number of memory transfers after which the EMIF will elevate the priority
+      of the oldest command in the command FIFO. Setting this field to 255
+      disables this feature, thereby allowing old commands to stay in the FIFO
+      indefinitely.
+
+- ti,emifa-ce-config:
+      Configuration values for each of the supported chip selects.
+
+Example:
+
+       emifa@70000000 {
+               compatible = "ti,c64x+emifa", "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <0x70000000 0x100>;
+               ranges = <0x2 0x0 0xa0000000 0x00000008
+                         0x3 0x0 0xb0000000 0x00400000
+                         0x4 0x0 0xc0000000 0x10000000
+                         0x5 0x0 0xD0000000 0x10000000>;
+
+               ti,dscr-dev-enable = <13>;
+               ti,emifa-burst-priority = <255>;
+               ti,emifa-ce-config = <0x00240120
+                                     0x00240120
+                                     0x00240122
+                                     0x00240122>;
+
+               flash@3,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x3 0x0 0x400000>;
+                       bank-width = <1>;
+                       device-width = <1>;
+                       partition@0 {
+                               reg = <0x0 0x400000>;
+                               label = "NOR";
+                       };
+               };
+       };
+
+This shows a flash chip attached to chip select 3.
diff --git a/Documentation/devicetree/bindings/c6x/interrupt.txt b/Documentation/devicetree/bindings/c6x/interrupt.txt
new file mode 100644 (file)
index 0000000..42bb796
--- /dev/null
@@ -0,0 +1,104 @@
+C6X Interrupt Chips
+-------------------
+
+* C64X+ Core Interrupt Controller
+
+  The core interrupt controller provides 16 prioritized interrupts to the
+  C64X+ core. Priority 0 and 1 are used for reset and NMI respectively.
+  Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt
+  sources coming from outside the core.
+
+  Required properties:
+  --------------------
+  - compatible: Should be "ti,c64x+core-pic";
+  - #interrupt-cells: <1>
+
+  Interrupt Specifier Definition
+  ------------------------------
+  Single cell specifying the core interrupt priority level (4-15) where
+  4 is highest priority and 15 is lowest priority.
+
+  Example
+  -------
+  core_pic: interrupt-controller@0 {
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       compatible = "ti,c64x+core-pic";
+  };
+
+
+
+* C64x+ Megamodule Interrupt Controller
+
+  The megamodule PIC consists of four interrupt mupliplexers each of which
+  combine up to 32 interrupt inputs into a single interrupt output which
+  may be cascaded into the core interrupt controller. The megamodule PIC
+  has a total of 12 outputs cascading into the core interrupt controller.
+  One for each core interrupt priority level. In addition to the combined
+  interrupt sources, individual megamodule interrupts may be cascaded to
+  the core interrupt controller. When an individual interrupt is cascaded,
+  it is no longer handled through a megamodule interrupt combiner and is
+  considered to have the core interrupt controller as the parent.
+
+  Required properties:
+  --------------------
+  - compatible: "ti,c64x+megamod-pic"
+  - interrupt-controller
+  - #interrupt-cells: <1>
+  - reg: base address and size of register area
+  - interrupt-parent: must be core interrupt controller
+  - interrupts: This should have four cells; one for each interrupt combiner.
+                The cells contain the core priority interrupt to which the
+                corresponding combiner output is wired.
+
+  Optional properties:
+  --------------------
+  - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core
+                             priority interrupts. The first cell corresponds to
+                             core priority 4 and the last cell corresponds to
+                             core priority 15. The value of each cell is the
+                             megamodule interrupt source which is MUXed to
+                             the core interrupt corresponding to the cell
+                             position. Allowed values are 4 - 127. Mapping for
+                             interrupts 0 - 3 (combined interrupt sources) are
+                             ignored.
+
+  Interrupt Specifier Definition
+  ------------------------------
+  Single cell specifying the megamodule interrupt source (4-127). Note that
+  interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will
+  use the core interrupt controller as their parent and the specifier will
+  be the core priority level, not the megamodule interrupt number.
+
+  Examples
+  --------
+  megamod_pic: interrupt-controller@1800000 {
+       compatible = "ti,c64x+megamod-pic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       reg = <0x1800000 0x1000>;
+       interrupt-parent = <&core_pic>;
+       interrupts = < 12 13 14 15 >;
+  };
+
+  This is a minimal example where all individual interrupts go through a
+  combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped
+  to interrupt 13, etc.
+
+
+  megamod_pic: interrupt-controller@1800000 {
+       compatible = "ti,c64x+megamod-pic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+       reg = <0x1800000 0x1000>;
+       interrupt-parent = <&core_pic>;
+       interrupts = < 12 13 14 15 >;
+       ti,c64x+megamod-pic-mux = <  0  0  0  0
+                                    32  0  0  0
+                                     0  0  0  0 >;
+  };
+
+  This the same as the first example except that megamodule interrupt 32 is
+  mapped directly to core priority interrupt 8. The node using this interrupt
+  must set the core controller as its interrupt parent and use 8 in the
+  interrupt specifier value.
diff --git a/Documentation/devicetree/bindings/c6x/soc.txt b/Documentation/devicetree/bindings/c6x/soc.txt
new file mode 100644 (file)
index 0000000..b1e4973
--- /dev/null
@@ -0,0 +1,28 @@
+C6X System-on-Chip
+------------------
+
+Required properties:
+
+- compatible: "simple-bus"
+- #address-cells: must be 1
+- #size-cells: must be 1
+- ranges
+
+Optional properties:
+
+- model: specific SoC model
+
+- nodes for IP blocks within SoC
+
+
+Example:
+
+       soc {
+               compatible = "simple-bus";
+               model = "tms320c6455";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/c6x/timer64.txt b/Documentation/devicetree/bindings/c6x/timer64.txt
new file mode 100644 (file)
index 0000000..95911fe
--- /dev/null
@@ -0,0 +1,26 @@
+Timer64
+-------
+
+The timer64 node describes C6X event timers.
+
+Required properties:
+
+- compatible: must be "ti,c64x+timer64"
+- reg: base address and size of register region
+- interrupt-parent: interrupt controller
+- interrupts: interrupt id
+
+Optional properties:
+
+- ti,dscr-dev-enable: Device ID used to enable timer IP through DSCR interface.
+
+- ti,core-mask: on multi-core SoCs, bitmask of cores allowed to use this timer.
+
+Example:
+       timer0: timer@25e0000 {
+               compatible = "ti,c64x+timer64";
+               ti,core-mask = < 0x01 >;
+               reg = <0x25e0000 0x40>;
+               interrupt-parent = <&megamod_pic>;
+               interrupts = < 16 >;
+       };
diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
new file mode 100644 (file)
index 0000000..19f6af4
--- /dev/null
@@ -0,0 +1,78 @@
+* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC)
+
+Required properties:
+- compatible : Should be "fsl,mc13783" or "fsl,mc13892"
+
+Optional properties:
+- fsl,mc13xxx-uses-adc : Indicate the ADC is being used
+- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used
+- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used
+- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
+
+Sub-nodes:
+- regulators : Contain the regulator nodes.  The MC13892 regulators are
+  bound using their names as listed below with their registers and bits
+  for enabling.
+
+    vcoincell : regulator VCOINCELL (register 13, bit 23)
+    sw1       : regulator SW1      (register 24, bit 0)
+    sw2       : regulator SW2      (register 25, bit 0)
+    sw3       : regulator SW3      (register 26, bit 0)
+    sw4       : regulator SW4      (register 27, bit 0)
+    swbst     : regulator SWBST            (register 29, bit 20)
+    vgen1     : regulator VGEN1            (register 32, bit 0)
+    viohi     : regulator VIOHI            (register 32, bit 3)
+    vdig      : regulator VDIG     (register 32, bit 9)
+    vgen2     : regulator VGEN2            (register 32, bit 12)
+    vpll      : regulator VPLL     (register 32, bit 15)
+    vusb2     : regulator VUSB2            (register 32, bit 18)
+    vgen3     : regulator VGEN3            (register 33, bit 0)
+    vcam      : regulator VCAM     (register 33, bit 6)
+    vvideo    : regulator VVIDEO    (register 33, bit 12)
+    vaudio    : regulator VAUDIO    (register 33, bit 15)
+    vsd       : regulator VSD      (register 33, bit 18)
+    gpo1      : regulator GPO1     (register 34, bit 6)
+    gpo2      : regulator GPO2     (register 34, bit 8)
+    gpo3      : regulator GPO3     (register 34, bit 10)
+    gpo4      : regulator GPO4     (register 34, bit 12)
+    pwgt1spi  : regulator PWGT1SPI  (register 34, bit 15)
+    pwgt2spi  : regulator PWGT2SPI  (register 34, bit 16)
+    vusb      : regulator VUSB     (register 50, bit 3)
+
+  The bindings details of individual regulator device can be found in:
+  Documentation/devicetree/bindings/regulator/regulator.txt
+
+Examples:
+
+ecspi@70010000 { /* ECSPI1 */
+       fsl,spi-num-chipselects = <2>;
+       cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
+                  <&gpio3 25 0>; /* GPIO4_25 */
+       status = "okay";
+
+       pmic: mc13892@0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mc13892";
+               spi-max-frequency = <6000000>;
+               reg = <0>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <8>;
+
+               regulators {
+                       sw1_reg: mc13892__sw1 {
+                               regulator-min-microvolt = <600000>;
+                               regulator-max-microvolt = <1375000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sw2_reg: mc13892__sw2 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1850000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mfd/twl-familly.txt b/Documentation/devicetree/bindings/mfd/twl-familly.txt
new file mode 100644 (file)
index 0000000..a66fcf9
--- /dev/null
@@ -0,0 +1,47 @@
+Texas Instruments TWL family
+
+The TWLs are Integrated Power Management Chips.
+Some version might contain much more analog function like
+USB transceiver or Audio amplifier.
+These chips are connected to an i2c bus.
+
+
+Required properties:
+- compatible : Must be "ti,twl4030";
+  For Integrated power-management/audio CODEC device used in OMAP3
+  based boards
+- compatible : Must be "ti,twl6030";
+  For Integrated power-management used in OMAP4 based boards
+- interrupts : This i2c device has an IRQ line connected to the main SoC
+- interrupt-controller : Since the twl support several interrupts internally,
+  it is considered as an interrupt controller cascaded to the SoC one.
+- #interrupt-cells = <1>;
+- interrupt-parent : The parent interrupt controller.
+
+Optional node:
+- Child nodes contain in the twl. The twl family is made of several variants
+  that support a different number of features.
+  The children nodes will thus depend of the capability of the variant.
+
+
+Example:
+/*
+ * Integrated Power Management Chip
+ * http://www.ti.com/lit/ds/symlink/twl6030.pdf
+ */
+twl@48 {
+    compatible = "ti,twl6030";
+    reg = <0x48>;
+    interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */
+    interrupt-controller;
+    #interrupt-cells = <1>;
+    interrupt-parent = <&gic>;
+    #address-cells = <1>;
+    #size-cells = <0>;
+
+    twl_rtc {
+        compatible = "ti,twl_rtc";
+        interrupts = <11>;
+        reg = <0>;
+    };
+};
diff --git a/Documentation/devicetree/bindings/power_supply/olpc_battery.txt b/Documentation/devicetree/bindings/power_supply/olpc_battery.txt
new file mode 100644 (file)
index 0000000..c8901b3
--- /dev/null
@@ -0,0 +1,5 @@
+OLPC battery
+~~~~~~~~~~~~
+
+Required properties:
+  - compatible : "olpc,xo1-battery"
diff --git a/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt b/Documentation/devicetree/bindings/power_supply/sbs_sbs-battery.txt
new file mode 100644 (file)
index 0000000..c40e892
--- /dev/null
@@ -0,0 +1,23 @@
+SBS sbs-battery
+~~~~~~~~~~
+
+Required properties :
+ - compatible : "sbs,sbs-battery"
+
+Optional properties :
+ - sbs,i2c-retry-count : The number of times to retry i2c transactions on i2c
+   IO failure.
+ - sbs,poll-retry-count : The number of times to try looking for new status
+   after an external change notification.
+ - sbs,battery-detect-gpios : The gpio which signals battery detection and
+   a flag specifying its polarity.
+
+Example:
+
+       bq20z75@b {
+               compatible = "sbs,sbs-battery";
+               reg = < 0xb >;
+               sbs,i2c-retry-count = <2>;
+               sbs,poll-retry-count = <10>;
+               sbs,battery-detect-gpios = <&gpio-controller 122 1>;
+       }
diff --git a/Documentation/devicetree/bindings/rtc/twl-rtc.txt b/Documentation/devicetree/bindings/rtc/twl-rtc.txt
new file mode 100644 (file)
index 0000000..596e0c9
--- /dev/null
@@ -0,0 +1,12 @@
+* TI twl RTC
+
+The TWL family (twl4030/6030) contains a RTC.
+
+Required properties:
+- compatible : Should be twl4030-rtc
+
+Examples:
+
+rtc@0 {
+    compatible = "ti,twl4030-rtc";
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt
new file mode 100644 (file)
index 0000000..d5b0da8
--- /dev/null
@@ -0,0 +1,71 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8903"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the WM8903's pins, and the jacks on the board:
+
+  WM8903 pins:
+
+  * IN1L
+  * IN1R
+  * IN2L
+  * IN2R
+  * IN3L
+  * IN3R
+  * DMICDAT
+  * HPOUTL
+  * HPOUTR
+  * LINEOUTL
+  * LINEOUTR
+  * LOP
+  * LON
+  * ROP
+  * RON
+  * MICBIAS
+
+  Board connectors:
+
+  * Headphone Jack
+  * Int Spk
+  * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Optional properties:
+- nvidia,spkr-en-gpios : The GPIO that enables the speakers
+- nvidia,hp-mute-gpios : The GPIO that mutes the headphones
+- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in
+- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone
+- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-wm8903-harmony",
+                    "nvidia,tegra-audio-wm8903"
+       nvidia,model = "tegra-wm8903-harmony";
+
+       nvidia,audio-routing =
+               "Headphone Jack", "HPOUTR",
+               "Headphone Jack", "HPOUTL",
+               "Int Spk", "ROP",
+               "Int Spk", "RON",
+               "Int Spk", "LOP",
+               "Int Spk", "LON",
+               "Mic Jack", "MICBIAS",
+               "IN1L", "Mic Jack";
+
+       nvidia,i2s-controller = <&i2s1>;
+       nvidia,audio-codec = <&wm8903>;
+
+       nvidia,spkr-en-gpios = <&codec 2 0>;
+       nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+       nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+       nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+};
+
diff --git a/Documentation/devicetree/bindings/sound/tegra20-das.txt b/Documentation/devicetree/bindings/sound/tegra20-das.txt
new file mode 100644 (file)
index 0000000..6de3a7e
--- /dev/null
@@ -0,0 +1,12 @@
+NVIDIA Tegra 20 DAS (Digital Audio Switch) controller
+
+Required properties:
+- compatible : "nvidia,tegra20-das"
+- reg : Should contain DAS registers location and length
+
+Example:
+
+das@70000c00 {
+       compatible = "nvidia,tegra20-das";
+       reg = <0x70000c00 0x80>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/tegra20-i2s.txt
new file mode 100644 (file)
index 0000000..0df2b5c
--- /dev/null
@@ -0,0 +1,17 @@
+NVIDIA Tegra 20 I2S controller
+
+Required properties:
+- compatible : "nvidia,tegra20-i2s"
+- reg : Should contain I2S registers location and length
+- interrupts : Should contain I2S interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+  request selector for this I2S controller
+
+Example:
+
+i2s@70002800 {
+       compatible = "nvidia,tegra20-i2s";
+       reg = <0x70002800 0x200>;
+       interrupts = < 45 >;
+       nvidia,dma-request-selector = < &apbdma 2 >;
+};
diff --git a/Documentation/devicetree/bindings/sound/wm8903.txt b/Documentation/devicetree/bindings/sound/wm8903.txt
new file mode 100644 (file)
index 0000000..f102cbc
--- /dev/null
@@ -0,0 +1,50 @@
+WM8903 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "wlf,wm8903"
+
+  - reg : the I2C address of the device.
+
+  - gpio-controller : Indicates this device is a GPIO controller.
+
+  - #gpio-cells : Should be two. The first cell is the pin number and the
+    second cell is used to specify optional parameters (currently unused).
+
+Optional properties:
+
+  - interrupts : The interrupt line the codec is connected to.
+
+  - micdet-cfg : Default register value for R6 (Mic Bias). If absent, the
+    default is 0.
+
+  - micdet-delay : The debounce delay for microphone detection in mS. If
+    absent, the default is 100.
+
+  - gpio-cfg : A list of GPIO configuration register values. The list must
+    be 5 entries long. If absent, no configuration of these registers is
+    performed. If any entry has the value 0xffffffff, that GPIO's
+    configuration will not be modified.
+
+Example:
+
+codec: wm8903@1a {
+       compatible = "wlf,wm8903";
+       reg = <0x1a>;
+       interrupts = < 347 >;
+
+       gpio-controller;
+       #gpio-cells = <2>;
+
+       micdet-cfg = <0>;
+       micdet-delay = <100>;
+       gpio-cfg = <
+               0x0600 /* DMIC_LR, output */
+               0x0680 /* DMIC_DAT, input */
+               0x0000 /* GPIO, output, low */
+               0x0200 /* Interrupt, output */
+               0x01a0 /* BCLK, input, active high */
+       >;
+};
diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt
new file mode 100644 (file)
index 0000000..7a7eb1e
--- /dev/null
@@ -0,0 +1,18 @@
+WM1811/WM8994/WM8958 audio CODEC
+
+These devices support both I2C and SPI (configured with pin strapping
+on the board).
+
+Required properties:
+
+  - compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958"
+
+  - reg : the I2C address of the device for I2C, the chip select
+          number for SPI.
+
+Example:
+
+codec: wm8994@1a {
+       compatible = "wlf,wm8994";
+       reg = <0x1a>;
+};
index 18626965159e06447b369a7f931075f8570c32c7..ecc6a6cd26c198ff412ce2af839cc3b602d73a29 100644 (file)
@@ -34,6 +34,7 @@ powervr       Imagination Technologies
 qcom   Qualcomm, Inc.
 ramtron        Ramtron International
 samsung        Samsung Semiconductor
+sbs    Smart Battery System
 schindler      Schindler
 sil    Silicon Image
 simtek
@@ -41,4 +42,5 @@ sirf  SiRF Technology, Inc.
 st     STMicroelectronics
 stericsson     ST-Ericsson
 ti     Texas Instruments
+wlf    Wolfson Microelectronics
 xlnx   Xilinx
diff --git a/Documentation/digsig.txt b/Documentation/digsig.txt
new file mode 100644 (file)
index 0000000..3f68288
--- /dev/null
@@ -0,0 +1,96 @@
+Digital Signature Verification API
+
+CONTENTS
+
+1. Introduction
+2. API
+3. User-space utilities
+
+
+1. Introduction
+
+Digital signature verification API provides a method to verify digital signature.
+Currently digital signatures are used by the IMA/EVM integrity protection subsystem.
+
+Digital signature verification is implemented using cut-down kernel port of
+GnuPG multi-precision integers (MPI) library. The kernel port provides
+memory allocation errors handling, has been refactored according to kernel
+coding style, and checkpatch.pl reported errors and warnings have been fixed.
+
+Public key and signature consist of header and MPIs.
+
+struct pubkey_hdr {
+       uint8_t         version;        /* key format version */
+       time_t          timestamp;      /* key made, always 0 for now */
+       uint8_t         algo;
+       uint8_t         nmpi;
+       char            mpi[0];
+} __packed;
+
+struct signature_hdr {
+       uint8_t         version;        /* signature format version */
+       time_t          timestamp;      /* signature made */
+       uint8_t         algo;
+       uint8_t         hash;
+       uint8_t         keyid[8];
+       uint8_t         nmpi;
+       char            mpi[0];
+} __packed;
+
+keyid equals to SHA1[12-19] over the total key content.
+Signature header is used as an input to generate a signature.
+Such approach insures that key or signature header could not be changed.
+It protects timestamp from been changed and can be used for rollback
+protection.
+
+2. API
+
+API currently includes only 1 function:
+
+       digsig_verify() - digital signature verification with public key
+
+
+/**
+ * digsig_verify() - digital signature verification with public key
+ * @keyring:   keyring to search key in
+ * @sig:       digital signature
+ * @sigen:     length of the signature
+ * @data:      data
+ * @datalen:   length of the data
+ * @return:    0 on success, -EINVAL otherwise
+ *
+ * Verifies data integrity against digital signature.
+ * Currently only RSA is supported.
+ * Normally hash of the content is used as a data for this function.
+ *
+ */
+int digsig_verify(struct key *keyring, const char *sig, int siglen,
+                                               const char *data, int datalen);
+
+3. User-space utilities
+
+The signing and key management utilities evm-utils provide functionality
+to generate signatures, to load keys into the kernel keyring.
+Keys can be in PEM or converted to the kernel format.
+When the key is added to the kernel keyring, the keyid defines the name
+of the key: 5D2B05FC633EE3E8 in the example bellow.
+
+Here is example output of the keyctl utility.
+
+$ keyctl show
+Session Keyring
+       -3 --alswrv      0     0  keyring: _ses
+603976250 --alswrv      0    -1   \_ keyring: _uid.0
+817777377 --alswrv      0     0       \_ user: kmk
+891974900 --alswrv      0     0       \_ encrypted: evm-key
+170323636 --alswrv      0     0       \_ keyring: _module
+548221616 --alswrv      0     0       \_ keyring: _ima
+128198054 --alswrv      0     0       \_ keyring: _evm
+
+$ keyctl list 128198054
+1 key in keyring:
+620789745: --alswrv     0     0 user: 5D2B05FC633EE3E8
+
+
+Dmitry Kasatkin
+06.10.2011
index 510eab32f392066233fba702b83a123ec6e2d9c4..225f96d88f55e055ff3f3c089f24b5f93d6d275b 100644 (file)
@@ -219,6 +219,10 @@ NOTES:
    If the exporter chooses not to allow an attach() operation once a
    map_dma_buf() API has been called, it simply returns an error.
 
+Miscellaneous notes:
+- Any exporters or users of the dma-buf buffer sharing framework must have
+  a 'select DMA_SHARED_BUFFER' in their respective Kconfigs.
+
 References:
 [1] struct dma_buf_ops in include/linux/dma-buf.h
 [2] All interfaces mentioned above defined in include/linux/dma-buf.h
index 5575759b84eedccead799d851499ec69c5da3d8d..d49c2ec72d12762ee01c2c9474bc573efb53c26a 100644 (file)
@@ -544,3 +544,15 @@ When:      3.5
 Why:   The iwlagn module has been renamed iwlwifi.  The alias will be around
        for backward compatibility for several cycles and then dropped.
 Who:   Don Fry <donald.h.fry@intel.com>
+
+----------------------------
+
+What:  pci_scan_bus_parented()
+When:  3.5
+Why:   The pci_scan_bus_parented() interface creates a new root bus.  The
+       bus is created with default resources (ioport_resource and
+       iomem_resource) that are always wrong, so we rely on arch code to
+       correct them later.  Callers of pci_scan_bus_parented() should
+       convert to using pci_scan_root_bus() so they can supply a list of
+       bus resources when the bus is created.
+Who:   Bjorn Helgaas <bhelgaas@google.com>
index 763d8ebbbebdeb59129742daa5f5b7a105ac8fbb..d6030aa3337605e7550397a303820952c8666bc8 100644 (file)
@@ -119,12 +119,20 @@ Mount Options
        must rely on TCP's error correction to detect data corruption
        in the data payload.
 
-  noasyncreaddir
-       Disable client's use its local cache to satisfy readdir
-       requests.  (This does not change correctness; the client uses
-       cached metadata only when a lease or capability ensures it is
-       valid.)
+  dcache
+        Use the dcache contents to perform negative lookups and
+        readdir when the client has the entire directory contents in
+        its cache.  (This does not change correctness; the client uses
+        cached metadata only when a lease or capability ensures it is
+        valid.)
+
+  nodcache
+        Do not use the dcache as above.  This avoids a significant amount of
+        complex code, sacrificing performance without affecting correctness,
+        and is useful for tracking down bugs.
 
+  noasyncreaddir
+       Do not use the dcache as above for readdir.
 
 More Information
 ================
index 4917cf24a5e0885518cf06a12e53d4057f5c91fa..10ec4639f1522dad34d66eea61443750435fe3ae 100644 (file)
@@ -581,6 +581,13 @@ Table of Ext4 specific ioctls
                              behaviour may change in the future as it is
                              not necessary and has been done this way only
                              for sake of simplicity.
+
+ EXT4_IOC_RESIZE_FS          Resize the filesystem to a new size.  The number
+                             of blocks of resized filesystem is passed in via
+                             64 bit integer argument.  The kernel allocates
+                             bitmaps and inode table, the userspace tool thus
+                             just passes the new number of blocks.
+
 ..............................................................................
 
 References
index 0ec91f03422e5befe8dd7f69d22dec4a22250f69..a76a26a1db8a6fe855b0eeea32dee251296c0c8a 100644 (file)
@@ -41,6 +41,8 @@ Table of Contents
   3.5  /proc/<pid>/mountinfo - Information about mounts
   3.6  /proc/<pid>/comm  & /proc/<pid>/task/<tid>/comm
 
+  4    Configuring procfs
+  4.1  Mount options
 
 ------------------------------------------------------------------------------
 Preface
@@ -305,6 +307,9 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
   blkio_ticks   time spent waiting for block IO
   gtime         guest time of the task in jiffies
   cgtime        guest time of the task children in jiffies
+  start_data    address above which program data+bss is placed
+  end_data      address below which program data+bss is placed
+  start_brk     address above which program heap can be expanded with brk()
 ..............................................................................
 
 The /proc/PID/maps file containing the currently mapped memory regions and
@@ -1542,3 +1547,40 @@ a task to set its own or one of its thread siblings comm value. The comm value
 is limited in size compared to the cmdline value, so writing anything longer
 then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated
 comm value.
+
+
+------------------------------------------------------------------------------
+Configuring procfs
+------------------------------------------------------------------------------
+
+4.1    Mount options
+---------------------
+
+The following mount options are supported:
+
+       hidepid=        Set /proc/<pid>/ access mode.
+       gid=            Set the group authorized to learn processes information.
+
+hidepid=0 means classic mode - everybody may access all /proc/<pid>/ directories
+(default).
+
+hidepid=1 means users may not access any /proc/<pid>/ directories but their
+own.  Sensitive files like cmdline, sched*, status are now protected against
+other users.  This makes it impossible to learn whether any user runs
+specific program (given the program doesn't reveal itself by its behaviour).
+As an additional bonus, as /proc/<pid>/cmdline is unaccessible for other users,
+poorly written programs passing sensitive information via program arguments are
+now protected against local eavesdroppers.
+
+hidepid=2 means hidepid=1 plus all /proc/<pid>/ will be fully invisible to other
+users.  It doesn't mean that it hides a fact whether a process with a specific
+pid value exists (it can be learned by other means, e.g. by "kill -0 $PID"),
+but it hides process' uid and gid, which may be learned by stat()'ing
+/proc/<pid>/ otherwise.  It greatly complicates an intruder's task of gathering
+information about running processes, whether some daemon runs with elevated
+privileges, whether other user runs some sensitive program, whether other users
+run any program at all, etc.
+
+gid= defines a group authorized to learn processes information otherwise
+prohibited by hidepid=.  If you use some daemon like identd which needs to learn
+information about processes information, just add identd to this group.
index 7db3ebda5a4c9afdbd1c4a7baffd039ad220933e..403c090aca39954d378809b55b0585f74085422c 100644 (file)
@@ -93,8 +93,8 @@ byte alignment:
 
 Compressed data blocks are written to the filesystem as files are read from
 the source directory, and checked for duplicates.  Once all file data has been
-written the completed inode, directory, fragment, export and uid/gid lookup
-tables are written.
+written the completed inode, directory, fragment, export, uid/gid lookup and
+xattr tables are written.
 
 3.1 Compression options
 -----------------------
@@ -151,7 +151,7 @@ in each metadata block.  Directories are sorted in alphabetical order,
 and at lookup the index is scanned linearly looking for the first filename
 alphabetically larger than the filename being looked up.  At this point the
 location of the metadata block the filename is in has been found.
-The general idea of the index is ensure only one metadata block needs to be
+The general idea of the index is to ensure only one metadata block needs to be
 decompressed to do a lookup irrespective of the length of the directory.
 This scheme has the advantage that it doesn't require extra memory overhead
 and doesn't require much extra storage on disk.
index 9373d95319c15754069f2af1600a7ef61aa31e17..eb93fd0ec734760224a16e87c2be8b391f604b55 100644 (file)
@@ -628,6 +628,25 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        no_debug_objects
                        [KNL] Disable object debugging
 
+       debug_guardpage_minorder=
+                       [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this
+                       parameter allows control of the order of pages that will
+                       be intentionally kept free (and hence protected) by the
+                       buddy allocator. Bigger value increase the probability
+                       of catching random memory corruption, but reduce the
+                       amount of memory for normal system use. The maximum
+                       possible value is MAX_ORDER/2.  Setting this parameter
+                       to 1 or 2 should be enough to identify most random
+                       memory corruption problems caused by bugs in kernel or
+                       driver code when a CPU writes to (or reads from) a
+                       random memory location. Note that there exists a class
+                       of memory corruptions problems caused by buggy H/W or
+                       F/W or by drivers badly programing DMA (basically when
+                       memory is written at bus level and the CPU MMU is
+                       bypassed) which are not detectable by
+                       CONFIG_DEBUG_PAGEALLOC, hence this option will not help
+                       tracking down these problems.
+
        debugpat        [X86] Enable PAT debugging
 
        decnet.addr=    [HW,NET]
@@ -1634,12 +1653,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        The default is to return 64-bit inode numbers.
 
        nfs.nfs4_disable_idmapping=
-                       [NFSv4] When set, this option disables the NFSv4
-                       idmapper on the client, but only if the mount
-                       is using the 'sec=sys' security flavour. This may
-                       make migration from legacy NFSv2/v3 systems easier
-                       provided that the server has the appropriate support.
-                       The default is to always enable NFSv4 idmapping.
+                       [NFSv4] When set to the default of '1', this option
+                       ensures that both the RPC level authentication
+                       scheme and the NFS level operations agree to use
+                       numeric uids/gids if the mount is using the
+                       'sec=sys' security flavour. In effect it is
+                       disabling idmapping, which can make migration from
+                       legacy NFSv2/v3 systems to NFSv4 easier.
+                       Servers that do not support this mode of operation
+                       will be autodetected by the client, and it will fall
+                       back to using the idmapper.
+                       To turn off this behaviour, set the value to '0'.
 
        nmi_debug=      [KNL,AVR32,SH] Specify one or more actions to take
                        when a NMI is triggered.
@@ -1800,6 +1824,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        nomfgpt         [X86-32] Disable Multi-Function General Purpose
                        Timer usage (for AMD Geode machines).
 
+       nonmi_ipi       [X86] Disable using NMI IPIs during panic/reboot to
+                       shutdown the other cpus.  Instead use the REBOOT_VECTOR
+                       irq.
+
        nopat           [X86] Disable PAT (page attribute table extension of
                        pagetables) support.
 
@@ -2371,6 +2399,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        slram=          [HW,MTD]
 
+       slab_max_order= [MM, SLAB]
+                       Determines the maximum allowed order for slabs.
+                       A high setting may cause OOMs due to memory
+                       fragmentation.  Defaults to 1 for systems with
+                       more than 32MB of RAM, 0 otherwise.
+
        slub_debug[=options[,slabs]]    [MM, SLUB]
                        Enabling slub_debug allows one to determine the
                        culprit if slab objects become corrupted. Enabling
index 8898a95b41e5ee1b277cd64697870726b11bc2fa..22ae8441489fcef3fe8f21ff4322dc3a8b85e5e6 100644 (file)
@@ -64,3 +64,13 @@ Note on Erase Size and Preferred Erase Size:
        size specified by the card.
 
        "preferred_erase_size" is in bytes.
+
+SD/MMC/SDIO Clock Gating Attribute
+==================================
+
+Read and write access is provided to following attribute.
+This attribute appears only if CONFIG_MMC_CLKGATE is enabled.
+
+       clkgate_delay   Tune the clock gating delay with desired value in milliseconds.
+
+echo <desired delay> > /sys/class/mmc_host/mmcX/clkgate_delay
index 2db28b8e662fc870a0f63066c39ff24b1666eafa..f08d078d43cff58e7ab939dae1f1108f7c3a517b 100644 (file)
@@ -25,3 +25,16 @@ echo 0 > /sys/block/mmcblkXbootY/force_ro
 To re-enable read-only access:
 
 echo 1 > /sys/block/mmcblkXbootY/force_ro
+
+The boot partitions can also be locked read only until the next power on,
+with:
+
+echo 1 > /sys/block/mmcblkXbootY/ro_lock_until_next_power_on
+
+This is a feature of the card and not of the kernel. If the card does
+not support boot partition locking, the file will not exist. If the
+feature has been disabled on the card, the file will be read-only.
+
+The boot partitions can also be locked permanently, but this feature is
+not accessible through sysfs in order to avoid accidental or malicious
+bricking.
diff --git a/Documentation/power/charger-manager.txt b/Documentation/power/charger-manager.txt
new file mode 100644 (file)
index 0000000..fdcca99
--- /dev/null
@@ -0,0 +1,163 @@
+Charger Manager
+       (C) 2011 MyungJoo Ham <myungjoo.ham@samsung.com>, GPL
+
+Charger Manager provides in-kernel battery charger management that
+requires temperature monitoring during suspend-to-RAM state
+and where each battery may have multiple chargers attached and the userland
+wants to look at the aggregated information of the multiple chargers.
+
+Charger Manager is a platform_driver with power-supply-class entries.
+An instance of Charger Manager (a platform-device created with Charger-Manager)
+represents an independent battery with chargers. If there are multiple
+batteries with their own chargers acting independently in a system,
+the system may need multiple instances of Charger Manager.
+
+1. Introduction
+===============
+
+Charger Manager supports the following:
+
+* Support for multiple chargers (e.g., a device with USB, AC, and solar panels)
+       A system may have multiple chargers (or power sources) and some of
+       they may be activated at the same time. Each charger may have its
+       own power-supply-class and each power-supply-class can provide
+       different information about the battery status. This framework
+       aggregates charger-related information from multiple sources and
+       shows combined information as a single power-supply-class.
+
+* Support for in suspend-to-RAM polling (with suspend_again callback)
+       While the battery is being charged and the system is in suspend-to-RAM,
+       we may need to monitor the battery health by looking at the ambient or
+       battery temperature. We can accomplish this by waking up the system
+       periodically. However, such a method wakes up devices unncessary for
+       monitoring the battery health and tasks, and user processes that are
+       supposed to be kept suspended. That, in turn, incurs unnecessary power
+       consumption and slow down charging process. Or even, such peak power
+       consumption can stop chargers in the middle of charging
+       (external power input < device power consumption), which not
+       only affects the charging time, but the lifespan of the battery.
+
+       Charger Manager provides a function "cm_suspend_again" that can be
+       used as suspend_again callback of platform_suspend_ops. If the platform
+       requires tasks other than cm_suspend_again, it may implement its own
+       suspend_again callback that calls cm_suspend_again in the middle.
+       Normally, the platform will need to resume and suspend some devices
+       that are used by Charger Manager.
+
+2. Global Charger-Manager Data related with suspend_again
+========================================================
+In order to setup Charger Manager with suspend-again feature
+(in-suspend monitoring), the user should provide charger_global_desc
+with setup_charger_manager(struct charger_global_desc *).
+This charger_global_desc data for in-suspend monitoring is global
+as the name suggests. Thus, the user needs to provide only once even
+if there are multiple batteries. If there are multiple batteries, the
+multiple instances of Charger Manager share the same charger_global_desc
+and it will manage in-suspend monitoring for all instances of Charger Manager.
+
+The user needs to provide all the two entries properly in order to activate
+in-suspend monitoring:
+
+struct charger_global_desc {
+
+char *rtc_name;
+       : The name of rtc (e.g., "rtc0") used to wakeup the system from
+       suspend for Charger Manager. The alarm interrupt (AIE) of the rtc
+       should be able to wake up the system from suspend. Charger Manager
+       saves and restores the alarm value and use the previously-defined
+       alarm if it is going to go off earlier than Charger Manager so that
+       Charger Manager does not interfere with previously-defined alarms.
+
+bool (*rtc_only_wakeup)(void);
+       : This callback should let CM know whether
+       the wakeup-from-suspend is caused only by the alarm of "rtc" in the
+       same struct. If there is any other wakeup source triggered the
+       wakeup, it should return false. If the "rtc" is the only wakeup
+       reason, it should return true.
+};
+
+3. How to setup suspend_again
+=============================
+Charger Manager provides a function "extern bool cm_suspend_again(void)".
+When cm_suspend_again is called, it monitors every battery. The suspend_ops
+callback of the system's platform_suspend_ops can call cm_suspend_again
+function to know whether Charger Manager wants to suspend again or not.
+If there are no other devices or tasks that want to use suspend_again
+feature, the platform_suspend_ops may directly refer to cm_suspend_again
+for its suspend_again callback.
+
+The cm_suspend_again() returns true (meaning "I want to suspend again")
+if the system was woken up by Charger Manager and the polling
+(in-suspend monitoring) results in "normal".
+
+4. Charger-Manager Data (struct charger_desc)
+=============================================
+For each battery charged independently from other batteries (if a series of
+batteries are charged by a single charger, they are counted as one independent
+battery), an instance of Charger Manager is attached to it.
+
+struct charger_desc {
+
+char *psy_name;
+       : The power-supply-class name of the battery. Default is
+       "battery" if psy_name is NULL. Users can access the psy entries
+       at "/sys/class/power_supply/[psy_name]/".
+
+enum polling_modes polling_mode;
+       : CM_POLL_DISABLE: do not poll this battery.
+         CM_POLL_ALWAYS: always poll this battery.
+         CM_POLL_EXTERNAL_POWER_ONLY: poll this battery if and only if
+                                      an external power source is attached.
+         CM_POLL_CHARGING_ONLY: poll this battery if and only if the
+                                battery is being charged.
+
+unsigned int fullbatt_uV;
+       : If specified with a non-zero value, Charger Manager assumes
+       that the battery is full (capacity = 100) if the battery is not being
+       charged and the battery voltage is equal to or greater than
+       fullbatt_uV.
+
+unsigned int polling_interval_ms;
+       : Required polling interval in ms. Charger Manager will poll
+       this battery every polling_interval_ms or more frequently.
+
+enum data_source battery_present;
+       CM_FUEL_GAUGE: get battery presence information from fuel gauge.
+       CM_CHARGER_STAT: get battery presence from chargers.
+
+char **psy_charger_stat;
+       : An array ending with NULL that has power-supply-class names of
+       chargers. Each power-supply-class should provide "PRESENT" (if
+       battery_present is "CM_CHARGER_STAT"), "ONLINE" (shows whether an
+       external power source is attached or not), and "STATUS" (shows whether
+       the battery is {"FULL" or not FULL} or {"FULL", "Charging",
+       "Discharging", "NotCharging"}).
+
+int num_charger_regulators;
+struct regulator_bulk_data *charger_regulators;
+       : Regulators representing the chargers in the form for
+       regulator framework's bulk functions.
+
+char *psy_fuel_gauge;
+       : Power-supply-class name of the fuel gauge.
+
+int (*temperature_out_of_range)(int *mC);
+bool measure_battery_temp;
+       : This callback returns 0 if the temperature is safe for charging,
+       a positive number if it is too hot to charge, and a negative number
+       if it is too cold to charge. With the variable mC, the callback returns
+       the temperature in 1/1000 of centigrade.
+       The source of temperature can be battery or ambient one according to
+       the value of measure_battery_temp.
+};
+
+5. Other Considerations
+=======================
+
+At the charger/battery-related events such as battery-pulled-out,
+charger-pulled-out, charger-inserted, DCIN-over/under-voltage, charger-stopped,
+and others critical to chargers, the system should be configured to wake up.
+At least the following should wake up the system from a suspend:
+a) charger-on/off b) external-power-in/out c) battery-in/out (while charging)
+
+It is usually accomplished by configuring the PMIC as a wakeup source.
index 19bc49439cac30a9c7978a89f260d0813cbed4d4..99b85d39751cd76160d09e111d5e36f75047f39f 100644 (file)
@@ -1,5 +1,7 @@
 00-INDEX
        - this file.
+LSM.txt
+       - description of the Linux Security Module framework.
 SELinux.txt
        - how to get started with the SELinux security enhancement.
 Smack.txt
diff --git a/Documentation/security/LSM.txt b/Documentation/security/LSM.txt
new file mode 100644 (file)
index 0000000..c335a76
--- /dev/null
@@ -0,0 +1,34 @@
+Linux Security Module framework
+-------------------------------
+
+The Linux Security Module (LSM) framework provides a mechanism for
+various security checks to be hooked by new kernel extensions. The name
+"module" is a bit of a misnomer since these extensions are not actually
+loadable kernel modules. Instead, they are selectable at build-time via
+CONFIG_DEFAULT_SECURITY and can be overridden at boot-time via the
+"security=..." kernel command line argument, in the case where multiple
+LSMs were built into a given kernel.
+
+The primary users of the LSM interface are Mandatory Access Control
+(MAC) extensions which provide a comprehensive security policy. Examples
+include SELinux, Smack, Tomoyo, and AppArmor. In addition to the larger
+MAC extensions, other extensions can be built using the LSM to provide
+specific changes to system operation when these tweaks are not available
+in the core functionality of Linux itself.
+
+Without a specific LSM built into the kernel, the default LSM will be the
+Linux capabilities system. Most LSMs choose to extend the capabilities
+system, building their checks on top of the defined capability hooks.
+For more details on capabilities, see capabilities(7) in the Linux
+man-pages project.
+
+Based on http://kerneltrap.org/Linux/Documenting_Security_Module_Intent,
+a new LSM is accepted into the kernel when its intent (a description of
+what it tries to protect against and in what cases one would expect to
+use it) has been appropriately documented in Documentation/security/.
+This allows an LSM's code to be easily compared to its goals, and so
+that end users and distros can make a more informed decision about which
+LSMs suit their requirements.
+
+For extensive documentation on the available LSM hook interfaces, please
+see include/linux/security.h.
index fc0366cbd7ce6af2392d8a124d6c6a9ab8d7b963..86257052e31ad7dba6fab5b74c3d95e053a1bfa2 100644 (file)
@@ -221,10 +221,10 @@ The Linux kernel supports the following types of credentials:
  (5) LSM
 
      The Linux Security Module allows extra controls to be placed over the
-     operations that a task may do.  Currently Linux supports two main
-     alternate LSM options: SELinux and Smack.
+     operations that a task may do.  Currently Linux supports several LSM
+     options.
 
-     Both work by labelling the objects in a system and then applying sets of
+     Some work by labelling the objects in a system and then applying sets of
      rules (policies) that say what operations a task with one label may do to
      an object with another label.
 
index edad99abec215d4412d139a46b5cee8a8493ca43..c8c54544abc5c757e27c32c322b812fabf598769 100644 (file)
@@ -42,19 +42,7 @@ ALC260
 
 ALC262
 ======
-  fujitsu      Fujitsu Laptop
-  benq         Benq ED8
-  benq-t31     Benq T31
-  hippo                Hippo (ATI) with jack detection, Sony UX-90s
-  hippo_1      Hippo (Benq) with jack detection
-  toshiba-s06  Toshiba S06
-  toshiba-rx1  Toshiba RX1
-  tyan         Tyan Thunder n6650W (S2915-E)
-  ultra                Samsung Q1 Ultra Vista model
-  lenovo-3000  Lenovo 3000 y410
-  nec          NEC Versa S9100
-  basic                fixed pin assignment w/o SPDIF
-  auto         auto-config reading BIOS (default)
+  N/A
 
 ALC267/268
 ==========
@@ -350,7 +338,6 @@ STAC92HD83*
   mic-ref      Reference board with power management for ports
   dell-s14     Dell laptop
   dell-vostro-3500     Dell Vostro 3500 laptop
-  hp           HP laptops with (inverted) mute-LED
   hp-dv7-4000  HP dv-7 4000
   auto         BIOS setup (default)
 
diff --git a/Documentation/sound/alsa/compress_offload.txt b/Documentation/sound/alsa/compress_offload.txt
new file mode 100644 (file)
index 0000000..c83a835
--- /dev/null
@@ -0,0 +1,188 @@
+               compress_offload.txt
+               =====================
+       Pierre-Louis.Bossart <pierre-louis.bossart@linux.intel.com>
+               Vinod Koul <vinod.koul@linux.intel.com>
+
+Overview
+
+Since its early days, the ALSA API was defined with PCM support or
+constant bitrates payloads such as IEC61937 in mind. Arguments and
+returned values in frames are the norm, making it a challenge to
+extend the existing API to compressed data streams.
+
+In recent years, audio digital signal processors (DSP) were integrated
+in system-on-chip designs, and DSPs are also integrated in audio
+codecs. Processing compressed data on such DSPs results in a dramatic
+reduction of power consumption compared to host-based
+processing. Support for such hardware has not been very good in Linux,
+mostly because of a lack of a generic API available in the mainline
+kernel.
+
+Rather than requiring a compability break with an API change of the
+ALSA PCM interface, a new 'Compressed Data' API is introduced to
+provide a control and data-streaming interface for audio DSPs.
+
+The design of this API was inspired by the 2-year experience with the
+Intel Moorestown SOC, with many corrections required to upstream the
+API in the mainline kernel instead of the staging tree and make it
+usable by others.
+
+Requirements
+
+The main requirements are:
+
+- separation between byte counts and time. Compressed formats may have
+  a header per file, per frame, or no header at all. The payload size
+  may vary from frame-to-frame. As a result, it is not possible to
+  estimate reliably the duration of audio buffers when handling
+  compressed data. Dedicated mechanisms are required to allow for
+  reliable audio-video synchronization, which requires precise
+  reporting of the number of samples rendered at any given time.
+
+- Handling of multiple formats. PCM data only requires a specification
+  of the sampling rate, number of channels and bits per sample. In
+  contrast, compressed data comes in a variety of formats. Audio DSPs
+  may also provide support for a limited number of audio encoders and
+  decoders embedded in firmware, or may support more choices through
+  dynamic download of libraries.
+
+- Focus on main formats. This API provides support for the most
+  popular formats used for audio and video capture and playback. It is
+  likely that as audio compression technology advances, new formats
+  will be added.
+
+- Handling of multiple configurations. Even for a given format like
+  AAC, some implementations may support AAC multichannel but HE-AAC
+  stereo. Likewise WMA10 level M3 may require too much memory and cpu
+  cycles. The new API needs to provide a generic way of listing these
+  formats.
+
+- Rendering/Grabbing only. This API does not provide any means of
+  hardware acceleration, where PCM samples are provided back to
+  user-space for additional processing. This API focuses instead on
+  streaming compressed data to a DSP, with the assumption that the
+  decoded samples are routed to a physical output or logical back-end.
+
+ - Complexity hiding. Existing user-space multimedia frameworks all
+  have existing enums/structures for each compressed format. This new
+  API assumes the existence of a platform-specific compatibility layer
+  to expose, translate and make use of the capabilities of the audio
+  DSP, eg. Android HAL or PulseAudio sinks. By construction, regular
+  applications are not supposed to make use of this API.
+
+
+Design
+
+The new API shares a number of concepts with with the PCM API for flow
+control. Start, pause, resume, drain and stop commands have the same
+semantics no matter what the content is.
+
+The concept of memory ring buffer divided in a set of fragments is
+borrowed from the ALSA PCM API. However, only sizes in bytes can be
+specified.
+
+Seeks/trick modes are assumed to be handled by the host.
+
+The notion of rewinds/forwards is not supported. Data committed to the
+ring buffer cannot be invalidated, except when dropping all buffers.
+
+The Compressed Data API does not make any assumptions on how the data
+is transmitted to the audio DSP. DMA transfers from main memory to an
+embedded audio cluster or to a SPI interface for external DSPs are
+possible. As in the ALSA PCM case, a core set of routines is exposed;
+each driver implementer will have to write support for a set of
+mandatory routines and possibly make use of optional ones.
+
+The main additions are
+
+- get_caps
+This routine returns the list of audio formats supported. Querying the
+codecs on a capture stream will return encoders, decoders will be
+listed for playback streams.
+
+- get_codec_caps For each codec, this routine returns a list of
+capabilities. The intent is to make sure all the capabilities
+correspond to valid settings, and to minimize the risks of
+configuration failures. For example, for a complex codec such as AAC,
+the number of channels supported may depend on a specific profile. If
+the capabilities were exposed with a single descriptor, it may happen
+that a specific combination of profiles/channels/formats may not be
+supported. Likewise, embedded DSPs have limited memory and cpu cycles,
+it is likely that some implementations make the list of capabilities
+dynamic and dependent on existing workloads. In addition to codec
+settings, this routine returns the minimum buffer size handled by the
+implementation. This information can be a function of the DMA buffer
+sizes, the number of bytes required to synchronize, etc, and can be
+used by userspace to define how much needs to be written in the ring
+buffer before playback can start.
+
+- set_params
+This routine sets the configuration chosen for a specific codec. The
+most important field in the parameters is the codec type; in most
+cases decoders will ignore other fields, while encoders will strictly
+comply to the settings
+
+- get_params
+This routines returns the actual settings used by the DSP. Changes to
+the settings should remain the exception.
+
+- get_timestamp
+The timestamp becomes a multiple field structure. It lists the number
+of bytes transferred, the number of samples processed and the number
+of samples rendered/grabbed. All these values can be used to determine
+the avarage bitrate, figure out if the ring buffer needs to be
+refilled or the delay due to decoding/encoding/io on the DSP.
+
+Note that the list of codecs/profiles/modes was derived from the
+OpenMAX AL specification instead of reinventing the wheel.
+Modifications include:
+- Addition of FLAC and IEC formats
+- Merge of encoder/decoder capabilities
+- Profiles/modes listed as bitmasks to make descriptors more compact
+- Addition of set_params for decoders (missing in OpenMAX AL)
+- Addition of AMR/AMR-WB encoding modes (missing in OpenMAX AL)
+- Addition of format information for WMA
+- Addition of encoding options when required (derived from OpenMAX IL)
+- Addition of rateControlSupported (missing in OpenMAX AL)
+
+Not supported:
+
+- Support for VoIP/circuit-switched calls is not the target of this
+  API. Support for dynamic bit-rate changes would require a tight
+  coupling between the DSP and the host stack, limiting power savings.
+
+- Packet-loss concealment is not supported. This would require an
+  additional interface to let the decoder synthesize data when frames
+  are lost during transmission. This may be added in the future.
+
+- Volume control/routing is not handled by this API. Devices exposing a
+  compressed data interface will be considered as regular ALSA devices;
+  volume changes and routing information will be provided with regular
+  ALSA kcontrols.
+
+- Embedded audio effects. Such effects should be enabled in the same
+  manner, no matter if the input was PCM or compressed.
+
+- multichannel IEC encoding. Unclear if this is required.
+
+- Encoding/decoding acceleration is not supported as mentioned
+  above. It is possible to route the output of a decoder to a capture
+  stream, or even implement transcoding capabilities. This routing
+  would be enabled with ALSA kcontrols.
+
+- Audio policy/resource management. This API does not provide any
+  hooks to query the utilization of the audio DSP, nor any premption
+  mechanisms.
+
+- No notion of underun/overrun. Since the bytes written are compressed
+  in nature and data written/read doesn't translate directly to
+  rendered output in time, this does not deal with underrun/overun and
+  maybe dealt in user-library
+
+Credits:
+- Mark Brown and Liam Girdwood for discussions on the need for this API
+- Harsha Priya for her work on intel_sst compressed API
+- Rakesh Ughreja for valuable feedback
+- Sing Nallasellan, Sikkandar Madar and Prasanna Samaga for
+  demonstrating and quantifying the benefits of audio offload on a
+  real platform.
index 1f2463671a1a4d59d0981f0b877c2a1246da82db..8c20fbd8b42dd922daa92f223bbefa9ffcc4f8e3 100644 (file)
@@ -49,6 +49,7 @@ show up in /proc/sys/kernel:
 - panic
 - panic_on_oops
 - panic_on_unrecovered_nmi
+- panic_on_stackoverflow
 - pid_max
 - powersave-nap               [ PPC only ]
 - printk
@@ -393,6 +394,19 @@ Controls the kernel's behaviour when an oops or BUG is encountered.
 
 ==============================================================
 
+panic_on_stackoverflow:
+
+Controls the kernel's behavior when detecting the overflows of
+kernel, IRQ and exception stacks except a user stack.
+This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
+
+0: try to continue operation.
+
+1: panic immediately.
+
+==============================================================
+
+
 pid_max:
 
 PID allocation wrap value.  When the kernel's next PID value
@@ -401,6 +415,14 @@ PIDs of value pid_max or larger are not allocated.
 
 ==============================================================
 
+ns_last_pid:
+
+The last pid allocated in the current (the one task using this sysctl
+lives in) pid namespace. When selecting a pid for a next task on fork
+kernel tries to allocate a number starting from this one.
+
+==============================================================
+
 powersave-nap: (PPC only)
 
 If set, Linux-PPC will use the 'nap' mode of powersaving,
index aa82ee4a5a8762ef9528ef382b07b906c3d6094b..194800410061b3b73be4a68b762be0b7995f4558 100644 (file)
@@ -40,8 +40,8 @@ but the call_site can usually be used to extrapolate that information.
 ==================
 mm_page_alloc            page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s
 mm_page_alloc_zone_locked page=%p pfn=%lu order=%u migratetype=%d cpu=%d percpu_refill=%d
-mm_page_free_direct      page=%p pfn=%lu order=%d
-mm_pagevec_free                  page=%p pfn=%lu order=%d cold=%d
+mm_page_free             page=%p pfn=%lu order=%d
+mm_page_free_batched     page=%p pfn=%lu order=%d cold=%d
 
 These four events deal with page allocation and freeing. mm_page_alloc is
 a simple indicator of page allocator activity. Pages may be allocated from
@@ -53,13 +53,13 @@ amounts of activity imply high activity on the zone->lock. Taking this lock
 impairs performance by disabling interrupts, dirtying cache lines between
 CPUs and serialising many CPUs.
 
-When a page is freed directly by the caller, the mm_page_free_direct event
+When a page is freed directly by the caller, the only mm_page_free event
 is triggered. Significant amounts of activity here could indicate that the
 callers should be batching their activities.
 
-When pages are freed using a pagevec, the mm_pagevec_free is
-triggered. Broadly speaking, pages are taken off the LRU lock in bulk and
-freed in batch with a pagevec. Significant amounts of activity here could
+When pages are freed in batch, the also mm_page_free_batched is triggered.
+Broadly speaking, pages are taken off the LRU lock in bulk and
+freed in batch with a page list. Significant amounts of activity here could
 indicate that the system is under memory pressure and can also indicate
 contention on the zone->lru_lock.
 
index 7df50e8cf4d9510a7c0b8233ac52bdbcc3b8614f..0a120aae33ce5c9836dad948b18736ea183e6801 100644 (file)
@@ -17,8 +17,8 @@ use Getopt::Long;
 
 # Tracepoint events
 use constant MM_PAGE_ALLOC             => 1;
-use constant MM_PAGE_FREE_DIRECT       => 2;
-use constant MM_PAGEVEC_FREE           => 3;
+use constant MM_PAGE_FREE              => 2;
+use constant MM_PAGE_FREE_BATCHED      => 3;
 use constant MM_PAGE_PCPU_DRAIN                => 4;
 use constant MM_PAGE_ALLOC_ZONE_LOCKED => 5;
 use constant MM_PAGE_ALLOC_EXTFRAG     => 6;
@@ -223,10 +223,10 @@ EVENT_PROCESS:
                # Perl Switch() sucks majorly
                if ($tracepoint eq "mm_page_alloc") {
                        $perprocesspid{$process_pid}->{MM_PAGE_ALLOC}++;
-               } elsif ($tracepoint eq "mm_page_free_direct") {
-                       $perprocesspid{$process_pid}->{MM_PAGE_FREE_DIRECT}++;
-               } elsif ($tracepoint eq "mm_pagevec_free") {
-                       $perprocesspid{$process_pid}->{MM_PAGEVEC_FREE}++;
+               } elsif ($tracepoint eq "mm_page_free") {
+                       $perprocesspid{$process_pid}->{MM_PAGE_FREE}++
+               } elsif ($tracepoint eq "mm_page_free_batched") {
+                       $perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED}++;
                } elsif ($tracepoint eq "mm_page_pcpu_drain") {
                        $perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN}++;
                        $perprocesspid{$process_pid}->{STATE_PCPU_PAGES_DRAINED}++;
@@ -336,8 +336,8 @@ sub dump_stats {
                        $process_pid,
                        $stats{$process_pid}->{MM_PAGE_ALLOC},
                        $stats{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED},
-                       $stats{$process_pid}->{MM_PAGE_FREE_DIRECT},
-                       $stats{$process_pid}->{MM_PAGEVEC_FREE},
+                       $stats{$process_pid}->{MM_PAGE_FREE},
+                       $stats{$process_pid}->{MM_PAGE_FREE_BATCHED},
                        $stats{$process_pid}->{MM_PAGE_PCPU_DRAIN},
                        $stats{$process_pid}->{HIGH_PCPU_DRAINS},
                        $stats{$process_pid}->{HIGH_PCPU_REFILLS},
@@ -364,8 +364,8 @@ sub aggregate_perprocesspid() {
 
                $perprocess{$process}->{MM_PAGE_ALLOC} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC};
                $perprocess{$process}->{MM_PAGE_ALLOC_ZONE_LOCKED} += $perprocesspid{$process_pid}->{MM_PAGE_ALLOC_ZONE_LOCKED};
-               $perprocess{$process}->{MM_PAGE_FREE_DIRECT} += $perprocesspid{$process_pid}->{MM_PAGE_FREE_DIRECT};
-               $perprocess{$process}->{MM_PAGEVEC_FREE} += $perprocesspid{$process_pid}->{MM_PAGEVEC_FREE};
+               $perprocess{$process}->{MM_PAGE_FREE} += $perprocesspid{$process_pid}->{MM_PAGE_FREE};
+               $perprocess{$process}->{MM_PAGE_FREE_BATCHED} += $perprocesspid{$process_pid}->{MM_PAGE_FREE_BATCHED};
                $perprocess{$process}->{MM_PAGE_PCPU_DRAIN} += $perprocesspid{$process_pid}->{MM_PAGE_PCPU_DRAIN};
                $perprocess{$process}->{HIGH_PCPU_DRAINS} += $perprocesspid{$process_pid}->{HIGH_PCPU_DRAINS};
                $perprocess{$process}->{HIGH_PCPU_REFILLS} += $perprocesspid{$process_pid}->{HIGH_PCPU_REFILLS};
index 87bee3c129ba71f8c359b5e849bafd177f421136..058cc6c9dc56d442e4fad72c1957a82c7f630f4d 100644 (file)
@@ -93,14 +93,14 @@ By specifying the -a switch and analysing sleep, the system-wide events
 for a duration of time can be examined.
 
  $ perf stat -a \
-       -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \
-       -e kmem:mm_pagevec_free \
+       -e kmem:mm_page_alloc -e kmem:mm_page_free \
+       -e kmem:mm_page_free_batched \
        sleep 10
  Performance counter stats for 'sleep 10':
 
            9630  kmem:mm_page_alloc
-           2143  kmem:mm_page_free_direct
-           7424  kmem:mm_pagevec_free
+           2143  kmem:mm_page_free
+           7424  kmem:mm_page_free_batched
 
    10.002577764  seconds time elapsed
 
@@ -119,15 +119,15 @@ basis using set_ftrace_pid.
 Events can be activated and tracked for the duration of a process on a local
 basis using PCL such as follows.
 
-  $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \
-                -e kmem:mm_pagevec_free ./hackbench 10
+  $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free \
+                -e kmem:mm_page_free_batched ./hackbench 10
   Time: 0.909
 
     Performance counter stats for './hackbench 10':
 
           17803  kmem:mm_page_alloc
-          12398  kmem:mm_page_free_direct
-           4827  kmem:mm_pagevec_free
+          12398  kmem:mm_page_free
+           4827  kmem:mm_page_free_batched
 
     0.973913387  seconds time elapsed
 
@@ -146,8 +146,8 @@ to know what the standard deviation is. By and large, this is left to the
 performance analyst to do it by hand. In the event that the discrete event
 occurrences are useful to the performance analyst, then perf can be used.
 
-  $ perf stat --repeat 5 -e kmem:mm_page_alloc -e kmem:mm_page_free_direct
-                       -e kmem:mm_pagevec_free ./hackbench 10
+  $ perf stat --repeat 5 -e kmem:mm_page_alloc -e kmem:mm_page_free
+                       -e kmem:mm_page_free_batched ./hackbench 10
   Time: 0.890
   Time: 0.895
   Time: 0.915
@@ -157,8 +157,8 @@ occurrences are useful to the performance analyst, then perf can be used.
    Performance counter stats for './hackbench 10' (5 runs):
 
           16630  kmem:mm_page_alloc         ( +-   3.542% )
-          11486  kmem:mm_page_free_direct   ( +-   4.771% )
-           4730  kmem:mm_pagevec_free       ( +-   2.325% )
+          11486  kmem:mm_page_free         ( +-   4.771% )
+           4730  kmem:mm_page_free_batched  ( +-   2.325% )
 
     0.982653002  seconds time elapsed   ( +-   1.448% )
 
@@ -168,15 +168,15 @@ aggregation of discrete events, then a script would need to be developed.
 Using --repeat, it is also possible to view how events are fluctuating over
 time on a system-wide basis using -a and sleep.
 
-  $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \
-               -e kmem:mm_pagevec_free \
+  $ perf stat -e kmem:mm_page_alloc -e kmem:mm_page_free \
+               -e kmem:mm_page_free_batched \
                -a --repeat 10 \
                sleep 1
   Performance counter stats for 'sleep 1' (10 runs):
 
            1066  kmem:mm_page_alloc         ( +-  26.148% )
-            182  kmem:mm_page_free_direct   ( +-   5.464% )
-            890  kmem:mm_pagevec_free       ( +-  30.079% )
+            182  kmem:mm_page_free          ( +-   5.464% )
+            890  kmem:mm_page_free_batched  ( +-  30.079% )
 
     1.002251757  seconds time elapsed   ( +-   0.005% )
 
@@ -220,8 +220,8 @@ were generating events within the kernel. To begin this sort of analysis, the
 data must be recorded. At the time of writing, this required root:
 
   $ perf record -c 1 \
-       -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \
-       -e kmem:mm_pagevec_free \
+       -e kmem:mm_page_alloc -e kmem:mm_page_free \
+       -e kmem:mm_page_free_batched \
        ./hackbench 10
   Time: 0.894
   [ perf record: Captured and wrote 0.733 MB perf.data (~32010 samples) ]
@@ -260,8 +260,8 @@ noticed that X was generating an insane amount of page allocations so let's look
 at it:
 
   $ perf record -c 1 -f \
-               -e kmem:mm_page_alloc -e kmem:mm_page_free_direct \
-               -e kmem:mm_pagevec_free \
+               -e kmem:mm_page_alloc -e kmem:mm_page_free \
+               -e kmem:mm_page_free_batched \
                -p `pidof X`
 
 This was interrupted after a few seconds and
diff --git a/Documentation/virtual/lguest/.gitignore b/Documentation/virtual/lguest/.gitignore
deleted file mode 100644 (file)
index 115587f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-lguest
diff --git a/Documentation/virtual/lguest/Makefile b/Documentation/virtual/lguest/Makefile
deleted file mode 100644 (file)
index 0ac3420..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# This creates the demonstration utility "lguest" which runs a Linux guest.
-# Missing headers?  Add "-I../../../include -I../../../arch/x86/include"
-CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
-
-all: lguest
-
-clean:
-       rm -f lguest
diff --git a/Documentation/virtual/lguest/extract b/Documentation/virtual/lguest/extract
deleted file mode 100644 (file)
index 7730bb6..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#! /bin/sh
-
-set -e
-
-PREFIX=$1
-shift
-
-trap 'rm -r $TMPDIR' 0
-TMPDIR=`mktemp -d`
-
-exec 3>/dev/null
-for f; do
-    while IFS="
-" read -r LINE; do
-       case "$LINE" in
-           *$PREFIX:[0-9]*:\**)
-               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
-               if [ -f $TMPDIR/$NUM ]; then
-                   echo "$TMPDIR/$NUM already exits prior to $f"
-                   exit 1
-               fi
-               exec 3>>$TMPDIR/$NUM
-               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
-               /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3
-               ;;
-           *$PREFIX:[0-9]*)
-               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
-               if [ -f $TMPDIR/$NUM ]; then
-                   echo "$TMPDIR/$NUM already exits prior to $f"
-                   exit 1
-               fi
-               exec 3>>$TMPDIR/$NUM
-               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
-               /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3
-               ;;
-           *:\**)
-               /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3
-               echo >&3
-               exec 3>/dev/null
-               ;;
-           *)
-               /bin/echo "$LINE" >&3
-               ;;
-       esac
-    done < $f
-    echo >&3
-    exec 3>/dev/null
-done
-
-LASTFILE=""
-for f in $TMPDIR/*; do
-    if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then
-       LASTFILE=$(cat $TMPDIR/.$(basename $f) )
-       echo "[ $LASTFILE ]"
-    fi
-    cat $f
-done
-
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c
deleted file mode 100644 (file)
index c095d79..0000000
+++ /dev/null
@@ -1,2065 +0,0 @@
-/*P:100
- * This is the Launcher code, a simple program which lays out the "physical"
- * memory for the new Guest by mapping the kernel image and the virtual
- * devices, then opens /dev/lguest to tell the kernel about the Guest and
- * control it.
-:*/
-#define _LARGEFILE64_SOURCE
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <err.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <elf.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/eventfd.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <time.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <linux/sockios.h>
-#include <linux/if_tun.h>
-#include <sys/uio.h>
-#include <termios.h>
-#include <getopt.h>
-#include <assert.h>
-#include <sched.h>
-#include <limits.h>
-#include <stddef.h>
-#include <signal.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <linux/virtio_config.h>
-#include <linux/virtio_net.h>
-#include <linux/virtio_blk.h>
-#include <linux/virtio_console.h>
-#include <linux/virtio_rng.h>
-#include <linux/virtio_ring.h>
-#include <asm/bootparam.h>
-#include "../../../include/linux/lguest_launcher.h"
-/*L:110
- * We can ignore the 43 include files we need for this program, but I do want
- * to draw attention to the use of kernel-style types.
- *
- * As Linus said, "C is a Spartan language, and so should your naming be."  I
- * like these abbreviations, so we define them here.  Note that u64 is always
- * unsigned long long, which works on all Linux systems: this means that we can
- * use %llu in printf for any u64.
- */
-typedef unsigned long long u64;
-typedef uint32_t u32;
-typedef uint16_t u16;
-typedef uint8_t u8;
-/*:*/
-
-#define BRIDGE_PFX "bridge:"
-#ifndef SIOCBRADDIF
-#define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
-#endif
-/* We can have up to 256 pages for devices. */
-#define DEVICE_PAGES 256
-/* This will occupy 3 pages: it must be a power of 2. */
-#define VIRTQUEUE_NUM 256
-
-/*L:120
- * verbose is both a global flag and a macro.  The C preprocessor allows
- * this, and although I wouldn't recommend it, it works quite nicely here.
- */
-static bool verbose;
-#define verbose(args...) \
-       do { if (verbose) printf(args); } while(0)
-/*:*/
-
-/* The pointer to the start of guest memory. */
-static void *guest_base;
-/* The maximum guest physical address allowed, and maximum possible. */
-static unsigned long guest_limit, guest_max;
-/* The /dev/lguest file descriptor. */
-static int lguest_fd;
-
-/* a per-cpu variable indicating whose vcpu is currently running */
-static unsigned int __thread cpu_id;
-
-/* This is our list of devices. */
-struct device_list {
-       /* Counter to assign interrupt numbers. */
-       unsigned int next_irq;
-
-       /* Counter to print out convenient device numbers. */
-       unsigned int device_num;
-
-       /* The descriptor page for the devices. */
-       u8 *descpage;
-
-       /* A single linked list of devices. */
-       struct device *dev;
-       /* And a pointer to the last device for easy append. */
-       struct device *lastdev;
-};
-
-/* The list of Guest devices, based on command line arguments. */
-static struct device_list devices;
-
-/* The device structure describes a single device. */
-struct device {
-       /* The linked-list pointer. */
-       struct device *next;
-
-       /* The device's descriptor, as mapped into the Guest. */
-       struct lguest_device_desc *desc;
-
-       /* We can't trust desc values once Guest has booted: we use these. */
-       unsigned int feature_len;
-       unsigned int num_vq;
-
-       /* The name of this device, for --verbose. */
-       const char *name;
-
-       /* Any queues attached to this device */
-       struct virtqueue *vq;
-
-       /* Is it operational */
-       bool running;
-
-       /* Device-specific data. */
-       void *priv;
-};
-
-/* The virtqueue structure describes a queue attached to a device. */
-struct virtqueue {
-       struct virtqueue *next;
-
-       /* Which device owns me. */
-       struct device *dev;
-
-       /* The configuration for this queue. */
-       struct lguest_vqconfig config;
-
-       /* The actual ring of buffers. */
-       struct vring vring;
-
-       /* Last available index we saw. */
-       u16 last_avail_idx;
-
-       /* How many are used since we sent last irq? */
-       unsigned int pending_used;
-
-       /* Eventfd where Guest notifications arrive. */
-       int eventfd;
-
-       /* Function for the thread which is servicing this virtqueue. */
-       void (*service)(struct virtqueue *vq);
-       pid_t thread;
-};
-
-/* Remember the arguments to the program so we can "reboot" */
-static char **main_args;
-
-/* The original tty settings to restore on exit. */
-static struct termios orig_term;
-
-/*
- * We have to be careful with barriers: our devices are all run in separate
- * threads and so we need to make sure that changes visible to the Guest happen
- * in precise order.
- */
-#define wmb() __asm__ __volatile__("" : : : "memory")
-#define mb() __asm__ __volatile__("" : : : "memory")
-
-/*
- * Convert an iovec element to the given type.
- *
- * This is a fairly ugly trick: we need to know the size of the type and
- * alignment requirement to check the pointer is kosher.  It's also nice to
- * have the name of the type in case we report failure.
- *
- * Typing those three things all the time is cumbersome and error prone, so we
- * have a macro which sets them all up and passes to the real function.
- */
-#define convert(iov, type) \
-       ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
-
-static void *_convert(struct iovec *iov, size_t size, size_t align,
-                     const char *name)
-{
-       if (iov->iov_len != size)
-               errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
-       if ((unsigned long)iov->iov_base % align != 0)
-               errx(1, "Bad alignment %p for %s", iov->iov_base, name);
-       return iov->iov_base;
-}
-
-/* Wrapper for the last available index.  Makes it easier to change. */
-#define lg_last_avail(vq)      ((vq)->last_avail_idx)
-
-/*
- * The virtio configuration space is defined to be little-endian.  x86 is
- * little-endian too, but it's nice to be explicit so we have these helpers.
- */
-#define cpu_to_le16(v16) (v16)
-#define cpu_to_le32(v32) (v32)
-#define cpu_to_le64(v64) (v64)
-#define le16_to_cpu(v16) (v16)
-#define le32_to_cpu(v32) (v32)
-#define le64_to_cpu(v64) (v64)
-
-/* Is this iovec empty? */
-static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
-{
-       unsigned int i;
-
-       for (i = 0; i < num_iov; i++)
-               if (iov[i].iov_len)
-                       return false;
-       return true;
-}
-
-/* Take len bytes from the front of this iovec. */
-static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
-{
-       unsigned int i;
-
-       for (i = 0; i < num_iov; i++) {
-               unsigned int used;
-
-               used = iov[i].iov_len < len ? iov[i].iov_len : len;
-               iov[i].iov_base += used;
-               iov[i].iov_len -= used;
-               len -= used;
-       }
-       assert(len == 0);
-}
-
-/* The device virtqueue descriptors are followed by feature bitmasks. */
-static u8 *get_feature_bits(struct device *dev)
-{
-       return (u8 *)(dev->desc + 1)
-               + dev->num_vq * sizeof(struct lguest_vqconfig);
-}
-
-/*L:100
- * The Launcher code itself takes us out into userspace, that scary place where
- * pointers run wild and free!  Unfortunately, like most userspace programs,
- * it's quite boring (which is why everyone likes to hack on the kernel!).
- * Perhaps if you make up an Lguest Drinking Game at this point, it will get
- * you through this section.  Or, maybe not.
- *
- * The Launcher sets up a big chunk of memory to be the Guest's "physical"
- * memory and stores it in "guest_base".  In other words, Guest physical ==
- * Launcher virtual with an offset.
- *
- * This can be tough to get your head around, but usually it just means that we
- * use these trivial conversion functions when the Guest gives us its
- * "physical" addresses:
- */
-static void *from_guest_phys(unsigned long addr)
-{
-       return guest_base + addr;
-}
-
-static unsigned long to_guest_phys(const void *addr)
-{
-       return (addr - guest_base);
-}
-
-/*L:130
- * Loading the Kernel.
- *
- * We start with couple of simple helper routines.  open_or_die() avoids
- * error-checking code cluttering the callers:
- */
-static int open_or_die(const char *name, int flags)
-{
-       int fd = open(name, flags);
-       if (fd < 0)
-               err(1, "Failed to open %s", name);
-       return fd;
-}
-
-/* map_zeroed_pages() takes a number of pages. */
-static void *map_zeroed_pages(unsigned int num)
-{
-       int fd = open_or_die("/dev/zero", O_RDONLY);
-       void *addr;
-
-       /*
-        * We use a private mapping (ie. if we write to the page, it will be
-        * copied). We allocate an extra two pages PROT_NONE to act as guard
-        * pages against read/write attempts that exceed allocated space.
-        */
-       addr = mmap(NULL, getpagesize() * (num+2),
-                   PROT_NONE, MAP_PRIVATE, fd, 0);
-
-       if (addr == MAP_FAILED)
-               err(1, "Mmapping %u pages of /dev/zero", num);
-
-       if (mprotect(addr + getpagesize(), getpagesize() * num,
-                    PROT_READ|PROT_WRITE) == -1)
-               err(1, "mprotect rw %u pages failed", num);
-
-       /*
-        * One neat mmap feature is that you can close the fd, and it
-        * stays mapped.
-        */
-       close(fd);
-
-       /* Return address after PROT_NONE page */
-       return addr + getpagesize();
-}
-
-/* Get some more pages for a device. */
-static void *get_pages(unsigned int num)
-{
-       void *addr = from_guest_phys(guest_limit);
-
-       guest_limit += num * getpagesize();
-       if (guest_limit > guest_max)
-               errx(1, "Not enough memory for devices");
-       return addr;
-}
-
-/*
- * This routine is used to load the kernel or initrd.  It tries mmap, but if
- * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
- * it falls back to reading the memory in.
- */
-static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
-{
-       ssize_t r;
-
-       /*
-        * We map writable even though for some segments are marked read-only.
-        * The kernel really wants to be writable: it patches its own
-        * instructions.
-        *
-        * MAP_PRIVATE means that the page won't be copied until a write is
-        * done to it.  This allows us to share untouched memory between
-        * Guests.
-        */
-       if (mmap(addr, len, PROT_READ|PROT_WRITE,
-                MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
-               return;
-
-       /* pread does a seek and a read in one shot: saves a few lines. */
-       r = pread(fd, addr, len, offset);
-       if (r != len)
-               err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
-}
-
-/*
- * This routine takes an open vmlinux image, which is in ELF, and maps it into
- * the Guest memory.  ELF = Embedded Linking Format, which is the format used
- * by all modern binaries on Linux including the kernel.
- *
- * The ELF headers give *two* addresses: a physical address, and a virtual
- * address.  We use the physical address; the Guest will map itself to the
- * virtual address.
- *
- * We return the starting address.
- */
-static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
-{
-       Elf32_Phdr phdr[ehdr->e_phnum];
-       unsigned int i;
-
-       /*
-        * Sanity checks on the main ELF header: an x86 executable with a
-        * reasonable number of correctly-sized program headers.
-        */
-       if (ehdr->e_type != ET_EXEC
-           || ehdr->e_machine != EM_386
-           || ehdr->e_phentsize != sizeof(Elf32_Phdr)
-           || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
-               errx(1, "Malformed elf header");
-
-       /*
-        * An ELF executable contains an ELF header and a number of "program"
-        * headers which indicate which parts ("segments") of the program to
-        * load where.
-        */
-
-       /* We read in all the program headers at once: */
-       if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
-               err(1, "Seeking to program headers");
-       if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
-               err(1, "Reading program headers");
-
-       /*
-        * Try all the headers: there are usually only three.  A read-only one,
-        * a read-write one, and a "note" section which we don't load.
-        */
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               /* If this isn't a loadable segment, we ignore it */
-               if (phdr[i].p_type != PT_LOAD)
-                       continue;
-
-               verbose("Section %i: size %i addr %p\n",
-                       i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
-
-               /* We map this section of the file at its physical address. */
-               map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
-                      phdr[i].p_offset, phdr[i].p_filesz);
-       }
-
-       /* The entry point is given in the ELF header. */
-       return ehdr->e_entry;
-}
-
-/*L:150
- * A bzImage, unlike an ELF file, is not meant to be loaded.  You're supposed
- * to jump into it and it will unpack itself.  We used to have to perform some
- * hairy magic because the unpacking code scared me.
- *
- * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
- * a small patch to jump over the tricky bits in the Guest, so now we just read
- * the funky header so we know where in the file to load, and away we go!
- */
-static unsigned long load_bzimage(int fd)
-{
-       struct boot_params boot;
-       int r;
-       /* Modern bzImages get loaded at 1M. */
-       void *p = from_guest_phys(0x100000);
-
-       /*
-        * Go back to the start of the file and read the header.  It should be
-        * a Linux boot header (see Documentation/x86/boot.txt)
-        */
-       lseek(fd, 0, SEEK_SET);
-       read(fd, &boot, sizeof(boot));
-
-       /* Inside the setup_hdr, we expect the magic "HdrS" */
-       if (memcmp(&boot.hdr.header, "HdrS", 4) != 0)
-               errx(1, "This doesn't look like a bzImage to me");
-
-       /* Skip over the extra sectors of the header. */
-       lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET);
-
-       /* Now read everything into memory. in nice big chunks. */
-       while ((r = read(fd, p, 65536)) > 0)
-               p += r;
-
-       /* Finally, code32_start tells us where to enter the kernel. */
-       return boot.hdr.code32_start;
-}
-
-/*L:140
- * Loading the kernel is easy when it's a "vmlinux", but most kernels
- * come wrapped up in the self-decompressing "bzImage" format.  With a little
- * work, we can load those, too.
- */
-static unsigned long load_kernel(int fd)
-{
-       Elf32_Ehdr hdr;
-
-       /* Read in the first few bytes. */
-       if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
-               err(1, "Reading kernel");
-
-       /* If it's an ELF file, it starts with "\177ELF" */
-       if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
-               return map_elf(fd, &hdr);
-
-       /* Otherwise we assume it's a bzImage, and try to load it. */
-       return load_bzimage(fd);
-}
-
-/*
- * This is a trivial little helper to align pages.  Andi Kleen hated it because
- * it calls getpagesize() twice: "it's dumb code."
- *
- * Kernel guys get really het up about optimization, even when it's not
- * necessary.  I leave this code as a reaction against that.
- */
-static inline unsigned long page_align(unsigned long addr)
-{
-       /* Add upwards and truncate downwards. */
-       return ((addr + getpagesize()-1) & ~(getpagesize()-1));
-}
-
-/*L:180
- * An "initial ram disk" is a disk image loaded into memory along with the
- * kernel which the kernel can use to boot from without needing any drivers.
- * Most distributions now use this as standard: the initrd contains the code to
- * load the appropriate driver modules for the current machine.
- *
- * Importantly, James Morris works for RedHat, and Fedora uses initrds for its
- * kernels.  He sent me this (and tells me when I break it).
- */
-static unsigned long load_initrd(const char *name, unsigned long mem)
-{
-       int ifd;
-       struct stat st;
-       unsigned long len;
-
-       ifd = open_or_die(name, O_RDONLY);
-       /* fstat() is needed to get the file size. */
-       if (fstat(ifd, &st) < 0)
-               err(1, "fstat() on initrd '%s'", name);
-
-       /*
-        * We map the initrd at the top of memory, but mmap wants it to be
-        * page-aligned, so we round the size up for that.
-        */
-       len = page_align(st.st_size);
-       map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
-       /*
-        * Once a file is mapped, you can close the file descriptor.  It's a
-        * little odd, but quite useful.
-        */
-       close(ifd);
-       verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len);
-
-       /* We return the initrd size. */
-       return len;
-}
-/*:*/
-
-/*
- * Simple routine to roll all the commandline arguments together with spaces
- * between them.
- */
-static void concat(char *dst, char *args[])
-{
-       unsigned int i, len = 0;
-
-       for (i = 0; args[i]; i++) {
-               if (i) {
-                       strcat(dst+len, " ");
-                       len++;
-               }
-               strcpy(dst+len, args[i]);
-               len += strlen(args[i]);
-       }
-       /* In case it's empty. */
-       dst[len] = '\0';
-}
-
-/*L:185
- * This is where we actually tell the kernel to initialize the Guest.  We
- * saw the arguments it expects when we looked at initialize() in lguest_user.c:
- * the base of Guest "physical" memory, the top physical page to allow and the
- * entry point for the Guest.
- */
-static void tell_kernel(unsigned long start)
-{
-       unsigned long args[] = { LHREQ_INITIALIZE,
-                                (unsigned long)guest_base,
-                                guest_limit / getpagesize(), start };
-       verbose("Guest: %p - %p (%#lx)\n",
-               guest_base, guest_base + guest_limit, guest_limit);
-       lguest_fd = open_or_die("/dev/lguest", O_RDWR);
-       if (write(lguest_fd, args, sizeof(args)) < 0)
-               err(1, "Writing to /dev/lguest");
-}
-/*:*/
-
-/*L:200
- * Device Handling.
- *
- * When the Guest gives us a buffer, it sends an array of addresses and sizes.
- * We need to make sure it's not trying to reach into the Launcher itself, so
- * we have a convenient routine which checks it and exits with an error message
- * if something funny is going on:
- */
-static void *_check_pointer(unsigned long addr, unsigned int size,
-                           unsigned int line)
-{
-       /*
-        * Check if the requested address and size exceeds the allocated memory,
-        * or addr + size wraps around.
-        */
-       if ((addr + size) > guest_limit || (addr + size) < addr)
-               errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
-       /*
-        * We return a pointer for the caller's convenience, now we know it's
-        * safe to use.
-        */
-       return from_guest_phys(addr);
-}
-/* A macro which transparently hands the line number to the real function. */
-#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
-
-/*
- * Each buffer in the virtqueues is actually a chain of descriptors.  This
- * function returns the next descriptor in the chain, or vq->vring.num if we're
- * at the end.
- */
-static unsigned next_desc(struct vring_desc *desc,
-                         unsigned int i, unsigned int max)
-{
-       unsigned int next;
-
-       /* If this descriptor says it doesn't chain, we're done. */
-       if (!(desc[i].flags & VRING_DESC_F_NEXT))
-               return max;
-
-       /* Check they're not leading us off end of descriptors. */
-       next = desc[i].next;
-       /* Make sure compiler knows to grab that: we don't want it changing! */
-       wmb();
-
-       if (next >= max)
-               errx(1, "Desc next is %u", next);
-
-       return next;
-}
-
-/*
- * This actually sends the interrupt for this virtqueue, if we've used a
- * buffer.
- */
-static void trigger_irq(struct virtqueue *vq)
-{
-       unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
-
-       /* Don't inform them if nothing used. */
-       if (!vq->pending_used)
-               return;
-       vq->pending_used = 0;
-
-       /* If they don't want an interrupt, don't send one... */
-       if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
-               return;
-       }
-
-       /* Send the Guest an interrupt tell them we used something up. */
-       if (write(lguest_fd, buf, sizeof(buf)) != 0)
-               err(1, "Triggering irq %i", vq->config.irq);
-}
-
-/*
- * This looks in the virtqueue for the first available buffer, and converts
- * it to an iovec for convenient access.  Since descriptors consist of some
- * number of output then some number of input descriptors, it's actually two
- * iovecs, but we pack them into one and note how many of each there were.
- *
- * This function waits if necessary, and returns the descriptor number found.
- */
-static unsigned wait_for_vq_desc(struct virtqueue *vq,
-                                struct iovec iov[],
-                                unsigned int *out_num, unsigned int *in_num)
-{
-       unsigned int i, head, max;
-       struct vring_desc *desc;
-       u16 last_avail = lg_last_avail(vq);
-
-       /* There's nothing available? */
-       while (last_avail == vq->vring.avail->idx) {
-               u64 event;
-
-               /*
-                * Since we're about to sleep, now is a good time to tell the
-                * Guest about what we've used up to now.
-                */
-               trigger_irq(vq);
-
-               /* OK, now we need to know about added descriptors. */
-               vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-
-               /*
-                * They could have slipped one in as we were doing that: make
-                * sure it's written, then check again.
-                */
-               mb();
-               if (last_avail != vq->vring.avail->idx) {
-                       vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-                       break;
-               }
-
-               /* Nothing new?  Wait for eventfd to tell us they refilled. */
-               if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
-                       errx(1, "Event read failed?");
-
-               /* We don't need to be notified again. */
-               vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
-       }
-
-       /* Check it isn't doing very strange things with descriptor numbers. */
-       if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
-               errx(1, "Guest moved used index from %u to %u",
-                    last_avail, vq->vring.avail->idx);
-
-       /*
-        * Grab the next descriptor number they're advertising, and increment
-        * the index we've seen.
-        */
-       head = vq->vring.avail->ring[last_avail % vq->vring.num];
-       lg_last_avail(vq)++;
-
-       /* If their number is silly, that's a fatal mistake. */
-       if (head >= vq->vring.num)
-               errx(1, "Guest says index %u is available", head);
-
-       /* When we start there are none of either input nor output. */
-       *out_num = *in_num = 0;
-
-       max = vq->vring.num;
-       desc = vq->vring.desc;
-       i = head;
-
-       /*
-        * If this is an indirect entry, then this buffer contains a descriptor
-        * table which we handle as if it's any normal descriptor chain.
-        */
-       if (desc[i].flags & VRING_DESC_F_INDIRECT) {
-               if (desc[i].len % sizeof(struct vring_desc))
-                       errx(1, "Invalid size for indirect buffer table");
-
-               max = desc[i].len / sizeof(struct vring_desc);
-               desc = check_pointer(desc[i].addr, desc[i].len);
-               i = 0;
-       }
-
-       do {
-               /* Grab the first descriptor, and check it's OK. */
-               iov[*out_num + *in_num].iov_len = desc[i].len;
-               iov[*out_num + *in_num].iov_base
-                       = check_pointer(desc[i].addr, desc[i].len);
-               /* If this is an input descriptor, increment that count. */
-               if (desc[i].flags & VRING_DESC_F_WRITE)
-                       (*in_num)++;
-               else {
-                       /*
-                        * If it's an output descriptor, they're all supposed
-                        * to come before any input descriptors.
-                        */
-                       if (*in_num)
-                               errx(1, "Descriptor has out after in");
-                       (*out_num)++;
-               }
-
-               /* If we've got too many, that implies a descriptor loop. */
-               if (*out_num + *in_num > max)
-                       errx(1, "Looped descriptor");
-       } while ((i = next_desc(desc, i, max)) != max);
-
-       return head;
-}
-
-/*
- * After we've used one of their buffers, we tell the Guest about it.  Sometime
- * later we'll want to send them an interrupt using trigger_irq(); note that
- * wait_for_vq_desc() does that for us if it has to wait.
- */
-static void add_used(struct virtqueue *vq, unsigned int head, int len)
-{
-       struct vring_used_elem *used;
-
-       /*
-        * The virtqueue contains a ring of used buffers.  Get a pointer to the
-        * next entry in that used ring.
-        */
-       used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
-       used->id = head;
-       used->len = len;
-       /* Make sure buffer is written before we update index. */
-       wmb();
-       vq->vring.used->idx++;
-       vq->pending_used++;
-}
-
-/* And here's the combo meal deal.  Supersize me! */
-static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
-{
-       add_used(vq, head, len);
-       trigger_irq(vq);
-}
-
-/*
- * The Console
- *
- * We associate some data with the console for our exit hack.
- */
-struct console_abort {
-       /* How many times have they hit ^C? */
-       int count;
-       /* When did they start? */
-       struct timeval start;
-};
-
-/* This is the routine which handles console input (ie. stdin). */
-static void console_input(struct virtqueue *vq)
-{
-       int len;
-       unsigned int head, in_num, out_num;
-       struct console_abort *abort = vq->dev->priv;
-       struct iovec iov[vq->vring.num];
-
-       /* Make sure there's a descriptor available. */
-       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
-       if (out_num)
-               errx(1, "Output buffers in console in queue?");
-
-       /* Read into it.  This is where we usually wait. */
-       len = readv(STDIN_FILENO, iov, in_num);
-       if (len <= 0) {
-               /* Ran out of input? */
-               warnx("Failed to get console input, ignoring console.");
-               /*
-                * For simplicity, dying threads kill the whole Launcher.  So
-                * just nap here.
-                */
-               for (;;)
-                       pause();
-       }
-
-       /* Tell the Guest we used a buffer. */
-       add_used_and_trigger(vq, head, len);
-
-       /*
-        * Three ^C within one second?  Exit.
-        *
-        * This is such a hack, but works surprisingly well.  Each ^C has to
-        * be in a buffer by itself, so they can't be too fast.  But we check
-        * that we get three within about a second, so they can't be too
-        * slow.
-        */
-       if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
-               abort->count = 0;
-               return;
-       }
-
-       abort->count++;
-       if (abort->count == 1)
-               gettimeofday(&abort->start, NULL);
-       else if (abort->count == 3) {
-               struct timeval now;
-               gettimeofday(&now, NULL);
-               /* Kill all Launcher processes with SIGINT, like normal ^C */
-               if (now.tv_sec <= abort->start.tv_sec+1)
-                       kill(0, SIGINT);
-               abort->count = 0;
-       }
-}
-
-/* This is the routine which handles console output (ie. stdout). */
-static void console_output(struct virtqueue *vq)
-{
-       unsigned int head, out, in;
-       struct iovec iov[vq->vring.num];
-
-       /* We usually wait in here, for the Guest to give us something. */
-       head = wait_for_vq_desc(vq, iov, &out, &in);
-       if (in)
-               errx(1, "Input buffers in console output queue?");
-
-       /* writev can return a partial write, so we loop here. */
-       while (!iov_empty(iov, out)) {
-               int len = writev(STDOUT_FILENO, iov, out);
-               if (len <= 0) {
-                       warn("Write to stdout gave %i (%d)", len, errno);
-                       break;
-               }
-               iov_consume(iov, out, len);
-       }
-
-       /*
-        * We're finished with that buffer: if we're going to sleep,
-        * wait_for_vq_desc() will prod the Guest with an interrupt.
-        */
-       add_used(vq, head, 0);
-}
-
-/*
- * The Network
- *
- * Handling output for network is also simple: we get all the output buffers
- * and write them to /dev/net/tun.
- */
-struct net_info {
-       int tunfd;
-};
-
-static void net_output(struct virtqueue *vq)
-{
-       struct net_info *net_info = vq->dev->priv;
-       unsigned int head, out, in;
-       struct iovec iov[vq->vring.num];
-
-       /* We usually wait in here for the Guest to give us a packet. */
-       head = wait_for_vq_desc(vq, iov, &out, &in);
-       if (in)
-               errx(1, "Input buffers in net output queue?");
-       /*
-        * Send the whole thing through to /dev/net/tun.  It expects the exact
-        * same format: what a coincidence!
-        */
-       if (writev(net_info->tunfd, iov, out) < 0)
-               warnx("Write to tun failed (%d)?", errno);
-
-       /*
-        * Done with that one; wait_for_vq_desc() will send the interrupt if
-        * all packets are processed.
-        */
-       add_used(vq, head, 0);
-}
-
-/*
- * Handling network input is a bit trickier, because I've tried to optimize it.
- *
- * First we have a helper routine which tells is if from this file descriptor
- * (ie. the /dev/net/tun device) will block:
- */
-static bool will_block(int fd)
-{
-       fd_set fdset;
-       struct timeval zero = { 0, 0 };
-       FD_ZERO(&fdset);
-       FD_SET(fd, &fdset);
-       return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
-}
-
-/*
- * This handles packets coming in from the tun device to our Guest.  Like all
- * service routines, it gets called again as soon as it returns, so you don't
- * see a while(1) loop here.
- */
-static void net_input(struct virtqueue *vq)
-{
-       int len;
-       unsigned int head, out, in;
-       struct iovec iov[vq->vring.num];
-       struct net_info *net_info = vq->dev->priv;
-
-       /*
-        * Get a descriptor to write an incoming packet into.  This will also
-        * send an interrupt if they're out of descriptors.
-        */
-       head = wait_for_vq_desc(vq, iov, &out, &in);
-       if (out)
-               errx(1, "Output buffers in net input queue?");
-
-       /*
-        * If it looks like we'll block reading from the tun device, send them
-        * an interrupt.
-        */
-       if (vq->pending_used && will_block(net_info->tunfd))
-               trigger_irq(vq);
-
-       /*
-        * Read in the packet.  This is where we normally wait (when there's no
-        * incoming network traffic).
-        */
-       len = readv(net_info->tunfd, iov, in);
-       if (len <= 0)
-               warn("Failed to read from tun (%d).", errno);
-
-       /*
-        * Mark that packet buffer as used, but don't interrupt here.  We want
-        * to wait until we've done as much work as we can.
-        */
-       add_used(vq, head, len);
-}
-/*:*/
-
-/* This is the helper to create threads: run the service routine in a loop. */
-static int do_thread(void *_vq)
-{
-       struct virtqueue *vq = _vq;
-
-       for (;;)
-               vq->service(vq);
-       return 0;
-}
-
-/*
- * When a child dies, we kill our entire process group with SIGTERM.  This
- * also has the side effect that the shell restores the console for us!
- */
-static void kill_launcher(int signal)
-{
-       kill(0, SIGTERM);
-}
-
-static void reset_device(struct device *dev)
-{
-       struct virtqueue *vq;
-
-       verbose("Resetting device %s\n", dev->name);
-
-       /* Clear any features they've acked. */
-       memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len);
-
-       /* We're going to be explicitly killing threads, so ignore them. */
-       signal(SIGCHLD, SIG_IGN);
-
-       /* Zero out the virtqueues, get rid of their threads */
-       for (vq = dev->vq; vq; vq = vq->next) {
-               if (vq->thread != (pid_t)-1) {
-                       kill(vq->thread, SIGTERM);
-                       waitpid(vq->thread, NULL, 0);
-                       vq->thread = (pid_t)-1;
-               }
-               memset(vq->vring.desc, 0,
-                      vring_size(vq->config.num, LGUEST_VRING_ALIGN));
-               lg_last_avail(vq) = 0;
-       }
-       dev->running = false;
-
-       /* Now we care if threads die. */
-       signal(SIGCHLD, (void *)kill_launcher);
-}
-
-/*L:216
- * This actually creates the thread which services the virtqueue for a device.
- */
-static void create_thread(struct virtqueue *vq)
-{
-       /*
-        * Create stack for thread.  Since the stack grows upwards, we point
-        * the stack pointer to the end of this region.
-        */
-       char *stack = malloc(32768);
-       unsigned long args[] = { LHREQ_EVENTFD,
-                                vq->config.pfn*getpagesize(), 0 };
-
-       /* Create a zero-initialized eventfd. */
-       vq->eventfd = eventfd(0, 0);
-       if (vq->eventfd < 0)
-               err(1, "Creating eventfd");
-       args[2] = vq->eventfd;
-
-       /*
-        * Attach an eventfd to this virtqueue: it will go off when the Guest
-        * does an LHCALL_NOTIFY for this vq.
-        */
-       if (write(lguest_fd, &args, sizeof(args)) != 0)
-               err(1, "Attaching eventfd");
-
-       /*
-        * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so
-        * we get a signal if it dies.
-        */
-       vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
-       if (vq->thread == (pid_t)-1)
-               err(1, "Creating clone");
-
-       /* We close our local copy now the child has it. */
-       close(vq->eventfd);
-}
-
-static void start_device(struct device *dev)
-{
-       unsigned int i;
-       struct virtqueue *vq;
-
-       verbose("Device %s OK: offered", dev->name);
-       for (i = 0; i < dev->feature_len; i++)
-               verbose(" %02x", get_feature_bits(dev)[i]);
-       verbose(", accepted");
-       for (i = 0; i < dev->feature_len; i++)
-               verbose(" %02x", get_feature_bits(dev)
-                       [dev->feature_len+i]);
-
-       for (vq = dev->vq; vq; vq = vq->next) {
-               if (vq->service)
-                       create_thread(vq);
-       }
-       dev->running = true;
-}
-
-static void cleanup_devices(void)
-{
-       struct device *dev;
-
-       for (dev = devices.dev; dev; dev = dev->next)
-               reset_device(dev);
-
-       /* If we saved off the original terminal settings, restore them now. */
-       if (orig_term.c_lflag & (ISIG|ICANON|ECHO))
-               tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
-}
-
-/* When the Guest tells us they updated the status field, we handle it. */
-static void update_device_status(struct device *dev)
-{
-       /* A zero status is a reset, otherwise it's a set of flags. */
-       if (dev->desc->status == 0)
-               reset_device(dev);
-       else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
-               warnx("Device %s configuration FAILED", dev->name);
-               if (dev->running)
-                       reset_device(dev);
-       } else {
-               if (dev->running)
-                       err(1, "Device %s features finalized twice", dev->name);
-               start_device(dev);
-       }
-}
-
-/*L:215
- * This is the generic routine we call when the Guest uses LHCALL_NOTIFY.  In
- * particular, it's used to notify us of device status changes during boot.
- */
-static void handle_output(unsigned long addr)
-{
-       struct device *i;
-
-       /* Check each device. */
-       for (i = devices.dev; i; i = i->next) {
-               struct virtqueue *vq;
-
-               /*
-                * Notifications to device descriptors mean they updated the
-                * device status.
-                */
-               if (from_guest_phys(addr) == i->desc) {
-                       update_device_status(i);
-                       return;
-               }
-
-               /* Devices should not be used before features are finalized. */
-               for (vq = i->vq; vq; vq = vq->next) {
-                       if (addr != vq->config.pfn*getpagesize())
-                               continue;
-                       errx(1, "Notification on %s before setup!", i->name);
-               }
-       }
-
-       /*
-        * Early console write is done using notify on a nul-terminated string
-        * in Guest memory.  It's also great for hacking debugging messages
-        * into a Guest.
-        */
-       if (addr >= guest_limit)
-               errx(1, "Bad NOTIFY %#lx", addr);
-
-       write(STDOUT_FILENO, from_guest_phys(addr),
-             strnlen(from_guest_phys(addr), guest_limit - addr));
-}
-
-/*L:190
- * Device Setup
- *
- * All devices need a descriptor so the Guest knows it exists, and a "struct
- * device" so the Launcher can keep track of it.  We have common helper
- * routines to allocate and manage them.
- */
-
-/*
- * The layout of the device page is a "struct lguest_device_desc" followed by a
- * number of virtqueue descriptors, then two sets of feature bits, then an
- * array of configuration bytes.  This routine returns the configuration
- * pointer.
- */
-static u8 *device_config(const struct device *dev)
-{
-       return (void *)(dev->desc + 1)
-               + dev->num_vq * sizeof(struct lguest_vqconfig)
-               + dev->feature_len * 2;
-}
-
-/*
- * This routine allocates a new "struct lguest_device_desc" from descriptor
- * table page just above the Guest's normal memory.  It returns a pointer to
- * that descriptor.
- */
-static struct lguest_device_desc *new_dev_desc(u16 type)
-{
-       struct lguest_device_desc d = { .type = type };
-       void *p;
-
-       /* Figure out where the next device config is, based on the last one. */
-       if (devices.lastdev)
-               p = device_config(devices.lastdev)
-                       + devices.lastdev->desc->config_len;
-       else
-               p = devices.descpage;
-
-       /* We only have one page for all the descriptors. */
-       if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
-               errx(1, "Too many devices");
-
-       /* p might not be aligned, so we memcpy in. */
-       return memcpy(p, &d, sizeof(d));
-}
-
-/*
- * Each device descriptor is followed by the description of its virtqueues.  We
- * specify how many descriptors the virtqueue is to have.
- */
-static void add_virtqueue(struct device *dev, unsigned int num_descs,
-                         void (*service)(struct virtqueue *))
-{
-       unsigned int pages;
-       struct virtqueue **i, *vq = malloc(sizeof(*vq));
-       void *p;
-
-       /* First we need some memory for this virtqueue. */
-       pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1)
-               / getpagesize();
-       p = get_pages(pages);
-
-       /* Initialize the virtqueue */
-       vq->next = NULL;
-       vq->last_avail_idx = 0;
-       vq->dev = dev;
-
-       /*
-        * This is the routine the service thread will run, and its Process ID
-        * once it's running.
-        */
-       vq->service = service;
-       vq->thread = (pid_t)-1;
-
-       /* Initialize the configuration. */
-       vq->config.num = num_descs;
-       vq->config.irq = devices.next_irq++;
-       vq->config.pfn = to_guest_phys(p) / getpagesize();
-
-       /* Initialize the vring. */
-       vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);
-
-       /*
-        * Append virtqueue to this device's descriptor.  We use
-        * device_config() to get the end of the device's current virtqueues;
-        * we check that we haven't added any config or feature information
-        * yet, otherwise we'd be overwriting them.
-        */
-       assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
-       memcpy(device_config(dev), &vq->config, sizeof(vq->config));
-       dev->num_vq++;
-       dev->desc->num_vq++;
-
-       verbose("Virtqueue page %#lx\n", to_guest_phys(p));
-
-       /*
-        * Add to tail of list, so dev->vq is first vq, dev->vq->next is
-        * second.
-        */
-       for (i = &dev->vq; *i; i = &(*i)->next);
-       *i = vq;
-}
-
-/*
- * The first half of the feature bitmask is for us to advertise features.  The
- * second half is for the Guest to accept features.
- */
-static void add_feature(struct device *dev, unsigned bit)
-{
-       u8 *features = get_feature_bits(dev);
-
-       /* We can't extend the feature bits once we've added config bytes */
-       if (dev->desc->feature_len <= bit / CHAR_BIT) {
-               assert(dev->desc->config_len == 0);
-               dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1;
-       }
-
-       features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
-}
-
-/*
- * This routine sets the configuration fields for an existing device's
- * descriptor.  It only works for the last device, but that's OK because that's
- * how we use it.
- */
-static void set_config(struct device *dev, unsigned len, const void *conf)
-{
-       /* Check we haven't overflowed our single page. */
-       if (device_config(dev) + len > devices.descpage + getpagesize())
-               errx(1, "Too many devices");
-
-       /* Copy in the config information, and store the length. */
-       memcpy(device_config(dev), conf, len);
-       dev->desc->config_len = len;
-
-       /* Size must fit in config_len field (8 bits)! */
-       assert(dev->desc->config_len == len);
-}
-
-/*
- * This routine does all the creation and setup of a new device, including
- * calling new_dev_desc() to allocate the descriptor and device memory.  We
- * don't actually start the service threads until later.
- *
- * See what I mean about userspace being boring?
- */
-static struct device *new_device(const char *name, u16 type)
-{
-       struct device *dev = malloc(sizeof(*dev));
-
-       /* Now we populate the fields one at a time. */
-       dev->desc = new_dev_desc(type);
-       dev->name = name;
-       dev->vq = NULL;
-       dev->feature_len = 0;
-       dev->num_vq = 0;
-       dev->running = false;
-
-       /*
-        * Append to device list.  Prepending to a single-linked list is
-        * easier, but the user expects the devices to be arranged on the bus
-        * in command-line order.  The first network device on the command line
-        * is eth0, the first block device /dev/vda, etc.
-        */
-       if (devices.lastdev)
-               devices.lastdev->next = dev;
-       else
-               devices.dev = dev;
-       devices.lastdev = dev;
-
-       return dev;
-}
-
-/*
- * Our first setup routine is the console.  It's a fairly simple device, but
- * UNIX tty handling makes it uglier than it could be.
- */
-static void setup_console(void)
-{
-       struct device *dev;
-
-       /* If we can save the initial standard input settings... */
-       if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
-               struct termios term = orig_term;
-               /*
-                * Then we turn off echo, line buffering and ^C etc: We want a
-                * raw input stream to the Guest.
-                */
-               term.c_lflag &= ~(ISIG|ICANON|ECHO);
-               tcsetattr(STDIN_FILENO, TCSANOW, &term);
-       }
-
-       dev = new_device("console", VIRTIO_ID_CONSOLE);
-
-       /* We store the console state in dev->priv, and initialize it. */
-       dev->priv = malloc(sizeof(struct console_abort));
-       ((struct console_abort *)dev->priv)->count = 0;
-
-       /*
-        * The console needs two virtqueues: the input then the output.  When
-        * they put something the input queue, we make sure we're listening to
-        * stdin.  When they put something in the output queue, we write it to
-        * stdout.
-        */
-       add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
-       add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
-
-       verbose("device %u: console\n", ++devices.device_num);
-}
-/*:*/
-
-/*M:010
- * Inter-guest networking is an interesting area.  Simplest is to have a
- * --sharenet=<name> option which opens or creates a named pipe.  This can be
- * used to send packets to another guest in a 1:1 manner.
- *
- * More sophisticated is to use one of the tools developed for project like UML
- * to do networking.
- *
- * Faster is to do virtio bonding in kernel.  Doing this 1:1 would be
- * completely generic ("here's my vring, attach to your vring") and would work
- * for any traffic.  Of course, namespace and permissions issues need to be
- * dealt with.  A more sophisticated "multi-channel" virtio_net.c could hide
- * multiple inter-guest channels behind one interface, although it would
- * require some manner of hotplugging new virtio channels.
- *
- * Finally, we could use a virtio network switch in the kernel, ie. vhost.
-:*/
-
-static u32 str2ip(const char *ipaddr)
-{
-       unsigned int b[4];
-
-       if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4)
-               errx(1, "Failed to parse IP address '%s'", ipaddr);
-       return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
-}
-
-static void str2mac(const char *macaddr, unsigned char mac[6])
-{
-       unsigned int m[6];
-       if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
-                  &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6)
-               errx(1, "Failed to parse mac address '%s'", macaddr);
-       mac[0] = m[0];
-       mac[1] = m[1];
-       mac[2] = m[2];
-       mac[3] = m[3];
-       mac[4] = m[4];
-       mac[5] = m[5];
-}
-
-/*
- * This code is "adapted" from libbridge: it attaches the Host end of the
- * network device to the bridge device specified by the command line.
- *
- * This is yet another James Morris contribution (I'm an IP-level guy, so I
- * dislike bridging), and I just try not to break it.
- */
-static void add_to_bridge(int fd, const char *if_name, const char *br_name)
-{
-       int ifidx;
-       struct ifreq ifr;
-
-       if (!*br_name)
-               errx(1, "must specify bridge name");
-
-       ifidx = if_nametoindex(if_name);
-       if (!ifidx)
-               errx(1, "interface %s does not exist!", if_name);
-
-       strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
-       ifr.ifr_name[IFNAMSIZ-1] = '\0';
-       ifr.ifr_ifindex = ifidx;
-       if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
-               err(1, "can't add %s to bridge %s", if_name, br_name);
-}
-
-/*
- * This sets up the Host end of the network device with an IP address, brings
- * it up so packets will flow, the copies the MAC address into the hwaddr
- * pointer.
- */
-static void configure_device(int fd, const char *tapif, u32 ipaddr)
-{
-       struct ifreq ifr;
-       struct sockaddr_in sin;
-
-       memset(&ifr, 0, sizeof(ifr));
-       strcpy(ifr.ifr_name, tapif);
-
-       /* Don't read these incantations.  Just cut & paste them like I did! */
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = htonl(ipaddr);
-       memcpy(&ifr.ifr_addr, &sin, sizeof(sin));
-       if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
-               err(1, "Setting %s interface address", tapif);
-       ifr.ifr_flags = IFF_UP;
-       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
-               err(1, "Bringing interface %s up", tapif);
-}
-
-static int get_tun_device(char tapif[IFNAMSIZ])
-{
-       struct ifreq ifr;
-       int netfd;
-
-       /* Start with this zeroed.  Messy but sure. */
-       memset(&ifr, 0, sizeof(ifr));
-
-       /*
-        * We open the /dev/net/tun device and tell it we want a tap device.  A
-        * tap device is like a tun device, only somehow different.  To tell
-        * the truth, I completely blundered my way through this code, but it
-        * works now!
-        */
-       netfd = open_or_die("/dev/net/tun", O_RDWR);
-       ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
-       strcpy(ifr.ifr_name, "tap%d");
-       if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
-               err(1, "configuring /dev/net/tun");
-
-       if (ioctl(netfd, TUNSETOFFLOAD,
-                 TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0)
-               err(1, "Could not set features for tun device");
-
-       /*
-        * We don't need checksums calculated for packets coming in this
-        * device: trust us!
-        */
-       ioctl(netfd, TUNSETNOCSUM, 1);
-
-       memcpy(tapif, ifr.ifr_name, IFNAMSIZ);
-       return netfd;
-}
-
-/*L:195
- * Our network is a Host<->Guest network.  This can either use bridging or
- * routing, but the principle is the same: it uses the "tun" device to inject
- * packets into the Host as if they came in from a normal network card.  We
- * just shunt packets between the Guest and the tun device.
- */
-static void setup_tun_net(char *arg)
-{
-       struct device *dev;
-       struct net_info *net_info = malloc(sizeof(*net_info));
-       int ipfd;
-       u32 ip = INADDR_ANY;
-       bool bridging = false;
-       char tapif[IFNAMSIZ], *p;
-       struct virtio_net_config conf;
-
-       net_info->tunfd = get_tun_device(tapif);
-
-       /* First we create a new network device. */
-       dev = new_device("net", VIRTIO_ID_NET);
-       dev->priv = net_info;
-
-       /* Network devices need a recv and a send queue, just like console. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
-       add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
-
-       /*
-        * We need a socket to perform the magic network ioctls to bring up the
-        * tap interface, connect to the bridge etc.  Any socket will do!
-        */
-       ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
-       if (ipfd < 0)
-               err(1, "opening IP socket");
-
-       /* If the command line was --tunnet=bridge:<name> do bridging. */
-       if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
-               arg += strlen(BRIDGE_PFX);
-               bridging = true;
-       }
-
-       /* A mac address may follow the bridge name or IP address */
-       p = strchr(arg, ':');
-       if (p) {
-               str2mac(p+1, conf.mac);
-               add_feature(dev, VIRTIO_NET_F_MAC);
-               *p = '\0';
-       }
-
-       /* arg is now either an IP address or a bridge name */
-       if (bridging)
-               add_to_bridge(ipfd, tapif, arg);
-       else
-               ip = str2ip(arg);
-
-       /* Set up the tun device. */
-       configure_device(ipfd, tapif, ip);
-
-       /* Expect Guest to handle everything except UFO */
-       add_feature(dev, VIRTIO_NET_F_CSUM);
-       add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
-       add_feature(dev, VIRTIO_NET_F_GUEST_TSO4);
-       add_feature(dev, VIRTIO_NET_F_GUEST_TSO6);
-       add_feature(dev, VIRTIO_NET_F_GUEST_ECN);
-       add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
-       add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
-       add_feature(dev, VIRTIO_NET_F_HOST_ECN);
-       /* We handle indirect ring entries */
-       add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
-       set_config(dev, sizeof(conf), &conf);
-
-       /* We don't need the socket any more; setup is done. */
-       close(ipfd);
-
-       devices.device_num++;
-
-       if (bridging)
-               verbose("device %u: tun %s attached to bridge: %s\n",
-                       devices.device_num, tapif, arg);
-       else
-               verbose("device %u: tun %s: %s\n",
-                       devices.device_num, tapif, arg);
-}
-/*:*/
-
-/* This hangs off device->priv. */
-struct vblk_info {
-       /* The size of the file. */
-       off64_t len;
-
-       /* The file descriptor for the file. */
-       int fd;
-
-};
-
-/*L:210
- * The Disk
- *
- * The disk only has one virtqueue, so it only has one thread.  It is really
- * simple: the Guest asks for a block number and we read or write that position
- * in the file.
- *
- * Before we serviced each virtqueue in a separate thread, that was unacceptably
- * slow: the Guest waits until the read is finished before running anything
- * else, even if it could have been doing useful work.
- *
- * We could have used async I/O, except it's reputed to suck so hard that
- * characters actually go missing from your code when you try to use it.
- */
-static void blk_request(struct virtqueue *vq)
-{
-       struct vblk_info *vblk = vq->dev->priv;
-       unsigned int head, out_num, in_num, wlen;
-       int ret;
-       u8 *in;
-       struct virtio_blk_outhdr *out;
-       struct iovec iov[vq->vring.num];
-       off64_t off;
-
-       /*
-        * Get the next request, where we normally wait.  It triggers the
-        * interrupt to acknowledge previously serviced requests (if any).
-        */
-       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
-
-       /*
-        * Every block request should contain at least one output buffer
-        * (detailing the location on disk and the type of request) and one
-        * input buffer (to hold the result).
-        */
-       if (out_num == 0 || in_num == 0)
-               errx(1, "Bad virtblk cmd %u out=%u in=%u",
-                    head, out_num, in_num);
-
-       out = convert(&iov[0], struct virtio_blk_outhdr);
-       in = convert(&iov[out_num+in_num-1], u8);
-       /*
-        * For historical reasons, block operations are expressed in 512 byte
-        * "sectors".
-        */
-       off = out->sector * 512;
-
-       /*
-        * In general the virtio block driver is allowed to try SCSI commands.
-        * It'd be nice if we supported eject, for example, but we don't.
-        */
-       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
-               fprintf(stderr, "Scsi commands unsupported\n");
-               *in = VIRTIO_BLK_S_UNSUPP;
-               wlen = sizeof(*in);
-       } else if (out->type & VIRTIO_BLK_T_OUT) {
-               /*
-                * Write
-                *
-                * Move to the right location in the block file.  This can fail
-                * if they try to write past end.
-                */
-               if (lseek64(vblk->fd, off, SEEK_SET) != off)
-                       err(1, "Bad seek to sector %llu", out->sector);
-
-               ret = writev(vblk->fd, iov+1, out_num-1);
-               verbose("WRITE to sector %llu: %i\n", out->sector, ret);
-
-               /*
-                * Grr... Now we know how long the descriptor they sent was, we
-                * make sure they didn't try to write over the end of the block
-                * file (possibly extending it).
-                */
-               if (ret > 0 && off + ret > vblk->len) {
-                       /* Trim it back to the correct length */
-                       ftruncate64(vblk->fd, vblk->len);
-                       /* Die, bad Guest, die. */
-                       errx(1, "Write past end %llu+%u", off, ret);
-               }
-
-               wlen = sizeof(*in);
-               *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
-       } else if (out->type & VIRTIO_BLK_T_FLUSH) {
-               /* Flush */
-               ret = fdatasync(vblk->fd);
-               verbose("FLUSH fdatasync: %i\n", ret);
-               wlen = sizeof(*in);
-               *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
-       } else {
-               /*
-                * Read
-                *
-                * Move to the right location in the block file.  This can fail
-                * if they try to read past end.
-                */
-               if (lseek64(vblk->fd, off, SEEK_SET) != off)
-                       err(1, "Bad seek to sector %llu", out->sector);
-
-               ret = readv(vblk->fd, iov+1, in_num-1);
-               verbose("READ from sector %llu: %i\n", out->sector, ret);
-               if (ret >= 0) {
-                       wlen = sizeof(*in) + ret;
-                       *in = VIRTIO_BLK_S_OK;
-               } else {
-                       wlen = sizeof(*in);
-                       *in = VIRTIO_BLK_S_IOERR;
-               }
-       }
-
-       /* Finished that request. */
-       add_used(vq, head, wlen);
-}
-
-/*L:198 This actually sets up a virtual block device. */
-static void setup_block_file(const char *filename)
-{
-       struct device *dev;
-       struct vblk_info *vblk;
-       struct virtio_blk_config conf;
-
-       /* Creat the device. */
-       dev = new_device("block", VIRTIO_ID_BLOCK);
-
-       /* The device has one virtqueue, where the Guest places requests. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, blk_request);
-
-       /* Allocate the room for our own bookkeeping */
-       vblk = dev->priv = malloc(sizeof(*vblk));
-
-       /* First we open the file and store the length. */
-       vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
-       vblk->len = lseek64(vblk->fd, 0, SEEK_END);
-
-       /* We support FLUSH. */
-       add_feature(dev, VIRTIO_BLK_F_FLUSH);
-
-       /* Tell Guest how many sectors this device has. */
-       conf.capacity = cpu_to_le64(vblk->len / 512);
-
-       /*
-        * Tell Guest not to put in too many descriptors at once: two are used
-        * for the in and out elements.
-        */
-       add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
-       conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
-
-       /* Don't try to put whole struct: we have 8 bit limit. */
-       set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf);
-
-       verbose("device %u: virtblock %llu sectors\n",
-               ++devices.device_num, le64_to_cpu(conf.capacity));
-}
-
-/*L:211
- * Our random number generator device reads from /dev/random into the Guest's
- * input buffers.  The usual case is that the Guest doesn't want random numbers
- * and so has no buffers although /dev/random is still readable, whereas
- * console is the reverse.
- *
- * The same logic applies, however.
- */
-struct rng_info {
-       int rfd;
-};
-
-static void rng_input(struct virtqueue *vq)
-{
-       int len;
-       unsigned int head, in_num, out_num, totlen = 0;
-       struct rng_info *rng_info = vq->dev->priv;
-       struct iovec iov[vq->vring.num];
-
-       /* First we need a buffer from the Guests's virtqueue. */
-       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
-       if (out_num)
-               errx(1, "Output buffers in rng?");
-
-       /*
-        * Just like the console write, we loop to cover the whole iovec.
-        * In this case, short reads actually happen quite a bit.
-        */
-       while (!iov_empty(iov, in_num)) {
-               len = readv(rng_info->rfd, iov, in_num);
-               if (len <= 0)
-                       err(1, "Read from /dev/random gave %i", len);
-               iov_consume(iov, in_num, len);
-               totlen += len;
-       }
-
-       /* Tell the Guest about the new input. */
-       add_used(vq, head, totlen);
-}
-
-/*L:199
- * This creates a "hardware" random number device for the Guest.
- */
-static void setup_rng(void)
-{
-       struct device *dev;
-       struct rng_info *rng_info = malloc(sizeof(*rng_info));
-
-       /* Our device's privat info simply contains the /dev/random fd. */
-       rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
-
-       /* Create the new device. */
-       dev = new_device("rng", VIRTIO_ID_RNG);
-       dev->priv = rng_info;
-
-       /* The device has one virtqueue, where the Guest places inbufs. */
-       add_virtqueue(dev, VIRTQUEUE_NUM, rng_input);
-
-       verbose("device %u: rng\n", devices.device_num++);
-}
-/* That's the end of device setup. */
-
-/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
-static void __attribute__((noreturn)) restart_guest(void)
-{
-       unsigned int i;
-
-       /*
-        * Since we don't track all open fds, we simply close everything beyond
-        * stderr.
-        */
-       for (i = 3; i < FD_SETSIZE; i++)
-               close(i);
-
-       /* Reset all the devices (kills all threads). */
-       cleanup_devices();
-
-       execv(main_args[0], main_args);
-       err(1, "Could not exec %s", main_args[0]);
-}
-
-/*L:220
- * Finally we reach the core of the Launcher which runs the Guest, serves
- * its input and output, and finally, lays it to rest.
- */
-static void __attribute__((noreturn)) run_guest(void)
-{
-       for (;;) {
-               unsigned long notify_addr;
-               int readval;
-
-               /* We read from the /dev/lguest device to run the Guest. */
-               readval = pread(lguest_fd, &notify_addr,
-                               sizeof(notify_addr), cpu_id);
-
-               /* One unsigned long means the Guest did HCALL_NOTIFY */
-               if (readval == sizeof(notify_addr)) {
-                       verbose("Notify on address %#lx\n", notify_addr);
-                       handle_output(notify_addr);
-               /* ENOENT means the Guest died.  Reading tells us why. */
-               } else if (errno == ENOENT) {
-                       char reason[1024] = { 0 };
-                       pread(lguest_fd, reason, sizeof(reason)-1, cpu_id);
-                       errx(1, "%s", reason);
-               /* ERESTART means that we need to reboot the guest */
-               } else if (errno == ERESTART) {
-                       restart_guest();
-               /* Anything else means a bug or incompatible change. */
-               } else
-                       err(1, "Running guest failed");
-       }
-}
-/*L:240
- * This is the end of the Launcher.  The good news: we are over halfway
- * through!  The bad news: the most fiendish part of the code still lies ahead
- * of us.
- *
- * Are you ready?  Take a deep breath and join me in the core of the Host, in
- * "make Host".
-:*/
-
-static struct option opts[] = {
-       { "verbose", 0, NULL, 'v' },
-       { "tunnet", 1, NULL, 't' },
-       { "block", 1, NULL, 'b' },
-       { "rng", 0, NULL, 'r' },
-       { "initrd", 1, NULL, 'i' },
-       { "username", 1, NULL, 'u' },
-       { "chroot", 1, NULL, 'c' },
-       { NULL },
-};
-static void usage(void)
-{
-       errx(1, "Usage: lguest [--verbose] "
-            "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n"
-            "|--block=<filename>|--initrd=<filename>]...\n"
-            "<mem-in-mb> vmlinux [args...]");
-}
-
-/*L:105 The main routine is where the real work begins: */
-int main(int argc, char *argv[])
-{
-       /* Memory, code startpoint and size of the (optional) initrd. */
-       unsigned long mem = 0, start, initrd_size = 0;
-       /* Two temporaries. */
-       int i, c;
-       /* The boot information for the Guest. */
-       struct boot_params *boot;
-       /* If they specify an initrd file to load. */
-       const char *initrd_name = NULL;
-
-       /* Password structure for initgroups/setres[gu]id */
-       struct passwd *user_details = NULL;
-
-       /* Directory to chroot to */
-       char *chroot_path = NULL;
-
-       /* Save the args: we "reboot" by execing ourselves again. */
-       main_args = argv;
-
-       /*
-        * First we initialize the device list.  We keep a pointer to the last
-        * device, and the next interrupt number to use for devices (1:
-        * remember that 0 is used by the timer).
-        */
-       devices.lastdev = NULL;
-       devices.next_irq = 1;
-
-       /* We're CPU 0.  In fact, that's the only CPU possible right now. */
-       cpu_id = 0;
-
-       /*
-        * We need to know how much memory so we can set up the device
-        * descriptor and memory pages for the devices as we parse the command
-        * line.  So we quickly look through the arguments to find the amount
-        * of memory now.
-        */
-       for (i = 1; i < argc; i++) {
-               if (argv[i][0] != '-') {
-                       mem = atoi(argv[i]) * 1024 * 1024;
-                       /*
-                        * We start by mapping anonymous pages over all of
-                        * guest-physical memory range.  This fills it with 0,
-                        * and ensures that the Guest won't be killed when it
-                        * tries to access it.
-                        */
-                       guest_base = map_zeroed_pages(mem / getpagesize()
-                                                     + DEVICE_PAGES);
-                       guest_limit = mem;
-                       guest_max = mem + DEVICE_PAGES*getpagesize();
-                       devices.descpage = get_pages(1);
-                       break;
-               }
-       }
-
-       /* The options are fairly straight-forward */
-       while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
-               switch (c) {
-               case 'v':
-                       verbose = true;
-                       break;
-               case 't':
-                       setup_tun_net(optarg);
-                       break;
-               case 'b':
-                       setup_block_file(optarg);
-                       break;
-               case 'r':
-                       setup_rng();
-                       break;
-               case 'i':
-                       initrd_name = optarg;
-                       break;
-               case 'u':
-                       user_details = getpwnam(optarg);
-                       if (!user_details)
-                               err(1, "getpwnam failed, incorrect username?");
-                       break;
-               case 'c':
-                       chroot_path = optarg;
-                       break;
-               default:
-                       warnx("Unknown argument %s", argv[optind]);
-                       usage();
-               }
-       }
-       /*
-        * After the other arguments we expect memory and kernel image name,
-        * followed by command line arguments for the kernel.
-        */
-       if (optind + 2 > argc)
-               usage();
-
-       verbose("Guest base is at %p\n", guest_base);
-
-       /* We always have a console device */
-       setup_console();
-
-       /* Now we load the kernel */
-       start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
-
-       /* Boot information is stashed at physical address 0 */
-       boot = from_guest_phys(0);
-
-       /* Map the initrd image if requested (at top of physical memory) */
-       if (initrd_name) {
-               initrd_size = load_initrd(initrd_name, mem);
-               /*
-                * These are the location in the Linux boot header where the
-                * start and size of the initrd are expected to be found.
-                */
-               boot->hdr.ramdisk_image = mem - initrd_size;
-               boot->hdr.ramdisk_size = initrd_size;
-               /* The bootloader type 0xFF means "unknown"; that's OK. */
-               boot->hdr.type_of_loader = 0xFF;
-       }
-
-       /*
-        * The Linux boot header contains an "E820" memory map: ours is a
-        * simple, single region.
-        */
-       boot->e820_entries = 1;
-       boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
-       /*
-        * The boot header contains a command line pointer: we put the command
-        * line after the boot header.
-        */
-       boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
-       /* We use a simple helper to copy the arguments separated by spaces. */
-       concat((char *)(boot + 1), argv+optind+2);
-
-       /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
-       boot->hdr.kernel_alignment = 0x1000000;
-
-       /* Boot protocol version: 2.07 supports the fields for lguest. */
-       boot->hdr.version = 0x207;
-
-       /* The hardware_subarch value of "1" tells the Guest it's an lguest. */
-       boot->hdr.hardware_subarch = 1;
-
-       /* Tell the entry path not to try to reload segment registers. */
-       boot->hdr.loadflags |= KEEP_SEGMENTS;
-
-       /* We tell the kernel to initialize the Guest. */
-       tell_kernel(start);
-
-       /* Ensure that we terminate if a device-servicing child dies. */
-       signal(SIGCHLD, kill_launcher);
-
-       /* If we exit via err(), this kills all the threads, restores tty. */
-       atexit(cleanup_devices);
-
-       /* If requested, chroot to a directory */
-       if (chroot_path) {
-               if (chroot(chroot_path) != 0)
-                       err(1, "chroot(\"%s\") failed", chroot_path);
-
-               if (chdir("/") != 0)
-                       err(1, "chdir(\"/\") failed");
-
-               verbose("chroot done\n");
-       }
-
-       /* If requested, drop privileges */
-       if (user_details) {
-               uid_t u;
-               gid_t g;
-
-               u = user_details->pw_uid;
-               g = user_details->pw_gid;
-
-               if (initgroups(user_details->pw_name, g) != 0)
-                       err(1, "initgroups failed");
-
-               if (setresgid(g, g, g) != 0)
-                       err(1, "setresgid failed");
-
-               if (setresuid(u, u, u) != 0)
-                       err(1, "setresuid failed");
-
-               verbose("Dropping privileges completed\n");
-       }
-
-       /* Finally, run the Guest.  This doesn't return. */
-       run_guest();
-}
-/*:*/
-
-/*M:999
- * Mastery is done: you now know everything I do.
- *
- * But surely you have seen code, features and bugs in your wanderings which
- * you now yearn to attack?  That is the real game, and I look forward to you
- * patching and forking lguest into the Your-Name-Here-visor.
- *
- * Farewell, and good coding!
- * Rusty Russell.
- */
diff --git a/Documentation/virtual/lguest/lguest.txt b/Documentation/virtual/lguest/lguest.txt
deleted file mode 100644 (file)
index bff0c55..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-      __
- (___()'`;  Rusty's Remarkably Unreliable Guide to Lguest
- /,    /`      - or, A Young Coder's Illustrated Hypervisor
- \\"--\\    http://lguest.ozlabs.org
-
-Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel,
-for Linux developers and users to experiment with virtualization with the
-minimum of complexity.  Nonetheless, it should have sufficient features to
-make it useful for specific tasks, and, of course, you are encouraged to fork
-and enhance it (see drivers/lguest/README).
-
-Features:
-
-- Kernel module which runs in a normal kernel.
-- Simple I/O model for communication.
-- Simple program to create new guests.
-- Logo contains cute puppies: http://lguest.ozlabs.org
-
-Developer features:
-
-- Fun to hack on.
-- No ABI: being tied to a specific kernel anyway, you can change anything.
-- Many opportunities for improvement or feature implementation.
-
-Running Lguest:
-
-- The easiest way to run lguest is to use same kernel as guest and host.
-  You can configure them differently, but usually it's easiest not to.
-
-  You will need to configure your kernel with the following options:
-
-  "General setup":
-     "Prompt for development and/or incomplete code/drivers" = Y
-        (CONFIG_EXPERIMENTAL=y)
-
-  "Processor type and features":
-     "Paravirtualized guest support" = Y
-        "Lguest guest support" = Y
-     "High Memory Support" = off/4GB
-     "Alignment value to which kernel should be aligned" = 0x100000
-        (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
-         CONFIG_PHYSICAL_ALIGN=0x100000)
-
-  "Device Drivers":
-     "Block devices"
-        "Virtio block driver (EXPERIMENTAL)" = M/Y
-     "Network device support"
-        "Universal TUN/TAP device driver support" = M/Y
-        "Virtio network driver (EXPERIMENTAL)" = M/Y
-           (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m)
-
-  "Virtualization"
-     "Linux hypervisor example code" = M/Y
-        (CONFIG_LGUEST=m)
-
-- A tool called "lguest" is available in this directory: type "make"
-  to build it.  If you didn't build your kernel in-tree, use "make
-  O=<builddir>".
-
-- Create or find a root disk image.  There are several useful ones
-  around, such as the xm-test tiny root image at
-         http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img
-
-  For more serious work, I usually use a distribution ISO image and
-  install it under qemu, then make multiple copies:
-
-         dd if=/dev/zero of=rootfile bs=1M count=2048
-         qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
-
-  Make sure that you install a getty on /dev/hvc0 if you want to log in on the
-  console!
-
-- "modprobe lg" if you built it as a module.
-
-- Run an lguest as root:
-
-      Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \
-        --block=rootfile root=/dev/vda
-
-   Explanation:
-    64: the amount of memory to use, in MB.
-
-    vmlinux: the kernel image found in the top of your build directory.  You
-       can also use a standard bzImage.
-
-    --tunnet=192.168.19.1: configures a "tap" device for networking with this
-       IP address.
-
-    --block=rootfile: a file or block device which becomes /dev/vda
-       inside the guest.
-
-    root=/dev/vda: this (and anything else on the command line) are
-       kernel boot parameters.
-
-- Configuring networking.  I usually have the host masquerade, using
-  "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 >
-  /proc/sys/net/ipv4/ip_forward".  In this example, I would configure
-  eth0 inside the guest at 192.168.19.2.
-
-  Another method is to bridge the tap device to an external interface
-  using --tunnet=bridge:<bridgename>, and perhaps run dhcp on the guest
-  to obtain an IP address.  The bridge needs to be configured first:
-  this option simply adds the tap interface to it.
-
-  A simple example on my system:
-
-    ifconfig eth0 0.0.0.0
-    brctl addbr lg0
-    ifconfig lg0 up
-    brctl addif lg0 eth0
-    dhclient lg0
-
-  Then use --tunnet=bridge:lg0 when launching the guest.
-
-  See:
-  
-    http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
-    
-  for general information on how to get bridging to work.
-
-- Random number generation. Using the --rng option will provide a
-  /dev/hwrng in the guest that will read from the host's /dev/random.
-  Use this option in conjunction with rng-tools (see ../hw_random.txt)
-  to provide entropy to the guest kernel's /dev/random.
-
-There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
-
-Good luck!
-Rusty Russell rusty@rustcorp.com.au.
index f464f47bc60dacd77fecc7797dfe658708acb41e..6752870c4970d73721c48a041b15aa36af929ab5 100644 (file)
@@ -117,7 +117,7 @@ can be influenced by kernel parameters:
 
 slub_min_objects=x             (default 4)
 slub_min_order=x               (default 0)
-slub_max_order=x               (default 1)
+slub_max_order=x               (default 3 (PAGE_ALLOC_COSTLY_ORDER))
 
 slub_min_objects allows to specify how many objects must at least fit
 into one slab in order for the allocation order to be acceptable.
@@ -131,7 +131,10 @@ slub_min_objects.
 slub_max_order specified the order at which slub_min_objects should no
 longer be checked. This is useful to avoid SLUB trying to generate
 super large order pages to fit slub_min_objects of a slab cache with
-large object sizes into one high order page.
+large object sizes into one high order page. Setting command line
+parameter debug_guardpage_minorder=N (N > 0), forces setting
+slub_max_order to 0, what cause minimum possible order of slabs
+allocation.
 
 SLUB Debug output
 -----------------
index a2883a283698b1cf89f317ec075ae4948583a383..7559c1ca56ba7afc11104e430c20417d905654f9 100644 (file)
@@ -342,7 +342,7 @@ S:  Supported
 F:     drivers/mfd/adp5520.c
 F:     drivers/video/backlight/adp5520_bl.c
 F:     drivers/leds/leds-adp5520.c
-F:     drivers/gpio/adp5520-gpio.c
+F:     drivers/gpio/gpio-adp5520.c
 F:     drivers/input/keyboard/adp5520-keys.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
@@ -351,7 +351,7 @@ L:  device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5588
 S:     Supported
 F:     drivers/input/keyboard/adp5588-keys.c
-F:     drivers/gpio/adp5588-gpio.c
+F:     drivers/gpio/gpio-adp5588.c
 
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
@@ -537,6 +537,7 @@ F:  sound/soc/codecs/adau*
 F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/ad1*
 F:     sound/soc/codecs/ssm*
+F:     sound/soc/codecs/sigmadsp.*
 
 ANALOG DEVICES INC ASOC DRIVERS
 L:     uclinux-dist-devel@blackfin.uclinux.org
@@ -914,7 +915,6 @@ M:  Lennert Buytenhek <kernel@wantstofly.org>
 M:     Nicolas Pitre <nico@fluxnic.net>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Odd Fixes
-F:     arch/arm/mach-loki/
 F:     arch/arm/mach-kirkwood/
 F:     arch/arm/mach-mv78xx0/
 F:     arch/arm/mach-orion5x/
@@ -1076,8 +1076,8 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-s5pv210/mach-aquila.c
 F:     arch/arm/mach-s5pv210/mach-goni.c
-F:     arch/arm/mach-exynos4/mach-universal_c210.c
-F:     arch/arm/mach-exynos4/mach-nuri.c
+F:     arch/arm/mach-exynos/mach-universal_c210.c
+F:     arch/arm/mach-exynos/mach-nuri.c
 
 ARM/SAMSUNG S5P SERIES FIMC SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -1105,7 +1105,6 @@ M:        Tomasz Stanislawski <t.stanislaws@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     arch/arm/plat-s5p/dev-tv.c
 F:     drivers/media/video/s5p-tv/
 
 ARM/SHMOBILE ARM ARCHITECTURE
@@ -1140,14 +1139,13 @@ L:      linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.mcuos.com
 S:     Maintained
 F:     arch/arm/mach-w90x900/
-F:     arch/arm/mach-nuc93x/
 F:     drivers/input/keyboard/w90p910_keypad.c
 F:     drivers/input/touchscreen/w90p910_ts.c
 F:     drivers/watchdog/nuc900_wdt.c
 F:     drivers/net/ethernet/nuvoton/w90p910_ether.c
 F:     drivers/mtd/nand/nuc900_nand.c
 F:     drivers/rtc/rtc-nuc900.c
-F:     drivers/spi/spi_nuc900.c
+F:     drivers/spi/spi-nuc900.c
 F:     drivers/usb/host/ehci-w90x900.c
 F:     drivers/video/nuc900fb.c
 
@@ -1172,7 +1170,6 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-ux500/
 F:     drivers/dma/ste_dma40*
-F:     drivers/mfd/ab3550*
 F:     drivers/mfd/abx500*
 F:     drivers/mfd/ab8500*
 F:     drivers/mfd/stmpe*
@@ -1352,7 +1349,7 @@ F:        drivers/net/ethernet/cadence/
 ATMEL SPI DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
 S:     Supported
-F:     drivers/spi/atmel_spi.*
+F:     drivers/spi/spi-atmel.*
 
 ATMEL USBA UDC DRIVER
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -1491,7 +1488,7 @@ M:        Sonic Zhang <sonic.zhang@analog.com>
 L:     uclinux-dist-devel@blackfin.uclinux.org
 W:     http://blackfin.uclinux.org
 S:     Supported
-F:     drivers/tty/serial/bfin_5xx.c
+F:     drivers/tty/serial/bfin_uart.c
 
 BLACKFIN WATCHDOG DRIVER
 M:     Mike Frysinger <vapier.adi@gmail.com>
@@ -1621,7 +1618,7 @@ BT8XXGPIO DRIVER
 M:     Michael Buesch <m@bues.ch>
 W:     http://bu3sch.de/btgpio.php
 S:     Maintained
-F:     drivers/gpio/bt8xxgpio.c
+F:     drivers/gpio/gpio-bt8xx.c
 
 BTRFS FILE SYSTEM
 M:     Chris Mason <chris.mason@oracle.com>
@@ -1649,6 +1646,14 @@ T:       git git://git.alsa-project.org/alsa-kernel.git
 S:     Maintained
 F:     sound/pci/oxygen/
 
+C6X ARCHITECTURE
+M:     Mark Salter <msalter@redhat.com>
+M:     Aurelien Jacquiot <a-jacquiot@ti.com>
+L:     linux-c6x-dev@linux-c6x.org
+W:     http://www.linux-c6x.org/wiki/index.php/Main_Page
+S:     Maintained
+F:     arch/c6x/
+
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
 L:     linux-cachefs@redhat.com
@@ -1662,7 +1667,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
 S:     Maintained
 F:     Documentation/video4linux/cafe_ccic
-F:     drivers/media/video/cafe_ccic*
+F:     drivers/media/video/marvell-ccic/
 
 CAIF NETWORK LAYER
 M:     Sjur Braendeland <sjur.brandeland@stericsson.com>
@@ -2100,7 +2105,7 @@ DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
 L:     netdev@vger.kernel.org
 S:     Orphan
 F:     Documentation/networking/dmfe.txt
-F:     drivers/net/ethernet/tulip/dmfe.c
+F:     drivers/net/ethernet/dec/tulip/dmfe.c
 
 DC390/AM53C974 SCSI driver
 M:     Kurt Garloff <garloff@suse.de>
@@ -2173,6 +2178,13 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
 F:     drivers/usb/dwc3/
 
+DEVICE FREQUENCY (DEVFREQ)
+M:     MyungJoo Ham <myungjoo.ham@samsung.com>
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/devfreq/
+
 DEVICE NUMBER REGISTRY
 M:     Torben Mathiasen <device@lanana.org>
 W:     http://lanana.org/docs/device-list/index.html
@@ -2910,7 +2922,7 @@ GRETH 10/100/1G Ethernet MAC device driver
 M:     Kristoffer Glembo <kristoffer@gaisler.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/greth*
+F:     drivers/net/ethernet/aeroflex/
 
 GSPCA FINEPIX SUBDRIVER
 M:     Frank Zago <frank@zago.net>
@@ -3181,6 +3193,7 @@ F:        drivers/i2c/busses/i2c-stub.c
 I2C SUBSYSTEM
 M:     "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>
 M:     "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
+M:     "Wolfram Sang (embedded platforms)" <w.sang@pengutronix.de>
 L:     linux-i2c@vger.kernel.org
 W:     http://i2c.wiki.kernel.org/
 T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
@@ -3860,8 +3873,7 @@ L:        keyrings@linux-nfs.org
 S:     Supported
 F:     Documentation/security/keys-trusted-encrypted.txt
 F:     include/keys/encrypted-type.h
-F:     security/keys/encrypted.c
-F:     security/keys/encrypted.h
+F:     security/keys/encrypted-keys/
 
 KGDB / KDB /debug_core
 M:     Jason Wessel <jason.wessel@windriver.com>
@@ -4672,6 +4684,8 @@ Q:        http://patchwork.kernel.org/project/linux-omap/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git
 S:     Maintained
 F:     arch/arm/*omap*/
+F:     drivers/i2c/busses/i2c-omap.c
+F:     include/linux/i2c-omap.h
 
 OMAP CLOCK FRAMEWORK SUPPORT
 M:     Paul Walmsley <paul@pwsan.com>
@@ -5313,7 +5327,7 @@ T:        git git://git.linaro.org/people/ycmiao/pxa-linux.git
 S:     Maintained
 F:     arch/arm/mach-pxa/
 F:     drivers/pcmcia/pxa2xx*
-F:     drivers/spi/pxa2xx*
+F:     drivers/spi/spi-pxa2xx*
 F:     drivers/usb/gadget/pxa2*
 F:     include/sound/pxa2xx-lib.h
 F:     sound/arm/pxa*
@@ -5795,13 +5809,14 @@ L:      linux-mmc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 S:     Maintained
 F:     drivers/mmc/host/sdhci.*
+F:     drivers/mmc/host/sdhci-pltfm.[ch]
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
 M:     Anton Vorontsov <avorontsov@ru.mvista.com>
 L:     linuxppc-dev@lists.ozlabs.org
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
-F:     drivers/mmc/host/sdhci-of.*
+F:     drivers/mmc/host/sdhci-pltfm.[ch]
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
 M:     Ben Dooks <ben-linux@fluff.org>
@@ -5944,6 +5959,7 @@ L:        davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
 S:     Supported
 F:     arch/arm/mach-davinci
+F:     drivers/i2c/busses/i2c-davinci.c
 
 SIS 190 ETHERNET DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
@@ -6180,9 +6196,7 @@ M:        Viresh Kumar <viresh.kumar@st.com>
 W:     http://www.st.com/spear
 S:     Maintained
 F:     arch/arm/mach-spear*/clock.c
-F:     arch/arm/mach-spear*/include/mach/clkdev.h
 F:     arch/arm/plat-spear/clock.c
-F:     arch/arm/plat-spear/include/plat/clkdev.h
 F:     arch/arm/plat-spear/include/plat/clock.h
 
 SPEAR PAD MULTIPLEXING SUPPORT
@@ -6306,7 +6320,7 @@ STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS
 M:     Jarod Wilson <jarod@wilsonet.com>
 W:     http://www.lirc.org/
 S:     Odd Fixes
-F:     drivers/staging/lirc/
+F:     drivers/staging/media/lirc/
 
 STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
 M:     Julian Andres Klode <jak@jak-linux.org>
@@ -6342,7 +6356,7 @@ F:        drivers/staging/sm7xx/
 STAGING - SOFTLOGIC 6x10 MPEG CODEC
 M:     Ben Collins <bcollins@bluecherry.net>
 S:     Odd Fixes
-F:     drivers/staging/solo6x10/
+F:     drivers/staging/media/solo6x10/
 
 STAGING - SPEAKUP CONSOLE SPEECH DRIVER
 M:     William Hubbs <w.d.hubbs@gmail.com>
@@ -6645,7 +6659,7 @@ TULIP NETWORK DRIVERS
 M:     Grant Grundler <grundler@parisc-linux.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ethernet/tulip/
+F:     drivers/net/ethernet/dec/tulip/
 
 TUN/TAP driver
 M:     Maxim Krasnyansky <maxk@qualcomm.com>
index 2505740b81d2e24696ff4420f2f9af86713b817b..4f55c736be11ea3aa3ac6762b0ec3d1371b872ce 100644 (file)
@@ -185,4 +185,18 @@ config HAVE_RCU_TABLE_FREE
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
        bool
 
+config HAVE_ALIGNED_STRUCT_PAGE
+       bool
+       help
+         This makes sure that struct pages are double word aligned and that
+         e.g. the SLUB allocator can perform double word atomic operations
+         on a struct page for better performance. However selecting this
+         might increase the size of a struct page by a word.
+
+config HAVE_CMPXCHG_LOCAL
+       bool
+
+config HAVE_CMPXCHG_DOUBLE
+       bool
+
 source "kernel/gcov/Kconfig"
index 3d74801a40157b09e76263ea5af4546e67fedd30..56a4df952fb0f2e68889229133e38b2b34de4716 100644 (file)
@@ -70,10 +70,6 @@ config GENERIC_ISA_DMA
        bool
        default y
 
-config GENERIC_IOMAP
-       bool
-       default n
-
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
@@ -319,6 +315,7 @@ config ISA_DMA_API
 config PCI
        bool
        depends on !ALPHA_JENSEN
+       select GENERIC_PCI_IOMAP
        default y
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
index 246100ef07c2474fa5213163b0e1b899d10198a6..04eea4894ef33bc84c60335fc1e79e31553bd328 100644 (file)
@@ -185,15 +185,3 @@ struct dma_map_ops alpha_noop_ops = {
 
 struct dma_map_ops *dma_ops = &alpha_noop_ops;
 EXPORT_SYMBOL(dma_ops);
-
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       return NULL;
-}
-
-void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
-{
-}
-
-EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
index c9ab94ee1ca814090249356df8f90b992c59c5c1..8c723c1b086a03fd26ca69beabd794da836cc41b 100644 (file)
@@ -281,27 +281,9 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
 void __devinit
 pcibios_fixup_bus(struct pci_bus *bus)
 {
-       /* Propagate hose info into the subordinate devices.  */
-
-       struct pci_controller *hose = bus->sysdata;
        struct pci_dev *dev = bus->self;
 
-       if (!dev) {
-               /* Root bus. */
-               u32 pci_mem_end;
-               u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
-               unsigned long end;
-
-               bus->resource[0] = hose->io_space;
-               bus->resource[1] = hose->mem_space;
-
-               /* Adjust hose mem_space limit to prevent PCI allocations
-                  in the iommu windows. */
-               pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
-               end = hose->mem_space->start + pci_mem_end;
-               if (hose->mem_space->end > end)
-                       hose->mem_space->end = end;
-       } else if (pci_probe_only &&
+       if (pci_probe_only && dev &&
                   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_read_bridge_bases(bus);
                pcibios_fixup_device_resources(dev, bus);
@@ -414,13 +396,31 @@ void __init
 common_init_pci(void)
 {
        struct pci_controller *hose;
+       struct list_head resources;
        struct pci_bus *bus;
        int next_busno;
        int need_domain_info = 0;
+       u32 pci_mem_end;
+       u32 sg_base;
+       unsigned long end;
 
        /* Scan all of the recorded PCI controllers.  */
        for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
-               bus = pci_scan_bus(next_busno, alpha_mv.pci_ops, hose);
+               sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
+
+               /* Adjust hose mem_space limit to prevent PCI allocations
+                  in the iommu windows. */
+               pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
+               end = hose->mem_space->start + pci_mem_end;
+               if (hose->mem_space->end > end)
+                       hose->mem_space->end = end;
+
+               INIT_LIST_HEAD(&resources);
+               pci_add_resource(&resources, hose->io_space);
+               pci_add_resource(&resources, hose->mem_space);
+
+               bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
+                                       hose, &resources);
                hose->bus = bus;
                hose->need_domain_info = need_domain_info;
                next_busno = bus->subordinate + 1;
@@ -508,30 +508,7 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
        return -EOPNOTSUPP;
 }
 
-/* Create an __iomem token from a PCI BAR.  Copied from lib/iomap.c with
-   no changes, since we don't want the other things in that object file.  */
-
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               /* Not checking IORESOURCE_CACHEABLE because alpha does
-                  not distinguish between ioremap and ioremap_nocache.  */
-               return ioremap(start, len);
-       }
-       return NULL;
-}
-
-/* Destroy that token.  Not copied from lib/iomap.c.  */
+/* Destroy an __iomem token.  Not copied from lib/iomap.c.  */
 
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
@@ -539,7 +516,6 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
                iounmap(addr);
 }
 
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
 
 /* FIXME: Some boxes have multiple ISA bridges! */
index 9d66dfc33a5ac2b2a00ad56dfe130c3032954501..24626b0419ee97e963e68329a8eb6769360b46ea 100644 (file)
@@ -16,6 +16,7 @@ config ARM
        select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
        select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
+       select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZO
@@ -30,6 +31,7 @@ config ARM
        select HAVE_SPARSE_IRQ
        select GENERIC_IRQ_SHOW
        select CPU_PM if (SUSPEND || CPU_IDLE)
+       select GENERIC_PCI_IOMAP
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
index b539ec855e1a60180cbc519f7b23125338141720..d1bcd7b13ebc963c195fc88064fed9191984b4fe 100644 (file)
@@ -299,8 +299,8 @@ int __init it8152_pci_setup(int nr, struct pci_sys_data *sys)
                goto err1;
        }
 
-       sys->resource[0] = &it8152_io;
-       sys->resource[1] = &it8152_mem;
+       pci_add_resource(&sys->resources, &it8152_io);
+       pci_add_resource(&sys->resources, &it8152_mem);
 
        if (platform_notify || platform_notify_remove) {
                printk(KERN_ERR "PCI: Can't use platform_notify\n");
@@ -327,6 +327,9 @@ err0:
  */
 unsigned int pcibios_max_latency = 255;
 
+/* ITE bridge requires setting latency timer to avoid early bus access
+   termination by PCI bus master devices
+*/
 void pcibios_set_master(struct pci_dev *dev)
 {
        u8 lat;
@@ -352,7 +355,7 @@ void pcibios_set_master(struct pci_dev *dev)
 
 struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(nr, &it8152_ops, sys);
+       return pci_scan_root_bus(NULL, nr, &it8152_ops, sys, &sys->resources);
 }
 
 EXPORT_SYMBOL(dma_set_coherent_mask);
index 8421d39109b3a6ba28c16b3ccbd4efa4af4fb44a..67dd2affc57a3ed607bd431f662851ae27a57779 100644 (file)
@@ -86,7 +86,8 @@ int __init via82c505_setup(int nr, struct pci_sys_data *sys)
 struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata)
 {
        if (nr == 0)
-               return pci_scan_bus(0, &via82c505_ops, sysdata);
+               return pci_scan_root_bus(NULL, 0, &via82c505_ops, sysdata,
+                                        &sysdata->resources);
 
        return NULL;
 }
diff --git a/arch/arm/configs/bonito_defconfig b/arch/arm/configs/bonito_defconfig
new file mode 100644 (file)
index 0000000..5457108
--- /dev/null
@@ -0,0 +1,72 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_MACH_BONITO=y
+# CONFIG_SH_TIMER_TMU is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_FORCE_MAX_ZONEORDER=12
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySC5,115200 earlyprintk=sh-sci.5,115200 ignore_loglevel"
+CONFIG_KEXEC=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MTD_BLOCK2MTD=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=9
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SH_MOBILE=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_ARM_UNWIND is not set
diff --git a/arch/arm/configs/kota2_defconfig b/arch/arm/configs/kota2_defconfig
new file mode 100644 (file)
index 0000000..b7735d6
--- /dev/null
@@ -0,0 +1,122 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_CPUSETS=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_KOTA2=y
+CONFIG_MEMORY_SIZE=0x1e0000000
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_SWP_EMULATE is not set
+CONFIG_CPU_BPREDICT_DISABLE=y
+CONFIG_ARM_ERRATA_460075=y
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_742231=y
+CONFIG_PL310_ERRATA_588369=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_KEXEC=y
+CONFIG_CPU_IDLE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_SMSC911X=y
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_B43=y
+CONFIG_B43_PHY_N=y
+CONFIG_B43_DEBUG=y
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_SH_KEYSC=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=9
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_HWMON is not set
+CONFIG_BCMA=y
+CONFIG_BCMA_DEBUG=y
+CONFIG_FB=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_SDHI=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_RENESAS_TPU=y
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_USER=y
diff --git a/arch/arm/configs/marzen_defconfig b/arch/arm/configs/marzen_defconfig
new file mode 100644 (file)
index 0000000..864f9a5
--- /dev/null
@@ -0,0 +1,87 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_KERNEL_LZMA=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+# CONFIG_BLOCK is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_ARCH_R8A7779=y
+CONFIG_MACH_MARZEN=y
+CONFIG_MEMORY_START=0x60000000
+CONFIG_MEMORY_SIZE=0x10000000
+CONFIG_SHMOBILE_TIMER_HZ=1024
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SWP_EMULATE is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_458693=y
+CONFIG_ARM_ERRATA_460075=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_NO_HZ=y
+CONFIG_SMP=y
+# CONFIG_ARM_CPU_TOPOLOGY is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_KEXEC=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_SSB=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_USER=y
+CONFIG_AVERAGE=y
index 065d100fa63e7d608f49d3ef7f3a629d86cfe057..9275828feb3df24f481934a080572f8d53be3136 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #include <asm/system.h>
+#include <asm-generic/pci_iomap.h>
 
 /*
  * ISA I/O bus memory addresses are 1:1 with the physical address.
@@ -306,7 +307,6 @@ extern void ioport_unmap(void __iomem *addr);
 
 struct pci_dev;
 
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
 
 /*
index 186efd4e05c9975253a6a5b1d95ef4fb1718ace4..d943b7d20f1123b2672595e9c1a31c26b3bb54f7 100644 (file)
@@ -40,7 +40,7 @@ struct pci_sys_data {
        u64             mem_offset;     /* bus->cpu memory mapping offset       */
        unsigned long   io_offset;      /* bus->cpu IO mapping offset           */
        struct pci_bus  *bus;           /* PCI bus                              */
-       struct resource *resource[3];   /* Primary PCI bus resources            */
+       struct list_head resources;     /* root bus resources (apertures)       */
                                        /* Bridge swizzling                     */
        u8              (*swizzle)(struct pci_dev *, u8 *);
                                        /* IRQ mapping                          */
index 2b1f245db0c670200b557bc62ac613969eda818d..da337ba57ffd786ebcdd20efd60d98d22976357c 100644 (file)
@@ -31,18 +31,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 }
 #endif /* CONFIG_PCI_DOMAINS */
 
-#ifdef CONFIG_PCI_HOST_ITE8152
-/* ITE bridge requires setting latency timer to avoid early bus access
-   termination by PIC bus mater devices
-*/
-extern void pcibios_set_master(struct pci_dev *dev);
-#else
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-#endif
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index b530e9116a0c76283a1d5839868241abec382a1b..f58ba3589908ce541a7b8978712c19ed14bc5a00 100644 (file)
@@ -316,21 +316,6 @@ pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev)
        }
 }
 
-static void __devinit
-pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root)
-{
-       struct pci_dev *dev = bus->self;
-       int i;
-
-       if (!dev) {
-               /*
-                * Assign root bus resources.
-                */
-               for (i = 0; i < 3; i++)
-                       bus->resource[i] = root->resource[i];
-       }
-}
-
 /*
  * pcibios_fixup_bus - Called after each bus is probed,
  * but before its children are examined.
@@ -341,8 +326,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        struct pci_dev *dev;
        u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
 
-       pbus_assign_bus_resources(bus, root);
-
        /*
         * Walk the devices on this bus, working out what we can
         * and can't support.
@@ -508,12 +491,18 @@ static void __init pcibios_init_hw(struct hw_pci *hw)
                sys->busnr   = busnr;
                sys->swizzle = hw->swizzle;
                sys->map_irq = hw->map_irq;
-               sys->resource[0] = &ioport_resource;
-               sys->resource[1] = &iomem_resource;
+               INIT_LIST_HEAD(&sys->resources);
 
                ret = hw->setup(nr, sys);
 
                if (ret > 0) {
+                       if (list_empty(&sys->resources)) {
+                               pci_add_resource(&sys->resources,
+                                                &ioport_resource);
+                               pci_add_resource(&sys->resources,
+                                                &iomem_resource);
+                       }
+
                        sys->bus = hw->scan(nr, sys);
 
                        if (!sys->bus)
@@ -571,6 +560,13 @@ void __init pci_common_init(struct hw_pci *hw)
        }
 }
 
+#ifndef CONFIG_PCI_HOST_ITE8152
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+#endif
+
 char * __init pcibios_setup(char *str)
 {
        if (!strcmp(str, "debug")) {
index 0f8fca48a5eddd3a3c03421861b0d7b8fe6d1c1f..e159d69967c91b562ff6590d59141198447c534f 100644 (file)
@@ -151,13 +151,12 @@ static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
        struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
        struct resource *res_io = &cnspci->res_io;
        struct resource *res_mem = &cnspci->res_mem;
-       struct resource **sysres = sys->resource;
 
        BUG_ON(request_resource(&iomem_resource, res_io) ||
               request_resource(&iomem_resource, res_mem));
 
-       sysres[0] = res_io;
-       sysres[1] = res_mem;
+       pci_add_resource(&sys->resources, res_io);
+       pci_add_resource(&sys->resources, res_mem);
 
        return 1;
 }
@@ -169,7 +168,8 @@ static struct pci_ops cns3xxx_pcie_ops = {
 
 static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &cns3xxx_pcie_ops, sys,
+                                &sys->resources);
 }
 
 static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
index 6c11a4df71781493a9470b9c59af8541dbc41605..52e96d397ba8cfffe68b1085f3cdbf5eee2bc463 100644 (file)
@@ -69,7 +69,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[0].flags = IORESOURCE_IO;
        if (request_resource(&ioport_resource, &pp->res[0]))
                panic("Request PCIe IO resource failed\n");
-       sys->resource[0] = &pp->res[0];
+       pci_add_resource(&sys->resources, &pp->res[0]);
 
        /*
         * IORESOURCE_MEM
@@ -88,9 +88,7 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[1].flags = IORESOURCE_MEM;
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe Memory resource failed\n");
-       sys->resource[1] = &pp->res[1];
-
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &pp->res[1]);
 
        return 1;
 }
@@ -184,7 +182,8 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        struct pci_bus *bus;
 
        if (nr < num_pcie_ports) {
-               bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+               bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+                                       &sys->resources);
        } else {
                bus = NULL;
                BUG();
diff --git a/arch/arm/mach-exynos/include/mach/cpufreq.h b/arch/arm/mach-exynos/include/mach/cpufreq.h
new file mode 100644 (file)
index 0000000..3df27f2
--- /dev/null
@@ -0,0 +1,34 @@
+/* linux/arch/arm/mach-exynos/include/mach/cpufreq.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS - CPUFreq support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+enum cpufreq_level_index {
+       L0, L1, L2, L3, L4,
+       L5, L6, L7, L8, L9,
+       L10, L11, L12, L13, L14,
+       L15, L16, L17, L18, L19,
+       L20,
+};
+
+struct exynos_dvfs_info {
+       unsigned long   mpll_freq_khz;
+       unsigned int    pll_safe_idx;
+       unsigned int    pm_lock_idx;
+       unsigned int    max_support_idx;
+       unsigned int    min_support_idx;
+       struct clk      *cpu_clk;
+       unsigned int    *volt_table;
+       struct cpufreq_frequency_table  *freq_table;
+       void (*set_freq)(unsigned int, unsigned int);
+       bool (*need_apll_change)(unsigned int, unsigned int);
+};
+
+extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
index 18c32a5541d9e47c69b5ae38cee8d56ef8eaa333..f685650c25d7b00be7ca14939c41ce0cde81d812 100644 (file)
@@ -275,9 +275,9 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
        allocate_resource(&iomem_resource, &res[0], 0x40000000,
                          0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
 
-       sys->resource[0] = &ioport_resource;
-       sys->resource[1] = &res[0];
-       sys->resource[2] = &res[1];
+       pci_add_resource(&sys->resources, &ioport_resource);
+       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource(&sys->resources, &res[1]);
        sys->mem_offset  = DC21285_PCI_MEM;
 
        return 1;
@@ -285,7 +285,7 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
 
 struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(0, &dc21285_ops, sys);
+       return pci_scan_root_bus(NULL, 0, &dc21285_ops, sys, &sys->resources);
 }
 
 #define dc21285_request_irq(_a, _b, _c, _d, _e) \
index b4d8f8b8a08546b5fd4341ea88f7f3c8bbc20a03..3c82566acece2d8296d343eceddc8dad389a93c3 100644 (file)
@@ -359,7 +359,7 @@ static struct resource pre_mem = {
        .flags  = IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-static int __init pci_v3_setup_resources(struct resource **resource)
+static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
 {
        if (request_resource(&iomem_resource, &non_mem)) {
                printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
@@ -374,13 +374,13 @@ static int __init pci_v3_setup_resources(struct resource **resource)
        }
 
        /*
-        * bus->resource[0] is the IO resource for this bus
-        * bus->resource[1] is the mem resource for this bus
-        * bus->resource[2] is the prefetch mem resource for this bus
+        * the IO resource for this bus
+        * the mem resource for this bus
+        * the prefetch mem resource for this bus
         */
-       resource[0] = &ioport_resource;
-       resource[1] = &non_mem;
-       resource[2] = &pre_mem;
+       pci_add_resource(&sys->resources, &ioport_resource);
+       pci_add_resource(&sys->resources, &non_mem);
+       pci_add_resource(&sys->resources, &pre_mem);
 
        return 1;
 }
@@ -481,7 +481,7 @@ int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
 
        if (nr == 0) {
                sys->mem_offset = PHYS_PCI_MEM_BASE;
-               ret = pci_v3_setup_resources(sys->resource);
+               ret = pci_v3_setup_resources(sys);
        }
 
        return ret;
@@ -489,7 +489,8 @@ int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
 
 struct pci_bus * __init pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &pci_v3_ops, sys,
+                                &sys->resources);
 }
 
 /*
index db012fadf88c652e96d3d3d74c30cb132424f4b2..b8f5a87365112d0622b017dcbd2c7507e1e2934c 100644 (file)
@@ -537,14 +537,14 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
                        while(time_before(jiffies, atux_trhfa_timeout))
                                udelay(100);
 
-               bus = pci_bus_atux = pci_scan_bus(sys->busnr,
-                                                 &iop13xx_atux_ops,
-                                                 sys);
+               bus = pci_bus_atux = pci_scan_root_bus(NULL, sys->busnr,
+                                                      &iop13xx_atux_ops,
+                                                      sys, &sys->resources);
                break;
        case IOP13XX_INIT_ATU_ATUE:
-               bus = pci_bus_atue = pci_scan_bus(sys->busnr,
-                                                 &iop13xx_atue_ops,
-                                                 sys);
+               bus = pci_bus_atue = pci_scan_root_bus(NULL, sys->busnr,
+                                                      &iop13xx_atue_ops,
+                                                      sys, &sys->resources);
                break;
        }
 
@@ -1084,9 +1084,8 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
        request_resource(&ioport_resource, &res[0]);
        request_resource(&iomem_resource, &res[1]);
 
-       sys->resource[0] = &res[0];
-       sys->resource[1] = &res[1];
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource(&sys->resources, &res[1]);
 
        return 1;
 }
index ee525416f0d20b0ca6a69b42cd9820c8b45a0731..e872d238cd0fd36103f29581544404c3a08de098 100644 (file)
@@ -145,7 +145,8 @@ static struct pci_ops enp2611_pci_ops = {
 static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
                                                struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &enp2611_pci_ops, sys,
+                                &sys->resources);
 }
 
 static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
index f5098b306fd39693df59f974e17648a8e0cc8a02..626fda435aa921b8ecaa91d4e7e25da9abc31a01 100644 (file)
@@ -132,7 +132,8 @@ static struct pci_ops ixp2000_pci_ops = {
 
 struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
 {
-       return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
+       return pci_scan_root_bus(NULL, sysdata->busnr, &ixp2000_pci_ops,
+                                sysdata, &sysdata->resources);
 }
 
 
@@ -242,9 +243,8 @@ int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr >= 1)
                return 0;
 
-       sys->resource[0] = &ixp2000_pci_io_space;
-       sys->resource[1] = &ixp2000_pci_mem_space;
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &ixp2000_pci_io_space);
+       pci_add_resource(&sys->resources, &ixp2000_pci_mem_space);
 
        return 1;
 }
index e6be5711c700963f7997e47bbb491cdcb8548d6e..25b5c462cea2015703924bf74bf591d3ababb2c5 100644 (file)
@@ -143,7 +143,8 @@ struct pci_ops ixp23xx_pci_ops = {
 
 struct pci_bus *ixp23xx_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
 {
-       return pci_scan_bus(sysdata->busnr, &ixp23xx_pci_ops, sysdata);
+       return pci_scan_root_bus(NULL, sysdata->busnr, &ixp23xx_pci_ops,
+                                sysdata, &sysdata->resources);
 }
 
 int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
@@ -280,9 +281,8 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr >= 1)
                return 0;
 
-       sys->resource[0] = &ixp23xx_pci_io_space;
-       sys->resource[1] = &ixp23xx_pci_mem_space;
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &ixp23xx_pci_io_space);
+       pci_add_resource(&sys->resources, &ixp23xx_pci_mem_space);
 
        return 1;
 }
index 8325058ef8711d1019bea1eea7ad1383e79101d6..5eff15f24bc27e5a4f12dd56dab5eaea8cf4c118 100644 (file)
@@ -472,9 +472,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
        request_resource(&ioport_resource, &res[0]);
        request_resource(&iomem_resource, &res[1]);
 
-       sys->resource[0] = &res[0];
-       sys->resource[1] = &res[1];
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource(&sys->resources, &res[1]);
 
        platform_notify = ixp4xx_pci_platform_notify;
        platform_notify_remove = ixp4xx_pci_platform_notify_remove;
@@ -484,7 +483,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
 
 struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &ixp4xx_ops, sys,
+                                &sys->resources);
 }
 
 int dma_set_coherent_mask(struct device *dev, u64 mask)
index fb451bfe478b9ad5c32f5588caa71a7cb84786c1..a066a6d8d9d2126bc577401b8710e16a1b40d133 100644 (file)
@@ -198,9 +198,8 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe%d Memory resource failed\n", index);
 
-       sys->resource[0] = &pp->res[0];
-       sys->resource[1] = &pp->res[1];
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &pp->res[0]);
+       pci_add_resource(&sys->resources, &pp->res[1]);
        sys->io_offset = 0;
 
        /*
@@ -236,7 +235,8 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        struct pci_bus *bus;
 
        if (nr < num_pcie_ports) {
-               bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+               bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+                                       &sys->resources);
        } else {
                bus = NULL;
                BUG();
index c7c9a188d10552ed19fafba4cdc523fba066f7da..b26f992071df4553df94bf2da1d8356af03cc56f 100644 (file)
@@ -143,7 +143,8 @@ static struct pci_ops ks8695_pci_ops = {
 
 static struct pci_bus* __init ks8695_pci_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &ks8695_pci_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &ks8695_pci_ops, sys,
+                                &sys->resources);
 }
 
 static struct resource pci_mem = {
@@ -168,9 +169,8 @@ static int __init ks8695_pci_setup(int nr, struct pci_sys_data *sys)
        request_resource(&iomem_resource, &pci_mem);
        request_resource(&ioport_resource, &pci_io);
 
-       sys->resource[0] = &pci_io;
-       sys->resource[1] = &pci_mem;
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &pci_io);
+       pci_add_resource(&sys->resources, &pci_mem);
 
        /* Assign and enable processor bridge */
        ks8695_local_writeconfig(PCI_BASE_ADDRESS_0, KS8695_PCIMEM_PA);
index 12fcb108b0e13036c7de59583e3af5f7e1d99007..8459f6d7d8caff6091fe05d2862895ba94460626 100644 (file)
@@ -155,9 +155,8 @@ static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
        orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
        orion_pcie_setup(pp->base);
 
-       sys->resource[0] = &pp->res[0];
-       sys->resource[1] = &pp->res[1];
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &pp->res[0]);
+       pci_add_resource(&sys->resources, &pp->res[1]);
 
        return 1;
 }
@@ -251,7 +250,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        struct pci_bus *bus;
 
        if (nr < num_pcie_ports) {
-               bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+               bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+                                       &sys->resources);
        } else {
                bus = NULL;
                BUG();
index d67bcdf724d7365d518a2017286d8a25d555d710..acb4e77b39efd088538ef6d7c6542f64ab6411e1 100644 (file)
@@ -944,6 +944,9 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
                .platform_data  = &rx51_lp5523_platform_data,
        },
 #endif
+       {
+               I2C_BOARD_INFO("bq27200", 0x55),
+       },
        {
                I2C_BOARD_INFO("tpa6130a2", 0x60),
                .platform_data = &rx51_tpa6130a2_data,
index 28fcb27005d2912ec13dec5be59d777e721f67a6..fb4bcf81a183311c9a0baf95ed7a92af61ae01ff 100644 (file)
@@ -156,6 +156,9 @@ static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
                else
                        /* The FIFO has 128 locations */
                        pdata->buffer_size = 0x80;
+       } else if (oh->class->rev == MCBSP_CONFIG_TYPE4) {
+               /* The FIFO has 128 locations for all instances */
+               pdata->buffer_size = 0x80;
        }
 
        if (oh->class->rev >= MCBSP_CONFIG_TYPE3)
index a494c470e3e4c62dc0cb85d2de14e2b18fefb5a9..09a045f0c406c50b64275f450993874b1af18f02 100644 (file)
@@ -177,7 +177,7 @@ static int __init pcie_setup(struct pci_sys_data *sys)
        res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
        if (request_resource(&ioport_resource, &res[0]))
                panic("Request PCIe IO resource failed\n");
-       sys->resource[0] = &res[0];
+       pci_add_resource(&sys->resources, &res[0]);
 
        /*
         * IORESOURCE_MEM
@@ -188,9 +188,8 @@ static int __init pcie_setup(struct pci_sys_data *sys)
        res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
        if (request_resource(&iomem_resource, &res[1]))
                panic("Request PCIe Memory resource failed\n");
-       sys->resource[1] = &res[1];
+       pci_add_resource(&sys->resources, &res[1]);
 
-       sys->resource[2] = NULL;
        sys->io_offset = 0;
 
        return 1;
@@ -506,7 +505,7 @@ static int __init pci_setup(struct pci_sys_data *sys)
        res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
        if (request_resource(&ioport_resource, &res[0]))
                panic("Request PCI IO resource failed\n");
-       sys->resource[0] = &res[0];
+       pci_add_resource(&sys->resources, &res[0]);
 
        /*
         * IORESOURCE_MEM
@@ -517,9 +516,8 @@ static int __init pci_setup(struct pci_sys_data *sys)
        res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
        if (request_resource(&iomem_resource, &res[1]))
                panic("Request PCI Memory resource failed\n");
-       sys->resource[1] = &res[1];
+       pci_add_resource(&sys->resources, &res[1]);
 
-       sys->resource[2] = NULL;
        sys->io_offset = 0;
 
        return 1;
@@ -580,9 +578,11 @@ struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys
        struct pci_bus *bus;
 
        if (nr == 0) {
-               bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
+               bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
+                                       &sys->resources);
        } else if (nr == 1 && !orion5x_pci_disabled) {
-               bus = pci_scan_bus(sys->busnr, &pci_ops, sys);
+               bus = pci_scan_root_bus(NULL, sys->busnr, &pci_ops, sys,
+                                       &sys->resources);
        } else {
                bus = NULL;
                BUG();
index 66600f05e4364cd57b8cae96fafb5cb1811340dc..11f1e735966e534e3dd9dfe486e6581e32f2b55b 100644 (file)
@@ -435,6 +435,14 @@ static struct platform_device corgiled_device = {
        },
 };
 
+/*
+ * Corgi Audio
+ */
+static struct platform_device corgi_audio_device = {
+       .name   = "corgi-audio",
+       .id     = -1,
+};
+
 /*
  * MMC/SD Device
  *
@@ -641,6 +649,7 @@ static struct platform_device *devices[] __initdata = {
        &corgifb_device,
        &corgikbd_device,
        &corgiled_device,
+       &corgi_audio_device,
        &sharpsl_nand_device,
        &sharpsl_rom_device,
 };
index f79a610c62fc36c629002b855da09800883055a9..4cb2391a782e9125e97bae18bc8ba153e92c5bf3 100644 (file)
@@ -528,12 +528,18 @@ static struct platform_device e740_t7l66xb_device = {
        .resource      = eseries_tmio_resources,
 };
 
+static struct platform_device e740_audio_device = {
+       .name           = "e740-audio",
+       .id             = -1,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static struct platform_device *e740_devices[] __initdata = {
        &e740_fb_device,
        &e740_t7l66xb_device,
        &e7xx_gpio_vbus,
+       &e740_audio_device,
 };
 
 static void __init e740_init(void)
@@ -722,12 +728,18 @@ static struct platform_device e750_tc6393xb_device = {
        .resource      = eseries_tmio_resources,
 };
 
+static struct platform_device e750_audio_device = {
+       .name           = "e750-audio",
+       .id             = -1,
+};
+
 /* ------------------------------------------------------------- */
 
 static struct platform_device *e750_devices[] __initdata = {
        &e750_fb_device,
        &e750_tc6393xb_device,
        &e7xx_gpio_vbus,
+       &e750_audio_device,
 };
 
 static void __init e750_init(void)
@@ -929,12 +941,18 @@ static struct platform_device e800_tc6393xb_device = {
        .resource      = eseries_tmio_resources,
 };
 
+static struct platform_device e800_audio_device = {
+       .name           = "e800-audio",
+       .id             = -1,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static struct platform_device *e800_devices[] __initdata = {
        &e800_fb_device,
        &e800_tc6393xb_device,
        &e800_gpio_vbus,
+       &e800_audio_device,
 };
 
 static void __init e800_init(void)
index 69036e42ca31dc7f38f136c527add7e0f0e8fe95..744baee12c0cc83a70ef418231fd584fe323563a 100644 (file)
@@ -158,6 +158,11 @@ static struct scoop_pcmcia_config poodle_pcmcia_config = {
 EXPORT_SYMBOL(poodle_scoop_device);
 
 
+static struct platform_device poodle_audio_device = {
+       .name   = "poodle-audio",
+       .id     = -1,
+};
+
 /* LoCoMo device */
 static struct resource locomo_resources[] = {
        [0] = {
@@ -407,6 +412,7 @@ static struct platform_device sharpsl_rom_device = {
 static struct platform_device *devices[] __initdata = {
        &poodle_locomo_device,
        &poodle_scoop_device,
+       &poodle_audio_device,
        &sharpsl_nand_device,
        &sharpsl_rom_device,
 };
index d8a2467de92e3aabe7a366d17f59977a4cc4c473..b0656e158d90409f249cc4a6965483bb68e1dc52 100644 (file)
@@ -593,10 +593,16 @@ static struct pxa2xx_udc_mach_info imote2_udc_info __initdata = {
        .udc_command            = sg2_udc_command,
 };
 
+static struct platform_device imote2_audio_device = {
+       .name = "imote2-audio",
+       .id   = -1,
+};
+
 static struct platform_device *imote2_devices[] = {
        &stargate2_flash_device,
        &imote2_leds,
        &sht15,
+       &imote2_audio_device,
 };
 
 static void __init imote2_init(void)
index 7ce5c436cc4ed3cf99c55282e6e85ee2a6808757..4d4eb60bad1e81b39f8901369e6bd5273914be34 100644 (file)
@@ -889,6 +889,11 @@ static struct platform_device wm9712_device = {
        .id     = -1,
 };
 
+static struct platform_device tosa_audio_device = {
+       .name   = "tosa-audio",
+       .id     = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
        &tosascoop_device,
        &tosascoop_jc_device,
@@ -901,6 +906,7 @@ static struct platform_device *devices[] __initdata = {
        &sharpsl_rom_device,
        &wm9712_device,
        &tosa_gpio_vbus,
+       &tosa_audio_device,
 };
 
 static void tosa_poweroff(void)
index 680fd758ff2db73e8e2fc095f4a1e317f3560669..1cc91d794c973e538e52a9678bff72fa4e1b8d0e 100644 (file)
@@ -286,8 +286,8 @@ static struct platform_device lowland_device = {
        .id             = -1,
 };
 
-static struct platform_device speyside_wm8962_device = {
-       .name           = "speyside-wm8962",
+static struct platform_device tobermory_device = {
+       .name           = "tobermory",
        .id             = -1,
 };
 
@@ -347,7 +347,7 @@ static struct platform_device *crag6410_devices[] __initdata = {
        &crag6410_lcd_powerdev,
        &crag6410_backlight_device,
        &speyside_device,
-       &speyside_wm8962_device,
+       &tobermory_device,
        &littlemill_device,
        &lowland_device,
        &wallvdd_device,
index 6b93e200bcaceecec1bdc18c27929480b860066b..5bc6b3837b2033cbaccf57b69b91e07ffd0fe76f 100644 (file)
@@ -202,6 +202,7 @@ static struct irda_platform_data assabet_irda_data = {
 static struct mcp_plat_data assabet_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init assabet_init(void)
@@ -252,6 +253,17 @@ static void __init assabet_init(void)
        sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
                            ARRAY_SIZE(assabet_flash_resources));
        sa11x0_register_irda(&assabet_irda_data);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+       ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
        sa11x0_register_mcp(&assabet_mcp_data);
 }
 
index 11bb6d0b9be377b6c926f3e759a03a21d2e9ffff..d12d0f48b1dc4bec59f9a9939edc6c93e5f3ddcb 100644 (file)
@@ -124,12 +124,23 @@ static void __init cerf_map_io(void)
 static struct mcp_plat_data cerf_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init cerf_init(void)
 {
        platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
        sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&cerf_mcp_data);
 }
 
index b9060e236def9e90204fa2be99734ea3a4fc6417..c483912d08af4535ce964992a19d66f511c80c21 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/timer.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -85,10 +86,15 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
        .num_devs       = 1,
 };
 
+static struct ucb1x00_plat_data collie_ucb1x00_data = {
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+};
+
 static struct mcp_plat_data collie_mcp_data = {
        .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
        .sclk_rate      = 9216000,
-       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+       .codec          = "ucb1x00",
+       .codec_pdata    = &collie_ucb1x00_data,
 };
 
 /*
@@ -351,6 +357,16 @@ static void __init collie_init(void)
 
        sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
                            ARRAY_SIZE(collie_flash_resources));
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&collie_mcp_data);
 
        sharpsl_save_param();
index 480d2ea46b000a9f862c7bef28280a31730b47d9..e3a28ca2a7b754fff9b095eb5c58e113525b16df 100644 (file)
@@ -217,10 +217,15 @@ static struct platform_device sa11x0uart3_device = {
 static struct resource sa11x0mcp_resources[] = {
        [0] = {
                .start  = __PREG(Ser4MCCR0),
-               .end    = __PREG(Ser4MCCR0) + 0xffff,
+               .end    = __PREG(Ser4MCCR0) + 0x1C - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
+               .start  = __PREG(Ser4MCCR1),
+               .end    = __PREG(Ser4MCCR1) + 0x4 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
                .start  = IRQ_Ser4MCP,
                .end    = IRQ_Ser4MCP,
                .flags  = IORESOURCE_IRQ,
index ed1a331508a754bf2e802f537689a97ee2b524c5..586cec898b35ae8578025727e3ec4e2b679964e0 100644 (file)
@@ -17,6 +17,8 @@ struct mcp_plat_data {
        u32 mccr1;
        unsigned int sclk_rate;
        int gpio_base;
+       const char *codec;
+       void *codec_pdata;
 };
 
 #endif
index af4e2761f3dbf4a6254bfab53f98080334e5f387..d117ceab6215c4f8d814504aa313bacf17460b45 100644 (file)
 static struct mcp_plat_data lart_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init lart_init(void)
 {
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&lart_mcp_data);
 }
 
index dd39fee59549784aff6a7341966ad192f8904a09..0d01ca788922931f854846c03203089b8ae33648 100644 (file)
@@ -131,7 +131,8 @@ static int __init pci_nanoengine_map_irq(const struct pci_dev *dev, u8 slot,
 
 struct pci_bus * __init pci_nanoengine_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &pci_nano_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &pci_nano_ops, sys,
+                                &sys->resources);
 }
 
 static struct resource pci_io_ports = {
@@ -226,7 +227,7 @@ static struct resource pci_prefetchable_memory = {
        .flags  = IORESOURCE_MEM  | IORESOURCE_PREFETCH,
 };
 
-static int __init pci_nanoengine_setup_resources(struct resource **resource)
+static int __init pci_nanoengine_setup_resources(struct pci_sys_data *sys)
 {
        if (request_resource(&ioport_resource, &pci_io_ports)) {
                printk(KERN_ERR "PCI: unable to allocate io port region\n");
@@ -243,9 +244,9 @@ static int __init pci_nanoengine_setup_resources(struct resource **resource)
                printk(KERN_ERR "PCI: unable to allocate prefetchable\n");
                return -EBUSY;
        }
-       resource[0] = &pci_io_ports;
-       resource[1] = &pci_non_prefetchable_memory;
-       resource[2] = &pci_prefetchable_memory;
+       pci_add_resource(&sys->resources, &pci_io_ports);
+       pci_add_resource(&sys->resources, &pci_non_prefetchable_memory);
+       pci_add_resource(&sys->resources, &pci_prefetchable_memory);
 
        return 1;
 }
@@ -260,7 +261,7 @@ int __init pci_nanoengine_setup(int nr, struct pci_sys_data *sys)
        if (nr == 0) {
                sys->mem_offset = NANO_PCI_MEM_RW_PHYS;
                sys->io_offset = 0x400;
-               ret = pci_nanoengine_setup_resources(sys->resource);
+               ret = pci_nanoengine_setup_resources(sys);
                /* Enable alternate memory bus master mode, see
                 * "Intel StrongARM SA1110 Developer's Manual",
                 * section 10.8, "Alternate Memory Bus Master Mode". */
index 318b2b766a0b3ee7b8921c2904b65c0fdd551c8c..748d34435b3f070000f2afcfc420253d85ccb060 100644 (file)
@@ -55,11 +55,22 @@ static struct resource shannon_flash_resource = {
 static struct mcp_plat_data shannon_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
+       .codec          = "ucb1x00",
 };
 
 static void __init shannon_init(void)
 {
        sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&shannon_mcp_data);
 }
 
index e17c04d6e32428af6aa7c8eb1fbc35ca6d7a02d8..458ececefa58a122332de40798d3df7aae3d1ea2 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/mfd/ucb1x00.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -187,10 +188,15 @@ static struct resource simpad_flash_resources [] = {
        }
 };
 
+static struct ucb1x00_plat_data simpad_ucb1x00_data = {
+       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+};
+
 static struct mcp_plat_data simpad_mcp_data = {
        .mccr0          = MCCR0_ADM,
        .sclk_rate      = 11981000,
-       .gpio_base      = SIMPAD_UCB1X00_GPIO_BASE,
+       .codec          = "ucb1300",
+       .codec_pdata    = &simpad_ucb1x00_data,
 };
 
 
@@ -378,6 +384,16 @@ static int __init simpad_init(void)
 
        sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
                              ARRAY_SIZE(simpad_flash_resources));
+
+       /*
+        * Setup the PPC unit correctly.
+        */
+       PPDR &= ~PPC_RXD4;
+       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+       PSDR |= PPC_RXD4;
+       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
        sa11x0_register_mcp(&simpad_mcp_data);
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
index 0828fab2b65c7aa910dcfbcd73e712a1c56f0b61..060e5644c49c4711668835d451885f552a63a210 100644 (file)
@@ -28,6 +28,19 @@ config ARCH_SH73A0
        select ARM_GIC
        select I2C
 
+config ARCH_R8A7740
+       bool "R-Mobile A1 (R8A77400)"
+       select CPU_V7
+       select SH_CLK_CPG
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+
+config ARCH_R8A7779
+       bool "R-Car H1 (R8A77790)"
+       select CPU_V7
+       select SH_CLK_CPG
+       select ARM_GIC
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+
 comment "SH-Mobile Board Type"
 
 config MACH_G3EVM
@@ -75,6 +88,16 @@ config MACH_KOTA2
        select ARCH_REQUIRE_GPIOLIB
        depends on ARCH_SH73A0
 
+config MACH_BONITO
+       bool "bonito board"
+       select ARCH_REQUIRE_GPIOLIB
+       depends on ARCH_R8A7740
+
+config MACH_MARZEN
+       bool "MARZEN board"
+       depends on ARCH_R8A7779
+       select ARCH_REQUIRE_GPIOLIB
+
 comment "SH-Mobile System Configuration"
 
 menu "Memory configuration"
@@ -83,7 +106,7 @@ config MEMORY_START
        hex "Physical memory start address"
        default "0x50000000" if MACH_G3EVM
        default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \
-                               MACH_MACKEREL
+                               MACH_MACKEREL || MACH_BONITO
        default "0x41000000" if MACH_KOTA2
        default "0x00000000"
        ---help---
@@ -95,7 +118,7 @@ config MEMORY_SIZE
        hex "Physical memory size"
        default "0x08000000" if MACH_G3EVM
        default "0x08000000" if MACH_G4EVM
-       default "0x20000000" if MACH_AG5EVM
+       default "0x20000000" if MACH_AG5EVM || MACH_BONITO
        default "0x1e000000" if MACH_KOTA2
        default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL
        default "0x04000000"
index 5ca1f9d669953cec4f04b0b1ff806bed85fba150..7ad6954c46cd2e5780528808bdfc20d921a2aa0d 100644 (file)
@@ -10,12 +10,15 @@ obj-$(CONFIG_ARCH_SH7367)   += setup-sh7367.o clock-sh7367.o intc-sh7367.o
 obj-$(CONFIG_ARCH_SH7377)      += setup-sh7377.o clock-sh7377.o intc-sh7377.o
 obj-$(CONFIG_ARCH_SH7372)      += setup-sh7372.o clock-sh7372.o intc-sh7372.o
 obj-$(CONFIG_ARCH_SH73A0)      += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
+obj-$(CONFIG_ARCH_R8A7740)     += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
+obj-$(CONFIG_ARCH_R8A7779)     += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
 
 # SMP objects
 smp-y                          := platsmp.o headsmp.o
 smp-$(CONFIG_HOTPLUG_CPU)      += hotplug.o
 smp-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
 smp-$(CONFIG_ARCH_SH73A0)      += smp-sh73a0.o
+smp-$(CONFIG_ARCH_R8A7779)     += smp-r8a7779.o
 
 # Pinmux setup
 pfc-y                          :=
@@ -23,16 +26,20 @@ pfc-$(CONFIG_ARCH_SH7367)   += pfc-sh7367.o
 pfc-$(CONFIG_ARCH_SH7377)      += pfc-sh7377.o
 pfc-$(CONFIG_ARCH_SH7372)      += pfc-sh7372.o
 pfc-$(CONFIG_ARCH_SH73A0)      += pfc-sh73a0.o
+pfc-$(CONFIG_ARCH_R8A7740)     += pfc-r8a7740.o
+pfc-$(CONFIG_ARCH_R8A7779)     += pfc-r8a7779.o
 
 # IRQ objects
 obj-$(CONFIG_ARCH_SH7367)      += entry-intc.o
 obj-$(CONFIG_ARCH_SH7377)      += entry-intc.o
 obj-$(CONFIG_ARCH_SH7372)      += entry-intc.o
+obj-$(CONFIG_ARCH_R8A7740)     += entry-intc.o
 
 # PM objects
 obj-$(CONFIG_SUSPEND)          += suspend.o
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o
+obj-$(CONFIG_ARCH_R8A7779)     += pm-r8a7779.o
 
 # Board objects
 obj-$(CONFIG_MACH_G3EVM)       += board-g3evm.o
@@ -41,6 +48,8 @@ obj-$(CONFIG_MACH_AP4EVB)     += board-ap4evb.o
 obj-$(CONFIG_MACH_AG5EVM)      += board-ag5evm.o
 obj-$(CONFIG_MACH_MACKEREL)    += board-mackerel.o
 obj-$(CONFIG_MACH_KOTA2)       += board-kota2.o
+obj-$(CONFIG_MACH_BONITO)      += board-bonito.o
+obj-$(CONFIG_MACH_MARZEN)      += board-marzen.o
 
 # Framework support
 obj-$(CONFIG_SMP)              += $(smp-y)
index 6a6f9f7568c2d6b962818e2dbae9a151effebdd3..d2e7b73aa9b6418dce567e6be2216e07961fdb0c 100644 (file)
@@ -762,9 +762,22 @@ static struct platform_device fsi_device = {
        },
 };
 
+static struct fsi_ak4642_info fsi2_ak4643_info = {
+       .name           = "AK4643",
+       .card           = "FSI2A-AK4643",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi2",
+       .id             = FSI_PORT_A,
+};
+
 static struct platform_device fsi_ak4643_device = {
-       .name           = "sh_fsi2_a_ak4643",
+       .name   = "fsi-ak4642-audio",
+       .dev    = {
+               .platform_data  = &fsi_info,
+       },
 };
+
 static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
        .icb[0] = {
                .marker_icb     = 30,
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
new file mode 100644 (file)
index 0000000..4d22016
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * bonito board support
+ *
+ * Copyright (C) 2011 Renesas Solutions Corp.
+ * Copyright (C) 2011 Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <mach/common.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/r8a7740.h>
+#include <video/sh_mobile_lcdc.h>
+
+/*
+ * CS  Address         device                  note
+ *----------------------------------------------------------------
+ * 0   0x0000_0000     NOR Flash (64MB)        SW12 : bit3 = OFF
+ * 2   0x0800_0000     ExtNOR (64MB)           SW12 : bit3 = OFF
+ * 4                   -
+ * 5A                  -
+ * 5B  0x1600_0000     SRAM (8MB)
+ * 6   0x1800_0000     FPGA (64K)
+ *     0x1801_0000     Ether (4KB)
+ *     0x1801_1000     USB (4KB)
+ */
+
+/*
+ * SW12
+ *
+ *     bit1                    bit2                    bit3
+ *----------------------------------------------------------------------------
+ * ON  NOR WriteProtect        NAND WriteProtect       CS0 ExtNOR / CS2 NOR
+ * OFF NOR Not WriteProtect    NAND Not WriteProtect   CS0 NOR    / CS2 ExtNOR
+ */
+
+/*
+ * SCIFA5 (CN42)
+ *
+ * S38.3 = ON
+ * S39.6 = ON
+ * S43.1 = ON
+ */
+
+/*
+ * LCDC0 (CN3/CN4/CN7)
+ *
+ * S38.1 = OFF
+ * S38.2 = OFF
+ */
+
+/*
+ * FPGA
+ */
+#define IRQSR0         0x0020
+#define IRQSR1         0x0022
+#define IRQMR0         0x0030
+#define IRQMR1         0x0032
+#define BUSSWMR1       0x0070
+#define BUSSWMR2       0x0072
+#define BUSSWMR3       0x0074
+#define BUSSWMR4       0x0076
+
+#define LCDCR          0x10B4
+#define DEVRSTCR1      0x10D0
+#define DEVRSTCR2      0x10D2
+#define A1MDSR         0x10E0
+#define BVERR          0x1100
+
+/* FPGA IRQ */
+#define FPGA_IRQ_BASE          (512)
+#define FPGA_IRQ0              (FPGA_IRQ_BASE)
+#define FPGA_IRQ1              (FPGA_IRQ_BASE + 16)
+#define FPGA_ETH_IRQ           (FPGA_IRQ0 + 15)
+static u16 bonito_fpga_read(u32 offset)
+{
+       return __raw_readw(0xf0003000 + offset);
+}
+
+static void bonito_fpga_write(u32 offset, u16 val)
+{
+       __raw_writew(val, 0xf0003000 + offset);
+}
+
+static void bonito_fpga_irq_disable(struct irq_data *data)
+{
+       unsigned int irq = data->irq;
+       u32 addr = (irq < 1016) ? IRQMR0 : IRQMR1;
+       int shift = irq % 16;
+
+       bonito_fpga_write(addr, bonito_fpga_read(addr) | (1 << shift));
+}
+
+static void bonito_fpga_irq_enable(struct irq_data *data)
+{
+       unsigned int irq = data->irq;
+       u32 addr = (irq < 1016) ? IRQMR0 : IRQMR1;
+       int shift = irq % 16;
+
+       bonito_fpga_write(addr, bonito_fpga_read(addr) & ~(1 << shift));
+}
+
+static struct irq_chip bonito_fpga_irq_chip __read_mostly = {
+       .name           = "bonito FPGA",
+       .irq_mask       = bonito_fpga_irq_disable,
+       .irq_unmask     = bonito_fpga_irq_enable,
+};
+
+static void bonito_fpga_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       u32 val =  bonito_fpga_read(IRQSR1) << 16 |
+                  bonito_fpga_read(IRQSR0);
+       u32 mask = bonito_fpga_read(IRQMR1) << 16 |
+                  bonito_fpga_read(IRQMR0);
+
+       int i;
+
+       val &= ~mask;
+
+       for (i = 0; i < 32; i++) {
+               if (!(val & (1 << i)))
+                       continue;
+
+               generic_handle_irq(FPGA_IRQ_BASE + i);
+       }
+}
+
+static void bonito_fpga_init(void)
+{
+       int i;
+
+       bonito_fpga_write(IRQMR0, 0xffff); /* mask all */
+       bonito_fpga_write(IRQMR1, 0xffff); /* mask all */
+
+       /* Device reset */
+       bonito_fpga_write(DEVRSTCR1,
+                  (1 << 2));   /* Eth */
+
+       /* FPGA irq require special handling */
+       for (i = FPGA_IRQ_BASE; i < FPGA_IRQ_BASE + 32; i++) {
+               irq_set_chip_and_handler_name(i, &bonito_fpga_irq_chip,
+                                             handle_level_irq, "level");
+               set_irq_flags(i, IRQF_VALID); /* yuck */
+       }
+
+       irq_set_chained_handler(evt2irq(0x0340), bonito_fpga_irq_demux);
+       irq_set_irq_type(evt2irq(0x0340), IRQ_TYPE_LEVEL_LOW);
+}
+
+/*
+* PMIC settings
+*
+* FIXME
+*
+* bonito board needs some settings by pmic which use i2c access.
+* pmic settings use device_initcall() here for use it.
+*/
+static __u8 *pmic_settings = NULL;
+static __u8 pmic_do_2A[] = {
+       0x1C, 0x09,
+       0x1A, 0x80,
+       0xff, 0xff,
+};
+
+static int __init pmic_init(void)
+{
+       struct i2c_adapter *a = i2c_get_adapter(0);
+       struct i2c_msg msg;
+       __u8 buf[2];
+       int i, ret;
+
+       if (!pmic_settings)
+               return 0;
+       if (!a)
+               return 0;
+
+       msg.addr        = 0x46;
+       msg.buf         = buf;
+       msg.len         = 2;
+       msg.flags       = 0;
+
+       for (i = 0; ; i += 2) {
+               buf[0] = pmic_settings[i + 0];
+               buf[1] = pmic_settings[i + 1];
+
+               if ((0xff == buf[0]) && (0xff == buf[1]))
+                       break;
+
+               ret = i2c_transfer(a, &msg, 1);
+               if (ret < 0) {
+                       pr_err("i2c transfer fail\n");
+                       break;
+               }
+       }
+
+       return 0;
+}
+device_initcall(pmic_init);
+
+/*
+ * LCDC0
+ */
+static const struct fb_videomode lcdc0_mode = {
+       .name           = "WVGA Panel",
+       .xres           = 800,
+       .yres           = 480,
+       .left_margin    = 88,
+       .right_margin   = 40,
+       .hsync_len      = 128,
+       .upper_margin   = 20,
+       .lower_margin   = 5,
+       .vsync_len      = 5,
+       .sync           = 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+       .clock_source   = LCDC_CLK_BUS,
+       .ch[0] = {
+               .chan                   = LCDC_CHAN_MAINLCD,
+               .bpp                    = 16,
+               .interface_type         = RGB24,
+               .clock_divider          = 5,
+               .flags                  = 0,
+               .lcd_cfg                = &lcdc0_mode,
+               .num_cfg                = 1,
+               .lcd_size_cfg = {
+                       .width  = 152,
+                       .height = 91,
+               },
+       },
+};
+
+static struct resource lcdc0_resources[] = {
+       [0] = {
+               .name   = "LCDC0",
+               .start  = 0xfe940000,
+               .end    = 0xfe943fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x0580),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device lcdc0_device = {
+       .name           = "sh_mobile_lcdc_fb",
+       .id             = 0,
+       .resource       = lcdc0_resources,
+       .num_resources  = ARRAY_SIZE(lcdc0_resources),
+       .dev    = {
+               .platform_data  = &lcdc0_info,
+               .coherent_dma_mask = ~0,
+       },
+};
+
+/*
+ * SMSC 9221
+ */
+static struct resource smsc_resources[] = {
+       [0] = {
+               .start          = 0x18010000,
+               .end            = 0x18011000 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = FPGA_ETH_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config smsc_platdata = {
+       .flags          = SMSC911X_USE_16BIT,
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device smsc_device = {
+       .name           = "smsc911x",
+       .dev  = {
+               .platform_data = &smsc_platdata,
+       },
+       .resource       = smsc_resources,
+       .num_resources  = ARRAY_SIZE(smsc_resources),
+};
+
+/*
+ * core board devices
+ */
+static struct platform_device *bonito_core_devices[] __initdata = {
+};
+
+/*
+ * base board devices
+ */
+static struct platform_device *bonito_base_devices[] __initdata = {
+       &lcdc0_device,
+       &smsc_device,
+};
+
+/*
+ * map I/O
+ */
+static struct map_desc bonito_io_desc[] __initdata = {
+        /*
+         * for CPGA/INTC/PFC
+         * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff
+         */
+       {
+               .virtual        = 0xe6000000,
+               .pfn            = __phys_to_pfn(0xe6000000),
+               .length         = 160 << 20,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#ifdef CONFIG_CACHE_L2X0
+       /*
+        * for l2x0_init()
+        * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000
+        */
+       {
+               .virtual        = 0xf0002000,
+               .pfn            = __phys_to_pfn(0xf0100000),
+               .length         = PAGE_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       },
+#endif
+       /*
+        * for FPGA (0x1800000-0x19ffffff)
+        * 0x18000000-0x18002000 -> 0xf0003000-0xf0005000
+        */
+       {
+               .virtual        = 0xf0003000,
+               .pfn            = __phys_to_pfn(0x18000000),
+               .length         = PAGE_SIZE * 2,
+               .type           = MT_DEVICE_NONSHARED
+       }
+};
+
+static void __init bonito_map_io(void)
+{
+       iotable_init(bonito_io_desc, ARRAY_SIZE(bonito_io_desc));
+
+       /* setup early devices and console here as well */
+       r8a7740_add_early_devices();
+       shmobile_setup_console();
+}
+
+/*
+ * board init
+ */
+#define BIT_ON(sw, bit)                (sw & (1 << bit))
+#define BIT_OFF(sw, bit)       (!(sw & (1 << bit)))
+
+#define VCCQ1CR                0xE6058140
+#define VCCQ1LCDCR     0xE6058186
+
+static void __init bonito_init(void)
+{
+       u16 val;
+
+       r8a7740_pinmux_init();
+       bonito_fpga_init();
+
+       pmic_settings = pmic_do_2A;
+
+       /*
+        * core board settings
+        */
+
+#ifdef CONFIG_CACHE_L2X0
+       /* Early BRESP enable, Shared attribute override enable, 32K*8way */
+       l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff);
+#endif
+
+       r8a7740_add_standard_devices();
+
+       platform_add_devices(bonito_core_devices,
+                            ARRAY_SIZE(bonito_core_devices));
+
+       /*
+        * base board settings
+        */
+       gpio_request(GPIO_PORT176, NULL);
+       gpio_direction_input(GPIO_PORT176);
+       if (!gpio_get_value(GPIO_PORT176)) {
+               u16 bsw2;
+               u16 bsw3;
+               u16 bsw4;
+
+               /*
+                * FPGA
+                */
+               gpio_request(GPIO_FN_CS5B,              NULL);
+               gpio_request(GPIO_FN_CS6A,              NULL);
+               gpio_request(GPIO_FN_CS5A_PORT105,      NULL);
+               gpio_request(GPIO_FN_IRQ10,             NULL);
+
+               val = bonito_fpga_read(BVERR);
+               pr_info("bonito version: cpu %02x, base %02x\n",
+                       ((val >> 8) & 0xFF),
+                       ((val >> 0) & 0xFF));
+
+               bsw2 = bonito_fpga_read(BUSSWMR2);
+               bsw3 = bonito_fpga_read(BUSSWMR3);
+               bsw4 = bonito_fpga_read(BUSSWMR4);
+
+               /*
+                * SCIFA5 (CN42)
+                */
+               if (BIT_OFF(bsw2, 1) && /* S38.3 = ON */
+                   BIT_OFF(bsw3, 9) && /* S39.6 = ON */
+                   BIT_OFF(bsw4, 4)) { /* S43.1 = ON */
+                       gpio_request(GPIO_FN_SCIFA5_TXD_PORT91, NULL);
+                       gpio_request(GPIO_FN_SCIFA5_RXD_PORT92, NULL);
+               }
+
+               /*
+                * LCDC0 (CN3)
+                */
+               if (BIT_ON(bsw2, 3) &&  /* S38.1 = OFF */
+                   BIT_ON(bsw2, 2)) {  /* S38.2 = OFF */
+                       gpio_request(GPIO_FN_LCDC0_SELECT,      NULL);
+                       gpio_request(GPIO_FN_LCD0_D0,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D1,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D2,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D3,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D4,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D5,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D6,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D7,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D8,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D9,           NULL);
+                       gpio_request(GPIO_FN_LCD0_D10,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D11,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D12,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D13,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D14,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D15,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D16,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D17,          NULL);
+                       gpio_request(GPIO_FN_LCD0_D18_PORT163,  NULL);
+                       gpio_request(GPIO_FN_LCD0_D19_PORT162,  NULL);
+                       gpio_request(GPIO_FN_LCD0_D20_PORT161,  NULL);
+                       gpio_request(GPIO_FN_LCD0_D21_PORT158,  NULL);
+                       gpio_request(GPIO_FN_LCD0_D22_PORT160,  NULL);
+                       gpio_request(GPIO_FN_LCD0_D23_PORT159,  NULL);
+                       gpio_request(GPIO_FN_LCD0_DCK,          NULL);
+                       gpio_request(GPIO_FN_LCD0_VSYN,         NULL);
+                       gpio_request(GPIO_FN_LCD0_HSYN,         NULL);
+                       gpio_request(GPIO_FN_LCD0_DISP,         NULL);
+                       gpio_request(GPIO_FN_LCD0_LCLK_PORT165, NULL);
+
+                       gpio_request(GPIO_PORT61, NULL); /* LCDDON */
+                       gpio_direction_output(GPIO_PORT61, 1);
+
+                       /* backlight on */
+                       bonito_fpga_write(LCDCR, 1);
+
+                       /*  drivability Max */
+                       __raw_writew(0x00FF , VCCQ1LCDCR);
+                       __raw_writew(0xFFFF , VCCQ1CR);
+               }
+
+               platform_add_devices(bonito_base_devices,
+                                    ARRAY_SIZE(bonito_base_devices));
+       }
+}
+
+static void __init bonito_timer_init(void)
+{
+       u16 val;
+       u8 md_ck = 0;
+
+       /* read MD_CK value */
+       val = bonito_fpga_read(A1MDSR);
+       if (val & (1 << 10))
+               md_ck |= MD_CK2;
+       if (val & (1 << 9))
+               md_ck |= MD_CK1;
+       if (val & (1 << 8))
+               md_ck |= MD_CK0;
+
+       r8a7740_clock_init(md_ck);
+       shmobile_timer.init();
+}
+
+struct sys_timer bonito_timer = {
+       .init   = bonito_timer_init,
+};
+
+MACHINE_START(BONITO, "bonito")
+       .map_io         = bonito_map_io,
+       .init_irq       = r8a7740_init_irq,
+       .handle_irq     = shmobile_handle_irq_intc,
+       .init_machine   = bonito_init,
+       .timer          = &bonito_timer,
+MACHINE_END
index ed5256687397fd292496c73e3b2743f9c487114c..cbc5934ae03f0f0fa26057ee42c7d275ae7500fe 100644 (file)
@@ -990,8 +990,20 @@ static struct platform_device fsi_device = {
        },
 };
 
+static struct fsi_ak4642_info fsi2_ak4643_info = {
+       .name           = "AK4643",
+       .card           = "FSI2A-AK4643",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi2",
+       .id             = FSI_PORT_A,
+};
+
 static struct platform_device fsi_ak4643_device = {
-       .name           = "sh_fsi2_a_ak4643",
+       .name   = "fsi-ak4642-audio",
+       .dev    = {
+               .platform_data  = &fsi2_ak4643_info,
+       },
 };
 
 /*
diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c
new file mode 100644 (file)
index 0000000..f0e02c0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * marzen board support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/dma-mapping.h>
+#include <linux/smsc911x.h>
+#include <mach/hardware.h>
+#include <mach/r8a7779.h>
+#include <mach/common.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/gic.h>
+#include <asm/traps.h>
+
+/* SMSC LAN89218 */
+static struct resource smsc911x_resources[] = {
+       [0] = {
+               .start          = 0x18000000, /* ExCS0 */
+               .end            = 0x180000ff, /* A1->A7 */
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = gic_spi(28), /* IRQ 1 */
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smsc911x_platform_config smsc911x_platdata = {
+       .flags          = SMSC911X_USE_32BIT, /* 32-bit SW on 16-bit HW bus */
+       .phy_interface  = PHY_INTERFACE_MODE_MII,
+       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device eth_device = {
+       .name           = "smsc911x",
+       .id             = 0,
+       .dev  = {
+               .platform_data = &smsc911x_platdata,
+       },
+       .resource       = smsc911x_resources,
+       .num_resources  = ARRAY_SIZE(smsc911x_resources),
+};
+
+static struct platform_device *marzen_devices[] __initdata = {
+       &eth_device,
+};
+
+static struct map_desc marzen_io_desc[] __initdata = {
+       /* 2M entity map for 0xf0000000 (MPCORE) */
+       {
+               .virtual        = 0xf0000000,
+               .pfn            = __phys_to_pfn(0xf0000000),
+               .length         = SZ_2M,
+               .type           = MT_DEVICE_NONSHARED
+       },
+       /* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
+       {
+               .virtual        = 0xfe000000,
+               .pfn            = __phys_to_pfn(0xfe000000),
+               .length         = SZ_16M,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+static void __init marzen_map_io(void)
+{
+       iotable_init(marzen_io_desc, ARRAY_SIZE(marzen_io_desc));
+}
+
+static void __init marzen_init_early(void)
+{
+       r8a7779_add_early_devices();
+
+       /* Early serial console setup is not included here due to
+        * memory map collisions. The SCIF serial ports in r8a7779
+        * are difficult to entity map 1:1 due to collision with the
+        * virtual memory range used by the coherent DMA code on ARM.
+        *
+        * Anyone wanting to debug early can remove UPF_IOREMAP from
+        * the sh-sci serial console platform data, adjust mapbase
+        * to a static M:N virt:phys mapping that needs to be added to
+        * the mappings passed with iotable_init() above.
+        *
+        * Then add a call to shmobile_setup_console() from this function.
+        *
+        * As a final step pass earlyprint=sh-sci.2,115200 on the kernel
+        * command line.
+        */
+}
+
+static void __init marzen_init(void)
+{
+       r8a7779_pinmux_init();
+
+       /* SCIF2 (CN18: DEBUG0) */
+       gpio_request(GPIO_FN_TX2_C, NULL);
+       gpio_request(GPIO_FN_RX2_C, NULL);
+
+       /* SCIF4 (CN19: DEBUG1) */
+       gpio_request(GPIO_FN_TX4, NULL);
+       gpio_request(GPIO_FN_RX4, NULL);
+
+       /* LAN89218 */
+       gpio_request(GPIO_FN_EX_CS0, NULL); /* nCS */
+       gpio_request(GPIO_FN_IRQ1_B, NULL); /* IRQ + PME */
+
+       r8a7779_add_standard_devices();
+       platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
+}
+
+static void __init marzen_timer_init(void)
+{
+       r8a7779_clock_init();
+       shmobile_timer.init();
+       return;
+}
+
+struct sys_timer marzen_timer = {
+       .init   = marzen_timer_init,
+};
+
+MACHINE_START(MARZEN, "marzen")
+       .map_io         = marzen_map_io,
+       .init_early     = marzen_init_early,
+       .nr_irqs        = NR_IRQS_LEGACY,
+       .init_irq       = r8a7779_init_irq,
+       .handle_irq     = gic_handle_irq,
+       .init_machine   = marzen_init,
+       .timer          = &marzen_timer,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
new file mode 100644 (file)
index 0000000..3b35b9a
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * R8A7740 processor support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <linux/clkdev.h>
+#include <mach/common.h>
+#include <mach/r8a7740.h>
+
+/*
+ *        |  MDx  |  XTAL1/EXTAL1   |  System   | EXTALR |
+ *  Clock |-------+-----------------+  clock    | 32.768 |   RCLK
+ *  Mode  | 2/1/0 | src         MHz |  source   |  KHz   |  source
+ * -------+-------+-----------------+-----------+--------+----------
+ *    0   | 0 0 0 | External  20~50 | XTAL1     |    O   |  EXTALR
+ *    1   | 0 0 1 | Crystal   20~30 | XTAL1     |    O   |  EXTALR
+ *    2   | 0 1 0 | External  40~50 | XTAL1 / 2 |    O   |  EXTALR
+ *    3   | 0 1 1 | Crystal   40~50 | XTAL1 / 2 |    O   |  EXTALR
+ *    4   | 1 0 0 | External  20~50 | XTAL1     |    x   |  XTAL1 / 1024
+ *    5   | 1 0 1 | Crystal   20~30 | XTAL1     |    x   |  XTAL1 / 1024
+ *    6   | 1 1 0 | External  40~50 | XTAL1 / 2 |    x   |  XTAL1 / 2048
+ *    7   | 1 1 1 | Crystal   40~50 | XTAL1 / 2 |    x   |  XTAL1 / 2048
+ */
+
+/* CPG registers */
+#define FRQCRA         0xe6150000
+#define FRQCRB         0xe6150004
+#define FRQCRC         0xe61500e0
+#define PLLC01CR       0xe6150028
+
+#define SUBCKCR                0xe6150080
+
+#define MSTPSR0                0xe6150030
+#define MSTPSR1                0xe6150038
+#define MSTPSR2                0xe6150040
+#define MSTPSR3                0xe6150048
+#define MSTPSR4                0xe615004c
+#define SMSTPCR0       0xe6150130
+#define SMSTPCR1       0xe6150134
+#define SMSTPCR2       0xe6150138
+#define SMSTPCR3       0xe615013c
+#define SMSTPCR4       0xe6150140
+
+/* Fixed 32 KHz root clock from EXTALR pin */
+static struct clk extalr_clk = {
+       .rate   = 32768,
+};
+
+/*
+ * 25MHz default rate for the EXTAL1 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+static struct clk extal1_clk = {
+       .rate   = 25000000,
+};
+
+/*
+ * 48MHz default rate for the EXTAL2 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+static struct clk extal2_clk = {
+       .rate   = 48000000,
+};
+
+/*
+ * 27MHz default rate for the DV_CLKI root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+static struct clk dv_clk = {
+       .rate   = 27000000,
+};
+
+static unsigned long div_recalc(struct clk *clk)
+{
+       return clk->parent->rate / (int)(clk->priv);
+}
+
+static struct clk_ops div_clk_ops = {
+       .recalc = div_recalc,
+};
+
+/* extal1 / 2 */
+static struct clk extal1_div2_clk = {
+       .ops    = &div_clk_ops,
+       .priv   = (void *)2,
+       .parent = &extal1_clk,
+};
+
+/* extal1 / 1024 */
+static struct clk extal1_div1024_clk = {
+       .ops    = &div_clk_ops,
+       .priv   = (void *)1024,
+       .parent = &extal1_clk,
+};
+
+/* extal1 / 2 / 1024 */
+static struct clk extal1_div2048_clk = {
+       .ops    = &div_clk_ops,
+       .priv   = (void *)1024,
+       .parent = &extal1_div2_clk,
+};
+
+/* extal2 / 2 */
+static struct clk extal2_div2_clk = {
+       .ops    = &div_clk_ops,
+       .priv   = (void *)2,
+       .parent = &extal2_clk,
+};
+
+static struct clk_ops followparent_clk_ops = {
+       .recalc = followparent_recalc,
+};
+
+/* Main clock */
+static struct clk system_clk = {
+       .ops    = &followparent_clk_ops,
+};
+
+static struct clk system_div2_clk = {
+       .ops    = &div_clk_ops,
+       .priv   = (void *)2,
+       .parent = &system_clk,
+};
+
+/* r_clk */
+static struct clk r_clk = {
+       .ops    = &followparent_clk_ops,
+};
+
+/* PLLC0/PLLC1 */
+static unsigned long pllc01_recalc(struct clk *clk)
+{
+       unsigned long mult = 1;
+
+       if (__raw_readl(PLLC01CR) & (1 << 14))
+               mult = ((__raw_readl(clk->enable_reg) >> 24) & 0x7f) + 1;
+
+       return clk->parent->rate * mult;
+}
+
+static struct clk_ops pllc01_clk_ops = {
+       .recalc         = pllc01_recalc,
+};
+
+static struct clk pllc0_clk = {
+       .ops            = &pllc01_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &system_clk,
+       .enable_reg     = (void __iomem *)FRQCRC,
+};
+
+static struct clk pllc1_clk = {
+       .ops            = &pllc01_clk_ops,
+       .flags          = CLK_ENABLE_ON_INIT,
+       .parent         = &system_div2_clk,
+       .enable_reg     = (void __iomem *)FRQCRA,
+};
+
+/* PLLC1 / 2 */
+static struct clk pllc1_div2_clk = {
+       .ops            = &div_clk_ops,
+       .priv           = (void *)2,
+       .parent         = &pllc1_clk,
+};
+
+struct clk *main_clks[] = {
+       &extalr_clk,
+       &extal1_clk,
+       &extal2_clk,
+       &extal1_div2_clk,
+       &extal1_div1024_clk,
+       &extal1_div2048_clk,
+       &extal2_div2_clk,
+       &dv_clk,
+       &system_clk,
+       &system_div2_clk,
+       &r_clk,
+       &pllc0_clk,
+       &pllc1_clk,
+       &pllc1_div2_clk,
+};
+
+static void div4_kick(struct clk *clk)
+{
+       unsigned long value;
+
+       /* set KICK bit in FRQCRB to update hardware setting */
+       value = __raw_readl(FRQCRB);
+       value |= (1 << 31);
+       __raw_writel(value, FRQCRB);
+}
+
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
+                         24, 32, 36, 48, 0, 72, 96, 0 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+       .kick = div4_kick,
+};
+
+enum {
+       DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
+       DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
+       DIV4_NR
+};
+
+struct clk div4_clks[DIV4_NR] = {
+       [DIV4_I]        = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT),
+       [DIV4_ZG]       = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT),
+       [DIV4_B]        = SH_CLK_DIV4(&pllc1_clk, FRQCRA,  8, 0x6fff, CLK_ENABLE_ON_INIT),
+       [DIV4_M1]       = SH_CLK_DIV4(&pllc1_clk, FRQCRA,  4, 0x6fff, CLK_ENABLE_ON_INIT),
+       [DIV4_HP]       = SH_CLK_DIV4(&pllc1_clk, FRQCRB,  4, 0x6fff, 0),
+       [DIV4_HPP]      = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
+       [DIV4_S]        = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
+       [DIV4_ZB]       = SH_CLK_DIV4(&pllc1_clk, FRQCRC,  8, 0x6fff, 0),
+       [DIV4_M3]       = SH_CLK_DIV4(&pllc1_clk, FRQCRC,  4, 0x6fff, 0),
+       [DIV4_CP]       = SH_CLK_DIV4(&pllc1_clk, FRQCRC,  0, 0x6fff, 0),
+};
+
+enum {
+       DIV6_SUB,
+       DIV6_NR
+};
+
+static struct clk div6_clks[DIV6_NR] = {
+       [DIV6_SUB]      = SH_CLK_DIV6(&pllc1_div2_clk, SUBCKCR, 0),
+};
+
+enum {
+       MSTP125,
+       MSTP116, MSTP111, MSTP100, MSTP117,
+
+       MSTP230,
+       MSTP222,
+       MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+
+       MSTP329, MSTP323,
+
+       MSTP_NR
+};
+
+static struct clk mstp_clks[MSTP_NR] = {
+       [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
+       [MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   SMSTPCR1, 17, 0), /* LCDC1 */
+       [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 11, 0), /* TMU1 */
+       [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   SMSTPCR1,  0, 0), /* LCDC0 */
+
+       [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */
+       [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */
+       [MSTP207] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  7, 0), /* SCIFA5 */
+       [MSTP206] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  6, 0), /* SCIFB */
+       [MSTP204] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  4, 0), /* SCIFA0 */
+       [MSTP203] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  3, 0), /* SCIFA1 */
+       [MSTP202] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  2, 0), /* SCIFA2 */
+       [MSTP201] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  1, 0), /* SCIFA3 */
+       [MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2,  0, 0), /* SCIFA4 */
+
+       [MSTP329] = SH_CLK_MSTP32(&r_clk,               SMSTPCR3, 29, 0), /* CMT10 */
+       [MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
+};
+
+static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("extalr",                 &extalr_clk),
+       CLKDEV_CON_ID("extal1",                 &extal1_clk),
+       CLKDEV_CON_ID("extal2",                 &extal2_clk),
+       CLKDEV_CON_ID("extal1_div2",            &extal1_div2_clk),
+       CLKDEV_CON_ID("extal1_div1024",         &extal1_div1024_clk),
+       CLKDEV_CON_ID("extal1_div2048",         &extal1_div2048_clk),
+       CLKDEV_CON_ID("extal2_div2",            &extal2_div2_clk),
+       CLKDEV_CON_ID("dv_clk",                 &dv_clk),
+       CLKDEV_CON_ID("system_clk",             &system_clk),
+       CLKDEV_CON_ID("system_div2_clk",        &system_div2_clk),
+       CLKDEV_CON_ID("r_clk",                  &r_clk),
+       CLKDEV_CON_ID("pllc0_clk",              &pllc0_clk),
+       CLKDEV_CON_ID("pllc1_clk",              &pllc1_clk),
+       CLKDEV_CON_ID("pllc1_div2_clk",         &pllc1_div2_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("i_clk",                  &div4_clks[DIV4_I]),
+       CLKDEV_CON_ID("zg_clk",                 &div4_clks[DIV4_ZG]),
+       CLKDEV_CON_ID("b_clk",                  &div4_clks[DIV4_B]),
+       CLKDEV_CON_ID("m1_clk",                 &div4_clks[DIV4_M1]),
+       CLKDEV_CON_ID("hp_clk",                 &div4_clks[DIV4_HP]),
+       CLKDEV_CON_ID("hpp_clk",                &div4_clks[DIV4_HPP]),
+       CLKDEV_CON_ID("s_clk",                  &div4_clks[DIV4_S]),
+       CLKDEV_CON_ID("zb_clk",                 &div4_clks[DIV4_ZB]),
+       CLKDEV_CON_ID("m3_clk",                 &div4_clks[DIV4_M3]),
+       CLKDEV_CON_ID("cp_clk",                 &div4_clks[DIV4_CP]),
+
+       /* DIV6 clocks */
+       CLKDEV_CON_ID("sub_clk",                &div6_clks[DIV6_SUB]),
+
+       /* MSTP32 clocks */
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0",    &mstp_clks[MSTP100]),
+       CLKDEV_DEV_ID("sh_tmu.1",               &mstp_clks[MSTP111]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0",        &mstp_clks[MSTP116]),
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1",    &mstp_clks[MSTP117]),
+       CLKDEV_DEV_ID("sh_tmu.0",               &mstp_clks[MSTP125]),
+
+       CLKDEV_DEV_ID("sh-sci.4",               &mstp_clks[MSTP200]),
+       CLKDEV_DEV_ID("sh-sci.3",               &mstp_clks[MSTP201]),
+       CLKDEV_DEV_ID("sh-sci.2",               &mstp_clks[MSTP202]),
+       CLKDEV_DEV_ID("sh-sci.1",               &mstp_clks[MSTP203]),
+       CLKDEV_DEV_ID("sh-sci.0",               &mstp_clks[MSTP204]),
+       CLKDEV_DEV_ID("sh-sci.8",               &mstp_clks[MSTP206]),
+       CLKDEV_DEV_ID("sh-sci.5",               &mstp_clks[MSTP207]),
+
+       CLKDEV_DEV_ID("sh-sci.7",               &mstp_clks[MSTP222]),
+       CLKDEV_DEV_ID("sh-sci.6",               &mstp_clks[MSTP230]),
+
+       CLKDEV_DEV_ID("sh_cmt.10",              &mstp_clks[MSTP329]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.1",        &mstp_clks[MSTP323]),
+};
+
+void __init r8a7740_clock_init(u8 md_ck)
+{
+       int k, ret = 0;
+
+       /* detect system clock parent */
+       if (md_ck & MD_CK1)
+               system_clk.parent = &extal1_div2_clk;
+       else
+               system_clk.parent = &extal1_clk;
+
+       /* detect RCLK parent */
+       switch (md_ck & (MD_CK2 | MD_CK1)) {
+       case MD_CK2 | MD_CK1:
+               r_clk.parent = &extal1_div2048_clk;
+               break;
+       case MD_CK2:
+               r_clk.parent = &extal1_div1024_clk;
+               break;
+       case MD_CK1:
+       default:
+               r_clk.parent = &extalr_clk;
+               break;
+       }
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+       if (!ret)
+               clk_init();
+       else
+               panic("failed to setup r8a7740 clocks\n");
+}
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
new file mode 100644 (file)
index 0000000..b4b0e8c
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * r8a7779 clock framework support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <linux/clkdev.h>
+#include <mach/common.h>
+
+#define FRQMR   0xffc80014
+#define MSTPCR0 0xffc80030
+#define MSTPCR1 0xffc80034
+#define MSTPCR3 0xffc8003c
+#define MSTPSR1 0xffc80044
+#define MSTPSR4 0xffc80048
+#define MSTPSR6 0xffc8004c
+#define MSTPCR4 0xffc80050
+#define MSTPCR5 0xffc80054
+#define MSTPCR6 0xffc80058
+#define MSTPCR7 0xffc80040
+
+/* ioremap() through clock mapping mandatory to avoid
+ * collision with ARM coherent DMA virtual memory range.
+ */
+
+static struct clk_mapping cpg_mapping = {
+       .phys   = 0xffc80000,
+       .len    = 0x80,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk plla_clk = {
+       .rate           = 1500000000,
+       .mapping        = &cpg_mapping,
+};
+
+static struct clk *main_clks[] = {
+       &plla_clk,
+};
+
+static int divisors[] = { 0, 0, 0, 6, 8, 12, 16, 0, 24, 32, 36, 0, 0, 0, 0, 0 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+       .divisors = divisors,
+       .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+static struct clk_div4_table div4_table = {
+       .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_S, DIV4_OUT, DIV4_S4, DIV4_S3, DIV4_S1, DIV4_P, DIV4_NR };
+
+static struct clk div4_clks[DIV4_NR] = {
+       [DIV4_S]        = SH_CLK_DIV4(&plla_clk, FRQMR, 20,
+                                     0x0018, CLK_ENABLE_ON_INIT),
+       [DIV4_OUT]      = SH_CLK_DIV4(&plla_clk, FRQMR, 16,
+                                     0x0700, CLK_ENABLE_ON_INIT),
+       [DIV4_S4]       = SH_CLK_DIV4(&plla_clk, FRQMR, 12,
+                                     0x0040, CLK_ENABLE_ON_INIT),
+       [DIV4_S3]       = SH_CLK_DIV4(&plla_clk, FRQMR, 8,
+                                     0x0010, CLK_ENABLE_ON_INIT),
+       [DIV4_S1]       = SH_CLK_DIV4(&plla_clk, FRQMR, 4,
+                                     0x0060, CLK_ENABLE_ON_INIT),
+       [DIV4_P]        = SH_CLK_DIV4(&plla_clk, FRQMR, 0,
+                                     0x0300, CLK_ENABLE_ON_INIT),
+};
+
+enum { MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
+       MSTP016, MSTP015, MSTP014,
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+       [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0), /* SCIF0 */
+       [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0), /* SCIF1 */
+       [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0), /* SCIF2 */
+       [MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0), /* SCIF3 */
+       [MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0), /* SCIF4 */
+       [MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0), /* SCIF5 */
+       [MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0), /* TMU0 */
+       [MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0), /* TMU1 */
+       [MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0), /* TMU2 */
+};
+
+static unsigned long mul4_recalc(struct clk *clk)
+{
+       return clk->parent->rate * 4;
+}
+
+static struct clk_ops mul4_clk_ops = {
+       .recalc         = mul4_recalc,
+};
+
+struct clk clkz_clk = {
+       .ops            = &mul4_clk_ops,
+       .parent         = &div4_clks[DIV4_S],
+};
+
+struct clk clkzs_clk = {
+       /* clks x 4 / 4 = clks */
+       .parent         = &div4_clks[DIV4_S],
+};
+
+static struct clk *late_main_clks[] = {
+       &clkz_clk,
+       &clkzs_clk,
+};
+
+static struct clk_lookup lookups[] = {
+       /* main clocks */
+       CLKDEV_CON_ID("plla_clk", &plla_clk),
+       CLKDEV_CON_ID("clkz_clk", &clkz_clk),
+       CLKDEV_CON_ID("clkzs_clk", &clkzs_clk),
+
+       /* DIV4 clocks */
+       CLKDEV_CON_ID("shyway_clk",     &div4_clks[DIV4_S]),
+       CLKDEV_CON_ID("bus_clk",        &div4_clks[DIV4_OUT]),
+       CLKDEV_CON_ID("shyway4_clk",    &div4_clks[DIV4_S4]),
+       CLKDEV_CON_ID("shyway3_clk",    &div4_clks[DIV4_S3]),
+       CLKDEV_CON_ID("shyway1_clk",    &div4_clks[DIV4_S1]),
+       CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+       /* MSTP32 clocks */
+       CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP016]), /* TMU00 */
+       CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP016]), /* TMU01 */
+       CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP026]), /* SCIF0 */
+       CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP025]), /* SCIF1 */
+       CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP024]), /* SCIF2 */
+       CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP023]), /* SCIF3 */
+       CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP022]), /* SCIF4 */
+       CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP021]), /* SCIF6 */
+};
+
+void __init r8a7779_clock_init(void)
+{
+       int k, ret = 0;
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+               ret = clk_register(main_clks[k]);
+
+       if (!ret)
+               ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+       if (!ret)
+               ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+       for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+               ret = clk_register(late_main_clks[k]);
+
+       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+       if (!ret)
+               clk_init();
+       else
+               panic("failed to setup r8a7779 clocks\n");
+}
index 995a9c3aec8fbe60da9c78f3dba9835d20db9003..e349c22a0d71c93c54e49466549814795c80b77b 100644 (file)
@@ -411,11 +411,11 @@ static struct clk *fsibckcr_parent[] = {
 };
 
 static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
-       [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0,
+       [DIV6_HDMI] = SH_CLK_DIV6_EXT(HDMICKCR, 0,
                                      hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
-       [DIV6_FSIA] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIACKCR, 0,
+       [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
                                      fsiackcr_parent, ARRAY_SIZE(fsiackcr_parent), 6, 2),
-       [DIV6_FSIB] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIBCKCR, 0,
+       [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
                                      fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
 };
 
index 1370a89ca358ba548c80ae5ed3ec29b52156b501..34944d01bf1ed99db00a49f4b9845271ddce3a3e 100644 (file)
@@ -92,6 +92,24 @@ static struct clk_ops div2_clk_ops = {
        .recalc         = div2_recalc,
 };
 
+static unsigned long div7_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 7;
+}
+
+static struct clk_ops div7_clk_ops = {
+       .recalc         = div7_recalc,
+};
+
+static unsigned long div13_recalc(struct clk *clk)
+{
+       return clk->parent->rate / 13;
+}
+
+static struct clk_ops div13_clk_ops = {
+       .recalc         = div13_recalc,
+};
+
 /* Divide extal1 by two */
 static struct clk extal1_div2_clk = {
        .ops            = &div2_clk_ops,
@@ -174,12 +192,29 @@ static struct clk pll3_clk = {
        .enable_bit     = 3,
 };
 
-/* Divide PLL1 by two */
+/* Divide PLL */
 static struct clk pll1_div2_clk = {
        .ops            = &div2_clk_ops,
        .parent         = &pll1_clk,
 };
 
+static struct clk pll1_div7_clk = {
+       .ops            = &div7_clk_ops,
+       .parent         = &pll1_clk,
+};
+
+static struct clk pll1_div13_clk = {
+       .ops            = &div13_clk_ops,
+       .parent         = &pll1_clk,
+};
+
+/* External input clock */
+struct clk sh73a0_extcki_clk = {
+};
+
+struct clk sh73a0_extalr_clk = {
+};
+
 static struct clk *main_clks[] = {
        &r_clk,
        &sh73a0_extal1_clk,
@@ -193,6 +228,10 @@ static struct clk *main_clks[] = {
        &pll2_clk,
        &pll3_clk,
        &pll1_div2_clk,
+       &pll1_div7_clk,
+       &pll1_div13_clk,
+       &sh73a0_extcki_clk,
+       &sh73a0_extalr_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -246,27 +285,84 @@ enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
        DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
        DIV6_NR };
 
+static struct clk *vck_parent[8] = {
+       [0] = &pll1_div2_clk,
+       [1] = &pll2_clk,
+       [2] = &sh73a0_extcki_clk,
+       [3] = &sh73a0_extal2_clk,
+       [4] = &main_div2_clk,
+       [5] = &sh73a0_extalr_clk,
+       [6] = &main_clk,
+};
+
+static struct clk *pll_parent[4] = {
+       [0] = &pll1_div2_clk,
+       [1] = &pll2_clk,
+       [2] = &pll1_div13_clk,
+};
+
+static struct clk *hsi_parent[4] = {
+       [0] = &pll1_div2_clk,
+       [1] = &pll2_clk,
+       [2] = &pll1_div7_clk,
+};
+
+static struct clk *pll_extal2_parent[] = {
+       [0] = &pll1_div2_clk,
+       [1] = &pll2_clk,
+       [2] = &sh73a0_extal2_clk,
+       [3] = &sh73a0_extal2_clk,
+};
+
+static struct clk *dsi_parent[8] = {
+       [0] = &pll1_div2_clk,
+       [1] = &pll2_clk,
+       [2] = &main_clk,
+       [3] = &sh73a0_extal2_clk,
+       [4] = &sh73a0_extcki_clk,
+};
+
 static struct clk div6_clks[DIV6_NR] = {
-       [DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0),
-       [DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0),
-       [DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0),
-       [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT),
-       [DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0),
-       [DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0),
-       [DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),
-       [DIV6_SDHI2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0),
-       [DIV6_FSIA] = SH_CLK_DIV6(&pll1_div2_clk, FSIACKCR, 0),
-       [DIV6_FSIB] = SH_CLK_DIV6(&pll1_div2_clk, FSIBCKCR, 0),
-       [DIV6_SUB] = SH_CLK_DIV6(&sh73a0_extal2_clk, SUBCKCR, 0),
-       [DIV6_SPUA] = SH_CLK_DIV6(&pll1_div2_clk, SPUACKCR, 0),
-       [DIV6_SPUV] = SH_CLK_DIV6(&pll1_div2_clk, SPUVCKCR, 0),
-       [DIV6_MSU] = SH_CLK_DIV6(&pll1_div2_clk, MSUCKCR, 0),
-       [DIV6_HSI] = SH_CLK_DIV6(&pll1_div2_clk, HSICKCR, 0),
-       [DIV6_MFG1] = SH_CLK_DIV6(&pll1_div2_clk, MFCK1CR, 0),
-       [DIV6_MFG2] = SH_CLK_DIV6(&pll1_div2_clk, MFCK2CR, 0),
-       [DIV6_DSIT] = SH_CLK_DIV6(&pll1_div2_clk, DSITCKCR, 0),
-       [DIV6_DSI0P] = SH_CLK_DIV6(&pll1_div2_clk, DSI0PCKCR, 0),
-       [DIV6_DSI1P] = SH_CLK_DIV6(&pll1_div2_clk, DSI1PCKCR, 0),
+       [DIV6_VCK1] = SH_CLK_DIV6_EXT(VCLKCR1, 0,
+                       vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+       [DIV6_VCK2] = SH_CLK_DIV6_EXT(VCLKCR2, 0,
+                       vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+       [DIV6_VCK3] = SH_CLK_DIV6_EXT(VCLKCR3, 0,
+                       vck_parent, ARRAY_SIZE(vck_parent), 12, 3),
+       [DIV6_ZB1] = SH_CLK_DIV6_EXT(ZBCKCR, CLK_ENABLE_ON_INIT,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_FLCTL] = SH_CLK_DIV6_EXT(FLCKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_SDHI0] = SH_CLK_DIV6_EXT(SD0CKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+       [DIV6_SDHI1] = SH_CLK_DIV6_EXT(SD1CKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+       [DIV6_SDHI2] = SH_CLK_DIV6_EXT(SD2CKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 6, 2),
+       [DIV6_FSIA] = SH_CLK_DIV6_EXT(FSIACKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 6, 1),
+       [DIV6_FSIB] = SH_CLK_DIV6_EXT(FSIBCKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 6, 1),
+       [DIV6_SUB] = SH_CLK_DIV6_EXT(SUBCKCR, 0,
+                       pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+       [DIV6_SPUA] = SH_CLK_DIV6_EXT(SPUACKCR, 0,
+                       pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+       [DIV6_SPUV] = SH_CLK_DIV6_EXT(SPUVCKCR, 0,
+                       pll_extal2_parent, ARRAY_SIZE(pll_extal2_parent), 6, 2),
+       [DIV6_MSU] = SH_CLK_DIV6_EXT(MSUCKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_HSI] = SH_CLK_DIV6_EXT(HSICKCR, 0,
+                       hsi_parent, ARRAY_SIZE(hsi_parent), 6, 2),
+       [DIV6_MFG1] = SH_CLK_DIV6_EXT(MFCK1CR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_MFG2] = SH_CLK_DIV6_EXT(MFCK2CR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_DSIT] = SH_CLK_DIV6_EXT(DSITCKCR, 0,
+                       pll_parent, ARRAY_SIZE(pll_parent), 7, 1),
+       [DIV6_DSI0P] = SH_CLK_DIV6_EXT(DSI0PCKCR, 0,
+                       dsi_parent, ARRAY_SIZE(dsi_parent), 12, 3),
+       [DIV6_DSI1P] = SH_CLK_DIV6_EXT(DSI1PCKCR, 0,
+                       dsi_parent, ARRAY_SIZE(dsi_parent), 12, 3),
 };
 
 enum { MSTP001,
@@ -403,7 +499,7 @@ void __init sh73a0_clock_init(void)
                ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 
        if (!ret)
-               ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+               ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
 
        if (!ret)
                ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
index 26079d933d913e1bf4f04e68d6a23e1eb3225e3d..6ac015c892060e72b29c2a60735a810762b0c115 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include <asm/memory.h>
 
-       __INIT
+       __CPUINIT
 
 /*
  * Reset vector for secondary CPUs.
index 238a0d97d2d5d110ba6a8d70762c8fa26d62e474..828d22f3af5750b022f898bdb44aa79d56577e4d 100644 (file)
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <mach/common.h>
+#include <asm/cacheflush.h>
+
+static cpumask_t dead_cpus;
 
 int platform_cpu_kill(unsigned int cpu)
 {
-       return 1;
+       int k;
+
+       /* this function is running on another CPU than the offline target,
+        * here we need wait for shutdown code in platform_cpu_die() to
+        * finish before asking SoC-specific code to power off the CPU core.
+        */
+       for (k = 0; k < 1000; k++) {
+               if (cpumask_test_cpu(cpu, &dead_cpus))
+                       return shmobile_platform_cpu_kill(cpu);
+
+               mdelay(1);
+       }
+
+       return 0;
 }
 
 void platform_cpu_die(unsigned int cpu)
 {
+       /* hardware shutdown code running on the CPU that is being offlined */
+       flush_cache_all();
+       dsb();
+
+       /* notify platform_cpu_kill() that hardware shutdown is finished */
+       cpumask_set_cpu(cpu, &dead_cpus);
+
+       /* wait for SoC code in platform_cpu_kill() to shut off CPU core
+        * power. CPU bring up starts from the reset vector.
+        */
        while (1) {
                /*
                 * here's the WFI
@@ -33,6 +62,7 @@ void platform_cpu_die(unsigned int cpu)
 
 int platform_cpu_disable(unsigned int cpu)
 {
+       cpumask_clear_cpu(cpu, &dead_cpus);
        /*
         * we don't allow CPU 0 to be shutdown (it is still too special
         * e.g. clock tick interrupts)
index be78a2c73db4784a598f180b076cc239e693e0c9..e4b945e271e73db84b5fa608ce4eba82267d13dc 100644 (file)
@@ -4,6 +4,7 @@
 extern struct sys_timer shmobile_timer;
 extern void shmobile_setup_console(void);
 extern void shmobile_secondary_vector(void);
+extern int shmobile_platform_cpu_kill(unsigned int cpu);
 struct clk;
 extern int clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
@@ -46,10 +47,31 @@ extern void sh73a0_clock_init(void);
 extern void sh73a0_pinmux_init(void);
 extern struct clk sh73a0_extal1_clk;
 extern struct clk sh73a0_extal2_clk;
+extern struct clk sh73a0_extcki_clk;
+extern struct clk sh73a0_extalr_clk;
 
 extern unsigned int sh73a0_get_core_count(void);
 extern void sh73a0_secondary_init(unsigned int cpu);
 extern int sh73a0_boot_secondary(unsigned int cpu);
 extern void sh73a0_smp_prepare_cpus(void);
 
+extern void r8a7740_init_irq(void);
+extern void r8a7740_add_early_devices(void);
+extern void r8a7740_add_standard_devices(void);
+extern void r8a7740_clock_init(u8 md_ck);
+extern void r8a7740_pinmux_init(void);
+
+extern void r8a7779_init_irq(void);
+extern void r8a7779_add_early_devices(void);
+extern void r8a7779_add_standard_devices(void);
+extern void r8a7779_clock_init(void);
+extern void r8a7779_pinmux_init(void);
+extern void r8a7779_pm_init(void);
+
+extern unsigned int r8a7779_get_core_count(void);
+extern int r8a7779_platform_cpu_kill(unsigned int cpu);
+extern void r8a7779_secondary_init(unsigned int cpu);
+extern int r8a7779_boot_secondary(unsigned int cpu);
+extern void r8a7779_smp_prepare_cpus(void);
+
 #endif /* __ARCH_MACH_COMMON_H */
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7740.h b/arch/arm/mach-shmobile/include/mach/r8a7740.h
new file mode 100644 (file)
index 0000000..9d447ab
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __ASM_R8A7740_H__
+#define __ASM_R8A7740_H__
+
+/*
+ * MD_CKx pin
+ */
+#define MD_CK2 (1 << 2)
+#define MD_CK1 (1 << 1)
+#define MD_CK0 (1 << 0)
+
+/*
+ * Pin Function Controller:
+ *     GPIO_FN_xx - GPIO used to select pin function
+ *     GPIO_PORTxx - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+       /* PORT */
+       GPIO_PORT0, GPIO_PORT1, GPIO_PORT2, GPIO_PORT3, GPIO_PORT4,
+       GPIO_PORT5, GPIO_PORT6, GPIO_PORT7, GPIO_PORT8, GPIO_PORT9,
+
+       GPIO_PORT10, GPIO_PORT11, GPIO_PORT12, GPIO_PORT13, GPIO_PORT14,
+       GPIO_PORT15, GPIO_PORT16, GPIO_PORT17, GPIO_PORT18, GPIO_PORT19,
+
+       GPIO_PORT20, GPIO_PORT21, GPIO_PORT22, GPIO_PORT23, GPIO_PORT24,
+       GPIO_PORT25, GPIO_PORT26, GPIO_PORT27, GPIO_PORT28, GPIO_PORT29,
+
+       GPIO_PORT30, GPIO_PORT31, GPIO_PORT32, GPIO_PORT33, GPIO_PORT34,
+       GPIO_PORT35, GPIO_PORT36, GPIO_PORT37, GPIO_PORT38, GPIO_PORT39,
+
+       GPIO_PORT40, GPIO_PORT41, GPIO_PORT42, GPIO_PORT43, GPIO_PORT44,
+       GPIO_PORT45, GPIO_PORT46, GPIO_PORT47, GPIO_PORT48, GPIO_PORT49,
+
+       GPIO_PORT50, GPIO_PORT51, GPIO_PORT52, GPIO_PORT53, GPIO_PORT54,
+       GPIO_PORT55, GPIO_PORT56, GPIO_PORT57, GPIO_PORT58, GPIO_PORT59,
+
+       GPIO_PORT60, GPIO_PORT61, GPIO_PORT62, GPIO_PORT63, GPIO_PORT64,
+       GPIO_PORT65, GPIO_PORT66, GPIO_PORT67, GPIO_PORT68, GPIO_PORT69,
+
+       GPIO_PORT70, GPIO_PORT71, GPIO_PORT72, GPIO_PORT73, GPIO_PORT74,
+       GPIO_PORT75, GPIO_PORT76, GPIO_PORT77, GPIO_PORT78, GPIO_PORT79,
+
+       GPIO_PORT80, GPIO_PORT81, GPIO_PORT82, GPIO_PORT83, GPIO_PORT84,
+       GPIO_PORT85, GPIO_PORT86, GPIO_PORT87, GPIO_PORT88, GPIO_PORT89,
+
+       GPIO_PORT90, GPIO_PORT91, GPIO_PORT92, GPIO_PORT93, GPIO_PORT94,
+       GPIO_PORT95, GPIO_PORT96, GPIO_PORT97, GPIO_PORT98, GPIO_PORT99,
+
+       GPIO_PORT100, GPIO_PORT101, GPIO_PORT102, GPIO_PORT103, GPIO_PORT104,
+       GPIO_PORT105, GPIO_PORT106, GPIO_PORT107, GPIO_PORT108, GPIO_PORT109,
+
+       GPIO_PORT110, GPIO_PORT111, GPIO_PORT112, GPIO_PORT113, GPIO_PORT114,
+       GPIO_PORT115, GPIO_PORT116, GPIO_PORT117, GPIO_PORT118, GPIO_PORT119,
+
+       GPIO_PORT120, GPIO_PORT121, GPIO_PORT122, GPIO_PORT123, GPIO_PORT124,
+       GPIO_PORT125, GPIO_PORT126, GPIO_PORT127, GPIO_PORT128, GPIO_PORT129,
+
+       GPIO_PORT130, GPIO_PORT131, GPIO_PORT132, GPIO_PORT133, GPIO_PORT134,
+       GPIO_PORT135, GPIO_PORT136, GPIO_PORT137, GPIO_PORT138, GPIO_PORT139,
+
+       GPIO_PORT140, GPIO_PORT141, GPIO_PORT142, GPIO_PORT143, GPIO_PORT144,
+       GPIO_PORT145, GPIO_PORT146, GPIO_PORT147, GPIO_PORT148, GPIO_PORT149,
+
+       GPIO_PORT150, GPIO_PORT151, GPIO_PORT152, GPIO_PORT153, GPIO_PORT154,
+       GPIO_PORT155, GPIO_PORT156, GPIO_PORT157, GPIO_PORT158, GPIO_PORT159,
+
+       GPIO_PORT160, GPIO_PORT161, GPIO_PORT162, GPIO_PORT163, GPIO_PORT164,
+       GPIO_PORT165, GPIO_PORT166, GPIO_PORT167, GPIO_PORT168, GPIO_PORT169,
+
+       GPIO_PORT170, GPIO_PORT171, GPIO_PORT172, GPIO_PORT173, GPIO_PORT174,
+       GPIO_PORT175, GPIO_PORT176, GPIO_PORT177, GPIO_PORT178, GPIO_PORT179,
+
+       GPIO_PORT180, GPIO_PORT181, GPIO_PORT182, GPIO_PORT183, GPIO_PORT184,
+       GPIO_PORT185, GPIO_PORT186, GPIO_PORT187, GPIO_PORT188, GPIO_PORT189,
+
+       GPIO_PORT190, GPIO_PORT191, GPIO_PORT192, GPIO_PORT193, GPIO_PORT194,
+       GPIO_PORT195, GPIO_PORT196, GPIO_PORT197, GPIO_PORT198, GPIO_PORT199,
+
+       GPIO_PORT200, GPIO_PORT201, GPIO_PORT202, GPIO_PORT203, GPIO_PORT204,
+       GPIO_PORT205, GPIO_PORT206, GPIO_PORT207, GPIO_PORT208, GPIO_PORT209,
+
+       GPIO_PORT210, GPIO_PORT211,
+
+       /* IRQ */
+       GPIO_FN_IRQ0_PORT2,     GPIO_FN_IRQ0_PORT13,
+       GPIO_FN_IRQ1,
+       GPIO_FN_IRQ2_PORT11,    GPIO_FN_IRQ2_PORT12,
+       GPIO_FN_IRQ3_PORT10,    GPIO_FN_IRQ3_PORT14,
+       GPIO_FN_IRQ4_PORT15,    GPIO_FN_IRQ4_PORT172,
+       GPIO_FN_IRQ5_PORT0,     GPIO_FN_IRQ5_PORT1,
+       GPIO_FN_IRQ6_PORT121,   GPIO_FN_IRQ6_PORT173,
+       GPIO_FN_IRQ7_PORT120,   GPIO_FN_IRQ7_PORT209,
+       GPIO_FN_IRQ8,
+       GPIO_FN_IRQ9_PORT118,   GPIO_FN_IRQ9_PORT210,
+       GPIO_FN_IRQ10,
+       GPIO_FN_IRQ11,
+       GPIO_FN_IRQ12_PORT42,   GPIO_FN_IRQ12_PORT97,
+       GPIO_FN_IRQ13_PORT64,   GPIO_FN_IRQ13_PORT98,
+       GPIO_FN_IRQ14_PORT63,   GPIO_FN_IRQ14_PORT99,
+       GPIO_FN_IRQ15_PORT62,   GPIO_FN_IRQ15_PORT100,
+       GPIO_FN_IRQ16_PORT68,   GPIO_FN_IRQ16_PORT211,
+       GPIO_FN_IRQ17,
+       GPIO_FN_IRQ18,
+       GPIO_FN_IRQ19,
+       GPIO_FN_IRQ20,
+       GPIO_FN_IRQ21,
+       GPIO_FN_IRQ22,
+       GPIO_FN_IRQ23,
+       GPIO_FN_IRQ24,
+       GPIO_FN_IRQ25,
+       GPIO_FN_IRQ26_PORT58,   GPIO_FN_IRQ26_PORT81,
+       GPIO_FN_IRQ27_PORT57,   GPIO_FN_IRQ27_PORT168,
+       GPIO_FN_IRQ28_PORT56,   GPIO_FN_IRQ28_PORT169,
+       GPIO_FN_IRQ29_PORT50,   GPIO_FN_IRQ29_PORT170,
+       GPIO_FN_IRQ30_PORT49,   GPIO_FN_IRQ30_PORT171,
+       GPIO_FN_IRQ31_PORT41,   GPIO_FN_IRQ31_PORT167,
+
+       /* Function */
+
+       /* DBGT */
+       GPIO_FN_DBGMDT2,        GPIO_FN_DBGMDT1,        GPIO_FN_DBGMDT0,
+       GPIO_FN_DBGMD10,        GPIO_FN_DBGMD11,        GPIO_FN_DBGMD20,
+       GPIO_FN_DBGMD21,
+
+       /* FSI */
+       GPIO_FN_FSIAISLD_PORT0,         /* FSIAISLD Port 0/5 */
+       GPIO_FN_FSIAISLD_PORT5,
+       GPIO_FN_FSIASPDIF_PORT9,        /* FSIASPDIF Port 9/18 */
+       GPIO_FN_FSIASPDIF_PORT18,
+       GPIO_FN_FSIAOSLD1,      GPIO_FN_FSIAOSLD2,
+       GPIO_FN_FSIAOLR,        GPIO_FN_FSIAOBT,
+       GPIO_FN_FSIAOSLD,       GPIO_FN_FSIAOMC,
+       GPIO_FN_FSIACK,         GPIO_FN_FSIAILR,
+       GPIO_FN_FSIAIBT,
+
+       /* FMSI */
+       GPIO_FN_FMSISLD_PORT1, /* FMSISLD Port 1/6 */
+       GPIO_FN_FMSISLD_PORT6,
+       GPIO_FN_FMSIILR,        GPIO_FN_FMSIIBT,
+       GPIO_FN_FMSIOLR,        GPIO_FN_FMSIOBT,
+       GPIO_FN_FMSICK,         GPIO_FN_FMSOILR,
+       GPIO_FN_FMSOIBT,        GPIO_FN_FMSOOLR,
+       GPIO_FN_FMSOOBT,        GPIO_FN_FMSOSLD,
+       GPIO_FN_FMSOCK,
+
+       /* SCIFA0 */
+       GPIO_FN_SCIFA0_SCK,     GPIO_FN_SCIFA0_CTS,
+       GPIO_FN_SCIFA0_RTS,     GPIO_FN_SCIFA0_RXD,
+       GPIO_FN_SCIFA0_TXD,
+
+       /* SCIFA1 */
+       GPIO_FN_SCIFA1_CTS,     GPIO_FN_SCIFA1_SCK,
+       GPIO_FN_SCIFA1_RXD,     GPIO_FN_SCIFA1_TXD,
+       GPIO_FN_SCIFA1_RTS,
+
+       /* SCIFA2 */
+       GPIO_FN_SCIFA2_SCK_PORT22, /* SCIFA2_SCK Port 22/199 */
+       GPIO_FN_SCIFA2_SCK_PORT199,
+       GPIO_FN_SCIFA2_RXD,     GPIO_FN_SCIFA2_TXD,
+       GPIO_FN_SCIFA2_CTS,     GPIO_FN_SCIFA2_RTS,
+
+       /* SCIFA3 */
+       GPIO_FN_SCIFA3_RTS_PORT105, /* MSEL5CR_8_0 */
+       GPIO_FN_SCIFA3_SCK_PORT116,
+       GPIO_FN_SCIFA3_CTS_PORT117,
+       GPIO_FN_SCIFA3_RXD_PORT174,
+       GPIO_FN_SCIFA3_TXD_PORT175,
+
+       GPIO_FN_SCIFA3_RTS_PORT161, /* MSEL5CR_8_1 */
+       GPIO_FN_SCIFA3_SCK_PORT158,
+       GPIO_FN_SCIFA3_CTS_PORT162,
+       GPIO_FN_SCIFA3_RXD_PORT159,
+       GPIO_FN_SCIFA3_TXD_PORT160,
+
+       /* SCIFA4 */
+       GPIO_FN_SCIFA4_RXD_PORT12, /* MSEL5CR[12:11] = 00 */
+       GPIO_FN_SCIFA4_TXD_PORT13,
+
+       GPIO_FN_SCIFA4_RXD_PORT204, /* MSEL5CR[12:11] = 01 */
+       GPIO_FN_SCIFA4_TXD_PORT203,
+
+       GPIO_FN_SCIFA4_RXD_PORT94, /* MSEL5CR[12:11] = 10 */
+       GPIO_FN_SCIFA4_TXD_PORT93,
+
+       GPIO_FN_SCIFA4_SCK_PORT21, /* SCIFA4_SCK Port 21/205 */
+       GPIO_FN_SCIFA4_SCK_PORT205,
+
+       /* SCIFA5 */
+       GPIO_FN_SCIFA5_TXD_PORT20, /* MSEL5CR[15:14] = 00 */
+       GPIO_FN_SCIFA5_RXD_PORT10,
+
+       GPIO_FN_SCIFA5_RXD_PORT207, /* MSEL5CR[15:14] = 01 */
+       GPIO_FN_SCIFA5_TXD_PORT208,
+
+       GPIO_FN_SCIFA5_TXD_PORT91, /* MSEL5CR[15:14] = 10 */
+       GPIO_FN_SCIFA5_RXD_PORT92,
+
+       GPIO_FN_SCIFA5_SCK_PORT23, /* SCIFA5_SCK Port 23/206 */
+       GPIO_FN_SCIFA5_SCK_PORT206,
+
+       /* SCIFA6 */
+       GPIO_FN_SCIFA6_SCK,     GPIO_FN_SCIFA6_RXD,     GPIO_FN_SCIFA6_TXD,
+
+       /* SCIFA7 */
+       GPIO_FN_SCIFA7_TXD,     GPIO_FN_SCIFA7_RXD,
+
+       /* SCIFAB */
+       GPIO_FN_SCIFB_SCK_PORT190, /* MSEL5CR_17_0 */
+       GPIO_FN_SCIFB_RXD_PORT191,
+       GPIO_FN_SCIFB_TXD_PORT192,
+       GPIO_FN_SCIFB_RTS_PORT186,
+       GPIO_FN_SCIFB_CTS_PORT187,
+
+       GPIO_FN_SCIFB_SCK_PORT2, /* MSEL5CR_17_1 */
+       GPIO_FN_SCIFB_RXD_PORT3,
+       GPIO_FN_SCIFB_TXD_PORT4,
+       GPIO_FN_SCIFB_RTS_PORT172,
+       GPIO_FN_SCIFB_CTS_PORT173,
+
+       /* LCD0 */
+       GPIO_FN_LCDC0_SELECT,
+       GPIO_FN_LCD0_D0,        GPIO_FN_LCD0_D1,        GPIO_FN_LCD0_D2,
+       GPIO_FN_LCD0_D3,        GPIO_FN_LCD0_D4,        GPIO_FN_LCD0_D5,
+       GPIO_FN_LCD0_D6,        GPIO_FN_LCD0_D7,        GPIO_FN_LCD0_D8,
+       GPIO_FN_LCD0_D9,        GPIO_FN_LCD0_D10,       GPIO_FN_LCD0_D11,
+       GPIO_FN_LCD0_D12,       GPIO_FN_LCD0_D13,       GPIO_FN_LCD0_D14,
+       GPIO_FN_LCD0_D15,       GPIO_FN_LCD0_D16,       GPIO_FN_LCD0_D17,
+       GPIO_FN_LCD0_DON,       GPIO_FN_LCD0_VCPWC,     GPIO_FN_LCD0_VEPWC,
+
+       GPIO_FN_LCD0_DCK,       GPIO_FN_LCD0_VSYN, /* for RGB */
+       GPIO_FN_LCD0_HSYN,      GPIO_FN_LCD0_DISP, /* for RGB */
+
+       GPIO_FN_LCD0_WR,        GPIO_FN_LCD0_RD, /* for SYS */
+       GPIO_FN_LCD0_CS,        GPIO_FN_LCD0_RS, /* for SYS */
+
+       GPIO_FN_LCD0_D18_PORT163,       GPIO_FN_LCD0_D19_PORT162,
+       GPIO_FN_LCD0_D20_PORT161,       GPIO_FN_LCD0_D21_PORT158,
+       GPIO_FN_LCD0_D22_PORT160,       GPIO_FN_LCD0_D23_PORT159,
+       GPIO_FN_LCD0_LCLK_PORT165,       /* MSEL5CR_6_1 */
+
+       GPIO_FN_LCD0_D18_PORT40,        GPIO_FN_LCD0_D19_PORT4,
+       GPIO_FN_LCD0_D20_PORT3,         GPIO_FN_LCD0_D21_PORT2,
+       GPIO_FN_LCD0_D22_PORT0,         GPIO_FN_LCD0_D23_PORT1,
+       GPIO_FN_LCD0_LCLK_PORT102,      /* MSEL5CR_6_0 */
+
+       /* LCD1 */
+       GPIO_FN_LCDC1_SELECT,
+       GPIO_FN_LCD1_D0,        GPIO_FN_LCD1_D1,        GPIO_FN_LCD1_D2,
+       GPIO_FN_LCD1_D3,        GPIO_FN_LCD1_D4,        GPIO_FN_LCD1_D5,
+       GPIO_FN_LCD1_D6,        GPIO_FN_LCD1_D7,        GPIO_FN_LCD1_D8,
+       GPIO_FN_LCD1_D9,        GPIO_FN_LCD1_D10,       GPIO_FN_LCD1_D11,
+       GPIO_FN_LCD1_D12,       GPIO_FN_LCD1_D13,       GPIO_FN_LCD1_D14,
+       GPIO_FN_LCD1_D15,       GPIO_FN_LCD1_D16,       GPIO_FN_LCD1_D17,
+       GPIO_FN_LCD1_D18,       GPIO_FN_LCD1_D19,       GPIO_FN_LCD1_D20,
+       GPIO_FN_LCD1_D21,       GPIO_FN_LCD1_D22,       GPIO_FN_LCD1_D23,
+       GPIO_FN_LCD1_DON,       GPIO_FN_LCD1_VCPWC,
+       GPIO_FN_LCD1_LCLK,      GPIO_FN_LCD1_VEPWC,
+
+       GPIO_FN_LCD1_DCK,       GPIO_FN_LCD1_VSYN, /* for RGB */
+       GPIO_FN_LCD1_HSYN,      GPIO_FN_LCD1_DISP, /* for RGB */
+
+       GPIO_FN_LCD1_WR,        GPIO_FN_LCD1_RD, /* for SYS */
+       GPIO_FN_LCD1_CS,        GPIO_FN_LCD1_RS, /* for SYS */
+
+       /* RSPI */
+       GPIO_FN_RSPI_SSL0_A,    GPIO_FN_RSPI_SSL1_A,
+       GPIO_FN_RSPI_SSL2_A,    GPIO_FN_RSPI_SSL3_A,
+       GPIO_FN_RSPI_MOSI_A,    GPIO_FN_RSPI_MISO_A,
+       GPIO_FN_RSPI_CK_A,
+
+       /* VIO CKO */
+       GPIO_FN_VIO_CKO1,
+       GPIO_FN_VIO_CKO2,
+       GPIO_FN_VIO_CKO_1,
+       GPIO_FN_VIO_CKO,
+
+       /* VIO0 */
+       GPIO_FN_VIO0_D0,        GPIO_FN_VIO0_D1,        GPIO_FN_VIO0_D2,
+       GPIO_FN_VIO0_D3,        GPIO_FN_VIO0_D4,        GPIO_FN_VIO0_D5,
+       GPIO_FN_VIO0_D6,        GPIO_FN_VIO0_D7,        GPIO_FN_VIO0_D8,
+       GPIO_FN_VIO0_D9,        GPIO_FN_VIO0_D10,       GPIO_FN_VIO0_D11,
+       GPIO_FN_VIO0_D12,       GPIO_FN_VIO0_VD,        GPIO_FN_VIO0_HD,
+       GPIO_FN_VIO0_CLK,       GPIO_FN_VIO0_FIELD,
+
+       GPIO_FN_VIO0_D13_PORT26, /* MSEL5CR_27_0 */
+       GPIO_FN_VIO0_D14_PORT25,
+       GPIO_FN_VIO0_D15_PORT24,
+
+       GPIO_FN_VIO0_D13_PORT22, /* MSEL5CR_27_1 */
+       GPIO_FN_VIO0_D14_PORT95,
+       GPIO_FN_VIO0_D15_PORT96,
+
+       /* VIO1 */
+       GPIO_FN_VIO1_D0,        GPIO_FN_VIO1_D1,        GPIO_FN_VIO1_D2,
+       GPIO_FN_VIO1_D3,        GPIO_FN_VIO1_D4,        GPIO_FN_VIO1_D5,
+       GPIO_FN_VIO1_D6,        GPIO_FN_VIO1_D7,        GPIO_FN_VIO1_VD,
+       GPIO_FN_VIO1_HD,        GPIO_FN_VIO1_CLK,       GPIO_FN_VIO1_FIELD,
+
+       /* TPU0 */
+       GPIO_FN_TPU0TO0,        GPIO_FN_TPU0TO1,
+       GPIO_FN_TPU0TO3,
+       GPIO_FN_TPU0TO2_PORT66, /* TPU0TO2 Port 66/202 */
+       GPIO_FN_TPU0TO2_PORT202,
+
+       /* SSP1 0 */
+       GPIO_FN_STP0_IPD0,      GPIO_FN_STP0_IPD1,      GPIO_FN_STP0_IPD2,
+       GPIO_FN_STP0_IPD3,      GPIO_FN_STP0_IPD4,      GPIO_FN_STP0_IPD5,
+       GPIO_FN_STP0_IPD6,      GPIO_FN_STP0_IPD7,      GPIO_FN_STP0_IPEN,
+       GPIO_FN_STP0_IPCLK,     GPIO_FN_STP0_IPSYNC,
+
+       /* SSP1 1 */
+       GPIO_FN_STP1_IPD1,      GPIO_FN_STP1_IPD2,      GPIO_FN_STP1_IPD3,
+       GPIO_FN_STP1_IPD4,      GPIO_FN_STP1_IPD5,      GPIO_FN_STP1_IPD6,
+       GPIO_FN_STP1_IPD7,      GPIO_FN_STP1_IPCLK,     GPIO_FN_STP1_IPSYNC,
+
+       GPIO_FN_STP1_IPD0_PORT186, /* MSEL5CR_23_0 */
+       GPIO_FN_STP1_IPEN_PORT187,
+
+       GPIO_FN_STP1_IPD0_PORT194, /* MSEL5CR_23_1 */
+       GPIO_FN_STP1_IPEN_PORT193,
+
+       /* SIM */
+       GPIO_FN_SIM_RST,        GPIO_FN_SIM_CLK,
+       GPIO_FN_SIM_D_PORT22, /* SIM_D  Port 22/199 */
+       GPIO_FN_SIM_D_PORT199,
+
+       /* SDHI0 */
+       GPIO_FN_SDHI0_D0,       GPIO_FN_SDHI0_D1,       GPIO_FN_SDHI0_D2,
+       GPIO_FN_SDHI0_D3,       GPIO_FN_SDHI0_CD,       GPIO_FN_SDHI0_WP,
+       GPIO_FN_SDHI0_CMD,      GPIO_FN_SDHI0_CLK,
+
+       /* SDHI1 */
+       GPIO_FN_SDHI1_D0,       GPIO_FN_SDHI1_D1,       GPIO_FN_SDHI1_D2,
+       GPIO_FN_SDHI1_D3,       GPIO_FN_SDHI1_CD,       GPIO_FN_SDHI1_WP,
+       GPIO_FN_SDHI1_CMD,      GPIO_FN_SDHI1_CLK,
+
+       /* SDHI2 */
+       GPIO_FN_SDHI2_D0,       GPIO_FN_SDHI2_D1,       GPIO_FN_SDHI2_D2,
+       GPIO_FN_SDHI2_D3,       GPIO_FN_SDHI2_CLK,      GPIO_FN_SDHI2_CMD,
+
+       GPIO_FN_SDHI2_CD_PORT24, /* MSEL5CR_19_0 */
+       GPIO_FN_SDHI2_WP_PORT25,
+
+       GPIO_FN_SDHI2_WP_PORT177, /* MSEL5CR_19_1 */
+       GPIO_FN_SDHI2_CD_PORT202,
+
+       /* MSIOF2 */
+       GPIO_FN_MSIOF2_TXD,     GPIO_FN_MSIOF2_RXD,     GPIO_FN_MSIOF2_TSCK,
+       GPIO_FN_MSIOF2_SS2,     GPIO_FN_MSIOF2_TSYNC,   GPIO_FN_MSIOF2_SS1,
+       GPIO_FN_MSIOF2_MCK1,    GPIO_FN_MSIOF2_MCK0,    GPIO_FN_MSIOF2_RSYNC,
+       GPIO_FN_MSIOF2_RSCK,
+
+       /* KEYSC */
+       GPIO_FN_KEYIN4,         GPIO_FN_KEYIN5,
+       GPIO_FN_KEYIN6,         GPIO_FN_KEYIN7,
+       GPIO_FN_KEYOUT0,        GPIO_FN_KEYOUT1,        GPIO_FN_KEYOUT2,
+       GPIO_FN_KEYOUT3,        GPIO_FN_KEYOUT4,        GPIO_FN_KEYOUT5,
+       GPIO_FN_KEYOUT6,        GPIO_FN_KEYOUT7,
+
+       GPIO_FN_KEYIN0_PORT43, /* MSEL4CR_18_0 */
+       GPIO_FN_KEYIN1_PORT44,
+       GPIO_FN_KEYIN2_PORT45,
+       GPIO_FN_KEYIN3_PORT46,
+
+       GPIO_FN_KEYIN0_PORT58, /* MSEL4CR_18_1 */
+       GPIO_FN_KEYIN1_PORT57,
+       GPIO_FN_KEYIN2_PORT56,
+       GPIO_FN_KEYIN3_PORT55,
+
+       /* VOU */
+       GPIO_FN_DV_D0,  GPIO_FN_DV_D1,  GPIO_FN_DV_D2,  GPIO_FN_DV_D3,
+       GPIO_FN_DV_D4,  GPIO_FN_DV_D5,  GPIO_FN_DV_D6,  GPIO_FN_DV_D7,
+       GPIO_FN_DV_D8,  GPIO_FN_DV_D9,  GPIO_FN_DV_D10, GPIO_FN_DV_D11,
+       GPIO_FN_DV_D12, GPIO_FN_DV_D13, GPIO_FN_DV_D14, GPIO_FN_DV_D15,
+       GPIO_FN_DV_CLK,
+       GPIO_FN_DV_VSYNC,
+       GPIO_FN_DV_HSYNC,
+
+       /* MEMC */
+       GPIO_FN_MEMC_AD0,       GPIO_FN_MEMC_AD1,       GPIO_FN_MEMC_AD2,
+       GPIO_FN_MEMC_AD3,       GPIO_FN_MEMC_AD4,       GPIO_FN_MEMC_AD5,
+       GPIO_FN_MEMC_AD6,       GPIO_FN_MEMC_AD7,       GPIO_FN_MEMC_AD8,
+       GPIO_FN_MEMC_AD9,       GPIO_FN_MEMC_AD10,      GPIO_FN_MEMC_AD11,
+       GPIO_FN_MEMC_AD12,      GPIO_FN_MEMC_AD13,      GPIO_FN_MEMC_AD14,
+       GPIO_FN_MEMC_AD15,      GPIO_FN_MEMC_CS0,       GPIO_FN_MEMC_INT,
+       GPIO_FN_MEMC_NWE,       GPIO_FN_MEMC_NOE,
+
+       GPIO_FN_MEMC_CS1, /* MSEL4CR_6_0 */
+       GPIO_FN_MEMC_ADV,
+       GPIO_FN_MEMC_WAIT,
+       GPIO_FN_MEMC_BUSCLK,
+
+       GPIO_FN_MEMC_A1, /* MSEL4CR_6_1 */
+       GPIO_FN_MEMC_DREQ0,
+       GPIO_FN_MEMC_DREQ1,
+       GPIO_FN_MEMC_A0,
+
+       /* MMC */
+       GPIO_FN_MMC0_D0_PORT68,         GPIO_FN_MMC0_D1_PORT69,
+       GPIO_FN_MMC0_D2_PORT70,         GPIO_FN_MMC0_D3_PORT71,
+       GPIO_FN_MMC0_D4_PORT72,         GPIO_FN_MMC0_D5_PORT73,
+       GPIO_FN_MMC0_D6_PORT74,         GPIO_FN_MMC0_D7_PORT75,
+       GPIO_FN_MMC0_CLK_PORT66,
+       GPIO_FN_MMC0_CMD_PORT67,        /* MSEL4CR_15_0 */
+
+       GPIO_FN_MMC1_D0_PORT149,        GPIO_FN_MMC1_D1_PORT148,
+       GPIO_FN_MMC1_D2_PORT147,        GPIO_FN_MMC1_D3_PORT146,
+       GPIO_FN_MMC1_D4_PORT145,        GPIO_FN_MMC1_D5_PORT144,
+       GPIO_FN_MMC1_D6_PORT143,        GPIO_FN_MMC1_D7_PORT142,
+       GPIO_FN_MMC1_CLK_PORT103,
+       GPIO_FN_MMC1_CMD_PORT104,       /* MSEL4CR_15_1 */
+
+       /* MSIOF0 */
+       GPIO_FN_MSIOF0_SS1,     GPIO_FN_MSIOF0_SS2,
+       GPIO_FN_MSIOF0_RXD,     GPIO_FN_MSIOF0_TXD,
+       GPIO_FN_MSIOF0_MCK0,    GPIO_FN_MSIOF0_MCK1,
+       GPIO_FN_MSIOF0_RSYNC,   GPIO_FN_MSIOF0_RSCK,
+       GPIO_FN_MSIOF0_TSCK,    GPIO_FN_MSIOF0_TSYNC,
+
+       /* MSIOF1 */
+       GPIO_FN_MSIOF1_RSCK,    GPIO_FN_MSIOF1_RSYNC,
+       GPIO_FN_MSIOF1_MCK0,    GPIO_FN_MSIOF1_MCK1,
+
+       GPIO_FN_MSIOF1_SS2_PORT116,     GPIO_FN_MSIOF1_SS1_PORT117,
+       GPIO_FN_MSIOF1_RXD_PORT118,     GPIO_FN_MSIOF1_TXD_PORT119,
+       GPIO_FN_MSIOF1_TSYNC_PORT120,
+       GPIO_FN_MSIOF1_TSCK_PORT121,    /* MSEL4CR_10_0 */
+
+       GPIO_FN_MSIOF1_SS1_PORT67,      GPIO_FN_MSIOF1_TSCK_PORT72,
+       GPIO_FN_MSIOF1_TSYNC_PORT73,    GPIO_FN_MSIOF1_TXD_PORT74,
+       GPIO_FN_MSIOF1_RXD_PORT75,
+       GPIO_FN_MSIOF1_SS2_PORT202,     /* MSEL4CR_10_1 */
+
+       /* GPIO */
+       GPIO_FN_GPO0,   GPIO_FN_GPI0,
+       GPIO_FN_GPO1,   GPIO_FN_GPI1,
+
+       /* USB0 */
+       GPIO_FN_USB0_OCI,       GPIO_FN_USB0_PPON,      GPIO_FN_VBUS,
+
+       /* USB1 */
+       GPIO_FN_USB1_OCI,       GPIO_FN_USB1_PPON,
+
+       /* BBIF1 */
+       GPIO_FN_BBIF1_RXD,      GPIO_FN_BBIF1_TXD,      GPIO_FN_BBIF1_TSYNC,
+       GPIO_FN_BBIF1_TSCK,     GPIO_FN_BBIF1_RSCK,     GPIO_FN_BBIF1_RSYNC,
+       GPIO_FN_BBIF1_FLOW,     GPIO_FN_BBIF1_RX_FLOW_N,
+
+       /* BBIF2 */
+       GPIO_FN_BBIF2_TXD2_PORT5, /* MSEL5CR_0_0 */
+       GPIO_FN_BBIF2_RXD2_PORT60,
+       GPIO_FN_BBIF2_TSYNC2_PORT6,
+       GPIO_FN_BBIF2_TSCK2_PORT59,
+
+       GPIO_FN_BBIF2_RXD2_PORT90, /* MSEL5CR_0_1 */
+       GPIO_FN_BBIF2_TXD2_PORT183,
+       GPIO_FN_BBIF2_TSCK2_PORT89,
+       GPIO_FN_BBIF2_TSYNC2_PORT184,
+
+       /* BSC / FLCTL / PCMCIA */
+       GPIO_FN_CS0,    GPIO_FN_CS2,    GPIO_FN_CS4,
+       GPIO_FN_CS5B,   GPIO_FN_CS6A,
+       GPIO_FN_CS5A_PORT105, /* CS5A PORT 19/105 */
+       GPIO_FN_CS5A_PORT19,
+       GPIO_FN_IOIS16, /* ? */
+
+       GPIO_FN_A0,     GPIO_FN_A1,     GPIO_FN_A2,     GPIO_FN_A3,
+       GPIO_FN_A4_FOE,         /* share with FLCTL */
+       GPIO_FN_A5_FCDE,        /* share with FLCTL */
+       GPIO_FN_A6,     GPIO_FN_A7,     GPIO_FN_A8,     GPIO_FN_A9,
+       GPIO_FN_A10,    GPIO_FN_A11,    GPIO_FN_A12,    GPIO_FN_A13,
+       GPIO_FN_A14,    GPIO_FN_A15,    GPIO_FN_A16,    GPIO_FN_A17,
+       GPIO_FN_A18,    GPIO_FN_A19,    GPIO_FN_A20,    GPIO_FN_A21,
+       GPIO_FN_A22,    GPIO_FN_A23,    GPIO_FN_A24,    GPIO_FN_A25,
+       GPIO_FN_A26,
+
+       GPIO_FN_D0_NAF0,        GPIO_FN_D1_NAF1,        /* share with FLCTL */
+       GPIO_FN_D2_NAF2,        GPIO_FN_D3_NAF3,        /* share with FLCTL */
+       GPIO_FN_D4_NAF4,        GPIO_FN_D5_NAF5,        /* share with FLCTL */
+       GPIO_FN_D6_NAF6,        GPIO_FN_D7_NAF7,        /* share with FLCTL */
+       GPIO_FN_D8_NAF8,        GPIO_FN_D9_NAF9,        /* share with FLCTL */
+       GPIO_FN_D10_NAF10,      GPIO_FN_D11_NAF11,      /* share with FLCTL */
+       GPIO_FN_D12_NAF12,      GPIO_FN_D13_NAF13,      /* share with FLCTL */
+       GPIO_FN_D14_NAF14,      GPIO_FN_D15_NAF15,      /* share with FLCTL */
+
+       GPIO_FN_D16,    GPIO_FN_D17,    GPIO_FN_D18,    GPIO_FN_D19,
+       GPIO_FN_D20,    GPIO_FN_D21,    GPIO_FN_D22,    GPIO_FN_D23,
+       GPIO_FN_D24,    GPIO_FN_D25,    GPIO_FN_D26,    GPIO_FN_D27,
+       GPIO_FN_D28,    GPIO_FN_D29,    GPIO_FN_D30,    GPIO_FN_D31,
+
+       GPIO_FN_WE0_FWE,        /* share with FLCTL */
+       GPIO_FN_WE1,
+       GPIO_FN_WE2_ICIORD,     /* share with PCMCIA */
+       GPIO_FN_WE3_ICIOWR,     /* share with PCMCIA */
+       GPIO_FN_CKO,    GPIO_FN_BS,     GPIO_FN_RDWR,
+       GPIO_FN_RD_FSC,         /* share with FLCTL */
+       GPIO_FN_WAIT_PORT177,   /* WAIT Port 90/177 */
+       GPIO_FN_WAIT_PORT90,
+
+       GPIO_FN_FCE0,   GPIO_FN_FCE1,   GPIO_FN_FRB, /* FLCTL */
+
+       /* IRDA */
+       GPIO_FN_IRDA_FIRSEL,    GPIO_FN_IRDA_IN,        GPIO_FN_IRDA_OUT,
+
+       /* ATAPI */
+       GPIO_FN_IDE_D0,         GPIO_FN_IDE_D1,         GPIO_FN_IDE_D2,
+       GPIO_FN_IDE_D3,         GPIO_FN_IDE_D4,         GPIO_FN_IDE_D5,
+       GPIO_FN_IDE_D6,         GPIO_FN_IDE_D7,         GPIO_FN_IDE_D8,
+       GPIO_FN_IDE_D9,         GPIO_FN_IDE_D10,        GPIO_FN_IDE_D11,
+       GPIO_FN_IDE_D12,        GPIO_FN_IDE_D13,        GPIO_FN_IDE_D14,
+       GPIO_FN_IDE_D15,        GPIO_FN_IDE_A0,         GPIO_FN_IDE_A1,
+       GPIO_FN_IDE_A2,         GPIO_FN_IDE_CS0,        GPIO_FN_IDE_CS1,
+       GPIO_FN_IDE_IOWR,       GPIO_FN_IDE_IORD,       GPIO_FN_IDE_IORDY,
+       GPIO_FN_IDE_INT,        GPIO_FN_IDE_RST,        GPIO_FN_IDE_DIRECTION,
+       GPIO_FN_IDE_EXBUF_ENB,  GPIO_FN_IDE_IODACK,     GPIO_FN_IDE_IODREQ,
+
+       /* RMII */
+       GPIO_FN_RMII_CRS_DV,    GPIO_FN_RMII_RX_ER,     GPIO_FN_RMII_RXD0,
+       GPIO_FN_RMII_RXD1,      GPIO_FN_RMII_TX_EN,     GPIO_FN_RMII_TXD0,
+       GPIO_FN_RMII_MDC,       GPIO_FN_RMII_TXD1,      GPIO_FN_RMII_MDIO,
+       GPIO_FN_RMII_REF50CK,   /* for RMII */
+       GPIO_FN_RMII_REF125CK,  /* for GMII */
+
+       /* GEther */
+       GPIO_FN_ET_TX_CLK,      GPIO_FN_ET_TX_EN,       GPIO_FN_ET_ETXD0,
+       GPIO_FN_ET_ETXD1,       GPIO_FN_ET_ETXD2,       GPIO_FN_ET_ETXD3,
+       GPIO_FN_ET_ETXD4,       GPIO_FN_ET_ETXD5, /* for GEther */
+       GPIO_FN_ET_ETXD6,       GPIO_FN_ET_ETXD7, /* for GEther */
+       GPIO_FN_ET_COL,         GPIO_FN_ET_TX_ER,
+       GPIO_FN_ET_RX_CLK,      GPIO_FN_ET_RX_DV,
+       GPIO_FN_ET_ERXD0,       GPIO_FN_ET_ERXD1,
+       GPIO_FN_ET_ERXD2,       GPIO_FN_ET_ERXD3,
+       GPIO_FN_ET_ERXD4,       GPIO_FN_ET_ERXD5, /* for GEther */
+       GPIO_FN_ET_ERXD6,       GPIO_FN_ET_ERXD7, /* for GEther */
+       GPIO_FN_ET_RX_ER,       GPIO_FN_ET_CRS,
+       GPIO_FN_ET_MDC,         GPIO_FN_ET_MDIO,
+       GPIO_FN_ET_LINK,        GPIO_FN_ET_PHY_INT,
+       GPIO_FN_ET_WOL,         GPIO_FN_ET_GTX_CLK,
+
+       /* DMA0 */
+       GPIO_FN_DREQ0,          GPIO_FN_DACK0,
+
+       /* DMA1 */
+       GPIO_FN_DREQ1,          GPIO_FN_DACK1,
+
+       /* SYSC */
+       GPIO_FN_RESETOUTS,
+       GPIO_FN_RESETP_PULLUP,
+       GPIO_FN_RESETP_PLAIN,
+
+       /* SDENC */
+       GPIO_FN_SDENC_CPG,
+       GPIO_FN_SDENC_DV_CLKI,
+
+       /* IRREM */
+       GPIO_FN_IROUT,
+
+       /* DEBUG */
+       GPIO_FN_EDEBGREQ_PULLDOWN,
+       GPIO_FN_EDEBGREQ_PULLUP,
+
+       GPIO_FN_TRACEAUD_FROM_VIO,
+       GPIO_FN_TRACEAUD_FROM_LCDC0,
+       GPIO_FN_TRACEAUD_FROM_MEMC,
+};
+
+#endif /* __ASM_R8A7740_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h
new file mode 100644 (file)
index 0000000..b07ad31
--- /dev/null
@@ -0,0 +1,363 @@
+#ifndef __ASM_R8A7779_H__
+#define __ASM_R8A7779_H__
+
+#include <linux/sh_clk.h>
+#include <linux/pm_domain.h>
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+       GPIO_GP_0_0, GPIO_GP_0_1, GPIO_GP_0_2, GPIO_GP_0_3,
+       GPIO_GP_0_4, GPIO_GP_0_5, GPIO_GP_0_6, GPIO_GP_0_7,
+       GPIO_GP_0_8, GPIO_GP_0_9, GPIO_GP_0_10, GPIO_GP_0_11,
+       GPIO_GP_0_12, GPIO_GP_0_13, GPIO_GP_0_14, GPIO_GP_0_15,
+       GPIO_GP_0_16, GPIO_GP_0_17, GPIO_GP_0_18, GPIO_GP_0_19,
+       GPIO_GP_0_20, GPIO_GP_0_21, GPIO_GP_0_22, GPIO_GP_0_23,
+       GPIO_GP_0_24, GPIO_GP_0_25, GPIO_GP_0_26, GPIO_GP_0_27,
+       GPIO_GP_0_28, GPIO_GP_0_29, GPIO_GP_0_30, GPIO_GP_0_31,
+
+       GPIO_GP_1_0, GPIO_GP_1_1, GPIO_GP_1_2, GPIO_GP_1_3,
+       GPIO_GP_1_4, GPIO_GP_1_5, GPIO_GP_1_6, GPIO_GP_1_7,
+       GPIO_GP_1_8, GPIO_GP_1_9, GPIO_GP_1_10, GPIO_GP_1_11,
+       GPIO_GP_1_12, GPIO_GP_1_13, GPIO_GP_1_14, GPIO_GP_1_15,
+       GPIO_GP_1_16, GPIO_GP_1_17, GPIO_GP_1_18, GPIO_GP_1_19,
+       GPIO_GP_1_20, GPIO_GP_1_21, GPIO_GP_1_22, GPIO_GP_1_23,
+       GPIO_GP_1_24, GPIO_GP_1_25, GPIO_GP_1_26, GPIO_GP_1_27,
+       GPIO_GP_1_28, GPIO_GP_1_29, GPIO_GP_1_30, GPIO_GP_1_31,
+
+       GPIO_GP_2_0, GPIO_GP_2_1, GPIO_GP_2_2, GPIO_GP_2_3,
+       GPIO_GP_2_4, GPIO_GP_2_5, GPIO_GP_2_6, GPIO_GP_2_7,
+       GPIO_GP_2_8, GPIO_GP_2_9, GPIO_GP_2_10, GPIO_GP_2_11,
+       GPIO_GP_2_12, GPIO_GP_2_13, GPIO_GP_2_14, GPIO_GP_2_15,
+       GPIO_GP_2_16, GPIO_GP_2_17, GPIO_GP_2_18, GPIO_GP_2_19,
+       GPIO_GP_2_20, GPIO_GP_2_21, GPIO_GP_2_22, GPIO_GP_2_23,
+       GPIO_GP_2_24, GPIO_GP_2_25, GPIO_GP_2_26, GPIO_GP_2_27,
+       GPIO_GP_2_28, GPIO_GP_2_29, GPIO_GP_2_30, GPIO_GP_2_31,
+
+       GPIO_GP_3_0, GPIO_GP_3_1, GPIO_GP_3_2, GPIO_GP_3_3,
+       GPIO_GP_3_4, GPIO_GP_3_5, GPIO_GP_3_6, GPIO_GP_3_7,
+       GPIO_GP_3_8, GPIO_GP_3_9, GPIO_GP_3_10, GPIO_GP_3_11,
+       GPIO_GP_3_12, GPIO_GP_3_13, GPIO_GP_3_14, GPIO_GP_3_15,
+       GPIO_GP_3_16, GPIO_GP_3_17, GPIO_GP_3_18, GPIO_GP_3_19,
+       GPIO_GP_3_20, GPIO_GP_3_21, GPIO_GP_3_22, GPIO_GP_3_23,
+       GPIO_GP_3_24, GPIO_GP_3_25, GPIO_GP_3_26, GPIO_GP_3_27,
+       GPIO_GP_3_28, GPIO_GP_3_29, GPIO_GP_3_30, GPIO_GP_3_31,
+
+       GPIO_GP_4_0, GPIO_GP_4_1, GPIO_GP_4_2, GPIO_GP_4_3,
+       GPIO_GP_4_4, GPIO_GP_4_5, GPIO_GP_4_6, GPIO_GP_4_7,
+       GPIO_GP_4_8, GPIO_GP_4_9, GPIO_GP_4_10, GPIO_GP_4_11,
+       GPIO_GP_4_12, GPIO_GP_4_13, GPIO_GP_4_14, GPIO_GP_4_15,
+       GPIO_GP_4_16, GPIO_GP_4_17, GPIO_GP_4_18, GPIO_GP_4_19,
+       GPIO_GP_4_20, GPIO_GP_4_21, GPIO_GP_4_22, GPIO_GP_4_23,
+       GPIO_GP_4_24, GPIO_GP_4_25, GPIO_GP_4_26, GPIO_GP_4_27,
+       GPIO_GP_4_28, GPIO_GP_4_29, GPIO_GP_4_30, GPIO_GP_4_31,
+
+       GPIO_GP_5_0, GPIO_GP_5_1, GPIO_GP_5_2, GPIO_GP_5_3,
+       GPIO_GP_5_4, GPIO_GP_5_5, GPIO_GP_5_6, GPIO_GP_5_7,
+       GPIO_GP_5_8, GPIO_GP_5_9, GPIO_GP_5_10, GPIO_GP_5_11,
+       GPIO_GP_5_12, GPIO_GP_5_13, GPIO_GP_5_14, GPIO_GP_5_15,
+       GPIO_GP_5_16, GPIO_GP_5_17, GPIO_GP_5_18, GPIO_GP_5_19,
+       GPIO_GP_5_20, GPIO_GP_5_21, GPIO_GP_5_22, GPIO_GP_5_23,
+       GPIO_GP_5_24, GPIO_GP_5_25, GPIO_GP_5_26, GPIO_GP_5_27,
+       GPIO_GP_5_28, GPIO_GP_5_29, GPIO_GP_5_30, GPIO_GP_5_31,
+
+       GPIO_GP_6_0, GPIO_GP_6_1, GPIO_GP_6_2, GPIO_GP_6_3,
+       GPIO_GP_6_4, GPIO_GP_6_5, GPIO_GP_6_6, GPIO_GP_6_7,
+       GPIO_GP_6_8,
+
+       GPIO_FN_AVS1, GPIO_FN_AVS2, GPIO_FN_A17, GPIO_FN_A18,
+       GPIO_FN_A19,
+
+       /* IPSR0 */
+       GPIO_FN_PENC2, GPIO_FN_SCK0, GPIO_FN_PWM1, GPIO_FN_PWMFSW0,
+       GPIO_FN_SCIF_CLK, GPIO_FN_TCLK0_C, GPIO_FN_BS, GPIO_FN_SD1_DAT2,
+       GPIO_FN_MMC0_D2, GPIO_FN_FD2, GPIO_FN_ATADIR0, GPIO_FN_SDSELF,
+       GPIO_FN_HCTS1, GPIO_FN_TX4_C, GPIO_FN_A0, GPIO_FN_SD1_DAT3,
+       GPIO_FN_MMC0_D3, GPIO_FN_FD3, GPIO_FN_A20, GPIO_FN_TX5_D,
+       GPIO_FN_HSPI_TX2_B, GPIO_FN_A21, GPIO_FN_SCK5_D, GPIO_FN_HSPI_CLK2_B,
+       GPIO_FN_A22, GPIO_FN_RX5_D, GPIO_FN_HSPI_RX2_B, GPIO_FN_VI1_R0,
+       GPIO_FN_A23, GPIO_FN_FCLE, GPIO_FN_HSPI_CLK2, GPIO_FN_VI1_R1,
+       GPIO_FN_A24, GPIO_FN_SD1_CD, GPIO_FN_MMC0_D4, GPIO_FN_FD4,
+       GPIO_FN_HSPI_CS2, GPIO_FN_VI1_R2, GPIO_FN_SSI_WS78_B, GPIO_FN_A25,
+       GPIO_FN_SD1_WP, GPIO_FN_MMC0_D5, GPIO_FN_FD5, GPIO_FN_HSPI_RX2,
+       GPIO_FN_VI1_R3, GPIO_FN_TX5_B, GPIO_FN_SSI_SDATA7_B, GPIO_FN_CTS0_B,
+       GPIO_FN_CLKOUT, GPIO_FN_TX3C_IRDA_TX_C, GPIO_FN_PWM0_B, GPIO_FN_CS0,
+       GPIO_FN_HSPI_CS2_B, GPIO_FN_CS1_A26, GPIO_FN_HSPI_TX2,
+       GPIO_FN_SDSELF_B, GPIO_FN_RD_WR, GPIO_FN_FWE, GPIO_FN_ATAG0,
+       GPIO_FN_VI1_R7, GPIO_FN_HRTS1, GPIO_FN_RX4_C,
+
+       /* IPSR1 */
+       GPIO_FN_EX_CS0, GPIO_FN_RX3_C_IRDA_RX_C, GPIO_FN_MMC0_D6,
+       GPIO_FN_FD6, GPIO_FN_EX_CS1, GPIO_FN_MMC0_D7, GPIO_FN_FD7,
+       GPIO_FN_EX_CS2, GPIO_FN_SD1_CLK, GPIO_FN_MMC0_CLK, GPIO_FN_FALE,
+       GPIO_FN_ATACS00, GPIO_FN_EX_CS3, GPIO_FN_SD1_CMD, GPIO_FN_MMC0_CMD,
+       GPIO_FN_FRE, GPIO_FN_ATACS10, GPIO_FN_VI1_R4, GPIO_FN_RX5_B,
+       GPIO_FN_HSCK1, GPIO_FN_SSI_SDATA8_B, GPIO_FN_RTS0_B_TANS_B,
+       GPIO_FN_SSI_SDATA9, GPIO_FN_EX_CS4, GPIO_FN_SD1_DAT0, GPIO_FN_MMC0_D0,
+       GPIO_FN_FD0, GPIO_FN_ATARD0, GPIO_FN_VI1_R5, GPIO_FN_SCK5_B,
+       GPIO_FN_HTX1, GPIO_FN_TX2_E, GPIO_FN_TX0_B, GPIO_FN_SSI_SCK9,
+       GPIO_FN_EX_CS5, GPIO_FN_SD1_DAT1, GPIO_FN_MMC0_D1, GPIO_FN_FD1,
+       GPIO_FN_ATAWR0, GPIO_FN_VI1_R6, GPIO_FN_HRX1, GPIO_FN_RX2_E,
+       GPIO_FN_RX0_B, GPIO_FN_SSI_WS9, GPIO_FN_MLB_CLK, GPIO_FN_PWM2,
+       GPIO_FN_SCK4, GPIO_FN_MLB_SIG, GPIO_FN_PWM3, GPIO_FN_TX4,
+       GPIO_FN_MLB_DAT, GPIO_FN_PWM4, GPIO_FN_RX4, GPIO_FN_HTX0,
+       GPIO_FN_TX1, GPIO_FN_SDATA, GPIO_FN_CTS0_C, GPIO_FN_SUB_TCK,
+       GPIO_FN_CC5_STATE2, GPIO_FN_CC5_STATE10, GPIO_FN_CC5_STATE18,
+       GPIO_FN_CC5_STATE26, GPIO_FN_CC5_STATE34,
+
+       /* IPSR2 */
+       GPIO_FN_HRX0, GPIO_FN_RX1, GPIO_FN_SCKZ, GPIO_FN_RTS0_C_TANS_C,
+       GPIO_FN_SUB_TDI, GPIO_FN_CC5_STATE3, GPIO_FN_CC5_STATE11,
+       GPIO_FN_CC5_STATE19, GPIO_FN_CC5_STATE27, GPIO_FN_CC5_STATE35,
+       GPIO_FN_HSCK0, GPIO_FN_SCK1, GPIO_FN_MTS, GPIO_FN_PWM5,
+       GPIO_FN_SCK0_C, GPIO_FN_SSI_SDATA9_B, GPIO_FN_SUB_TDO,
+       GPIO_FN_CC5_STATE0, GPIO_FN_CC5_STATE8, GPIO_FN_CC5_STATE16,
+       GPIO_FN_CC5_STATE24, GPIO_FN_CC5_STATE32, GPIO_FN_HCTS0, GPIO_FN_CTS1,
+       GPIO_FN_STM, GPIO_FN_PWM0_D, GPIO_FN_RX0_C, GPIO_FN_SCIF_CLK_C,
+       GPIO_FN_SUB_TRST, GPIO_FN_TCLK1_B, GPIO_FN_CC5_OSCOUT, GPIO_FN_HRTS0,
+       GPIO_FN_RTS1_TANS, GPIO_FN_MDATA, GPIO_FN_TX0_C, GPIO_FN_SUB_TMS,
+       GPIO_FN_CC5_STATE1, GPIO_FN_CC5_STATE9, GPIO_FN_CC5_STATE17,
+       GPIO_FN_CC5_STATE25, GPIO_FN_CC5_STATE33, GPIO_FN_DU0_DR0,
+       GPIO_FN_LCDOUT0, GPIO_FN_DREQ0, GPIO_FN_GPS_CLK_B, GPIO_FN_AUDATA0,
+       GPIO_FN_TX5_C, GPIO_FN_DU0_DR1, GPIO_FN_LCDOUT1, GPIO_FN_DACK0,
+       GPIO_FN_DRACK0, GPIO_FN_GPS_SIGN_B, GPIO_FN_AUDATA1, GPIO_FN_RX5_C,
+       GPIO_FN_DU0_DR2, GPIO_FN_LCDOUT2, GPIO_FN_DU0_DR3, GPIO_FN_LCDOUT3,
+       GPIO_FN_DU0_DR4, GPIO_FN_LCDOUT4, GPIO_FN_DU0_DR5, GPIO_FN_LCDOUT5,
+       GPIO_FN_DU0_DR6, GPIO_FN_LCDOUT6, GPIO_FN_DU0_DR7, GPIO_FN_LCDOUT7,
+       GPIO_FN_DU0_DG0, GPIO_FN_LCDOUT8, GPIO_FN_DREQ1, GPIO_FN_SCL2,
+       GPIO_FN_AUDATA2,
+
+       /* IPSR3 */
+       GPIO_FN_DU0_DG1, GPIO_FN_LCDOUT9, GPIO_FN_DACK1, GPIO_FN_SDA2,
+       GPIO_FN_AUDATA3, GPIO_FN_DU0_DG2, GPIO_FN_LCDOUT10, GPIO_FN_DU0_DG3,
+       GPIO_FN_LCDOUT11, GPIO_FN_DU0_DG4, GPIO_FN_LCDOUT12, GPIO_FN_DU0_DG5,
+       GPIO_FN_LCDOUT13, GPIO_FN_DU0_DG6, GPIO_FN_LCDOUT14, GPIO_FN_DU0_DG7,
+       GPIO_FN_LCDOUT15, GPIO_FN_DU0_DB0, GPIO_FN_LCDOUT16, GPIO_FN_EX_WAIT1,
+       GPIO_FN_SCL1, GPIO_FN_TCLK1, GPIO_FN_AUDATA4, GPIO_FN_DU0_DB1,
+       GPIO_FN_LCDOUT17, GPIO_FN_EX_WAIT2, GPIO_FN_SDA1, GPIO_FN_GPS_MAG_B,
+       GPIO_FN_AUDATA5, GPIO_FN_SCK5_C, GPIO_FN_DU0_DB2, GPIO_FN_LCDOUT18,
+       GPIO_FN_DU0_DB3, GPIO_FN_LCDOUT19, GPIO_FN_DU0_DB4, GPIO_FN_LCDOUT20,
+       GPIO_FN_DU0_DB5, GPIO_FN_LCDOUT21, GPIO_FN_DU0_DB6, GPIO_FN_LCDOUT22,
+       GPIO_FN_DU0_DB7, GPIO_FN_LCDOUT23, GPIO_FN_DU0_DOTCLKIN,
+       GPIO_FN_QSTVA_QVS, GPIO_FN_TX3_D_IRDA_TX_D, GPIO_FN_SCL3_B,
+       GPIO_FN_DU0_DOTCLKOUT0, GPIO_FN_QCLK, GPIO_FN_DU0_DOTCLKOUT1,
+       GPIO_FN_QSTVB_QVE, GPIO_FN_RX3_D_IRDA_RX_D, GPIO_FN_SDA3_B,
+       GPIO_FN_SDA2_C, GPIO_FN_DACK0_B, GPIO_FN_DRACK0_B,
+       GPIO_FN_DU0_EXHSYNC_DU0_HSYNC, GPIO_FN_QSTH_QHS,
+       GPIO_FN_DU0_EXVSYNC_DU0_VSYNC, GPIO_FN_QSTB_QHE,
+       GPIO_FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, GPIO_FN_QCPV_QDE,
+       GPIO_FN_CAN1_TX, GPIO_FN_TX2_C, GPIO_FN_SCL2_C, GPIO_FN_REMOCON,
+
+       /* IPSR4 */
+       GPIO_FN_DU0_DISP, GPIO_FN_QPOLA, GPIO_FN_CAN_CLK_C, GPIO_FN_SCK2_C,
+       GPIO_FN_DU0_CDE, GPIO_FN_QPOLB, GPIO_FN_CAN1_RX, GPIO_FN_RX2_C,
+       GPIO_FN_DREQ0_B, GPIO_FN_SSI_SCK78_B, GPIO_FN_SCK0_B, GPIO_FN_DU1_DR0,
+       GPIO_FN_VI2_DATA0_VI2_B0, GPIO_FN_PWM6, GPIO_FN_SD3_CLK,
+       GPIO_FN_TX3_E_IRDA_TX_E, GPIO_FN_AUDCK, GPIO_FN_PWMFSW0_B,
+       GPIO_FN_DU1_DR1, GPIO_FN_VI2_DATA1_VI2_B1, GPIO_FN_PWM0,
+       GPIO_FN_SD3_CMD, GPIO_FN_RX3_E_IRDA_RX_E, GPIO_FN_AUDSYNC,
+       GPIO_FN_CTS0_D, GPIO_FN_DU1_DR2, GPIO_FN_VI2_G0, GPIO_FN_DU1_DR3,
+       GPIO_FN_VI2_G1, GPIO_FN_DU1_DR4, GPIO_FN_VI2_G2, GPIO_FN_DU1_DR5,
+       GPIO_FN_VI2_G3, GPIO_FN_DU1_DR6, GPIO_FN_VI2_G4, GPIO_FN_DU1_DR7,
+       GPIO_FN_VI2_G5, GPIO_FN_DU1_DG0, GPIO_FN_VI2_DATA2_VI2_B2,
+       GPIO_FN_SCL1_B, GPIO_FN_SD3_DAT2, GPIO_FN_SCK3_E, GPIO_FN_AUDATA6,
+       GPIO_FN_TX0_D, GPIO_FN_DU1_DG1, GPIO_FN_VI2_DATA3_VI2_B3,
+       GPIO_FN_SDA1_B, GPIO_FN_SD3_DAT3, GPIO_FN_SCK5, GPIO_FN_AUDATA7,
+       GPIO_FN_RX0_D, GPIO_FN_DU1_DG2, GPIO_FN_VI2_G6, GPIO_FN_DU1_DG3,
+       GPIO_FN_VI2_G7, GPIO_FN_DU1_DG4, GPIO_FN_VI2_R0, GPIO_FN_DU1_DG5,
+       GPIO_FN_VI2_R1, GPIO_FN_DU1_DG6, GPIO_FN_VI2_R2, GPIO_FN_DU1_DG7,
+       GPIO_FN_VI2_R3, GPIO_FN_DU1_DB0, GPIO_FN_VI2_DATA4_VI2_B4,
+       GPIO_FN_SCL2_B, GPIO_FN_SD3_DAT0, GPIO_FN_TX5, GPIO_FN_SCK0_D,
+
+       /* IPSR5 */
+       GPIO_FN_DU1_DB1, GPIO_FN_VI2_DATA5_VI2_B5, GPIO_FN_SDA2_B,
+       GPIO_FN_SD3_DAT1, GPIO_FN_RX5, GPIO_FN_RTS0_D_TANS_D,
+       GPIO_FN_DU1_DB2, GPIO_FN_VI2_R4, GPIO_FN_DU1_DB3, GPIO_FN_VI2_R5,
+       GPIO_FN_DU1_DB4, GPIO_FN_VI2_R6, GPIO_FN_DU1_DB5, GPIO_FN_VI2_R7,
+       GPIO_FN_DU1_DB6, GPIO_FN_SCL2_D, GPIO_FN_DU1_DB7, GPIO_FN_SDA2_D,
+       GPIO_FN_DU1_DOTCLKIN, GPIO_FN_VI2_CLKENB, GPIO_FN_HSPI_CS1,
+       GPIO_FN_SCL1_D, GPIO_FN_DU1_DOTCLKOUT, GPIO_FN_VI2_FIELD,
+       GPIO_FN_SDA1_D, GPIO_FN_DU1_EXHSYNC_DU1_HSYNC, GPIO_FN_VI2_HSYNC,
+       GPIO_FN_VI3_HSYNC, GPIO_FN_DU1_EXVSYNC_DU1_VSYNC, GPIO_FN_VI2_VSYNC,
+       GPIO_FN_VI3_VSYNC, GPIO_FN_DU1_EXODDF_DU1_ODDF_DISP_CDE,
+       GPIO_FN_VI2_CLK, GPIO_FN_TX3_B_IRDA_TX_B, GPIO_FN_SD3_CD,
+       GPIO_FN_HSPI_TX1, GPIO_FN_VI1_CLKENB, GPIO_FN_VI3_CLKENB,
+       GPIO_FN_AUDIO_CLKC, GPIO_FN_TX2_D, GPIO_FN_SPEEDIN,
+       GPIO_FN_GPS_SIGN_D, GPIO_FN_DU1_DISP, GPIO_FN_VI2_DATA6_VI2_B6,
+       GPIO_FN_TCLK0, GPIO_FN_QSTVA_B_QVS_B, GPIO_FN_HSPI_CLK1,
+       GPIO_FN_SCK2_D, GPIO_FN_AUDIO_CLKOUT_B, GPIO_FN_GPS_MAG_D,
+       GPIO_FN_DU1_CDE, GPIO_FN_VI2_DATA7_VI2_B7, GPIO_FN_RX3_B_IRDA_RX_B,
+       GPIO_FN_SD3_WP, GPIO_FN_HSPI_RX1, GPIO_FN_VI1_FIELD, GPIO_FN_VI3_FIELD,
+       GPIO_FN_AUDIO_CLKOUT, GPIO_FN_RX2_D, GPIO_FN_GPS_CLK_C,
+       GPIO_FN_GPS_CLK_D, GPIO_FN_AUDIO_CLKA, GPIO_FN_CAN_TXCLK,
+       GPIO_FN_AUDIO_CLKB, GPIO_FN_USB_OVC2, GPIO_FN_CAN_DEBUGOUT0,
+       GPIO_FN_MOUT0,
+
+       /* IPSR6 */
+       GPIO_FN_SSI_SCK0129, GPIO_FN_CAN_DEBUGOUT1, GPIO_FN_MOUT1,
+       GPIO_FN_SSI_WS0129, GPIO_FN_CAN_DEBUGOUT2, GPIO_FN_MOUT2,
+       GPIO_FN_SSI_SDATA0, GPIO_FN_CAN_DEBUGOUT3, GPIO_FN_MOUT5,
+       GPIO_FN_SSI_SDATA1, GPIO_FN_CAN_DEBUGOUT4, GPIO_FN_MOUT6,
+       GPIO_FN_SSI_SDATA2, GPIO_FN_CAN_DEBUGOUT5, GPIO_FN_SSI_SCK34,
+       GPIO_FN_CAN_DEBUGOUT6, GPIO_FN_CAN0_TX_B, GPIO_FN_IERX,
+       GPIO_FN_SSI_SCK9_C, GPIO_FN_SSI_WS34, GPIO_FN_CAN_DEBUGOUT7,
+       GPIO_FN_CAN0_RX_B, GPIO_FN_IETX, GPIO_FN_SSI_WS9_C,
+       GPIO_FN_SSI_SDATA3, GPIO_FN_PWM0_C, GPIO_FN_CAN_DEBUGOUT8,
+       GPIO_FN_CAN_CLK_B, GPIO_FN_IECLK, GPIO_FN_SCIF_CLK_B, GPIO_FN_TCLK0_B,
+       GPIO_FN_SSI_SDATA4, GPIO_FN_CAN_DEBUGOUT9, GPIO_FN_SSI_SDATA9_C,
+       GPIO_FN_SSI_SCK5, GPIO_FN_ADICLK, GPIO_FN_CAN_DEBUGOUT10,
+       GPIO_FN_SCK3, GPIO_FN_TCLK0_D, GPIO_FN_SSI_WS5, GPIO_FN_ADICS_SAMP,
+       GPIO_FN_CAN_DEBUGOUT11, GPIO_FN_TX3_IRDA_TX, GPIO_FN_SSI_SDATA5,
+       GPIO_FN_ADIDATA, GPIO_FN_CAN_DEBUGOUT12, GPIO_FN_RX3_IRDA_RX,
+       GPIO_FN_SSI_SCK6, GPIO_FN_ADICHS0, GPIO_FN_CAN0_TX, GPIO_FN_IERX_B,
+
+       /* IPSR7 */
+       GPIO_FN_SSI_WS6, GPIO_FN_ADICHS1, GPIO_FN_CAN0_RX, GPIO_FN_IETX_B,
+       GPIO_FN_SSI_SDATA6, GPIO_FN_ADICHS2, GPIO_FN_CAN_CLK, GPIO_FN_IECLK_B,
+       GPIO_FN_SSI_SCK78, GPIO_FN_CAN_DEBUGOUT13, GPIO_FN_IRQ0_B,
+       GPIO_FN_SSI_SCK9_B, GPIO_FN_HSPI_CLK1_C, GPIO_FN_SSI_WS78,
+       GPIO_FN_CAN_DEBUGOUT14, GPIO_FN_IRQ1_B, GPIO_FN_SSI_WS9_B,
+       GPIO_FN_HSPI_CS1_C, GPIO_FN_SSI_SDATA7, GPIO_FN_CAN_DEBUGOUT15,
+       GPIO_FN_IRQ2_B, GPIO_FN_TCLK1_C, GPIO_FN_HSPI_TX1_C,
+       GPIO_FN_SSI_SDATA8, GPIO_FN_VSP, GPIO_FN_IRQ3_B, GPIO_FN_HSPI_RX1_C,
+       GPIO_FN_SD0_CLK, GPIO_FN_ATACS01, GPIO_FN_SCK1_B, GPIO_FN_SD0_CMD,
+       GPIO_FN_ATACS11, GPIO_FN_TX1_B, GPIO_FN_CC5_TDO, GPIO_FN_SD0_DAT0,
+       GPIO_FN_ATADIR1, GPIO_FN_RX1_B, GPIO_FN_CC5_TRST, GPIO_FN_SD0_DAT1,
+       GPIO_FN_ATAG1, GPIO_FN_SCK2_B, GPIO_FN_CC5_TMS, GPIO_FN_SD0_DAT2,
+       GPIO_FN_ATARD1, GPIO_FN_TX2_B, GPIO_FN_CC5_TCK, GPIO_FN_SD0_DAT3,
+       GPIO_FN_ATAWR1, GPIO_FN_RX2_B, GPIO_FN_CC5_TDI, GPIO_FN_SD0_CD,
+       GPIO_FN_DREQ2,  GPIO_FN_RTS1_B_TANS_B, GPIO_FN_SD0_WP, GPIO_FN_DACK2,
+       GPIO_FN_CTS1_B,
+
+       /* IPSR8 */
+       GPIO_FN_HSPI_CLK0, GPIO_FN_CTS0, GPIO_FN_USB_OVC0, GPIO_FN_AD_CLK,
+       GPIO_FN_CC5_STATE4, GPIO_FN_CC5_STATE12, GPIO_FN_CC5_STATE20,
+       GPIO_FN_CC5_STATE28, GPIO_FN_CC5_STATE36, GPIO_FN_HSPI_CS0,
+       GPIO_FN_RTS0_TANS, GPIO_FN_USB_OVC1, GPIO_FN_AD_DI,
+       GPIO_FN_CC5_STATE5, GPIO_FN_CC5_STATE13, GPIO_FN_CC5_STATE21,
+       GPIO_FN_CC5_STATE29, GPIO_FN_CC5_STATE37, GPIO_FN_HSPI_TX0,
+       GPIO_FN_TX0, GPIO_FN_CAN_DEBUG_HW_TRIGGER, GPIO_FN_AD_DO,
+       GPIO_FN_CC5_STATE6, GPIO_FN_CC5_STATE14, GPIO_FN_CC5_STATE22,
+       GPIO_FN_CC5_STATE30, GPIO_FN_CC5_STATE38, GPIO_FN_HSPI_RX0,
+       GPIO_FN_RX0, GPIO_FN_CAN_STEP0, GPIO_FN_AD_NCS, GPIO_FN_CC5_STATE7,
+       GPIO_FN_CC5_STATE15, GPIO_FN_CC5_STATE23, GPIO_FN_CC5_STATE31,
+       GPIO_FN_CC5_STATE39, GPIO_FN_FMCLK, GPIO_FN_RDS_CLK, GPIO_FN_PCMOE,
+       GPIO_FN_BPFCLK, GPIO_FN_PCMWE, GPIO_FN_FMIN, GPIO_FN_RDS_DATA,
+       GPIO_FN_VI0_CLK, GPIO_FN_MMC1_CLK, GPIO_FN_VI0_CLKENB, GPIO_FN_TX1_C,
+       GPIO_FN_HTX1_B, GPIO_FN_MT1_SYNC, GPIO_FN_VI0_FIELD, GPIO_FN_RX1_C,
+       GPIO_FN_HRX1_B, GPIO_FN_VI0_HSYNC, GPIO_FN_VI0_DATA0_B_VI0_B0_B,
+       GPIO_FN_CTS1_C, GPIO_FN_TX4_D, GPIO_FN_MMC1_CMD, GPIO_FN_HSCK1_B,
+       GPIO_FN_VI0_VSYNC, GPIO_FN_VI0_DATA1_B_VI0_B1_B,
+       GPIO_FN_RTS1_C_TANS_C, GPIO_FN_RX4_D, GPIO_FN_PWMFSW0_C,
+
+       /* IPSR9 */
+       GPIO_FN_VI0_DATA0_VI0_B0, GPIO_FN_HRTS1_B, GPIO_FN_MT1_VCXO,
+       GPIO_FN_VI0_DATA1_VI0_B1, GPIO_FN_HCTS1_B, GPIO_FN_MT1_PWM,
+       GPIO_FN_VI0_DATA2_VI0_B2, GPIO_FN_MMC1_D0, GPIO_FN_VI0_DATA3_VI0_B3,
+       GPIO_FN_MMC1_D1, GPIO_FN_VI0_DATA4_VI0_B4, GPIO_FN_MMC1_D2,
+       GPIO_FN_VI0_DATA5_VI0_B5, GPIO_FN_MMC1_D3, GPIO_FN_VI0_DATA6_VI0_B6,
+       GPIO_FN_MMC1_D4, GPIO_FN_ARM_TRACEDATA_0, GPIO_FN_VI0_DATA7_VI0_B7,
+       GPIO_FN_MMC1_D5, GPIO_FN_ARM_TRACEDATA_1, GPIO_FN_VI0_G0,
+       GPIO_FN_SSI_SCK78_C, GPIO_FN_IRQ0, GPIO_FN_ARM_TRACEDATA_2,
+       GPIO_FN_VI0_G1, GPIO_FN_SSI_WS78_C, GPIO_FN_IRQ1,
+       GPIO_FN_ARM_TRACEDATA_3, GPIO_FN_VI0_G2, GPIO_FN_ETH_TXD1,
+       GPIO_FN_MMC1_D6, GPIO_FN_ARM_TRACEDATA_4, GPIO_FN_TS_SPSYNC0,
+       GPIO_FN_VI0_G3, GPIO_FN_ETH_CRS_DV, GPIO_FN_MMC1_D7,
+       GPIO_FN_ARM_TRACEDATA_5, GPIO_FN_TS_SDAT0, GPIO_FN_VI0_G4,
+       GPIO_FN_ETH_TX_EN, GPIO_FN_SD2_DAT0_B, GPIO_FN_ARM_TRACEDATA_6,
+       GPIO_FN_VI0_G5, GPIO_FN_ETH_RX_ER, GPIO_FN_SD2_DAT1_B,
+       GPIO_FN_ARM_TRACEDATA_7, GPIO_FN_VI0_G6, GPIO_FN_ETH_RXD0,
+       GPIO_FN_SD2_DAT2_B, GPIO_FN_ARM_TRACEDATA_8, GPIO_FN_VI0_G7,
+       GPIO_FN_ETH_RXD1, GPIO_FN_SD2_DAT3_B, GPIO_FN_ARM_TRACEDATA_9,
+
+       /* IPSR10 */
+       GPIO_FN_VI0_R0, GPIO_FN_SSI_SDATA7_C, GPIO_FN_SCK1_C, GPIO_FN_DREQ1_B,
+       GPIO_FN_ARM_TRACEDATA_10, GPIO_FN_DREQ0_C, GPIO_FN_VI0_R1,
+       GPIO_FN_SSI_SDATA8_C, GPIO_FN_DACK1_B, GPIO_FN_ARM_TRACEDATA_11,
+       GPIO_FN_DACK0_C, GPIO_FN_DRACK0_C, GPIO_FN_VI0_R2, GPIO_FN_ETH_LINK,
+       GPIO_FN_SD2_CLK_B, GPIO_FN_IRQ2, GPIO_FN_ARM_TRACEDATA_12,
+       GPIO_FN_VI0_R3, GPIO_FN_ETH_MAGIC, GPIO_FN_SD2_CMD_B, GPIO_FN_IRQ3,
+       GPIO_FN_ARM_TRACEDATA_13, GPIO_FN_VI0_R4, GPIO_FN_ETH_REFCLK,
+       GPIO_FN_SD2_CD_B, GPIO_FN_HSPI_CLK1_B, GPIO_FN_ARM_TRACEDATA_14,
+       GPIO_FN_MT1_CLK, GPIO_FN_TS_SCK0, GPIO_FN_VI0_R5, GPIO_FN_ETH_TXD0,
+       GPIO_FN_SD2_WP_B, GPIO_FN_HSPI_CS1_B, GPIO_FN_ARM_TRACEDATA_15,
+       GPIO_FN_MT1_D, GPIO_FN_TS_SDEN0, GPIO_FN_VI0_R6, GPIO_FN_ETH_MDC,
+       GPIO_FN_DREQ2_C, GPIO_FN_HSPI_TX1_B, GPIO_FN_TRACECLK,
+       GPIO_FN_MT1_BEN, GPIO_FN_PWMFSW0_D, GPIO_FN_VI0_R7, GPIO_FN_ETH_MDIO,
+       GPIO_FN_DACK2_C, GPIO_FN_HSPI_RX1_B, GPIO_FN_SCIF_CLK_D,
+       GPIO_FN_TRACECTL, GPIO_FN_MT1_PEN, GPIO_FN_VI1_CLK, GPIO_FN_SIM_D,
+       GPIO_FN_SDA3, GPIO_FN_VI1_HSYNC, GPIO_FN_VI3_CLK, GPIO_FN_SSI_SCK4,
+       GPIO_FN_GPS_SIGN_C, GPIO_FN_PWMFSW0_E, GPIO_FN_VI1_VSYNC,
+       GPIO_FN_AUDIO_CLKOUT_C, GPIO_FN_SSI_WS4, GPIO_FN_SIM_CLK,
+       GPIO_FN_GPS_MAG_C, GPIO_FN_SPV_TRST, GPIO_FN_SCL3,
+
+       /* IPSR11 */
+       GPIO_FN_VI1_DATA0_VI1_B0, GPIO_FN_SD2_DAT0, GPIO_FN_SIM_RST,
+       GPIO_FN_SPV_TCK, GPIO_FN_ADICLK_B, GPIO_FN_VI1_DATA1_VI1_B1,
+       GPIO_FN_SD2_DAT1, GPIO_FN_MT0_CLK, GPIO_FN_SPV_TMS,
+       GPIO_FN_ADICS_B_SAMP_B, GPIO_FN_VI1_DATA2_VI1_B2, GPIO_FN_SD2_DAT2,
+       GPIO_FN_MT0_D, GPIO_FN_SPVTDI, GPIO_FN_ADIDATA_B,
+       GPIO_FN_VI1_DATA3_VI1_B3, GPIO_FN_SD2_DAT3, GPIO_FN_MT0_BEN,
+       GPIO_FN_SPV_TDO, GPIO_FN_ADICHS0_B, GPIO_FN_VI1_DATA4_VI1_B4,
+       GPIO_FN_SD2_CLK, GPIO_FN_MT0_PEN, GPIO_FN_SPA_TRST,
+       GPIO_FN_HSPI_CLK1_D, GPIO_FN_ADICHS1_B, GPIO_FN_VI1_DATA5_VI1_B5,
+       GPIO_FN_SD2_CMD, GPIO_FN_MT0_SYNC, GPIO_FN_SPA_TCK,
+       GPIO_FN_HSPI_CS1_D, GPIO_FN_ADICHS2_B, GPIO_FN_VI1_DATA6_VI1_B6,
+       GPIO_FN_SD2_CD, GPIO_FN_MT0_VCXO, GPIO_FN_SPA_TMS, GPIO_FN_HSPI_TX1_D,
+       GPIO_FN_VI1_DATA7_VI1_B7, GPIO_FN_SD2_WP, GPIO_FN_MT0_PWM,
+       GPIO_FN_SPA_TDI, GPIO_FN_HSPI_RX1_D, GPIO_FN_VI1_G0, GPIO_FN_VI3_DATA0,
+       GPIO_FN_DU1_DOTCLKOUT1, GPIO_FN_TS_SCK1, GPIO_FN_DREQ2_B, GPIO_FN_TX2,
+       GPIO_FN_SPA_TDO, GPIO_FN_HCTS0_B, GPIO_FN_VI1_G1, GPIO_FN_VI3_DATA1,
+       GPIO_FN_SSI_SCK1, GPIO_FN_TS_SDEN1, GPIO_FN_DACK2_B, GPIO_FN_RX2,
+       GPIO_FN_HRTS0_B,
+
+       /* IPSR12 */
+       GPIO_FN_VI1_G2, GPIO_FN_VI3_DATA2, GPIO_FN_SSI_WS1, GPIO_FN_TS_SPSYNC1,
+       GPIO_FN_SCK2, GPIO_FN_HSCK0_B, GPIO_FN_VI1_G3, GPIO_FN_VI3_DATA3,
+       GPIO_FN_SSI_SCK2, GPIO_FN_TS_SDAT1, GPIO_FN_SCL1_C, GPIO_FN_HTX0_B,
+       GPIO_FN_VI1_G4, GPIO_FN_VI3_DATA4, GPIO_FN_SSI_WS2, GPIO_FN_SDA1_C,
+       GPIO_FN_SIM_RST_B, GPIO_FN_HRX0_B, GPIO_FN_VI1_G5, GPIO_FN_VI3_DATA5,
+       GPIO_FN_GPS_CLK, GPIO_FN_FSE, GPIO_FN_TX4_B, GPIO_FN_SIM_D_B,
+       GPIO_FN_VI1_G6, GPIO_FN_VI3_DATA6, GPIO_FN_GPS_SIGN, GPIO_FN_FRB,
+       GPIO_FN_RX4_B, GPIO_FN_SIM_CLK_B, GPIO_FN_VI1_G7, GPIO_FN_VI3_DATA7,
+       GPIO_FN_GPS_MAG, GPIO_FN_FCE, GPIO_FN_SCK4_B,
+};
+
+struct platform_device;
+
+struct r8a7779_pm_ch {
+       unsigned long chan_offs;
+       unsigned int chan_bit;
+       unsigned int isr_bit;
+};
+
+struct r8a7779_pm_domain {
+       struct generic_pm_domain genpd;
+       struct r8a7779_pm_ch ch;
+};
+
+static inline struct r8a7779_pm_ch *to_r8a7779_ch(struct generic_pm_domain *d)
+{
+       return &container_of(d, struct r8a7779_pm_domain, genpd)->ch;
+}
+
+extern int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch);
+extern int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch);
+
+#ifdef CONFIG_PM
+extern struct r8a7779_pm_domain r8a7779_sh4a;
+extern struct r8a7779_pm_domain r8a7779_sgx;
+extern struct r8a7779_pm_domain r8a7779_vdp1;
+extern struct r8a7779_pm_domain r8a7779_impx3;
+
+extern void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd);
+extern void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
+                                       struct platform_device *pdev);
+#else
+#define r8a7779_init_pm_domain(pd) do { } while (0)
+#define r8a7779_add_device_to_domain(pd, pdev) do { } while (0)
+#endif /* CONFIG_PM */
+
+#endif /* __ASM_R8A7779_H__ */
diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c
new file mode 100644 (file)
index 0000000..272c84c
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * R8A7740 processor support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/sh_intc.h>
+#include <mach/intc.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+/*
+ *             INTCA
+ */
+enum {
+       UNUSED_INTCA = 0,
+
+       /* interrupt sources INTCA */
+       DIRC,
+       ATAPI,
+       IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI,
+       AP_ARM_COMMTX, AP_ARM_COMMRX,
+       MFI, MFIS,
+       BBIF1, BBIF2,
+       USBHSDMAC,
+       USBF_OUL_SOF, USBF_IXL_INT,
+       SGX540,
+       CMT1_0, CMT1_1, CMT1_2, CMT1_3,
+       CMT2,
+       CMT3,
+       KEYSC,
+       SCIFA0, SCIFA1, SCIFA2, SCIFA3,
+       MSIOF2, MSIOF1,
+       SCIFA4, SCIFA5, SCIFB,
+       FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+       SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3,
+       SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3,
+       AP_ARM_L2CINT,
+       IRDA,
+       TPU0,
+       SCIFA6, SCIFA7,
+       GbEther,
+       ICBS0,
+       DDM,
+       SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3,
+       RWDT0,
+       DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
+       DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
+       DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3,
+       DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR,
+       DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3,
+       DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR,
+       SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM,
+       USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND,
+       RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF,
+       SPU2_0, SPU2_1,
+       FSI, FMSI,
+       IPMMU,
+       AP_ARM_CTIIRQ, AP_ARM_PMURQ,
+       MFIS2,
+       CPORTR2S,
+       CMT14, CMT15,
+       MMCIF_0, MMCIF_1, MMCIF_2,
+       SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+       STPRO_0, STPRO_1, STPRO_2, STPRO_3, STPRO_4,
+
+       /* interrupt groups INTCA */
+       DMAC1_1, DMAC1_2,
+       DMAC2_1, DMAC2_2,
+       DMAC3_1, DMAC3_2,
+       AP_ARM1, AP_ARM2,
+       SDHI0, SDHI1, SDHI2,
+       SHWYSTAT,
+       USBF, USBH1, USBH2,
+       RSPI, SPU2, FLCTL, IIC1,
+};
+
+static struct intc_vect intca_vectors[] __initdata = {
+       INTC_VECT(DIRC,                 0x0560),
+       INTC_VECT(ATAPI,                0x05E0),
+       INTC_VECT(IIC1_ALI,             0x0780),
+       INTC_VECT(IIC1_TACKI,           0x07A0),
+       INTC_VECT(IIC1_WAITI,           0x07C0),
+       INTC_VECT(IIC1_DTEI,            0x07E0),
+       INTC_VECT(AP_ARM_COMMTX,        0x0840),
+       INTC_VECT(AP_ARM_COMMRX,        0x0860),
+       INTC_VECT(MFI,                  0x0900),
+       INTC_VECT(MFIS,                 0x0920),
+       INTC_VECT(BBIF1,                0x0940),
+       INTC_VECT(BBIF2,                0x0960),
+       INTC_VECT(USBHSDMAC,            0x0A00),
+       INTC_VECT(USBF_OUL_SOF,         0x0A20),
+       INTC_VECT(USBF_IXL_INT,         0x0A40),
+       INTC_VECT(SGX540,               0x0A60),
+       INTC_VECT(CMT1_0,               0x0B00),
+       INTC_VECT(CMT1_1,               0x0B20),
+       INTC_VECT(CMT1_2,               0x0B40),
+       INTC_VECT(CMT1_3,               0x0B60),
+       INTC_VECT(CMT2,                 0x0B80),
+       INTC_VECT(CMT3,                 0x0BA0),
+       INTC_VECT(KEYSC,                0x0BE0),
+       INTC_VECT(SCIFA0,               0x0C00),
+       INTC_VECT(SCIFA1,               0x0C20),
+       INTC_VECT(SCIFA2,               0x0C40),
+       INTC_VECT(SCIFA3,               0x0C60),
+       INTC_VECT(MSIOF2,               0x0C80),
+       INTC_VECT(MSIOF1,               0x0D00),
+       INTC_VECT(SCIFA4,               0x0D20),
+       INTC_VECT(SCIFA5,               0x0D40),
+       INTC_VECT(SCIFB,                0x0D60),
+       INTC_VECT(FLCTL_FLSTEI,         0x0D80),
+       INTC_VECT(FLCTL_FLTENDI,        0x0DA0),
+       INTC_VECT(FLCTL_FLTREQ0I,       0x0DC0),
+       INTC_VECT(FLCTL_FLTREQ1I,       0x0DE0),
+       INTC_VECT(SDHI0_0,              0x0E00),
+       INTC_VECT(SDHI0_1,              0x0E20),
+       INTC_VECT(SDHI0_2,              0x0E40),
+       INTC_VECT(SDHI0_3,              0x0E60),
+       INTC_VECT(SDHI1_0,              0x0E80),
+       INTC_VECT(SDHI1_1,              0x0EA0),
+       INTC_VECT(SDHI1_2,              0x0EC0),
+       INTC_VECT(SDHI1_3,              0x0EE0),
+       INTC_VECT(AP_ARM_L2CINT,        0x0FA0),
+       INTC_VECT(IRDA,                 0x0480),
+       INTC_VECT(TPU0,                 0x04A0),
+       INTC_VECT(SCIFA6,               0x04C0),
+       INTC_VECT(SCIFA7,               0x04E0),
+       INTC_VECT(GbEther,              0x0500),
+       INTC_VECT(ICBS0,                0x0540),
+       INTC_VECT(DDM,                  0x1140),
+       INTC_VECT(SDHI2_0,              0x1200),
+       INTC_VECT(SDHI2_1,              0x1220),
+       INTC_VECT(SDHI2_2,              0x1240),
+       INTC_VECT(SDHI2_3,              0x1260),
+       INTC_VECT(RWDT0,                0x1280),
+       INTC_VECT(DMAC1_1_DEI0,         0x2000),
+       INTC_VECT(DMAC1_1_DEI1,         0x2020),
+       INTC_VECT(DMAC1_1_DEI2,         0x2040),
+       INTC_VECT(DMAC1_1_DEI3,         0x2060),
+       INTC_VECT(DMAC1_2_DEI4,         0x2080),
+       INTC_VECT(DMAC1_2_DEI5,         0x20A0),
+       INTC_VECT(DMAC1_2_DADERR,       0x20C0),
+       INTC_VECT(DMAC2_1_DEI0,         0x2100),
+       INTC_VECT(DMAC2_1_DEI1,         0x2120),
+       INTC_VECT(DMAC2_1_DEI2,         0x2140),
+       INTC_VECT(DMAC2_1_DEI3,         0x2160),
+       INTC_VECT(DMAC2_2_DEI4,         0x2180),
+       INTC_VECT(DMAC2_2_DEI5,         0x21A0),
+       INTC_VECT(DMAC2_2_DADERR,       0x21C0),
+       INTC_VECT(DMAC3_1_DEI0,         0x2200),
+       INTC_VECT(DMAC3_1_DEI1,         0x2220),
+       INTC_VECT(DMAC3_1_DEI2,         0x2240),
+       INTC_VECT(DMAC3_1_DEI3,         0x2260),
+       INTC_VECT(DMAC3_2_DEI4,         0x2280),
+       INTC_VECT(DMAC3_2_DEI5,         0x22A0),
+       INTC_VECT(DMAC3_2_DADERR,       0x22C0),
+       INTC_VECT(SHWYSTAT_RT,          0x1300),
+       INTC_VECT(SHWYSTAT_HS,          0x1320),
+       INTC_VECT(SHWYSTAT_COM,         0x1340),
+       INTC_VECT(USBH_INT,             0x1540),
+       INTC_VECT(USBH_OHCI,            0x1560),
+       INTC_VECT(USBH_EHCI,            0x1580),
+       INTC_VECT(USBH_PME,             0x15A0),
+       INTC_VECT(USBH_BIND,            0x15C0),
+       INTC_VECT(RSPI_OVRF,            0x1780),
+       INTC_VECT(RSPI_SPTEF,           0x17A0),
+       INTC_VECT(RSPI_SPRF,            0x17C0),
+       INTC_VECT(SPU2_0,               0x1800),
+       INTC_VECT(SPU2_1,               0x1820),
+       INTC_VECT(FSI,                  0x1840),
+       INTC_VECT(FMSI,                 0x1860),
+       INTC_VECT(IPMMU,                0x1920),
+       INTC_VECT(AP_ARM_CTIIRQ,        0x1980),
+       INTC_VECT(AP_ARM_PMURQ,         0x19A0),
+       INTC_VECT(MFIS2,                0x1A00),
+       INTC_VECT(CPORTR2S,             0x1A20),
+       INTC_VECT(CMT14,                0x1A40),
+       INTC_VECT(CMT15,                0x1A60),
+       INTC_VECT(MMCIF_0,              0x1AA0),
+       INTC_VECT(MMCIF_1,              0x1AC0),
+       INTC_VECT(MMCIF_2,              0x1AE0),
+       INTC_VECT(SIM_ERI,              0x1C00),
+       INTC_VECT(SIM_RXI,              0x1C20),
+       INTC_VECT(SIM_TXI,              0x1C40),
+       INTC_VECT(SIM_TEI,              0x1C60),
+       INTC_VECT(STPRO_0,              0x1C80),
+       INTC_VECT(STPRO_1,              0x1CA0),
+       INTC_VECT(STPRO_2,              0x1CC0),
+       INTC_VECT(STPRO_3,              0x1CE0),
+       INTC_VECT(STPRO_4,              0x1D00),
+};
+
+static struct intc_group intca_groups[] __initdata = {
+       INTC_GROUP(DMAC1_1,
+                  DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3),
+       INTC_GROUP(DMAC1_2,
+                  DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR),
+       INTC_GROUP(DMAC2_1,
+                  DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3),
+       INTC_GROUP(DMAC2_2,
+                  DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR),
+       INTC_GROUP(DMAC3_1,
+                  DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3),
+       INTC_GROUP(DMAC3_2,
+                  DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR),
+       INTC_GROUP(AP_ARM1,
+                  AP_ARM_COMMTX, AP_ARM_COMMRX),
+       INTC_GROUP(AP_ARM2,
+                  AP_ARM_CTIIRQ, AP_ARM_PMURQ),
+       INTC_GROUP(USBF,
+                  USBF_OUL_SOF, USBF_IXL_INT),
+       INTC_GROUP(SDHI0,
+                  SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3),
+       INTC_GROUP(SDHI1,
+                  SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3),
+       INTC_GROUP(SDHI2,
+                  SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3),
+       INTC_GROUP(SHWYSTAT,
+                  SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
+       INTC_GROUP(USBH1, /* FIXME */
+                  USBH_INT, USBH_OHCI),
+       INTC_GROUP(USBH2, /* FIXME */
+                  USBH_EHCI,
+                  USBH_PME, USBH_BIND),
+       INTC_GROUP(RSPI,
+                  RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF),
+       INTC_GROUP(SPU2,
+                  SPU2_0, SPU2_1),
+       INTC_GROUP(FLCTL,
+                  FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+       INTC_GROUP(IIC1,
+                  IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI),
+};
+
+static struct intc_mask_reg intca_mask_registers[] __initdata = {
+       { /* IMR0A / IMCR0A */ 0xe6940080, 0xe69400c0, 8,
+         { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0,
+           0, 0, AP_ARM_COMMTX, AP_ARM_COMMRX } },
+       { /* IMR1A / IMCR1A */ 0xe6940084, 0xe69400c4, 8,
+         { ATAPI, 0, DIRC, 0,
+           DMAC1_1_DEI3, DMAC1_1_DEI2, DMAC1_1_DEI1, DMAC1_1_DEI0 } },
+       { /* IMR2A / IMCR2A */ 0xe6940088, 0xe69400c8, 8,
+         { 0, 0, 0, 0,
+           BBIF1, BBIF2, MFIS, MFI } },
+       { /* IMR3A / IMCR3A */ 0xe694008c, 0xe69400cc, 8,
+         { DMAC3_1_DEI3, DMAC3_1_DEI2, DMAC3_1_DEI1, DMAC3_1_DEI0,
+           DMAC3_2_DADERR, DMAC3_2_DEI5, DMAC3_2_DEI4, IRDA } },
+       { /* IMR4A / IMCR4A */ 0xe6940090, 0xe69400d0, 8,
+         { DDM, 0, 0, 0,
+           0, 0, 0, 0 } },
+       { /* IMR5A / IMCR5A */ 0xe6940094, 0xe69400d4, 8,
+         { KEYSC, DMAC1_2_DADERR, DMAC1_2_DEI5, DMAC1_2_DEI4,
+           SCIFA3, SCIFA2, SCIFA1, SCIFA0 } },
+       { /* IMR6A / IMCR6A */ 0xe6940098, 0xe69400d8, 8,
+         { SCIFB, SCIFA5, SCIFA4, MSIOF1,
+           0, 0, MSIOF2, 0 } },
+       { /* IMR7A / IMCR7A */ 0xe694009c, 0xe69400dc, 8,
+         { SDHI0_3, SDHI0_2, SDHI0_1, SDHI0_0,
+           FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
+       { /* IMR8A / IMCR8A */ 0xe69400a0, 0xe69400e0, 8,
+         { SDHI1_3, SDHI1_2, SDHI1_1, SDHI1_0,
+           0, USBHSDMAC, 0, AP_ARM_L2CINT } },
+       { /* IMR9A / IMCR9A */ 0xe69400a4, 0xe69400e4, 8,
+         { CMT1_3, CMT1_2, CMT1_1, CMT1_0,
+           CMT2, USBF_IXL_INT, USBF_OUL_SOF, SGX540 } },
+       { /* IMR10A / IMCR10A */ 0xe69400a8, 0xe69400e8, 8,
+         { 0, DMAC2_2_DADERR, DMAC2_2_DEI5, DMAC2_2_DEI4,
+           0, 0, 0, 0 } },
+       { /* IMR11A / IMCR11A */ 0xe69400ac, 0xe69400ec, 8,
+         { IIC1_DTEI, IIC1_WAITI, IIC1_TACKI, IIC1_ALI,
+           ICBS0, 0, 0, 0 } },
+       { /* IMR12A / IMCR12A */ 0xe69400b0, 0xe69400f0, 8,
+         { 0, 0, TPU0, SCIFA6,
+           SCIFA7, GbEther, 0, 0 } },
+       { /* IMR13A / IMCR13A */ 0xe69400b4, 0xe69400f4, 8,
+         { SDHI2_3, SDHI2_2, SDHI2_1, SDHI2_0,
+           0, CMT3, 0, RWDT0 } },
+       { /* IMR0A3 / IMCR0A3 */ 0xe6950080, 0xe69500c0, 8,
+         { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
+           0, 0, 0, 0 } },
+         /* IMR1A3 / IMCR1A3 */
+       { /* IMR2A3 / IMCR2A3 */ 0xe6950088, 0xe69500c8, 8,
+         { 0, 0, USBH_INT, USBH_OHCI,
+           USBH_EHCI, USBH_PME, USBH_BIND, 0 } },
+         /* IMR3A3 / IMCR3A3 */
+       { /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8,
+         { 0, 0, 0, 0,
+           RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } },
+       { /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8,
+         { SPU2_0, SPU2_1, FSI, FMSI,
+           0, 0, 0, 0 } },
+       { /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8,
+         { 0, IPMMU, 0, 0,
+           AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } },
+       { /* IMR7A3 / IMCR7A3 */ 0xe695009c, 0xe69500dc, 8,
+         { MFIS2, CPORTR2S, CMT14, CMT15,
+           0, MMCIF_0, MMCIF_1, MMCIF_2 } },
+         /* IMR8A3 / IMCR8A3 */
+       { /* IMR9A3 / IMCR9A3 */ 0xe69500a4, 0xe69500e4, 8,
+         { SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+           STPRO_0, STPRO_1, STPRO_2, STPRO_3 } },
+       { /* IMR10A3 / IMCR10A3 */ 0xe69500a8, 0xe69500e8, 8,
+         { STPRO_4, 0, 0, 0,
+           0, 0, 0, 0 } },
+};
+
+static struct intc_prio_reg intca_prio_registers[] __initdata = {
+       { 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, ICBS0 } },
+       { 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, 0, BBIF1, BBIF2 } },
+       { 0xe6940008, 0, 16, 4, /* IPRCA */ { ATAPI, 0, CMT1_1, AP_ARM1 } },
+       { 0xe694000c, 0, 16, 4, /* IPRDA */ { 0, 0, CMT1_2, 0 } },
+       { 0xe6940010, 0, 16, 4, /* IPREA */ { DMAC1_1, MFIS, MFI, USBF } },
+       { 0xe6940014, 0, 16, 4, /* IPRFA */ { KEYSC, DMAC1_2,
+                                             SGX540, CMT1_0 } },
+       { 0xe6940018, 0, 16, 4, /* IPRGA */ { SCIFA0, SCIFA1,
+                                             SCIFA2, SCIFA3 } },
+       { 0xe694001c, 0, 16, 4, /* IPRGH */ { MSIOF2, USBHSDMAC,
+                                             FLCTL, SDHI0 } },
+       { 0xe6940020, 0, 16, 4, /* IPRIA */ { MSIOF1, SCIFA4, 0, IIC1 } },
+       { 0xe6940024, 0, 16, 4, /* IPRJA */ { DMAC2_1, DMAC2_2,
+                                             AP_ARM_L2CINT, 0 } },
+       { 0xe6940028, 0, 16, 4, /* IPRKA */ { 0, CMT1_3, 0, SDHI1 } },
+       { 0xe694002c, 0, 16, 4, /* IPRLA */ { TPU0, SCIFA6,
+                                             SCIFA7, GbEther } },
+       { 0xe6940030, 0, 16, 4, /* IPRMA */ { 0, CMT3, 0, RWDT0 } },
+       { 0xe6940034, 0, 16, 4, /* IPRNA */ { SCIFB, SCIFA5, 0, DDM } },
+       { 0xe6940038, 0, 16, 4, /* IPROA */ { 0, 0, DIRC, SDHI2 } },
+       { 0xe6950000, 0, 16, 4, /* IPRAA3 */ { SHWYSTAT, 0, 0, 0 } },
+                               /* IPRBA3 */
+                               /* IPRCA3 */
+                               /* IPRDA3 */
+       { 0xe6950010, 0, 16, 4, /* IPREA3 */ { USBH1, 0, 0, 0 } },
+       { 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } },
+                               /* IPRGA3 */
+                               /* IPRHA3 */
+                               /* IPRIA3 */
+       { 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } },
+       { 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } },
+                               /* IPRLA3 */
+       { 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } },
+       { 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } },
+       { 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S,
+                                              CMT14, CMT15 } },
+       { 0xe695003c, 0, 16, 4, /* IPRPA3 */ { 0, MMCIF_0, MMCIF_1, MMCIF_2 } },
+                               /* IPRQA3 */
+                               /* IPRRA3 */
+       { 0xe6950048, 0, 16, 4, /* IPRSA3 */ { SIM_ERI, SIM_RXI,
+                                              SIM_TXI, SIM_TEI } },
+       { 0xe695004c, 0, 16, 4, /* IPRTA3 */ { STPRO_0, STPRO_1,
+                                              STPRO_2, STPRO_3 } },
+       { 0xe6950050, 0, 16, 4, /* IPRUA3 */ { STPRO_4, 0, 0, 0 } },
+};
+
+static DECLARE_INTC_DESC(intca_desc, "r8a7740-intca",
+                        intca_vectors, intca_groups,
+                        intca_mask_registers, intca_prio_registers,
+                        NULL);
+
+INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000,
+                INTC_VECT, "r8a7740-intca-irq-pins");
+
+
+/*
+ *             INTCS
+ */
+enum {
+       UNUSED_INTCS = 0,
+
+       INTCS,
+
+       /* interrupt sources INTCS */
+
+       /* HUDI */
+       /* STPRO */
+       /* RTDMAC(1) */
+       VPU5HA2,
+       _2DG_TRAP, _2DG_GPM_INT, _2DG_CER_INT,
+       /* MFI */
+       /* BBIF2 */
+       VPU5F,
+       _2DG_BRK_INT,
+       /* SGX540 */
+       /* 2DDMAC */
+       /* IPMMU */
+       /* RTDMAC 2 */
+       /* KEYSC */
+       /* MSIOF */
+       IIC0_ALI, IIC0_TACKI, IIC0_WAITI, IIC0_DTEI,
+       TMU0_0, TMU0_1, TMU0_2,
+       CMT0,
+       /* CMT2 */
+       LMB,
+       CTI,
+       VOU,
+       /* RWDT0 */
+       ICB,
+       VIO6C,
+       CEU20, CEU21,
+       JPU,
+       LCDC0,
+       LCRC,
+       /* RTDMAC2(1) */
+       /* RTDMAC2(2) */
+       LCDC1,
+       /* SPU2 */
+       /* FSI */
+       /* FMSI */
+       TMU1_0, TMU1_1, TMU1_2,
+       CMT4,
+       DISP,
+       DSRV,
+       /* MFIS2 */
+       CPORTS2R,
+
+       /* interrupt groups INTCS */
+       _2DG1,
+       IIC0, TMU1,
+};
+
+static struct intc_vect intcs_vectors[] = {
+       /* HUDI */
+       /* STPRO */
+       /* RTDMAC(1) */
+       INTCS_VECT(VPU5HA2,             0x0880),
+       INTCS_VECT(_2DG_TRAP,           0x08A0),
+       INTCS_VECT(_2DG_GPM_INT,        0x08C0),
+       INTCS_VECT(_2DG_CER_INT,        0x08E0),
+       /* MFI */
+       /* BBIF2 */
+       INTCS_VECT(VPU5F,               0x0980),
+       INTCS_VECT(_2DG_BRK_INT,        0x09A0),
+       /* SGX540 */
+       /* 2DDMAC */
+       /* IPMMU */
+       /* RTDMAC(2) */
+       /* KEYSC */
+       /* MSIOF */
+       INTCS_VECT(IIC0_ALI,            0x0E00),
+       INTCS_VECT(IIC0_TACKI,          0x0E20),
+       INTCS_VECT(IIC0_WAITI,          0x0E40),
+       INTCS_VECT(IIC0_DTEI,           0x0E60),
+       INTCS_VECT(TMU0_0,              0x0E80),
+       INTCS_VECT(TMU0_1,              0x0EA0),
+       INTCS_VECT(TMU0_2,              0x0EC0),
+       INTCS_VECT(CMT0,                0x0F00),
+       /* CMT2 */
+       INTCS_VECT(LMB,                 0x0F60),
+       INTCS_VECT(CTI,                 0x0400),
+       INTCS_VECT(VOU,                 0x0420),
+       /* RWDT0 */
+       INTCS_VECT(ICB,                 0x0480),
+       INTCS_VECT(VIO6C,               0x04E0),
+       INTCS_VECT(CEU20,               0x0500),
+       INTCS_VECT(CEU21,               0x0520),
+       INTCS_VECT(JPU,                 0x0560),
+       INTCS_VECT(LCDC0,               0x0580),
+       INTCS_VECT(LCRC,                0x05A0),
+       /* RTDMAC2(1) */
+       /* RTDMAC2(2) */
+       INTCS_VECT(LCDC1,               0x1780),
+       /* SPU2 */
+       /* FSI */
+       /* FMSI */
+       INTCS_VECT(TMU1_0,              0x1900),
+       INTCS_VECT(TMU1_1,              0x1920),
+       INTCS_VECT(TMU1_2,              0x1940),
+       INTCS_VECT(CMT4,                0x1980),
+       INTCS_VECT(DISP,                0x19A0),
+       INTCS_VECT(DSRV,                0x19C0),
+       /* MFIS2 */
+       INTCS_VECT(CPORTS2R,            0x1A20),
+
+       INTC_VECT(INTCS,                0xf80),
+};
+
+static struct intc_group intcs_groups[] __initdata = {
+       INTC_GROUP(_2DG1, /*FIXME*/
+                  _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP),
+       INTC_GROUP(IIC0,
+                  IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI),
+       INTC_GROUP(TMU1,
+                  TMU1_0, TMU1_1, TMU1_2),
+};
+
+static struct intc_mask_reg intcs_mask_registers[] = {
+         /* IMR0SA / IMCR0SA */ /* all 0 */
+       { /* IMR1SA / IMCR1SA */ 0xffd20184, 0xffd201c4, 8,
+         { _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP, VPU5HA2,
+           0, 0, 0, 0 /*STPRO*/ } },
+       { /* IMR2SA / IMCR2SA */ 0xffd20188, 0xffd201c8, 8,
+         { 0/*STPRO*/, 0, CEU21, VPU5F,
+           0/*BBIF2*/, 0, 0, 0/*MFI*/ } },
+       { /* IMR3SA / IMCR3SA */ 0xffd2018c, 0xffd201cc, 8,
+         { 0, 0, 0, 0, /*2DDMAC*/
+           VIO6C, 0, 0, ICB } },
+       { /* IMR4SA / IMCR4SA */ 0xffd20190, 0xffd201d0, 8,
+         { 0, 0, VOU, CTI,
+           JPU, 0, LCRC, LCDC0 } },
+         /* IMR5SA / IMCR5SA */ /*KEYSC/RTDMAC2/RTDMAC1*/
+         /* IMR6SA / IMCR6SA */ /*MSIOF/SGX540*/
+       { /* IMR7SA / IMCR7SA */ 0xffd2019c, 0xffd201dc, 8,
+         { 0, TMU0_2, TMU0_1, TMU0_0,
+           0, 0, 0, 0 } },
+       { /* IMR8SA / IMCR8SA */ 0xffd201a0, 0xffd201e0, 8,
+         { 0, 0, 0, 0,
+           CEU20, 0, 0, 0 } },
+       { /* IMR9SA / IMCR9SA */ 0xffd201a4, 0xffd201e4, 8,
+         { 0, 0/*RWDT0*/, 0/*CMT2*/, CMT0,
+           0, 0, 0, 0 } },
+         /* IMR10SA / IMCR10SA */ /*IPMMU*/
+       { /* IMR11SA / IMCR11SA */ 0xffd201ac, 0xffd201ec, 8,
+         { IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI,
+           0, _2DG_BRK_INT, LMB, 0 } },
+         /* IMR12SA / IMCR12SA */
+         /* IMR13SA / IMCR13SA */
+         /* IMR0SA3 / IMCR0SA3 */ /*RTDMAC2(1)/RTDMAC2(2)*/
+         /* IMR1SA3 / IMCR1SA3 */
+         /* IMR2SA3 / IMCR2SA3 */
+         /* IMR3SA3 / IMCR3SA3 */
+       { /* IMR4SA3 / IMCR4SA3 */ 0xffd50190, 0xffd501d0, 8,
+         { 0, 0, 0, 0,
+           LCDC1, 0, 0, 0 } },
+         /* IMR5SA3 / IMCR5SA3 */ /* SPU2/FSI/FMSI */
+       { /* IMR6SA3 / IMCR6SA3 */ 0xffd50198, 0xffd501d8, 8,
+         { TMU1_0, TMU1_1, TMU1_2, 0,
+           CMT4, DISP, DSRV, 0 } },
+       { /* IMR7SA3 / IMCR7SA3 */ 0xffd5019c, 0xffd501dc, 8,
+         { 0/*MFIS2*/, CPORTS2R, 0, 0,
+           0, 0, 0, 0 } },
+       { /* INTAMASK */ 0xffd20104, 0, 16,
+         { 0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, INTCS } },
+};
+
+/* Priority is needed for INTCA to receive the INTCS interrupt */
+static struct intc_prio_reg intcs_prio_registers[] = {
+       { 0xffd20000, 0, 16, 4, /* IPRAS */ { CTI, VOU, 0/*2DDMAC*/, ICB } },
+       { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPU, LCDC0, 0, LCRC } },
+                               /* IPRCS */ /*BBIF2*/
+                               /* IPRDS */
+       { 0xffd20010, 0, 16, 4, /* IPRES */ { 0/*RTDMAC(1)*/, VPU5HA2,
+                                             0/*MFI*/, VPU5F } },
+       { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0/*KEYSC*/, 0/*RTDMAC(2)*/,
+                                             0/*CMT2*/, CMT0 } },
+       { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU0_0, TMU0_1,
+                                             TMU0_2, _2DG1 } },
+       { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0/*STPRO*/, 0/*STPRO*/,
+                                             _2DG_BRK_INT/*FIXME*/ } },
+       { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, 0/*MSIOF*/, 0, IIC0 } },
+       { 0xffd20024, 0, 16, 4, /* IPRJS */ { CEU20, 0/*SGX540*/, 0, 0 } },
+       { 0xffd20028, 0, 16, 4, /* IPRKS */ { VIO6C, 0, LMB, 0 } },
+       { 0xffd2002c, 0, 16, 4, /* IPRLS */ { 0/*IPMMU*/, 0, CEU21, 0 } },
+                               /* IPRMS */ /*RWDT0*/
+                               /* IPRAS3 */ /*RTDMAC2(1)*/
+                               /* IPRBS3 */ /*RTDMAC2(2)*/
+                               /* IPRCS3 */
+                               /* IPRDS3 */
+                               /* IPRES3 */
+                               /* IPRFS3 */
+                               /* IPRGS3 */
+                               /* IPRHS3 */
+                               /* IPRIS3 */
+       { 0xffd50024, 0, 16, 4, /* IPRJS3 */ { LCDC1, 0, 0, 0 } },
+                               /* IPRKS3 */ /*SPU2/FSI/FMSi*/
+                               /* IPRLS3 */
+       { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } },
+       { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DISP, DSRV, 0 } },
+       { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0/*MFIS2*/, CPORTS2R, 0, 0 } },
+                               /* IPRPS3 */
+};
+
+static struct resource intcs_resources[] __initdata = {
+       [0] = {
+               .start  = 0xffd20000,
+               .end    = 0xffd201ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0xffd50000,
+               .end    = 0xffd501ff,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct intc_desc intcs_desc __initdata = {
+       .name = "r8a7740-intcs",
+       .resource = intcs_resources,
+       .num_resources = ARRAY_SIZE(intcs_resources),
+       .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
+                          intcs_prio_registers, NULL, NULL),
+};
+
+static void intcs_demux(unsigned int irq, struct irq_desc *desc)
+{
+       void __iomem *reg = (void *)irq_get_handler_data(irq);
+       unsigned int evtcodeas = ioread32(reg);
+
+       generic_handle_irq(intcs_evt2irq(evtcodeas));
+}
+
+void __init r8a7740_init_irq(void)
+{
+       void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+
+       register_intc_controller(&intca_desc);
+       register_intc_controller(&intca_irq_pins_desc);
+       register_intc_controller(&intcs_desc);
+
+       /* demux using INTEVTSA */
+       irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
+       irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
+}
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
new file mode 100644 (file)
index 0000000..5d92fcd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * r8a7779 processor support - INTC hardware block
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <mach/common.h>
+#include <mach/intc.h>
+#include <mach/r8a7779.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#define INT2SMSKCR0 0xfe7822a0
+#define INT2SMSKCR1 0xfe7822a4
+#define INT2SMSKCR2 0xfe7822a8
+#define INT2SMSKCR3 0xfe7822ac
+#define INT2SMSKCR4 0xfe7822b0
+
+static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
+{
+       return 0; /* always allow wakeup */
+}
+
+void __init r8a7779_init_irq(void)
+{
+       void __iomem *gic_dist_base = __io(0xf0001000);
+       void __iomem *gic_cpu_base = __io(0xf0000100);
+
+       /* use GIC to handle interrupts */
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+       gic_arch_extn.irq_set_wake = r8a7779_set_wake;
+
+       /* unmask all known interrupts in INTCS2 */
+       __raw_writel(0xfffffff0, INT2SMSKCR0);
+       __raw_writel(0xfff7ffff, INT2SMSKCR1);
+       __raw_writel(0xfffbffdf, INT2SMSKCR2);
+       __raw_writel(0xbffffffc, INT2SMSKCR3);
+       __raw_writel(0x003fee3f, INT2SMSKCR4);
+}
diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c
new file mode 100644 (file)
index 0000000..a4fff69
--- /dev/null
@@ -0,0 +1,2562 @@
+/*
+ * R8A7740 processor support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <mach/r8a7740.h>
+
+#define CPU_ALL_PORT(fn, pfx, sfx)                                     \
+       PORT_10(fn, pfx, sfx),          PORT_90(fn, pfx, sfx),          \
+       PORT_10(fn, pfx##10, sfx),      PORT_90(fn, pfx##1, sfx),       \
+       PORT_10(fn, pfx##20, sfx),                                      \
+       PORT_1(fn, pfx##210, sfx),      PORT_1(fn, pfx##211, sfx)
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       /* PORT0_DATA -> PORT211_DATA */
+       PINMUX_DATA_BEGIN,
+       PORT_ALL(DATA),
+       PINMUX_DATA_END,
+
+       /* PORT0_IN -> PORT211_IN */
+       PINMUX_INPUT_BEGIN,
+       PORT_ALL(IN),
+       PINMUX_INPUT_END,
+
+       /* PORT0_IN_PU -> PORT211_IN_PU */
+       PINMUX_INPUT_PULLUP_BEGIN,
+       PORT_ALL(IN_PU),
+       PINMUX_INPUT_PULLUP_END,
+
+       /* PORT0_IN_PD -> PORT211_IN_PD */
+       PINMUX_INPUT_PULLDOWN_BEGIN,
+       PORT_ALL(IN_PD),
+       PINMUX_INPUT_PULLDOWN_END,
+
+       /* PORT0_OUT -> PORT211_OUT */
+       PINMUX_OUTPUT_BEGIN,
+       PORT_ALL(OUT),
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       PORT_ALL(FN_IN),        /* PORT0_FN_IN -> PORT211_FN_IN */
+       PORT_ALL(FN_OUT),       /* PORT0_FN_OUT -> PORT211_FN_OUT */
+       PORT_ALL(FN0),          /* PORT0_FN0 -> PORT211_FN0 */
+       PORT_ALL(FN1),          /* PORT0_FN1 -> PORT211_FN1 */
+       PORT_ALL(FN2),          /* PORT0_FN2 -> PORT211_FN2 */
+       PORT_ALL(FN3),          /* PORT0_FN3 -> PORT211_FN3 */
+       PORT_ALL(FN4),          /* PORT0_FN4 -> PORT211_FN4 */
+       PORT_ALL(FN5),          /* PORT0_FN5 -> PORT211_FN5 */
+       PORT_ALL(FN6),          /* PORT0_FN6 -> PORT211_FN6 */
+       PORT_ALL(FN7),          /* PORT0_FN7 -> PORT211_FN7 */
+
+       MSEL1CR_31_0,   MSEL1CR_31_1,
+       MSEL1CR_30_0,   MSEL1CR_30_1,
+       MSEL1CR_29_0,   MSEL1CR_29_1,
+       MSEL1CR_28_0,   MSEL1CR_28_1,
+       MSEL1CR_27_0,   MSEL1CR_27_1,
+       MSEL1CR_26_0,   MSEL1CR_26_1,
+       MSEL1CR_16_0,   MSEL1CR_16_1,
+       MSEL1CR_15_0,   MSEL1CR_15_1,
+       MSEL1CR_14_0,   MSEL1CR_14_1,
+       MSEL1CR_13_0,   MSEL1CR_13_1,
+       MSEL1CR_12_0,   MSEL1CR_12_1,
+       MSEL1CR_9_0,    MSEL1CR_9_1,
+       MSEL1CR_7_0,    MSEL1CR_7_1,
+       MSEL1CR_6_0,    MSEL1CR_6_1,
+       MSEL1CR_5_0,    MSEL1CR_5_1,
+       MSEL1CR_4_0,    MSEL1CR_4_1,
+       MSEL1CR_3_0,    MSEL1CR_3_1,
+       MSEL1CR_2_0,    MSEL1CR_2_1,
+       MSEL1CR_0_0,    MSEL1CR_0_1,
+
+       MSEL3CR_15_0,   MSEL3CR_15_1, /* Trace / Debug ? */
+       MSEL3CR_6_0,    MSEL3CR_6_1,
+
+       MSEL4CR_19_0,   MSEL4CR_19_1,
+       MSEL4CR_18_0,   MSEL4CR_18_1,
+       MSEL4CR_15_0,   MSEL4CR_15_1,
+       MSEL4CR_10_0,   MSEL4CR_10_1,
+       MSEL4CR_6_0,    MSEL4CR_6_1,
+       MSEL4CR_4_0,    MSEL4CR_4_1,
+       MSEL4CR_1_0,    MSEL4CR_1_1,
+
+       MSEL5CR_31_0,   MSEL5CR_31_1, /* irq/fiq output */
+       MSEL5CR_30_0,   MSEL5CR_30_1,
+       MSEL5CR_29_0,   MSEL5CR_29_1,
+       MSEL5CR_27_0,   MSEL5CR_27_1,
+       MSEL5CR_25_0,   MSEL5CR_25_1,
+       MSEL5CR_23_0,   MSEL5CR_23_1,
+       MSEL5CR_21_0,   MSEL5CR_21_1,
+       MSEL5CR_19_0,   MSEL5CR_19_1,
+       MSEL5CR_17_0,   MSEL5CR_17_1,
+       MSEL5CR_15_0,   MSEL5CR_15_1,
+       MSEL5CR_14_0,   MSEL5CR_14_1,
+       MSEL5CR_13_0,   MSEL5CR_13_1,
+       MSEL5CR_12_0,   MSEL5CR_12_1,
+       MSEL5CR_11_0,   MSEL5CR_11_1,
+       MSEL5CR_10_0,   MSEL5CR_10_1,
+       MSEL5CR_8_0,    MSEL5CR_8_1,
+       MSEL5CR_7_0,    MSEL5CR_7_1,
+       MSEL5CR_6_0,    MSEL5CR_6_1,
+       MSEL5CR_5_0,    MSEL5CR_5_1,
+       MSEL5CR_4_0,    MSEL5CR_4_1,
+       MSEL5CR_3_0,    MSEL5CR_3_1,
+       MSEL5CR_2_0,    MSEL5CR_2_1,
+       MSEL5CR_0_0,    MSEL5CR_0_1,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+
+       /* IRQ */
+       IRQ0_PORT2_MARK,        IRQ0_PORT13_MARK,
+       IRQ1_MARK,
+       IRQ2_PORT11_MARK,       IRQ2_PORT12_MARK,
+       IRQ3_PORT10_MARK,       IRQ3_PORT14_MARK,
+       IRQ4_PORT15_MARK,       IRQ4_PORT172_MARK,
+       IRQ5_PORT0_MARK,        IRQ5_PORT1_MARK,
+       IRQ6_PORT121_MARK,      IRQ6_PORT173_MARK,
+       IRQ7_PORT120_MARK,      IRQ7_PORT209_MARK,
+       IRQ8_MARK,
+       IRQ9_PORT118_MARK,      IRQ9_PORT210_MARK,
+       IRQ10_MARK,
+       IRQ11_MARK,
+       IRQ12_PORT42_MARK,      IRQ12_PORT97_MARK,
+       IRQ13_PORT64_MARK,      IRQ13_PORT98_MARK,
+       IRQ14_PORT63_MARK,      IRQ14_PORT99_MARK,
+       IRQ15_PORT62_MARK,      IRQ15_PORT100_MARK,
+       IRQ16_PORT68_MARK,      IRQ16_PORT211_MARK,
+       IRQ17_MARK,
+       IRQ18_MARK,
+       IRQ19_MARK,
+       IRQ20_MARK,
+       IRQ21_MARK,
+       IRQ22_MARK,
+       IRQ23_MARK,
+       IRQ24_MARK,
+       IRQ25_MARK,
+       IRQ26_PORT58_MARK,      IRQ26_PORT81_MARK,
+       IRQ27_PORT57_MARK,      IRQ27_PORT168_MARK,
+       IRQ28_PORT56_MARK,      IRQ28_PORT169_MARK,
+       IRQ29_PORT50_MARK,      IRQ29_PORT170_MARK,
+       IRQ30_PORT49_MARK,      IRQ30_PORT171_MARK,
+       IRQ31_PORT41_MARK,      IRQ31_PORT167_MARK,
+
+       /* Function */
+
+       /* DBGT */
+       DBGMDT2_MARK,   DBGMDT1_MARK,   DBGMDT0_MARK,
+       DBGMD10_MARK,   DBGMD11_MARK,   DBGMD20_MARK,
+       DBGMD21_MARK,
+
+       /* FSI */
+       FSIAISLD_PORT0_MARK,    /* FSIAISLD Port 0/5 */
+       FSIAISLD_PORT5_MARK,
+       FSIASPDIF_PORT9_MARK,   /* FSIASPDIF Port 9/18 */
+       FSIASPDIF_PORT18_MARK,
+       FSIAOSLD1_MARK, FSIAOSLD2_MARK, FSIAOLR_MARK,
+       FSIAOBT_MARK,   FSIAOSLD_MARK,  FSIAOMC_MARK,
+       FSIACK_MARK,    FSIAILR_MARK,   FSIAIBT_MARK,
+
+       /* FMSI */
+       FMSISLD_PORT1_MARK, /* FMSISLD Port 1/6 */
+       FMSISLD_PORT6_MARK,
+       FMSIILR_MARK,   FMSIIBT_MARK,   FMSIOLR_MARK,   FMSIOBT_MARK,
+       FMSICK_MARK,    FMSOILR_MARK,   FMSOIBT_MARK,   FMSOOLR_MARK,
+       FMSOOBT_MARK,   FMSOSLD_MARK,   FMSOCK_MARK,
+
+       /* SCIFA0 */
+       SCIFA0_SCK_MARK,        SCIFA0_CTS_MARK,        SCIFA0_RTS_MARK,
+       SCIFA0_RXD_MARK,        SCIFA0_TXD_MARK,
+
+       /* SCIFA1 */
+       SCIFA1_CTS_MARK,        SCIFA1_SCK_MARK,        SCIFA1_RXD_MARK,
+       SCIFA1_TXD_MARK,        SCIFA1_RTS_MARK,
+
+       /* SCIFA2 */
+       SCIFA2_SCK_PORT22_MARK, /* SCIFA2_SCK Port 22/199 */
+       SCIFA2_SCK_PORT199_MARK,
+       SCIFA2_RXD_MARK,        SCIFA2_TXD_MARK,
+       SCIFA2_CTS_MARK,        SCIFA2_RTS_MARK,
+
+       /* SCIFA3 */
+       SCIFA3_RTS_PORT105_MARK, /* MSEL5CR_8_0 */
+       SCIFA3_SCK_PORT116_MARK,
+       SCIFA3_CTS_PORT117_MARK,
+       SCIFA3_RXD_PORT174_MARK,
+       SCIFA3_TXD_PORT175_MARK,
+
+       SCIFA3_RTS_PORT161_MARK, /* MSEL5CR_8_1 */
+       SCIFA3_SCK_PORT158_MARK,
+       SCIFA3_CTS_PORT162_MARK,
+       SCIFA3_RXD_PORT159_MARK,
+       SCIFA3_TXD_PORT160_MARK,
+
+       /* SCIFA4 */
+       SCIFA4_RXD_PORT12_MARK, /* MSEL5CR[12:11] = 00 */
+       SCIFA4_TXD_PORT13_MARK,
+
+       SCIFA4_RXD_PORT204_MARK, /* MSEL5CR[12:11] = 01 */
+       SCIFA4_TXD_PORT203_MARK,
+
+       SCIFA4_RXD_PORT94_MARK, /* MSEL5CR[12:11] = 10 */
+       SCIFA4_TXD_PORT93_MARK,
+
+       SCIFA4_SCK_PORT21_MARK, /* SCIFA4_SCK Port 21/205 */
+       SCIFA4_SCK_PORT205_MARK,
+
+       /* SCIFA5 */
+       SCIFA5_TXD_PORT20_MARK, /* MSEL5CR[15:14] = 00 */
+       SCIFA5_RXD_PORT10_MARK,
+
+       SCIFA5_RXD_PORT207_MARK, /* MSEL5CR[15:14] = 01 */
+       SCIFA5_TXD_PORT208_MARK,
+
+       SCIFA5_TXD_PORT91_MARK, /* MSEL5CR[15:14] = 10 */
+       SCIFA5_RXD_PORT92_MARK,
+
+       SCIFA5_SCK_PORT23_MARK, /* SCIFA5_SCK Port 23/206 */
+       SCIFA5_SCK_PORT206_MARK,
+
+       /* SCIFA6 */
+       SCIFA6_SCK_MARK,        SCIFA6_RXD_MARK,        SCIFA6_TXD_MARK,
+
+       /* SCIFA7 */
+       SCIFA7_TXD_MARK,        SCIFA7_RXD_MARK,
+
+       /* SCIFAB */
+       SCIFB_SCK_PORT190_MARK, /* MSEL5CR_17_0 */
+       SCIFB_RXD_PORT191_MARK,
+       SCIFB_TXD_PORT192_MARK,
+       SCIFB_RTS_PORT186_MARK,
+       SCIFB_CTS_PORT187_MARK,
+
+       SCIFB_SCK_PORT2_MARK, /* MSEL5CR_17_1 */
+       SCIFB_RXD_PORT3_MARK,
+       SCIFB_TXD_PORT4_MARK,
+       SCIFB_RTS_PORT172_MARK,
+       SCIFB_CTS_PORT173_MARK,
+
+       /* LCD0 */
+       LCDC0_SELECT_MARK,
+
+       LCD0_D0_MARK,   LCD0_D1_MARK,   LCD0_D2_MARK,   LCD0_D3_MARK,
+       LCD0_D4_MARK,   LCD0_D5_MARK,   LCD0_D6_MARK,   LCD0_D7_MARK,
+       LCD0_D8_MARK,   LCD0_D9_MARK,   LCD0_D10_MARK,  LCD0_D11_MARK,
+       LCD0_D12_MARK,  LCD0_D13_MARK,  LCD0_D14_MARK,  LCD0_D15_MARK,
+       LCD0_D16_MARK,  LCD0_D17_MARK,
+       LCD0_DON_MARK,  LCD0_VCPWC_MARK,        LCD0_VEPWC_MARK,
+       LCD0_DCK_MARK,  LCD0_VSYN_MARK, /* for RGB */
+       LCD0_HSYN_MARK, LCD0_DISP_MARK, /* for RGB */
+       LCD0_WR_MARK,   LCD0_RD_MARK,   /* for SYS */
+       LCD0_CS_MARK,   LCD0_RS_MARK,   /* for SYS */
+
+       LCD0_D21_PORT158_MARK,  LCD0_D23_PORT159_MARK, /* MSEL5CR_6_1 */
+       LCD0_D22_PORT160_MARK,  LCD0_D20_PORT161_MARK,
+       LCD0_D19_PORT162_MARK,  LCD0_D18_PORT163_MARK,
+       LCD0_LCLK_PORT165_MARK,
+
+       LCD0_D18_PORT40_MARK,   LCD0_D22_PORT0_MARK, /* MSEL5CR_6_0 */
+       LCD0_D23_PORT1_MARK,    LCD0_D21_PORT2_MARK,
+       LCD0_D20_PORT3_MARK,    LCD0_D19_PORT4_MARK,
+       LCD0_LCLK_PORT102_MARK,
+
+       /* LCD1 */
+       LCDC1_SELECT_MARK,
+
+       LCD1_D0_MARK,   LCD1_D1_MARK,   LCD1_D2_MARK,   LCD1_D3_MARK,
+       LCD1_D4_MARK,   LCD1_D5_MARK,   LCD1_D6_MARK,   LCD1_D7_MARK,
+       LCD1_D8_MARK,   LCD1_D9_MARK,   LCD1_D10_MARK,  LCD1_D11_MARK,
+       LCD1_D12_MARK,  LCD1_D13_MARK,  LCD1_D14_MARK,  LCD1_D15_MARK,
+       LCD1_D16_MARK,  LCD1_D17_MARK,  LCD1_D18_MARK,  LCD1_D19_MARK,
+       LCD1_D20_MARK,  LCD1_D21_MARK,  LCD1_D22_MARK,  LCD1_D23_MARK,
+       LCD1_DON_MARK,  LCD1_VCPWC_MARK,
+       LCD1_LCLK_MARK, LCD1_VEPWC_MARK,
+
+       LCD1_DCK_MARK,  LCD1_VSYN_MARK, /* for RGB */
+       LCD1_HSYN_MARK, LCD1_DISP_MARK, /* for RGB */
+       LCD1_RS_MARK,   LCD1_CS_MARK,   /* for SYS */
+       LCD1_RD_MARK,   LCD1_WR_MARK,   /* for SYS */
+
+       /* RSPI */
+       RSPI_SSL0_A_MARK,       RSPI_SSL1_A_MARK,       RSPI_SSL2_A_MARK,
+       RSPI_SSL3_A_MARK,       RSPI_CK_A_MARK,         RSPI_MOSI_A_MARK,
+       RSPI_MISO_A_MARK,
+
+       /* VIO CKO */
+       VIO_CKO1_MARK, /* needs fixup */
+       VIO_CKO2_MARK,
+       VIO_CKO_1_MARK,
+       VIO_CKO_MARK,
+
+       /* VIO0 */
+       VIO0_D0_MARK,   VIO0_D1_MARK,   VIO0_D2_MARK,   VIO0_D3_MARK,
+       VIO0_D4_MARK,   VIO0_D5_MARK,   VIO0_D6_MARK,   VIO0_D7_MARK,
+       VIO0_D8_MARK,   VIO0_D9_MARK,   VIO0_D10_MARK,  VIO0_D11_MARK,
+       VIO0_D12_MARK,  VIO0_VD_MARK,   VIO0_HD_MARK,   VIO0_CLK_MARK,
+       VIO0_FIELD_MARK,
+
+       VIO0_D13_PORT26_MARK, /* MSEL5CR_27_0 */
+       VIO0_D14_PORT25_MARK,
+       VIO0_D15_PORT24_MARK,
+
+       VIO0_D13_PORT22_MARK, /* MSEL5CR_27_1 */
+       VIO0_D14_PORT95_MARK,
+       VIO0_D15_PORT96_MARK,
+
+       /* VIO1 */
+       VIO1_D0_MARK,   VIO1_D1_MARK,   VIO1_D2_MARK,   VIO1_D3_MARK,
+       VIO1_D4_MARK,   VIO1_D5_MARK,   VIO1_D6_MARK,   VIO1_D7_MARK,
+       VIO1_VD_MARK,   VIO1_HD_MARK,   VIO1_CLK_MARK,  VIO1_FIELD_MARK,
+
+       /* TPU0 */
+       TPU0TO0_MARK,   TPU0TO1_MARK,   TPU0TO3_MARK,
+       TPU0TO2_PORT66_MARK, /* TPU0TO2 Port 66/202 */
+       TPU0TO2_PORT202_MARK,
+
+       /* SSP1 0 */
+       STP0_IPD0_MARK, STP0_IPD1_MARK, STP0_IPD2_MARK, STP0_IPD3_MARK,
+       STP0_IPD4_MARK, STP0_IPD5_MARK, STP0_IPD6_MARK, STP0_IPD7_MARK,
+       STP0_IPEN_MARK, STP0_IPCLK_MARK,        STP0_IPSYNC_MARK,
+
+       /* SSP1 1 */
+       STP1_IPD1_MARK, STP1_IPD2_MARK, STP1_IPD3_MARK, STP1_IPD4_MARK,
+       STP1_IPD5_MARK, STP1_IPD6_MARK, STP1_IPD7_MARK, STP1_IPCLK_MARK,
+       STP1_IPSYNC_MARK,
+
+       STP1_IPD0_PORT186_MARK, /* MSEL5CR_23_0 */
+       STP1_IPEN_PORT187_MARK,
+
+       STP1_IPD0_PORT194_MARK, /* MSEL5CR_23_1 */
+       STP1_IPEN_PORT193_MARK,
+
+       /* SIM */
+       SIM_RST_MARK,   SIM_CLK_MARK,
+       SIM_D_PORT22_MARK, /* SIM_D  Port 22/199 */
+       SIM_D_PORT199_MARK,
+
+       /* SDHI0 */
+       SDHI0_D0_MARK,  SDHI0_D1_MARK,  SDHI0_D2_MARK,  SDHI0_D3_MARK,
+       SDHI0_CD_MARK,  SDHI0_WP_MARK,  SDHI0_CMD_MARK, SDHI0_CLK_MARK,
+
+       /* SDHI1 */
+       SDHI1_D0_MARK,  SDHI1_D1_MARK,  SDHI1_D2_MARK,  SDHI1_D3_MARK,
+       SDHI1_CD_MARK,  SDHI1_WP_MARK,  SDHI1_CMD_MARK, SDHI1_CLK_MARK,
+
+       /* SDHI2 */
+       SDHI2_D0_MARK,  SDHI2_D1_MARK,  SDHI2_D2_MARK,  SDHI2_D3_MARK,
+       SDHI2_CLK_MARK, SDHI2_CMD_MARK,
+
+       SDHI2_CD_PORT24_MARK, /* MSEL5CR_19_0 */
+       SDHI2_WP_PORT25_MARK,
+
+       SDHI2_WP_PORT177_MARK, /* MSEL5CR_19_1 */
+       SDHI2_CD_PORT202_MARK,
+
+       /* MSIOF2 */
+       MSIOF2_TXD_MARK,        MSIOF2_RXD_MARK,        MSIOF2_TSCK_MARK,
+       MSIOF2_SS2_MARK,        MSIOF2_TSYNC_MARK,      MSIOF2_SS1_MARK,
+       MSIOF2_MCK1_MARK,       MSIOF2_MCK0_MARK,       MSIOF2_RSYNC_MARK,
+       MSIOF2_RSCK_MARK,
+
+       /* KEYSC */
+       KEYIN4_MARK,    KEYIN5_MARK,    KEYIN6_MARK,    KEYIN7_MARK,
+       KEYOUT0_MARK,   KEYOUT1_MARK,   KEYOUT2_MARK,   KEYOUT3_MARK,
+       KEYOUT4_MARK,   KEYOUT5_MARK,   KEYOUT6_MARK,   KEYOUT7_MARK,
+
+       KEYIN0_PORT43_MARK, /* MSEL4CR_18_0 */
+       KEYIN1_PORT44_MARK,
+       KEYIN2_PORT45_MARK,
+       KEYIN3_PORT46_MARK,
+
+       KEYIN0_PORT58_MARK, /* MSEL4CR_18_1 */
+       KEYIN1_PORT57_MARK,
+       KEYIN2_PORT56_MARK,
+       KEYIN3_PORT55_MARK,
+
+       /* VOU */
+       DV_D0_MARK,     DV_D1_MARK,     DV_D2_MARK,     DV_D3_MARK,
+       DV_D4_MARK,     DV_D5_MARK,     DV_D6_MARK,     DV_D7_MARK,
+       DV_D8_MARK,     DV_D9_MARK,     DV_D10_MARK,    DV_D11_MARK,
+       DV_D12_MARK,    DV_D13_MARK,    DV_D14_MARK,    DV_D15_MARK,
+       DV_CLK_MARK,    DV_VSYNC_MARK,  DV_HSYNC_MARK,
+
+       /* MEMC */
+       MEMC_AD0_MARK,  MEMC_AD1_MARK,  MEMC_AD2_MARK,  MEMC_AD3_MARK,
+       MEMC_AD4_MARK,  MEMC_AD5_MARK,  MEMC_AD6_MARK,  MEMC_AD7_MARK,
+       MEMC_AD8_MARK,  MEMC_AD9_MARK,  MEMC_AD10_MARK, MEMC_AD11_MARK,
+       MEMC_AD12_MARK, MEMC_AD13_MARK, MEMC_AD14_MARK, MEMC_AD15_MARK,
+       MEMC_CS0_MARK,  MEMC_INT_MARK,  MEMC_NWE_MARK,  MEMC_NOE_MARK,
+
+       MEMC_CS1_MARK, /* MSEL4CR_6_0 */
+       MEMC_ADV_MARK,
+       MEMC_WAIT_MARK,
+       MEMC_BUSCLK_MARK,
+
+       MEMC_A1_MARK, /* MSEL4CR_6_1 */
+       MEMC_DREQ0_MARK,
+       MEMC_DREQ1_MARK,
+       MEMC_A0_MARK,
+
+       /* MMC */
+       MMC0_D0_PORT68_MARK,    MMC0_D1_PORT69_MARK,    MMC0_D2_PORT70_MARK,
+       MMC0_D3_PORT71_MARK,    MMC0_D4_PORT72_MARK,    MMC0_D5_PORT73_MARK,
+       MMC0_D6_PORT74_MARK,    MMC0_D7_PORT75_MARK,    MMC0_CLK_PORT66_MARK,
+       MMC0_CMD_PORT67_MARK,   /* MSEL4CR_15_0 */
+
+       MMC1_D0_PORT149_MARK,   MMC1_D1_PORT148_MARK,   MMC1_D2_PORT147_MARK,
+       MMC1_D3_PORT146_MARK,   MMC1_D4_PORT145_MARK,   MMC1_D5_PORT144_MARK,
+       MMC1_D6_PORT143_MARK,   MMC1_D7_PORT142_MARK,   MMC1_CLK_PORT103_MARK,
+       MMC1_CMD_PORT104_MARK,  /* MSEL4CR_15_1 */
+
+       /* MSIOF0 */
+       MSIOF0_SS1_MARK,        MSIOF0_SS2_MARK,        MSIOF0_RXD_MARK,
+       MSIOF0_TXD_MARK,        MSIOF0_MCK0_MARK,       MSIOF0_MCK1_MARK,
+       MSIOF0_RSYNC_MARK,      MSIOF0_RSCK_MARK,       MSIOF0_TSCK_MARK,
+       MSIOF0_TSYNC_MARK,
+
+       /* MSIOF1 */
+       MSIOF1_RSCK_MARK,       MSIOF1_RSYNC_MARK,
+       MSIOF1_MCK0_MARK,       MSIOF1_MCK1_MARK,
+
+       MSIOF1_SS2_PORT116_MARK,        MSIOF1_SS1_PORT117_MARK,
+       MSIOF1_RXD_PORT118_MARK,        MSIOF1_TXD_PORT119_MARK,
+       MSIOF1_TSYNC_PORT120_MARK,
+       MSIOF1_TSCK_PORT121_MARK,       /* MSEL4CR_10_0 */
+
+       MSIOF1_SS1_PORT67_MARK,         MSIOF1_TSCK_PORT72_MARK,
+       MSIOF1_TSYNC_PORT73_MARK,       MSIOF1_TXD_PORT74_MARK,
+       MSIOF1_RXD_PORT75_MARK,
+       MSIOF1_SS2_PORT202_MARK,        /* MSEL4CR_10_1 */
+
+       /* GPIO */
+       GPO0_MARK,      GPI0_MARK,      GPO1_MARK,      GPI1_MARK,
+
+       /* USB0 */
+       USB0_OCI_MARK,  USB0_PPON_MARK, VBUS_MARK,
+
+       /* USB1 */
+       USB1_OCI_MARK,  USB1_PPON_MARK,
+
+       /* BBIF1 */
+       BBIF1_RXD_MARK,         BBIF1_TXD_MARK,         BBIF1_TSYNC_MARK,
+       BBIF1_TSCK_MARK,        BBIF1_RSCK_MARK,        BBIF1_RSYNC_MARK,
+       BBIF1_FLOW_MARK,        BBIF1_RX_FLOW_N_MARK,
+
+       /* BBIF2 */
+       BBIF2_TXD2_PORT5_MARK, /* MSEL5CR_0_0 */
+       BBIF2_RXD2_PORT60_MARK,
+       BBIF2_TSYNC2_PORT6_MARK,
+       BBIF2_TSCK2_PORT59_MARK,
+
+       BBIF2_RXD2_PORT90_MARK, /* MSEL5CR_0_1 */
+       BBIF2_TXD2_PORT183_MARK,
+       BBIF2_TSCK2_PORT89_MARK,
+       BBIF2_TSYNC2_PORT184_MARK,
+
+       /* BSC / FLCTL / PCMCIA */
+       CS0_MARK,       CS2_MARK,       CS4_MARK,
+       CS5B_MARK,      CS6A_MARK,
+       CS5A_PORT105_MARK, /* CS5A PORT 19/105 */
+       CS5A_PORT19_MARK,
+       IOIS16_MARK, /* ? */
+
+       A0_MARK,        A1_MARK,        A2_MARK,        A3_MARK,
+       A4_FOE_MARK,    /* share with FLCTL */
+       A5_FCDE_MARK,   /* share with FLCTL */
+       A6_MARK,        A7_MARK,        A8_MARK,        A9_MARK,
+       A10_MARK,       A11_MARK,       A12_MARK,       A13_MARK,
+       A14_MARK,       A15_MARK,       A16_MARK,       A17_MARK,
+       A18_MARK,       A19_MARK,       A20_MARK,       A21_MARK,
+       A22_MARK,       A23_MARK,       A24_MARK,       A25_MARK,
+       A26_MARK,
+
+       D0_NAF0_MARK,   D1_NAF1_MARK,   D2_NAF2_MARK,   /* share with FLCTL */
+       D3_NAF3_MARK,   D4_NAF4_MARK,   D5_NAF5_MARK,   /* share with FLCTL */
+       D6_NAF6_MARK,   D7_NAF7_MARK,   D8_NAF8_MARK,   /* share with FLCTL */
+       D9_NAF9_MARK,   D10_NAF10_MARK, D11_NAF11_MARK, /* share with FLCTL */
+       D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, /* share with FLCTL */
+       D15_NAF15_MARK,                                 /* share with FLCTL */
+       D16_MARK,       D17_MARK,       D18_MARK,       D19_MARK,
+       D20_MARK,       D21_MARK,       D22_MARK,       D23_MARK,
+       D24_MARK,       D25_MARK,       D26_MARK,       D27_MARK,
+       D28_MARK,       D29_MARK,       D30_MARK,       D31_MARK,
+
+       WE0_FWE_MARK,   /* share with FLCTL */
+       WE1_MARK,
+       WE2_ICIORD_MARK,        /* share with PCMCIA */
+       WE3_ICIOWR_MARK,        /* share with PCMCIA */
+       CKO_MARK,       BS_MARK,        RDWR_MARK,
+       RD_FSC_MARK,    /* share with FLCTL */
+       WAIT_PORT177_MARK, /* WAIT Port 90/177 */
+       WAIT_PORT90_MARK,
+
+       FCE0_MARK,      FCE1_MARK,      FRB_MARK, /* FLCTL */
+
+       /* IRDA */
+       IRDA_FIRSEL_MARK,       IRDA_IN_MARK,   IRDA_OUT_MARK,
+
+       /* ATAPI */
+       IDE_D0_MARK,    IDE_D1_MARK,    IDE_D2_MARK,    IDE_D3_MARK,
+       IDE_D4_MARK,    IDE_D5_MARK,    IDE_D6_MARK,    IDE_D7_MARK,
+       IDE_D8_MARK,    IDE_D9_MARK,    IDE_D10_MARK,   IDE_D11_MARK,
+       IDE_D12_MARK,   IDE_D13_MARK,   IDE_D14_MARK,   IDE_D15_MARK,
+       IDE_A0_MARK,    IDE_A1_MARK,    IDE_A2_MARK,    IDE_CS0_MARK,
+       IDE_CS1_MARK,   IDE_IOWR_MARK,  IDE_IORD_MARK,  IDE_IORDY_MARK,
+       IDE_INT_MARK,           IDE_RST_MARK,           IDE_DIRECTION_MARK,
+       IDE_EXBUF_ENB_MARK,     IDE_IODACK_MARK,        IDE_IODREQ_MARK,
+
+       /* RMII */
+       RMII_CRS_DV_MARK,       RMII_RX_ER_MARK,        RMII_RXD0_MARK,
+       RMII_RXD1_MARK,         RMII_TX_EN_MARK,        RMII_TXD0_MARK,
+       RMII_MDC_MARK,          RMII_TXD1_MARK,         RMII_MDIO_MARK,
+       RMII_REF50CK_MARK,      /* for RMII */
+       RMII_REF125CK_MARK,     /* for GMII */
+
+       /* GEther */
+       ET_TX_CLK_MARK, ET_TX_EN_MARK,  ET_ETXD0_MARK,  ET_ETXD1_MARK,
+       ET_ETXD2_MARK,  ET_ETXD3_MARK,
+       ET_ETXD4_MARK,  ET_ETXD5_MARK, /* for GEther */
+       ET_ETXD6_MARK,  ET_ETXD7_MARK, /* for GEther */
+       ET_COL_MARK,    ET_TX_ER_MARK,  ET_RX_CLK_MARK, ET_RX_DV_MARK,
+       ET_ERXD0_MARK,  ET_ERXD1_MARK,  ET_ERXD2_MARK,  ET_ERXD3_MARK,
+       ET_ERXD4_MARK,  ET_ERXD5_MARK, /* for GEther */
+       ET_ERXD6_MARK,  ET_ERXD7_MARK, /* for GEther */
+       ET_RX_ER_MARK,  ET_CRS_MARK,            ET_MDC_MARK,    ET_MDIO_MARK,
+       ET_LINK_MARK,   ET_PHY_INT_MARK,        ET_WOL_MARK,    ET_GTX_CLK_MARK,
+
+       /* DMA0 */
+       DREQ0_MARK,     DACK0_MARK,
+
+       /* DMA1 */
+       DREQ1_MARK,     DACK1_MARK,
+
+       /* SYSC */
+       RESETOUTS_MARK,         RESETP_PULLUP_MARK,     RESETP_PLAIN_MARK,
+
+       /* IRREM */
+       IROUT_MARK,
+
+       /* SDENC */
+       SDENC_CPG_MARK,         SDENC_DV_CLKI_MARK,
+
+       /* DEBUG */
+       EDEBGREQ_PULLUP_MARK,   /* for JTAG */
+       EDEBGREQ_PULLDOWN_MARK,
+
+       TRACEAUD_FROM_VIO_MARK, /* for TRACE/AUD */
+       TRACEAUD_FROM_LCDC0_MARK,
+       TRACEAUD_FROM_MEMC_MARK,
+
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+       /* specify valid pin states for each pin in GPIO mode */
+
+       /* I/O and Pull U/D */
+       PORT_DATA_IO_PD(0),             PORT_DATA_IO_PD(1),
+       PORT_DATA_IO_PD(2),             PORT_DATA_IO_PD(3),
+       PORT_DATA_IO_PD(4),             PORT_DATA_IO_PD(5),
+       PORT_DATA_IO_PD(6),             PORT_DATA_IO(7),
+       PORT_DATA_IO(8),                PORT_DATA_IO(9),
+
+       PORT_DATA_IO_PD(10),            PORT_DATA_IO_PD(11),
+       PORT_DATA_IO_PD(12),            PORT_DATA_IO_PU_PD(13),
+       PORT_DATA_IO_PD(14),            PORT_DATA_IO_PD(15),
+       PORT_DATA_IO_PD(16),            PORT_DATA_IO_PD(17),
+       PORT_DATA_IO(18),               PORT_DATA_IO_PU(19),
+
+       PORT_DATA_IO_PU_PD(20),         PORT_DATA_IO_PD(21),
+       PORT_DATA_IO_PU_PD(22),         PORT_DATA_IO(23),
+       PORT_DATA_IO_PU(24),            PORT_DATA_IO_PU(25),
+       PORT_DATA_IO_PU(26),            PORT_DATA_IO_PU(27),
+       PORT_DATA_IO_PU(28),            PORT_DATA_IO_PU(29),
+
+       PORT_DATA_IO_PU(30),            PORT_DATA_IO_PD(31),
+       PORT_DATA_IO_PD(32),            PORT_DATA_IO_PD(33),
+       PORT_DATA_IO_PD(34),            PORT_DATA_IO_PU(35),
+       PORT_DATA_IO_PU(36),            PORT_DATA_IO_PD(37),
+       PORT_DATA_IO_PU(38),            PORT_DATA_IO_PD(39),
+
+       PORT_DATA_IO_PU_PD(40),         PORT_DATA_IO_PD(41),
+       PORT_DATA_IO_PD(42),            PORT_DATA_IO_PU_PD(43),
+       PORT_DATA_IO_PU_PD(44),         PORT_DATA_IO_PU_PD(45),
+       PORT_DATA_IO_PU_PD(46),         PORT_DATA_IO_PU_PD(47),
+       PORT_DATA_IO_PU_PD(48),         PORT_DATA_IO_PU_PD(49),
+
+       PORT_DATA_IO_PU_PD(50),         PORT_DATA_IO_PD(51),
+       PORT_DATA_IO_PD(52),            PORT_DATA_IO_PD(53),
+       PORT_DATA_IO_PD(54),            PORT_DATA_IO_PU_PD(55),
+       PORT_DATA_IO_PU_PD(56),         PORT_DATA_IO_PU_PD(57),
+       PORT_DATA_IO_PU_PD(58),         PORT_DATA_IO_PU_PD(59),
+
+       PORT_DATA_IO_PU_PD(60),         PORT_DATA_IO_PD(61),
+       PORT_DATA_IO_PD(62),            PORT_DATA_IO_PD(63),
+       PORT_DATA_IO_PD(64),            PORT_DATA_IO_PD(65),
+       PORT_DATA_IO_PU_PD(66),         PORT_DATA_IO_PU_PD(67),
+       PORT_DATA_IO_PU_PD(68),         PORT_DATA_IO_PU_PD(69),
+
+       PORT_DATA_IO_PU_PD(70),         PORT_DATA_IO_PU_PD(71),
+       PORT_DATA_IO_PU_PD(72),         PORT_DATA_IO_PU_PD(73),
+       PORT_DATA_IO_PU_PD(74),         PORT_DATA_IO_PU_PD(75),
+       PORT_DATA_IO_PU_PD(76),         PORT_DATA_IO_PU_PD(77),
+       PORT_DATA_IO_PU_PD(78),         PORT_DATA_IO_PU_PD(79),
+
+       PORT_DATA_IO_PU_PD(80),         PORT_DATA_IO_PU_PD(81),
+       PORT_DATA_IO(82),               PORT_DATA_IO_PU_PD(83),
+       PORT_DATA_IO(84),               PORT_DATA_IO_PD(85),
+       PORT_DATA_IO_PD(86),            PORT_DATA_IO_PD(87),
+       PORT_DATA_IO_PD(88),            PORT_DATA_IO_PD(89),
+
+       PORT_DATA_IO_PD(90),            PORT_DATA_IO_PU_PD(91),
+       PORT_DATA_IO_PU_PD(92),         PORT_DATA_IO_PU_PD(93),
+       PORT_DATA_IO_PU_PD(94),         PORT_DATA_IO_PU_PD(95),
+       PORT_DATA_IO_PU_PD(96),         PORT_DATA_IO_PU_PD(97),
+       PORT_DATA_IO_PU_PD(98),         PORT_DATA_IO_PU_PD(99),
+
+       PORT_DATA_IO_PU_PD(100),        PORT_DATA_IO(101),
+       PORT_DATA_IO_PU(102),           PORT_DATA_IO_PU_PD(103),
+       PORT_DATA_IO_PU(104),           PORT_DATA_IO_PU(105),
+       PORT_DATA_IO_PU_PD(106),        PORT_DATA_IO(107),
+       PORT_DATA_IO(108),              PORT_DATA_IO(109),
+
+       PORT_DATA_IO(110),              PORT_DATA_IO(111),
+       PORT_DATA_IO(112),              PORT_DATA_IO(113),
+       PORT_DATA_IO_PU_PD(114),        PORT_DATA_IO(115),
+       PORT_DATA_IO_PD(116),           PORT_DATA_IO_PD(117),
+       PORT_DATA_IO_PD(118),           PORT_DATA_IO_PD(119),
+
+       PORT_DATA_IO_PD(120),           PORT_DATA_IO_PD(121),
+       PORT_DATA_IO_PD(122),           PORT_DATA_IO_PD(123),
+       PORT_DATA_IO_PD(124),           PORT_DATA_IO(125),
+       PORT_DATA_IO(126),              PORT_DATA_IO(127),
+       PORT_DATA_IO(128),              PORT_DATA_IO(129),
+
+       PORT_DATA_IO(130),              PORT_DATA_IO(131),
+       PORT_DATA_IO(132),              PORT_DATA_IO(133),
+       PORT_DATA_IO(134),              PORT_DATA_IO(135),
+       PORT_DATA_IO(136),              PORT_DATA_IO(137),
+       PORT_DATA_IO(138),              PORT_DATA_IO(139),
+
+       PORT_DATA_IO(140),              PORT_DATA_IO(141),
+       PORT_DATA_IO_PU(142),           PORT_DATA_IO_PU(143),
+       PORT_DATA_IO_PU(144),           PORT_DATA_IO_PU(145),
+       PORT_DATA_IO_PU(146),           PORT_DATA_IO_PU(147),
+       PORT_DATA_IO_PU(148),           PORT_DATA_IO_PU(149),
+
+       PORT_DATA_IO_PU(150),           PORT_DATA_IO_PU(151),
+       PORT_DATA_IO_PU(152),           PORT_DATA_IO_PU(153),
+       PORT_DATA_IO_PU(154),           PORT_DATA_IO_PU(155),
+       PORT_DATA_IO_PU(156),           PORT_DATA_IO_PU(157),
+       PORT_DATA_IO_PD(158),           PORT_DATA_IO_PD(159),
+
+       PORT_DATA_IO_PU_PD(160),        PORT_DATA_IO_PD(161),
+       PORT_DATA_IO_PD(162),           PORT_DATA_IO_PD(163),
+       PORT_DATA_IO_PD(164),           PORT_DATA_IO_PD(165),
+       PORT_DATA_IO_PU(166),           PORT_DATA_IO_PU(167),
+       PORT_DATA_IO_PU(168),           PORT_DATA_IO_PU(169),
+
+       PORT_DATA_IO_PU(170),           PORT_DATA_IO_PU(171),
+       PORT_DATA_IO_PD(172),           PORT_DATA_IO_PD(173),
+       PORT_DATA_IO_PD(174),           PORT_DATA_IO_PD(175),
+       PORT_DATA_IO_PU(176),           PORT_DATA_IO_PU_PD(177),
+       PORT_DATA_IO_PU(178),           PORT_DATA_IO_PD(179),
+
+       PORT_DATA_IO_PD(180),           PORT_DATA_IO_PU(181),
+       PORT_DATA_IO_PU(182),           PORT_DATA_IO(183),
+       PORT_DATA_IO_PD(184),           PORT_DATA_IO_PD(185),
+       PORT_DATA_IO_PD(186),           PORT_DATA_IO_PD(187),
+       PORT_DATA_IO_PD(188),           PORT_DATA_IO_PD(189),
+
+       PORT_DATA_IO_PD(190),           PORT_DATA_IO_PD(191),
+       PORT_DATA_IO_PD(192),           PORT_DATA_IO_PU_PD(193),
+       PORT_DATA_IO_PU_PD(194),        PORT_DATA_IO_PD(195),
+       PORT_DATA_IO_PU_PD(196),        PORT_DATA_IO_PD(197),
+       PORT_DATA_IO_PU_PD(198),        PORT_DATA_IO_PU_PD(199),
+
+       PORT_DATA_IO_PU_PD(200),        PORT_DATA_IO_PU(201),
+       PORT_DATA_IO_PU_PD(202),        PORT_DATA_IO(203),
+       PORT_DATA_IO_PU_PD(204),        PORT_DATA_IO_PU_PD(205),
+       PORT_DATA_IO_PU_PD(206),        PORT_DATA_IO_PU_PD(207),
+       PORT_DATA_IO_PU_PD(208),        PORT_DATA_IO_PD(209),
+
+       PORT_DATA_IO_PD(210),           PORT_DATA_IO_PD(211),
+
+       /* Port0 */
+       PINMUX_DATA(DBGMDT2_MARK,               PORT0_FN1),
+       PINMUX_DATA(FSIAISLD_PORT0_MARK,        PORT0_FN2,      MSEL5CR_3_0),
+       PINMUX_DATA(FSIAOSLD1_MARK,             PORT0_FN3),
+       PINMUX_DATA(LCD0_D22_PORT0_MARK,        PORT0_FN4,      MSEL5CR_6_0),
+       PINMUX_DATA(SCIFA7_RXD_MARK,            PORT0_FN6),
+       PINMUX_DATA(LCD1_D4_MARK,               PORT0_FN7),
+       PINMUX_DATA(IRQ5_PORT0_MARK,            PORT0_FN0,      MSEL1CR_5_0),
+
+       /* Port1 */
+       PINMUX_DATA(DBGMDT1_MARK,               PORT1_FN1),
+       PINMUX_DATA(FMSISLD_PORT1_MARK,         PORT1_FN2,      MSEL5CR_5_0),
+       PINMUX_DATA(FSIAOSLD2_MARK,             PORT1_FN3),
+       PINMUX_DATA(LCD0_D23_PORT1_MARK,        PORT1_FN4,      MSEL5CR_6_0),
+       PINMUX_DATA(SCIFA7_TXD_MARK,            PORT1_FN6),
+       PINMUX_DATA(LCD1_D3_MARK,               PORT1_FN7),
+       PINMUX_DATA(IRQ5_PORT1_MARK,            PORT1_FN0,      MSEL1CR_5_1),
+
+       /* Port2 */
+       PINMUX_DATA(DBGMDT0_MARK,               PORT2_FN1),
+       PINMUX_DATA(SCIFB_SCK_PORT2_MARK,       PORT2_FN2,      MSEL5CR_17_1),
+       PINMUX_DATA(LCD0_D21_PORT2_MARK,        PORT2_FN4,      MSEL5CR_6_0),
+       PINMUX_DATA(LCD1_D2_MARK,               PORT2_FN7),
+       PINMUX_DATA(IRQ0_PORT2_MARK,            PORT2_FN0,      MSEL1CR_0_1),
+
+       /* Port3 */
+       PINMUX_DATA(DBGMD21_MARK,               PORT3_FN1),
+       PINMUX_DATA(SCIFB_RXD_PORT3_MARK,       PORT3_FN2,      MSEL5CR_17_1),
+       PINMUX_DATA(LCD0_D20_PORT3_MARK,        PORT3_FN4,      MSEL5CR_6_0),
+       PINMUX_DATA(LCD1_D1_MARK,               PORT3_FN7),
+
+       /* Port4 */
+       PINMUX_DATA(DBGMD20_MARK,               PORT4_FN1),
+       PINMUX_DATA(SCIFB_TXD_PORT4_MARK,       PORT4_FN2,      MSEL5CR_17_1),
+       PINMUX_DATA(LCD0_D19_PORT4_MARK,        PORT4_FN4,      MSEL5CR_6_0),
+       PINMUX_DATA(LCD1_D0_MARK,               PORT4_FN7),
+
+       /* Port5 */
+       PINMUX_DATA(DBGMD11_MARK,               PORT5_FN1),
+       PINMUX_DATA(BBIF2_TXD2_PORT5_MARK,      PORT5_FN2,      MSEL5CR_0_0),
+       PINMUX_DATA(FSIAISLD_PORT5_MARK,        PORT5_FN4,      MSEL5CR_3_1),
+       PINMUX_DATA(RSPI_SSL0_A_MARK,           PORT5_FN6),
+       PINMUX_DATA(LCD1_VCPWC_MARK,            PORT5_FN7),
+
+       /* Port6 */
+       PINMUX_DATA(DBGMD10_MARK,               PORT6_FN1),
+       PINMUX_DATA(BBIF2_TSYNC2_PORT6_MARK,    PORT6_FN2,      MSEL5CR_0_0),
+       PINMUX_DATA(FMSISLD_PORT6_MARK,         PORT6_FN4,      MSEL5CR_5_1),
+       PINMUX_DATA(RSPI_SSL1_A_MARK,           PORT6_FN6),
+       PINMUX_DATA(LCD1_VEPWC_MARK,            PORT6_FN7),
+
+       /* Port7 */
+       PINMUX_DATA(FSIAOLR_MARK,               PORT7_FN1),
+
+       /* Port8 */
+       PINMUX_DATA(FSIAOBT_MARK,               PORT8_FN1),
+
+       /* Port9 */
+       PINMUX_DATA(FSIAOSLD_MARK,              PORT9_FN1),
+       PINMUX_DATA(FSIASPDIF_PORT9_MARK,       PORT9_FN2,      MSEL5CR_4_0),
+
+       /* Port10 */
+       PINMUX_DATA(FSIAOMC_MARK,               PORT10_FN1),
+       PINMUX_DATA(SCIFA5_RXD_PORT10_MARK,     PORT10_FN3,     MSEL5CR_14_0,   MSEL5CR_15_0),
+       PINMUX_DATA(IRQ3_PORT10_MARK,           PORT10_FN0,     MSEL1CR_3_0),
+
+       /* Port11 */
+       PINMUX_DATA(FSIACK_MARK,                PORT11_FN1),
+       PINMUX_DATA(IRQ2_PORT11_MARK,           PORT11_FN0,     MSEL1CR_2_0),
+
+       /* Port12 */
+       PINMUX_DATA(FSIAILR_MARK,               PORT12_FN1),
+       PINMUX_DATA(SCIFA4_RXD_PORT12_MARK,     PORT12_FN2,     MSEL5CR_12_0,   MSEL5CR_11_0),
+       PINMUX_DATA(LCD1_RS_MARK,               PORT12_FN6),
+       PINMUX_DATA(LCD1_DISP_MARK,             PORT12_FN7),
+       PINMUX_DATA(IRQ2_PORT12_MARK,           PORT12_FN0,     MSEL1CR_2_1),
+
+       /* Port13 */
+       PINMUX_DATA(FSIAIBT_MARK,               PORT13_FN1),
+       PINMUX_DATA(SCIFA4_TXD_PORT13_MARK,     PORT13_FN2,     MSEL5CR_12_0,   MSEL5CR_11_0),
+       PINMUX_DATA(LCD1_RD_MARK,               PORT13_FN7),
+       PINMUX_DATA(IRQ0_PORT13_MARK,           PORT13_FN0,     MSEL1CR_0_0),
+
+       /* Port14 */
+       PINMUX_DATA(FMSOILR_MARK,               PORT14_FN1),
+       PINMUX_DATA(FMSIILR_MARK,               PORT14_FN2),
+       PINMUX_DATA(VIO_CKO1_MARK,              PORT14_FN3),
+       PINMUX_DATA(LCD1_D23_MARK,              PORT14_FN7),
+       PINMUX_DATA(IRQ3_PORT14_MARK,           PORT14_FN0,     MSEL1CR_3_1),
+
+       /* Port15 */
+       PINMUX_DATA(FMSOIBT_MARK,               PORT15_FN1),
+       PINMUX_DATA(FMSIIBT_MARK,               PORT15_FN2),
+       PINMUX_DATA(VIO_CKO2_MARK,              PORT15_FN3),
+       PINMUX_DATA(LCD1_D22_MARK,              PORT15_FN7),
+       PINMUX_DATA(IRQ4_PORT15_MARK,           PORT15_FN0,     MSEL1CR_4_0),
+
+       /* Port16 */
+       PINMUX_DATA(FMSOOLR_MARK,               PORT16_FN1),
+       PINMUX_DATA(FMSIOLR_MARK,               PORT16_FN2),
+
+       /* Port17 */
+       PINMUX_DATA(FMSOOBT_MARK,               PORT17_FN1),
+       PINMUX_DATA(FMSIOBT_MARK,               PORT17_FN2),
+
+       /* Port18 */
+       PINMUX_DATA(FMSOSLD_MARK,               PORT18_FN1),
+       PINMUX_DATA(FSIASPDIF_PORT18_MARK,      PORT18_FN2,     MSEL5CR_4_1),
+
+       /* Port19 */
+       PINMUX_DATA(FMSICK_MARK,                PORT19_FN1),
+       PINMUX_DATA(CS5A_PORT19_MARK,           PORT19_FN7,     MSEL5CR_2_1),
+       PINMUX_DATA(IRQ10_MARK,                 PORT19_FN0),
+
+       /* Port20 */
+       PINMUX_DATA(FMSOCK_MARK,                PORT20_FN1),
+       PINMUX_DATA(SCIFA5_TXD_PORT20_MARK,     PORT20_FN3,     MSEL5CR_15_0,   MSEL5CR_14_0),
+       PINMUX_DATA(IRQ1_MARK,                  PORT20_FN0),
+
+       /* Port21 */
+       PINMUX_DATA(SCIFA1_CTS_MARK,            PORT21_FN1),
+       PINMUX_DATA(SCIFA4_SCK_PORT21_MARK,     PORT21_FN2,     MSEL5CR_10_0),
+       PINMUX_DATA(TPU0TO1_MARK,               PORT21_FN4),
+       PINMUX_DATA(VIO1_FIELD_MARK,            PORT21_FN5),
+       PINMUX_DATA(STP0_IPD5_MARK,             PORT21_FN6),
+       PINMUX_DATA(LCD1_D10_MARK,              PORT21_FN7),
+
+       /* Port22 */
+       PINMUX_DATA(SCIFA2_SCK_PORT22_MARK,     PORT22_FN1,     MSEL5CR_7_0),
+       PINMUX_DATA(SIM_D_PORT22_MARK,          PORT22_FN4,     MSEL5CR_21_0),
+       PINMUX_DATA(VIO0_D13_PORT22_MARK,       PORT22_FN7,     MSEL5CR_27_1),
+
+       /* Port23 */
+       PINMUX_DATA(SCIFA1_RTS_MARK,            PORT23_FN1),
+       PINMUX_DATA(SCIFA5_SCK_PORT23_MARK,     PORT23_FN3,     MSEL5CR_13_0),
+       PINMUX_DATA(TPU0TO0_MARK,               PORT23_FN4),
+       PINMUX_DATA(VIO_CKO_1_MARK,             PORT23_FN5),
+       PINMUX_DATA(STP0_IPD2_MARK,             PORT23_FN6),
+       PINMUX_DATA(LCD1_D7_MARK,               PORT23_FN7),
+
+       /* Port24 */
+       PINMUX_DATA(VIO0_D15_PORT24_MARK,       PORT24_FN1,     MSEL5CR_27_0),
+       PINMUX_DATA(VIO1_D7_MARK,               PORT24_FN5),
+       PINMUX_DATA(SCIFA6_SCK_MARK,            PORT24_FN6),
+       PINMUX_DATA(SDHI2_CD_PORT24_MARK,       PORT24_FN7,     MSEL5CR_19_0),
+
+       /* Port25 */
+       PINMUX_DATA(VIO0_D14_PORT25_MARK,       PORT25_FN1,     MSEL5CR_27_0),
+       PINMUX_DATA(VIO1_D6_MARK,               PORT25_FN5),
+       PINMUX_DATA(SCIFA6_RXD_MARK,            PORT25_FN6),
+       PINMUX_DATA(SDHI2_WP_PORT25_MARK,       PORT25_FN7,     MSEL5CR_19_0),
+
+       /* Port26 */
+       PINMUX_DATA(VIO0_D13_PORT26_MARK,       PORT26_FN1,     MSEL5CR_27_0),
+       PINMUX_DATA(VIO1_D5_MARK,               PORT26_FN5),
+       PINMUX_DATA(SCIFA6_TXD_MARK,            PORT26_FN6),
+
+       /* Port27 - Port39 Function */
+       PINMUX_DATA(VIO0_D7_MARK,               PORT27_FN1),
+       PINMUX_DATA(VIO0_D6_MARK,               PORT28_FN1),
+       PINMUX_DATA(VIO0_D5_MARK,               PORT29_FN1),
+       PINMUX_DATA(VIO0_D4_MARK,               PORT30_FN1),
+       PINMUX_DATA(VIO0_D3_MARK,               PORT31_FN1),
+       PINMUX_DATA(VIO0_D2_MARK,               PORT32_FN1),
+       PINMUX_DATA(VIO0_D1_MARK,               PORT33_FN1),
+       PINMUX_DATA(VIO0_D0_MARK,               PORT34_FN1),
+       PINMUX_DATA(VIO0_CLK_MARK,              PORT35_FN1),
+       PINMUX_DATA(VIO_CKO_MARK,               PORT36_FN1),
+       PINMUX_DATA(VIO0_HD_MARK,               PORT37_FN1),
+       PINMUX_DATA(VIO0_FIELD_MARK,            PORT38_FN1),
+       PINMUX_DATA(VIO0_VD_MARK,               PORT39_FN1),
+
+       /* Port38 IRQ */
+       PINMUX_DATA(IRQ25_MARK,                 PORT38_FN0),
+
+       /* Port40 */
+       PINMUX_DATA(LCD0_D18_PORT40_MARK,       PORT40_FN4,     MSEL5CR_6_0),
+       PINMUX_DATA(RSPI_CK_A_MARK,             PORT40_FN6),
+       PINMUX_DATA(LCD1_LCLK_MARK,             PORT40_FN7),
+
+       /* Port41 */
+       PINMUX_DATA(LCD0_D17_MARK,              PORT41_FN1),
+       PINMUX_DATA(MSIOF2_SS1_MARK,            PORT41_FN2),
+       PINMUX_DATA(IRQ31_PORT41_MARK,          PORT41_FN0,     MSEL1CR_31_1),
+
+       /* Port42 */
+       PINMUX_DATA(LCD0_D16_MARK,              PORT42_FN1),
+       PINMUX_DATA(MSIOF2_MCK1_MARK,           PORT42_FN2),
+       PINMUX_DATA(IRQ12_PORT42_MARK,          PORT42_FN0,     MSEL1CR_12_1),
+
+       /* Port43 */
+       PINMUX_DATA(LCD0_D15_MARK,              PORT43_FN1),
+       PINMUX_DATA(MSIOF2_MCK0_MARK,           PORT43_FN2),
+       PINMUX_DATA(KEYIN0_PORT43_MARK,         PORT43_FN3,     MSEL4CR_18_0),
+       PINMUX_DATA(DV_D15_MARK,                PORT43_FN6),
+
+       /* Port44 */
+       PINMUX_DATA(LCD0_D14_MARK,              PORT44_FN1),
+       PINMUX_DATA(MSIOF2_RSYNC_MARK,          PORT44_FN2),
+       PINMUX_DATA(KEYIN1_PORT44_MARK,         PORT44_FN3,     MSEL4CR_18_0),
+       PINMUX_DATA(DV_D14_MARK,                PORT44_FN6),
+
+       /* Port45 */
+       PINMUX_DATA(LCD0_D13_MARK,              PORT45_FN1),
+       PINMUX_DATA(MSIOF2_RSCK_MARK,           PORT45_FN2),
+       PINMUX_DATA(KEYIN2_PORT45_MARK,         PORT45_FN3,     MSEL4CR_18_0),
+       PINMUX_DATA(DV_D13_MARK,                PORT45_FN6),
+
+       /* Port46 */
+       PINMUX_DATA(LCD0_D12_MARK,              PORT46_FN1),
+       PINMUX_DATA(KEYIN3_PORT46_MARK,         PORT46_FN3,     MSEL4CR_18_0),
+       PINMUX_DATA(DV_D12_MARK,                PORT46_FN6),
+
+       /* Port47 */
+       PINMUX_DATA(LCD0_D11_MARK,              PORT47_FN1),
+       PINMUX_DATA(KEYIN4_MARK,                PORT47_FN3),
+       PINMUX_DATA(DV_D11_MARK,                PORT47_FN6),
+
+       /* Port48 */
+       PINMUX_DATA(LCD0_D10_MARK,              PORT48_FN1),
+       PINMUX_DATA(KEYIN5_MARK,                PORT48_FN3),
+       PINMUX_DATA(DV_D10_MARK,                PORT48_FN6),
+
+       /* Port49 */
+       PINMUX_DATA(LCD0_D9_MARK,               PORT49_FN1),
+       PINMUX_DATA(KEYIN6_MARK,                PORT49_FN3),
+       PINMUX_DATA(DV_D9_MARK,                 PORT49_FN6),
+       PINMUX_DATA(IRQ30_PORT49_MARK,          PORT49_FN0,     MSEL1CR_30_1),
+
+       /* Port50 */
+       PINMUX_DATA(LCD0_D8_MARK,               PORT50_FN1),
+       PINMUX_DATA(KEYIN7_MARK,                PORT50_FN3),
+       PINMUX_DATA(DV_D8_MARK,                 PORT50_FN6),
+       PINMUX_DATA(IRQ29_PORT50_MARK,          PORT50_FN0,     MSEL1CR_29_1),
+
+       /* Port51 */
+       PINMUX_DATA(LCD0_D7_MARK,               PORT51_FN1),
+       PINMUX_DATA(KEYOUT0_MARK,               PORT51_FN3),
+       PINMUX_DATA(DV_D7_MARK,                 PORT51_FN6),
+
+       /* Port52 */
+       PINMUX_DATA(LCD0_D6_MARK,               PORT52_FN1),
+       PINMUX_DATA(KEYOUT1_MARK,               PORT52_FN3),
+       PINMUX_DATA(DV_D6_MARK,                 PORT52_FN6),
+
+       /* Port53 */
+       PINMUX_DATA(LCD0_D5_MARK,               PORT53_FN1),
+       PINMUX_DATA(KEYOUT2_MARK,               PORT53_FN3),
+       PINMUX_DATA(DV_D5_MARK,                 PORT53_FN6),
+
+       /* Port54 */
+       PINMUX_DATA(LCD0_D4_MARK,               PORT54_FN1),
+       PINMUX_DATA(KEYOUT3_MARK,               PORT54_FN3),
+       PINMUX_DATA(DV_D4_MARK,                 PORT54_FN6),
+
+       /* Port55 */
+       PINMUX_DATA(LCD0_D3_MARK,               PORT55_FN1),
+       PINMUX_DATA(KEYOUT4_MARK,               PORT55_FN3),
+       PINMUX_DATA(KEYIN3_PORT55_MARK,         PORT55_FN4,     MSEL4CR_18_1),
+       PINMUX_DATA(DV_D3_MARK,                 PORT55_FN6),
+
+       /* Port56 */
+       PINMUX_DATA(LCD0_D2_MARK,               PORT56_FN1),
+       PINMUX_DATA(KEYOUT5_MARK,               PORT56_FN3),
+       PINMUX_DATA(KEYIN2_PORT56_MARK,         PORT56_FN4,     MSEL4CR_18_1),
+       PINMUX_DATA(DV_D2_MARK,                 PORT56_FN6),
+       PINMUX_DATA(IRQ28_PORT56_MARK,          PORT56_FN0,     MSEL1CR_28_1),
+
+       /* Port57 */
+       PINMUX_DATA(LCD0_D1_MARK,               PORT57_FN1),
+       PINMUX_DATA(KEYOUT6_MARK,               PORT57_FN3),
+       PINMUX_DATA(KEYIN1_PORT57_MARK,         PORT57_FN4,     MSEL4CR_18_1),
+       PINMUX_DATA(DV_D1_MARK,                 PORT57_FN6),
+       PINMUX_DATA(IRQ27_PORT57_MARK,          PORT57_FN0,     MSEL1CR_27_1),
+
+       /* Port58 */
+       PINMUX_DATA(LCD0_D0_MARK,               PORT58_FN1),
+       PINMUX_DATA(KEYOUT7_MARK,               PORT58_FN3),
+       PINMUX_DATA(KEYIN0_PORT58_MARK,         PORT58_FN4,     MSEL4CR_18_1),
+       PINMUX_DATA(DV_D0_MARK,                 PORT58_FN6),
+       PINMUX_DATA(IRQ26_PORT58_MARK,          PORT58_FN0,     MSEL1CR_26_1),
+
+       /* Port59 */
+       PINMUX_DATA(LCD0_VCPWC_MARK,            PORT59_FN1),
+       PINMUX_DATA(BBIF2_TSCK2_PORT59_MARK,    PORT59_FN2,     MSEL5CR_0_0),
+       PINMUX_DATA(RSPI_MOSI_A_MARK,           PORT59_FN6),
+
+       /* Port60 */
+       PINMUX_DATA(LCD0_VEPWC_MARK,            PORT60_FN1),
+       PINMUX_DATA(BBIF2_RXD2_PORT60_MARK,     PORT60_FN2,     MSEL5CR_0_0),
+       PINMUX_DATA(RSPI_MISO_A_MARK,           PORT60_FN6),
+
+       /* Port61 */
+       PINMUX_DATA(LCD0_DON_MARK,              PORT61_FN1),
+       PINMUX_DATA(MSIOF2_TXD_MARK,            PORT61_FN2),
+
+       /* Port62 */
+       PINMUX_DATA(LCD0_DCK_MARK,              PORT62_FN1),
+       PINMUX_DATA(LCD0_WR_MARK,               PORT62_FN4),
+       PINMUX_DATA(DV_CLK_MARK,                PORT62_FN6),
+       PINMUX_DATA(IRQ15_PORT62_MARK,          PORT62_FN0,     MSEL1CR_15_1),
+
+       /* Port63 */
+       PINMUX_DATA(LCD0_VSYN_MARK,             PORT63_FN1),
+       PINMUX_DATA(DV_VSYNC_MARK,              PORT63_FN6),
+       PINMUX_DATA(IRQ14_PORT63_MARK,          PORT63_FN0,     MSEL1CR_14_1),
+
+       /* Port64 */
+       PINMUX_DATA(LCD0_HSYN_MARK,             PORT64_FN1),
+       PINMUX_DATA(LCD0_CS_MARK,               PORT64_FN4),
+       PINMUX_DATA(DV_HSYNC_MARK,              PORT64_FN6),
+       PINMUX_DATA(IRQ13_PORT64_MARK,          PORT64_FN0,     MSEL1CR_13_1),
+
+       /* Port65 */
+       PINMUX_DATA(LCD0_DISP_MARK,             PORT65_FN1),
+       PINMUX_DATA(MSIOF2_TSCK_MARK,           PORT65_FN2),
+       PINMUX_DATA(LCD0_RS_MARK,               PORT65_FN4),
+
+       /* Port66 */
+       PINMUX_DATA(MEMC_INT_MARK,              PORT66_FN1),
+       PINMUX_DATA(TPU0TO2_PORT66_MARK,        PORT66_FN3,     MSEL5CR_25_0),
+       PINMUX_DATA(MMC0_CLK_PORT66_MARK,       PORT66_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(SDHI1_CLK_MARK,             PORT66_FN6),
+
+       /* Port67 - Port73 Function1 */
+       PINMUX_DATA(MEMC_CS0_MARK,              PORT67_FN1),
+       PINMUX_DATA(MEMC_AD8_MARK,              PORT68_FN1),
+       PINMUX_DATA(MEMC_AD9_MARK,              PORT69_FN1),
+       PINMUX_DATA(MEMC_AD10_MARK,             PORT70_FN1),
+       PINMUX_DATA(MEMC_AD11_MARK,             PORT71_FN1),
+       PINMUX_DATA(MEMC_AD12_MARK,             PORT72_FN1),
+       PINMUX_DATA(MEMC_AD13_MARK,             PORT73_FN1),
+
+       /* Port67 - Port73 Function2 */
+       PINMUX_DATA(MSIOF1_SS1_PORT67_MARK,     PORT67_FN2,     MSEL4CR_10_1),
+       PINMUX_DATA(MSIOF1_RSCK_MARK,           PORT68_FN2),
+       PINMUX_DATA(MSIOF1_RSYNC_MARK,          PORT69_FN2),
+       PINMUX_DATA(MSIOF1_MCK0_MARK,           PORT70_FN2),
+       PINMUX_DATA(MSIOF1_MCK1_MARK,           PORT71_FN2),
+       PINMUX_DATA(MSIOF1_TSCK_PORT72_MARK,    PORT72_FN2,     MSEL4CR_10_1),
+       PINMUX_DATA(MSIOF1_TSYNC_PORT73_MARK,   PORT73_FN2,     MSEL4CR_10_1),
+
+       /* Port67 - Port73 Function4 */
+       PINMUX_DATA(MMC0_CMD_PORT67_MARK,       PORT67_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D0_PORT68_MARK,        PORT68_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D1_PORT69_MARK,        PORT69_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D2_PORT70_MARK,        PORT70_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D3_PORT71_MARK,        PORT71_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D4_PORT72_MARK,        PORT72_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(MMC0_D5_PORT73_MARK,        PORT73_FN4,     MSEL4CR_15_0),
+
+       /* Port67 - Port73 Function6 */
+       PINMUX_DATA(SDHI1_CMD_MARK,             PORT67_FN6),
+       PINMUX_DATA(SDHI1_D0_MARK,              PORT68_FN6),
+       PINMUX_DATA(SDHI1_D1_MARK,              PORT69_FN6),
+       PINMUX_DATA(SDHI1_D2_MARK,              PORT70_FN6),
+       PINMUX_DATA(SDHI1_D3_MARK,              PORT71_FN6),
+       PINMUX_DATA(SDHI1_CD_MARK,              PORT72_FN6),
+       PINMUX_DATA(SDHI1_WP_MARK,              PORT73_FN6),
+
+       /* Port67 - Port71 IRQ */
+       PINMUX_DATA(IRQ20_MARK,                 PORT67_FN0),
+       PINMUX_DATA(IRQ16_PORT68_MARK,          PORT68_FN0,     MSEL1CR_16_0),
+       PINMUX_DATA(IRQ17_MARK,                 PORT69_FN0),
+       PINMUX_DATA(IRQ18_MARK,                 PORT70_FN0),
+       PINMUX_DATA(IRQ19_MARK,                 PORT71_FN0),
+
+       /* Port74 */
+       PINMUX_DATA(MEMC_AD14_MARK,             PORT74_FN1),
+       PINMUX_DATA(MSIOF1_TXD_PORT74_MARK,     PORT74_FN2,     MSEL4CR_10_1),
+       PINMUX_DATA(MMC0_D6_PORT74_MARK,        PORT74_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(STP1_IPD7_MARK,             PORT74_FN6),
+       PINMUX_DATA(LCD1_D21_MARK,              PORT74_FN7),
+
+       /* Port75 */
+       PINMUX_DATA(MEMC_AD15_MARK,             PORT75_FN1),
+       PINMUX_DATA(MSIOF1_RXD_PORT75_MARK,     PORT75_FN2,     MSEL4CR_10_1),
+       PINMUX_DATA(MMC0_D7_PORT75_MARK,        PORT75_FN4,     MSEL4CR_15_0),
+       PINMUX_DATA(STP1_IPD6_MARK,             PORT75_FN6),
+       PINMUX_DATA(LCD1_D20_MARK,              PORT75_FN7),
+
+       /* Port76 - Port80 Function */
+       PINMUX_DATA(SDHI0_CMD_MARK,             PORT76_FN1),
+       PINMUX_DATA(SDHI0_D0_MARK,              PORT77_FN1),
+       PINMUX_DATA(SDHI0_D1_MARK,              PORT78_FN1),
+       PINMUX_DATA(SDHI0_D2_MARK,              PORT79_FN1),
+       PINMUX_DATA(SDHI0_D3_MARK,              PORT80_FN1),
+
+       /* Port81 */
+       PINMUX_DATA(SDHI0_CD_MARK,              PORT81_FN1),
+       PINMUX_DATA(IRQ26_PORT81_MARK,          PORT81_FN0,     MSEL1CR_26_0),
+
+       /* Port82 - Port88 Function */
+       PINMUX_DATA(SDHI0_CLK_MARK,             PORT82_FN1),
+       PINMUX_DATA(SDHI0_WP_MARK,              PORT83_FN1),
+       PINMUX_DATA(RESETOUTS_MARK,             PORT84_FN1),
+       PINMUX_DATA(USB0_PPON_MARK,             PORT85_FN1),
+       PINMUX_DATA(USB0_OCI_MARK,              PORT86_FN1),
+       PINMUX_DATA(USB1_PPON_MARK,             PORT87_FN1),
+       PINMUX_DATA(USB1_OCI_MARK,              PORT88_FN1),
+
+       /* Port89 */
+       PINMUX_DATA(DREQ0_MARK,                 PORT89_FN1),
+       PINMUX_DATA(BBIF2_TSCK2_PORT89_MARK,    PORT89_FN2,     MSEL5CR_0_1),
+       PINMUX_DATA(RSPI_SSL3_A_MARK,           PORT89_FN6),
+
+       /* Port90 */
+       PINMUX_DATA(DACK0_MARK,                 PORT90_FN1),
+       PINMUX_DATA(BBIF2_RXD2_PORT90_MARK,     PORT90_FN2,     MSEL5CR_0_1),
+       PINMUX_DATA(RSPI_SSL2_A_MARK,           PORT90_FN6),
+       PINMUX_DATA(WAIT_PORT90_MARK,           PORT90_FN7,     MSEL5CR_2_1),
+
+       /* Port91 */
+       PINMUX_DATA(MEMC_AD0_MARK,              PORT91_FN1),
+       PINMUX_DATA(BBIF1_RXD_MARK,             PORT91_FN2),
+       PINMUX_DATA(SCIFA5_TXD_PORT91_MARK,     PORT91_FN3,     MSEL5CR_15_1,   MSEL5CR_14_0),
+       PINMUX_DATA(LCD1_D5_MARK,               PORT91_FN7),
+
+       /* Port92 */
+       PINMUX_DATA(MEMC_AD1_MARK,              PORT92_FN1),
+       PINMUX_DATA(BBIF1_TSYNC_MARK,           PORT92_FN2),
+       PINMUX_DATA(SCIFA5_RXD_PORT92_MARK,     PORT92_FN3,     MSEL5CR_15_1,   MSEL5CR_14_0),
+       PINMUX_DATA(STP0_IPD1_MARK,             PORT92_FN6),
+       PINMUX_DATA(LCD1_D6_MARK,               PORT92_FN7),
+
+       /* Port93 */
+       PINMUX_DATA(MEMC_AD2_MARK,              PORT93_FN1),
+       PINMUX_DATA(BBIF1_TSCK_MARK,            PORT93_FN2),
+       PINMUX_DATA(SCIFA4_TXD_PORT93_MARK,     PORT93_FN3,     MSEL5CR_12_1,   MSEL5CR_11_0),
+       PINMUX_DATA(STP0_IPD3_MARK,             PORT93_FN6),
+       PINMUX_DATA(LCD1_D8_MARK,               PORT93_FN7),
+
+       /* Port94 */
+       PINMUX_DATA(MEMC_AD3_MARK,              PORT94_FN1),
+       PINMUX_DATA(BBIF1_TXD_MARK,             PORT94_FN2),
+       PINMUX_DATA(SCIFA4_RXD_PORT94_MARK,     PORT94_FN3,     MSEL5CR_12_1,   MSEL5CR_11_0),
+       PINMUX_DATA(STP0_IPD4_MARK,             PORT94_FN6),
+       PINMUX_DATA(LCD1_D9_MARK,               PORT94_FN7),
+
+       /* Port95 */
+       PINMUX_DATA(MEMC_CS1_MARK,              PORT95_FN1,     MSEL4CR_6_0),
+       PINMUX_DATA(MEMC_A1_MARK,               PORT95_FN1,     MSEL4CR_6_1),
+
+       PINMUX_DATA(SCIFA2_CTS_MARK,            PORT95_FN2),
+       PINMUX_DATA(SIM_RST_MARK,               PORT95_FN4),
+       PINMUX_DATA(VIO0_D14_PORT95_MARK,       PORT95_FN7,     MSEL5CR_27_1),
+       PINMUX_DATA(IRQ22_MARK,                 PORT95_FN0),
+
+       /* Port96 */
+       PINMUX_DATA(MEMC_ADV_MARK,              PORT96_FN1,     MSEL4CR_6_0),
+       PINMUX_DATA(MEMC_DREQ0_MARK,            PORT96_FN1,     MSEL4CR_6_1),
+
+       PINMUX_DATA(SCIFA2_RTS_MARK,            PORT96_FN2),
+       PINMUX_DATA(SIM_CLK_MARK,               PORT96_FN4),
+       PINMUX_DATA(VIO0_D15_PORT96_MARK,       PORT96_FN7,     MSEL5CR_27_1),
+       PINMUX_DATA(IRQ23_MARK,                 PORT96_FN0),
+
+       /* Port97 */
+       PINMUX_DATA(MEMC_AD4_MARK,              PORT97_FN1),
+       PINMUX_DATA(BBIF1_RSCK_MARK,            PORT97_FN2),
+       PINMUX_DATA(LCD1_CS_MARK,               PORT97_FN6),
+       PINMUX_DATA(LCD1_HSYN_MARK,             PORT97_FN7),
+       PINMUX_DATA(IRQ12_PORT97_MARK,          PORT97_FN0,     MSEL1CR_12_0),
+
+       /* Port98 */
+       PINMUX_DATA(MEMC_AD5_MARK,              PORT98_FN1),
+       PINMUX_DATA(BBIF1_RSYNC_MARK,           PORT98_FN2),
+       PINMUX_DATA(LCD1_VSYN_MARK,             PORT98_FN7),
+       PINMUX_DATA(IRQ13_PORT98_MARK,          PORT98_FN0,     MSEL1CR_13_0),
+
+       /* Port99 */
+       PINMUX_DATA(MEMC_AD6_MARK,              PORT99_FN1),
+       PINMUX_DATA(BBIF1_FLOW_MARK,            PORT99_FN2),
+       PINMUX_DATA(LCD1_WR_MARK,               PORT99_FN6),
+       PINMUX_DATA(LCD1_DCK_MARK,              PORT99_FN7),
+       PINMUX_DATA(IRQ14_PORT99_MARK,          PORT99_FN0,     MSEL1CR_14_0),
+
+       /* Port100 */
+       PINMUX_DATA(MEMC_AD7_MARK,              PORT100_FN1),
+       PINMUX_DATA(BBIF1_RX_FLOW_N_MARK,       PORT100_FN2),
+       PINMUX_DATA(LCD1_DON_MARK,              PORT100_FN7),
+       PINMUX_DATA(IRQ15_PORT100_MARK,         PORT100_FN0,    MSEL1CR_15_0),
+
+       /* Port101 */
+       PINMUX_DATA(FCE0_MARK,                  PORT101_FN1),
+
+       /* Port102 */
+       PINMUX_DATA(FRB_MARK,                   PORT102_FN1),
+       PINMUX_DATA(LCD0_LCLK_PORT102_MARK,     PORT102_FN4,    MSEL5CR_6_0),
+
+       /* Port103 */
+       PINMUX_DATA(CS5B_MARK,                  PORT103_FN1),
+       PINMUX_DATA(FCE1_MARK,                  PORT103_FN2),
+       PINMUX_DATA(MMC1_CLK_PORT103_MARK,      PORT103_FN3,    MSEL4CR_15_1),
+
+       /* Port104 */
+       PINMUX_DATA(CS6A_MARK,                  PORT104_FN1),
+       PINMUX_DATA(MMC1_CMD_PORT104_MARK,      PORT104_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(IRQ11_MARK,                 PORT104_FN0),
+
+       /* Port105 */
+       PINMUX_DATA(CS5A_PORT105_MARK,          PORT105_FN1,    MSEL5CR_2_0),
+       PINMUX_DATA(SCIFA3_RTS_PORT105_MARK,    PORT105_FN4,    MSEL5CR_8_0),
+
+       /* Port106 */
+       PINMUX_DATA(IOIS16_MARK,                PORT106_FN1),
+       PINMUX_DATA(IDE_EXBUF_ENB_MARK,         PORT106_FN6),
+
+       /* Port107 - Port115 Function */
+       PINMUX_DATA(WE3_ICIOWR_MARK,            PORT107_FN1),
+       PINMUX_DATA(WE2_ICIORD_MARK,            PORT108_FN1),
+       PINMUX_DATA(CS0_MARK,                   PORT109_FN1),
+       PINMUX_DATA(CS2_MARK,                   PORT110_FN1),
+       PINMUX_DATA(CS4_MARK,                   PORT111_FN1),
+       PINMUX_DATA(WE1_MARK,                   PORT112_FN1),
+       PINMUX_DATA(WE0_FWE_MARK,               PORT113_FN1),
+       PINMUX_DATA(RDWR_MARK,                  PORT114_FN1),
+       PINMUX_DATA(RD_FSC_MARK,                PORT115_FN1),
+
+       /* Port116 */
+       PINMUX_DATA(A25_MARK,                   PORT116_FN1),
+       PINMUX_DATA(MSIOF0_SS2_MARK,            PORT116_FN2),
+       PINMUX_DATA(MSIOF1_SS2_PORT116_MARK,    PORT116_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(SCIFA3_SCK_PORT116_MARK,    PORT116_FN4,    MSEL5CR_8_0),
+       PINMUX_DATA(GPO1_MARK,                  PORT116_FN5),
+
+       /* Port117 */
+       PINMUX_DATA(A24_MARK,                   PORT117_FN1),
+       PINMUX_DATA(MSIOF0_SS1_MARK,            PORT117_FN2),
+       PINMUX_DATA(MSIOF1_SS1_PORT117_MARK,    PORT117_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(SCIFA3_CTS_PORT117_MARK,    PORT117_FN4,    MSEL5CR_8_0),
+       PINMUX_DATA(GPO0_MARK,                  PORT117_FN5),
+
+       /* Port118 */
+       PINMUX_DATA(A23_MARK,                   PORT118_FN1),
+       PINMUX_DATA(MSIOF0_MCK1_MARK,           PORT118_FN2),
+       PINMUX_DATA(MSIOF1_RXD_PORT118_MARK,    PORT118_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(GPI1_MARK,                  PORT118_FN5),
+       PINMUX_DATA(IRQ9_PORT118_MARK,          PORT118_FN0,    MSEL1CR_9_0),
+
+       /* Port119 */
+       PINMUX_DATA(A22_MARK,                   PORT119_FN1),
+       PINMUX_DATA(MSIOF0_MCK0_MARK,           PORT119_FN2),
+       PINMUX_DATA(MSIOF1_TXD_PORT119_MARK,    PORT119_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(GPI0_MARK,                  PORT119_FN5),
+       PINMUX_DATA(IRQ8_MARK,                  PORT119_FN0),
+
+       /* Port120 */
+       PINMUX_DATA(A21_MARK,                   PORT120_FN1),
+       PINMUX_DATA(MSIOF0_RSYNC_MARK,          PORT120_FN2),
+       PINMUX_DATA(MSIOF1_TSYNC_PORT120_MARK,  PORT120_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(IRQ7_PORT120_MARK,          PORT120_FN0,    MSEL1CR_7_0),
+
+       /* Port121 */
+       PINMUX_DATA(A20_MARK,                   PORT121_FN1),
+       PINMUX_DATA(MSIOF0_RSCK_MARK,           PORT121_FN2),
+       PINMUX_DATA(MSIOF1_TSCK_PORT121_MARK,   PORT121_FN3,    MSEL4CR_10_0),
+       PINMUX_DATA(IRQ6_PORT121_MARK,          PORT121_FN0,    MSEL1CR_6_0),
+
+       /* Port122 */
+       PINMUX_DATA(A19_MARK,                   PORT122_FN1),
+       PINMUX_DATA(MSIOF0_RXD_MARK,            PORT122_FN2),
+
+       /* Port123 */
+       PINMUX_DATA(A18_MARK,                   PORT123_FN1),
+       PINMUX_DATA(MSIOF0_TSCK_MARK,           PORT123_FN2),
+
+       /* Port124 */
+       PINMUX_DATA(A17_MARK,                   PORT124_FN1),
+       PINMUX_DATA(MSIOF0_TSYNC_MARK,          PORT124_FN2),
+
+       /* Port125 - Port141 Function */
+       PINMUX_DATA(A16_MARK,                   PORT125_FN1),
+       PINMUX_DATA(A15_MARK,                   PORT126_FN1),
+       PINMUX_DATA(A14_MARK,                   PORT127_FN1),
+       PINMUX_DATA(A13_MARK,                   PORT128_FN1),
+       PINMUX_DATA(A12_MARK,                   PORT129_FN1),
+       PINMUX_DATA(A11_MARK,                   PORT130_FN1),
+       PINMUX_DATA(A10_MARK,                   PORT131_FN1),
+       PINMUX_DATA(A9_MARK,                    PORT132_FN1),
+       PINMUX_DATA(A8_MARK,                    PORT133_FN1),
+       PINMUX_DATA(A7_MARK,                    PORT134_FN1),
+       PINMUX_DATA(A6_MARK,                    PORT135_FN1),
+       PINMUX_DATA(A5_FCDE_MARK,               PORT136_FN1),
+       PINMUX_DATA(A4_FOE_MARK,                PORT137_FN1),
+       PINMUX_DATA(A3_MARK,                    PORT138_FN1),
+       PINMUX_DATA(A2_MARK,                    PORT139_FN1),
+       PINMUX_DATA(A1_MARK,                    PORT140_FN1),
+       PINMUX_DATA(CKO_MARK,                   PORT141_FN1),
+
+       /* Port142 - Port157 Function1 */
+       PINMUX_DATA(D15_NAF15_MARK,             PORT142_FN1),
+       PINMUX_DATA(D14_NAF14_MARK,             PORT143_FN1),
+       PINMUX_DATA(D13_NAF13_MARK,             PORT144_FN1),
+       PINMUX_DATA(D12_NAF12_MARK,             PORT145_FN1),
+       PINMUX_DATA(D11_NAF11_MARK,             PORT146_FN1),
+       PINMUX_DATA(D10_NAF10_MARK,             PORT147_FN1),
+       PINMUX_DATA(D9_NAF9_MARK,               PORT148_FN1),
+       PINMUX_DATA(D8_NAF8_MARK,               PORT149_FN1),
+       PINMUX_DATA(D7_NAF7_MARK,               PORT150_FN1),
+       PINMUX_DATA(D6_NAF6_MARK,               PORT151_FN1),
+       PINMUX_DATA(D5_NAF5_MARK,               PORT152_FN1),
+       PINMUX_DATA(D4_NAF4_MARK,               PORT153_FN1),
+       PINMUX_DATA(D3_NAF3_MARK,               PORT154_FN1),
+       PINMUX_DATA(D2_NAF2_MARK,               PORT155_FN1),
+       PINMUX_DATA(D1_NAF1_MARK,               PORT156_FN1),
+       PINMUX_DATA(D0_NAF0_MARK,               PORT157_FN1),
+
+       /* Port142 - Port149 Function3 */
+       PINMUX_DATA(MMC1_D7_PORT142_MARK,       PORT142_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D6_PORT143_MARK,       PORT143_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D5_PORT144_MARK,       PORT144_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D4_PORT145_MARK,       PORT145_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D3_PORT146_MARK,       PORT146_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D2_PORT147_MARK,       PORT147_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D1_PORT148_MARK,       PORT148_FN3,    MSEL4CR_15_1),
+       PINMUX_DATA(MMC1_D0_PORT149_MARK,       PORT149_FN3,    MSEL4CR_15_1),
+
+       /* Port158 */
+       PINMUX_DATA(D31_MARK,                   PORT158_FN1),
+       PINMUX_DATA(SCIFA3_SCK_PORT158_MARK,    PORT158_FN2,    MSEL5CR_8_1),
+       PINMUX_DATA(RMII_REF125CK_MARK,         PORT158_FN3),
+       PINMUX_DATA(LCD0_D21_PORT158_MARK,      PORT158_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IRDA_FIRSEL_MARK,           PORT158_FN5),
+       PINMUX_DATA(IDE_D15_MARK,               PORT158_FN6),
+
+       /* Port159 */
+       PINMUX_DATA(D30_MARK,                   PORT159_FN1),
+       PINMUX_DATA(SCIFA3_RXD_PORT159_MARK,    PORT159_FN2,    MSEL5CR_8_1),
+       PINMUX_DATA(RMII_REF50CK_MARK,          PORT159_FN3),
+       PINMUX_DATA(LCD0_D23_PORT159_MARK,      PORT159_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IDE_D14_MARK,               PORT159_FN6),
+
+       /* Port160 */
+       PINMUX_DATA(D29_MARK,                   PORT160_FN1),
+       PINMUX_DATA(SCIFA3_TXD_PORT160_MARK,    PORT160_FN2,    MSEL5CR_8_1),
+       PINMUX_DATA(LCD0_D22_PORT160_MARK,      PORT160_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(VIO1_HD_MARK,               PORT160_FN5),
+       PINMUX_DATA(IDE_D13_MARK,               PORT160_FN6),
+
+       /* Port161 */
+       PINMUX_DATA(D28_MARK,                   PORT161_FN1),
+       PINMUX_DATA(SCIFA3_RTS_PORT161_MARK,    PORT161_FN2,    MSEL5CR_8_1),
+       PINMUX_DATA(ET_RX_DV_MARK,              PORT161_FN3),
+       PINMUX_DATA(LCD0_D20_PORT161_MARK,      PORT161_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IRDA_IN_MARK,               PORT161_FN5),
+       PINMUX_DATA(IDE_D12_MARK,               PORT161_FN6),
+
+       /* Port162 */
+       PINMUX_DATA(D27_MARK,                   PORT162_FN1),
+       PINMUX_DATA(SCIFA3_CTS_PORT162_MARK,    PORT162_FN2,    MSEL5CR_8_1),
+       PINMUX_DATA(LCD0_D19_PORT162_MARK,      PORT162_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IRDA_OUT_MARK,              PORT162_FN5),
+       PINMUX_DATA(IDE_D11_MARK,               PORT162_FN6),
+
+       /* Port163 */
+       PINMUX_DATA(D26_MARK,                   PORT163_FN1),
+       PINMUX_DATA(MSIOF2_SS2_MARK,            PORT163_FN2),
+       PINMUX_DATA(ET_COL_MARK,                PORT163_FN3),
+       PINMUX_DATA(LCD0_D18_PORT163_MARK,      PORT163_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IROUT_MARK,                 PORT163_FN5),
+       PINMUX_DATA(IDE_D10_MARK,               PORT163_FN6),
+
+       /* Port164 */
+       PINMUX_DATA(D25_MARK,                   PORT164_FN1),
+       PINMUX_DATA(MSIOF2_TSYNC_MARK,          PORT164_FN2),
+       PINMUX_DATA(ET_PHY_INT_MARK,            PORT164_FN3),
+       PINMUX_DATA(LCD0_RD_MARK,               PORT164_FN4),
+       PINMUX_DATA(IDE_D9_MARK,                PORT164_FN6),
+
+       /* Port165 */
+       PINMUX_DATA(D24_MARK,                   PORT165_FN1),
+       PINMUX_DATA(MSIOF2_RXD_MARK,            PORT165_FN2),
+       PINMUX_DATA(LCD0_LCLK_PORT165_MARK,     PORT165_FN4,    MSEL5CR_6_1),
+       PINMUX_DATA(IDE_D8_MARK,                PORT165_FN6),
+
+       /* Port166 - Port171 Function1 */
+       PINMUX_DATA(D21_MARK,                   PORT166_FN1),
+       PINMUX_DATA(D20_MARK,                   PORT167_FN1),
+       PINMUX_DATA(D19_MARK,                   PORT168_FN1),
+       PINMUX_DATA(D18_MARK,                   PORT169_FN1),
+       PINMUX_DATA(D17_MARK,                   PORT170_FN1),
+       PINMUX_DATA(D16_MARK,                   PORT171_FN1),
+
+       /* Port166 - Port171 Function3 */
+       PINMUX_DATA(ET_ETXD5_MARK,              PORT166_FN3),
+       PINMUX_DATA(ET_ETXD4_MARK,              PORT167_FN3),
+       PINMUX_DATA(ET_ETXD3_MARK,              PORT168_FN3),
+       PINMUX_DATA(ET_ETXD2_MARK,              PORT169_FN3),
+       PINMUX_DATA(ET_ETXD1_MARK,              PORT170_FN3),
+       PINMUX_DATA(ET_ETXD0_MARK,              PORT171_FN3),
+
+       /* Port166 - Port171 Function6 */
+       PINMUX_DATA(IDE_D5_MARK,                PORT166_FN6),
+       PINMUX_DATA(IDE_D4_MARK,                PORT167_FN6),
+       PINMUX_DATA(IDE_D3_MARK,                PORT168_FN6),
+       PINMUX_DATA(IDE_D2_MARK,                PORT169_FN6),
+       PINMUX_DATA(IDE_D1_MARK,                PORT170_FN6),
+       PINMUX_DATA(IDE_D0_MARK,                PORT171_FN6),
+
+       /* Port167 - Port171 IRQ */
+       PINMUX_DATA(IRQ31_PORT167_MARK,         PORT167_FN0,    MSEL1CR_31_0),
+       PINMUX_DATA(IRQ27_PORT168_MARK,         PORT168_FN0,    MSEL1CR_27_0),
+       PINMUX_DATA(IRQ28_PORT169_MARK,         PORT169_FN0,    MSEL1CR_28_0),
+       PINMUX_DATA(IRQ29_PORT170_MARK,         PORT170_FN0,    MSEL1CR_29_0),
+       PINMUX_DATA(IRQ30_PORT171_MARK,         PORT171_FN0,    MSEL1CR_30_0),
+
+       /* Port172 */
+       PINMUX_DATA(D23_MARK,                   PORT172_FN1),
+       PINMUX_DATA(SCIFB_RTS_PORT172_MARK,     PORT172_FN2,    MSEL5CR_17_1),
+       PINMUX_DATA(ET_ETXD7_MARK,              PORT172_FN3),
+       PINMUX_DATA(IDE_D7_MARK,                PORT172_FN6),
+       PINMUX_DATA(IRQ4_PORT172_MARK,          PORT172_FN0,    MSEL1CR_4_1),
+
+       /* Port173 */
+       PINMUX_DATA(D22_MARK,                   PORT173_FN1),
+       PINMUX_DATA(SCIFB_CTS_PORT173_MARK,     PORT173_FN2,    MSEL5CR_17_1),
+       PINMUX_DATA(ET_ETXD6_MARK,              PORT173_FN3),
+       PINMUX_DATA(IDE_D6_MARK,                PORT173_FN6),
+       PINMUX_DATA(IRQ6_PORT173_MARK,          PORT173_FN0,    MSEL1CR_6_1),
+
+       /* Port174 */
+       PINMUX_DATA(A26_MARK,                   PORT174_FN1),
+       PINMUX_DATA(MSIOF0_TXD_MARK,            PORT174_FN2),
+       PINMUX_DATA(ET_RX_CLK_MARK,             PORT174_FN3),
+       PINMUX_DATA(SCIFA3_RXD_PORT174_MARK,    PORT174_FN4,    MSEL5CR_8_0),
+
+       /* Port175 */
+       PINMUX_DATA(A0_MARK,                    PORT175_FN1),
+       PINMUX_DATA(BS_MARK,                    PORT175_FN2),
+       PINMUX_DATA(ET_WOL_MARK,                PORT175_FN3),
+       PINMUX_DATA(SCIFA3_TXD_PORT175_MARK,    PORT175_FN4,    MSEL5CR_8_0),
+
+       /* Port176 */
+       PINMUX_DATA(ET_GTX_CLK_MARK,            PORT176_FN3),
+
+       /* Port177 */
+       PINMUX_DATA(WAIT_PORT177_MARK,          PORT177_FN1,    MSEL5CR_2_0),
+       PINMUX_DATA(ET_LINK_MARK,               PORT177_FN3),
+       PINMUX_DATA(IDE_IOWR_MARK,              PORT177_FN6),
+       PINMUX_DATA(SDHI2_WP_PORT177_MARK,      PORT177_FN7,    MSEL5CR_19_1),
+
+       /* Port178 */
+       PINMUX_DATA(VIO0_D12_MARK,              PORT178_FN1),
+       PINMUX_DATA(VIO1_D4_MARK,               PORT178_FN5),
+       PINMUX_DATA(IDE_IORD_MARK,              PORT178_FN6),
+
+       /* Port179 */
+       PINMUX_DATA(VIO0_D11_MARK,              PORT179_FN1),
+       PINMUX_DATA(VIO1_D3_MARK,               PORT179_FN5),
+       PINMUX_DATA(IDE_IORDY_MARK,             PORT179_FN6),
+
+       /* Port180 */
+       PINMUX_DATA(VIO0_D10_MARK,              PORT180_FN1),
+       PINMUX_DATA(TPU0TO3_MARK,               PORT180_FN4),
+       PINMUX_DATA(VIO1_D2_MARK,               PORT180_FN5),
+       PINMUX_DATA(IDE_INT_MARK,               PORT180_FN6),
+       PINMUX_DATA(IRQ24_MARK,                 PORT180_FN0),
+
+       /* Port181 */
+       PINMUX_DATA(VIO0_D9_MARK,               PORT181_FN1),
+       PINMUX_DATA(VIO1_D1_MARK,               PORT181_FN5),
+       PINMUX_DATA(IDE_RST_MARK,               PORT181_FN6),
+
+       /* Port182 */
+       PINMUX_DATA(VIO0_D8_MARK,               PORT182_FN1),
+       PINMUX_DATA(VIO1_D0_MARK,               PORT182_FN5),
+       PINMUX_DATA(IDE_DIRECTION_MARK,         PORT182_FN6),
+
+       /* Port183 */
+       PINMUX_DATA(DREQ1_MARK,                 PORT183_FN1),
+       PINMUX_DATA(BBIF2_TXD2_PORT183_MARK,    PORT183_FN2,    MSEL5CR_0_1),
+       PINMUX_DATA(ET_TX_EN_MARK,              PORT183_FN3),
+
+       /* Port184 */
+       PINMUX_DATA(DACK1_MARK,                 PORT184_FN1),
+       PINMUX_DATA(BBIF2_TSYNC2_PORT184_MARK,  PORT184_FN2,    MSEL5CR_0_1),
+       PINMUX_DATA(ET_TX_CLK_MARK,             PORT184_FN3),
+
+       /* Port185 - Port192 Function1 */
+       PINMUX_DATA(SCIFA1_SCK_MARK,            PORT185_FN1),
+       PINMUX_DATA(SCIFB_RTS_PORT186_MARK,     PORT186_FN1,    MSEL5CR_17_0),
+       PINMUX_DATA(SCIFB_CTS_PORT187_MARK,     PORT187_FN1,    MSEL5CR_17_0),
+       PINMUX_DATA(SCIFA0_SCK_MARK,            PORT188_FN1),
+       PINMUX_DATA(SCIFB_SCK_PORT190_MARK,     PORT190_FN1,    MSEL5CR_17_0),
+       PINMUX_DATA(SCIFB_RXD_PORT191_MARK,     PORT191_FN1,    MSEL5CR_17_0),
+       PINMUX_DATA(SCIFB_TXD_PORT192_MARK,     PORT192_FN1,    MSEL5CR_17_0),
+
+       /* Port185 - Port192 Function3 */
+       PINMUX_DATA(ET_ERXD0_MARK,              PORT185_FN3),
+       PINMUX_DATA(ET_ERXD1_MARK,              PORT186_FN3),
+       PINMUX_DATA(ET_ERXD2_MARK,              PORT187_FN3),
+       PINMUX_DATA(ET_ERXD3_MARK,              PORT188_FN3),
+       PINMUX_DATA(ET_ERXD4_MARK,              PORT189_FN3),
+       PINMUX_DATA(ET_ERXD5_MARK,              PORT190_FN3),
+       PINMUX_DATA(ET_ERXD6_MARK,              PORT191_FN3),
+       PINMUX_DATA(ET_ERXD7_MARK,              PORT192_FN3),
+
+       /* Port185 - Port192 Function6 */
+       PINMUX_DATA(STP1_IPCLK_MARK,            PORT185_FN6),
+       PINMUX_DATA(STP1_IPD0_PORT186_MARK,     PORT186_FN6,    MSEL5CR_23_0),
+       PINMUX_DATA(STP1_IPEN_PORT187_MARK,     PORT187_FN6,    MSEL5CR_23_0),
+       PINMUX_DATA(STP1_IPSYNC_MARK,           PORT188_FN6),
+       PINMUX_DATA(STP0_IPCLK_MARK,            PORT189_FN6),
+       PINMUX_DATA(STP0_IPD0_MARK,             PORT190_FN6),
+       PINMUX_DATA(STP0_IPEN_MARK,             PORT191_FN6),
+       PINMUX_DATA(STP0_IPSYNC_MARK,           PORT192_FN6),
+
+       /* Port193 */
+       PINMUX_DATA(SCIFA0_CTS_MARK,            PORT193_FN1),
+       PINMUX_DATA(RMII_CRS_DV_MARK,           PORT193_FN3),
+       PINMUX_DATA(STP1_IPEN_PORT193_MARK,     PORT193_FN6,    MSEL5CR_23_1), /* ? */
+       PINMUX_DATA(LCD1_D17_MARK,              PORT193_FN7),
+
+       /* Port194 */
+       PINMUX_DATA(SCIFA0_RTS_MARK,            PORT194_FN1),
+       PINMUX_DATA(RMII_RX_ER_MARK,            PORT194_FN3),
+       PINMUX_DATA(STP1_IPD0_PORT194_MARK,     PORT194_FN6,    MSEL5CR_23_1), /* ? */
+       PINMUX_DATA(LCD1_D16_MARK,              PORT194_FN7),
+
+       /* Port195 */
+       PINMUX_DATA(SCIFA1_RXD_MARK,            PORT195_FN1),
+       PINMUX_DATA(RMII_RXD0_MARK,             PORT195_FN3),
+       PINMUX_DATA(STP1_IPD3_MARK,             PORT195_FN6),
+       PINMUX_DATA(LCD1_D15_MARK,              PORT195_FN7),
+
+       /* Port196 */
+       PINMUX_DATA(SCIFA1_TXD_MARK,            PORT196_FN1),
+       PINMUX_DATA(RMII_RXD1_MARK,             PORT196_FN3),
+       PINMUX_DATA(STP1_IPD2_MARK,             PORT196_FN6),
+       PINMUX_DATA(LCD1_D14_MARK,              PORT196_FN7),
+
+       /* Port197 */
+       PINMUX_DATA(SCIFA0_RXD_MARK,            PORT197_FN1),
+       PINMUX_DATA(VIO1_CLK_MARK,              PORT197_FN5),
+       PINMUX_DATA(STP1_IPD5_MARK,             PORT197_FN6),
+       PINMUX_DATA(LCD1_D19_MARK,              PORT197_FN7),
+
+       /* Port198 */
+       PINMUX_DATA(SCIFA0_TXD_MARK,            PORT198_FN1),
+       PINMUX_DATA(VIO1_VD_MARK,               PORT198_FN5),
+       PINMUX_DATA(STP1_IPD4_MARK,             PORT198_FN6),
+       PINMUX_DATA(LCD1_D18_MARK,              PORT198_FN7),
+
+       /* Port199 */
+       PINMUX_DATA(MEMC_NWE_MARK,              PORT199_FN1),
+       PINMUX_DATA(SCIFA2_SCK_PORT199_MARK,    PORT199_FN2,    MSEL5CR_7_1),
+       PINMUX_DATA(RMII_TX_EN_MARK,            PORT199_FN3),
+       PINMUX_DATA(SIM_D_PORT199_MARK,         PORT199_FN4,    MSEL5CR_21_1),
+       PINMUX_DATA(STP1_IPD1_MARK,             PORT199_FN6),
+       PINMUX_DATA(LCD1_D13_MARK,              PORT199_FN7),
+
+       /* Port200 */
+       PINMUX_DATA(MEMC_NOE_MARK,              PORT200_FN1),
+       PINMUX_DATA(SCIFA2_RXD_MARK,            PORT200_FN2),
+       PINMUX_DATA(RMII_TXD0_MARK,             PORT200_FN3),
+       PINMUX_DATA(STP0_IPD7_MARK,             PORT200_FN6),
+       PINMUX_DATA(LCD1_D12_MARK,              PORT200_FN7),
+
+       /* Port201 */
+       PINMUX_DATA(MEMC_WAIT_MARK,             PORT201_FN1,    MSEL4CR_6_0),
+       PINMUX_DATA(MEMC_DREQ1_MARK,            PORT201_FN1,    MSEL4CR_6_1),
+
+       PINMUX_DATA(SCIFA2_TXD_MARK,            PORT201_FN2),
+       PINMUX_DATA(RMII_TXD1_MARK,             PORT201_FN3),
+       PINMUX_DATA(STP0_IPD6_MARK,             PORT201_FN6),
+       PINMUX_DATA(LCD1_D11_MARK,              PORT201_FN7),
+
+       /* Port202 */
+       PINMUX_DATA(MEMC_BUSCLK_MARK,           PORT202_FN1,    MSEL4CR_6_0),
+       PINMUX_DATA(MEMC_A0_MARK,               PORT202_FN1,    MSEL4CR_6_1),
+
+       PINMUX_DATA(MSIOF1_SS2_PORT202_MARK,    PORT202_FN2,    MSEL4CR_10_1),
+       PINMUX_DATA(RMII_MDC_MARK,              PORT202_FN3),
+       PINMUX_DATA(TPU0TO2_PORT202_MARK,       PORT202_FN4,    MSEL5CR_25_1),
+       PINMUX_DATA(IDE_CS0_MARK,               PORT202_FN6),
+       PINMUX_DATA(SDHI2_CD_PORT202_MARK,      PORT202_FN7,    MSEL5CR_19_1),
+       PINMUX_DATA(IRQ21_MARK,                 PORT202_FN0),
+
+       /* Port203 - Port208 Function1 */
+       PINMUX_DATA(SDHI2_CLK_MARK,             PORT203_FN1),
+       PINMUX_DATA(SDHI2_CMD_MARK,             PORT204_FN1),
+       PINMUX_DATA(SDHI2_D0_MARK,              PORT205_FN1),
+       PINMUX_DATA(SDHI2_D1_MARK,              PORT206_FN1),
+       PINMUX_DATA(SDHI2_D2_MARK,              PORT207_FN1),
+       PINMUX_DATA(SDHI2_D3_MARK,              PORT208_FN1),
+
+       /* Port203 - Port208 Function3 */
+       PINMUX_DATA(ET_TX_ER_MARK,              PORT203_FN3),
+       PINMUX_DATA(ET_RX_ER_MARK,              PORT204_FN3),
+       PINMUX_DATA(ET_CRS_MARK,                PORT205_FN3),
+       PINMUX_DATA(ET_MDC_MARK,                PORT206_FN3),
+       PINMUX_DATA(ET_MDIO_MARK,               PORT207_FN3),
+       PINMUX_DATA(RMII_MDIO_MARK,             PORT208_FN3),
+
+       /* Port203 - Port208 Function6 */
+       PINMUX_DATA(IDE_A2_MARK,                PORT203_FN6),
+       PINMUX_DATA(IDE_A1_MARK,                PORT204_FN6),
+       PINMUX_DATA(IDE_A0_MARK,                PORT205_FN6),
+       PINMUX_DATA(IDE_IODACK_MARK,            PORT206_FN6),
+       PINMUX_DATA(IDE_IODREQ_MARK,            PORT207_FN6),
+       PINMUX_DATA(IDE_CS1_MARK,               PORT208_FN6),
+
+       /* Port203 - Port208 Function7 */
+       PINMUX_DATA(SCIFA4_TXD_PORT203_MARK,    PORT203_FN7,    MSEL5CR_12_0,   MSEL5CR_11_1),
+       PINMUX_DATA(SCIFA4_RXD_PORT204_MARK,    PORT204_FN7,    MSEL5CR_12_0,   MSEL5CR_11_1),
+       PINMUX_DATA(SCIFA4_SCK_PORT205_MARK,    PORT205_FN7,    MSEL5CR_10_1),
+       PINMUX_DATA(SCIFA5_SCK_PORT206_MARK,    PORT206_FN7,    MSEL5CR_13_1),
+       PINMUX_DATA(SCIFA5_RXD_PORT207_MARK,    PORT207_FN7,    MSEL5CR_15_0,   MSEL5CR_14_1),
+       PINMUX_DATA(SCIFA5_TXD_PORT208_MARK,    PORT208_FN7,    MSEL5CR_15_0,   MSEL5CR_14_1),
+
+       /* Port209 */
+       PINMUX_DATA(VBUS_MARK,                  PORT209_FN1),
+       PINMUX_DATA(IRQ7_PORT209_MARK,          PORT209_FN0,    MSEL1CR_7_1),
+
+       /* Port210 */
+       PINMUX_DATA(IRQ9_PORT210_MARK,          PORT210_FN0,    MSEL1CR_9_1),
+
+       /* Port211 */
+       PINMUX_DATA(IRQ16_PORT211_MARK,         PORT211_FN0,    MSEL1CR_16_1),
+
+       /* LCDC select */
+       PINMUX_DATA(LCDC0_SELECT_MARK,                          MSEL3CR_6_0),
+       PINMUX_DATA(LCDC1_SELECT_MARK,                          MSEL3CR_6_1),
+
+       /* SDENC */
+       PINMUX_DATA(SDENC_CPG_MARK,                             MSEL4CR_19_0),
+       PINMUX_DATA(SDENC_DV_CLKI_MARK,                         MSEL4CR_19_1),
+
+       /* SYSC */
+       PINMUX_DATA(RESETP_PULLUP_MARK,                         MSEL4CR_4_0),
+       PINMUX_DATA(RESETP_PLAIN_MARK,                          MSEL4CR_4_1),
+
+       /* DEBUG */
+       PINMUX_DATA(EDEBGREQ_PULLDOWN_MARK,                     MSEL4CR_1_0),
+       PINMUX_DATA(EDEBGREQ_PULLUP_MARK,                       MSEL4CR_1_1),
+
+       PINMUX_DATA(TRACEAUD_FROM_VIO_MARK,                     MSEL5CR_30_0,   MSEL5CR_29_0),
+       PINMUX_DATA(TRACEAUD_FROM_LCDC0_MARK,                   MSEL5CR_30_0,   MSEL5CR_29_1),
+       PINMUX_DATA(TRACEAUD_FROM_MEMC_MARK,                    MSEL5CR_30_1,   MSEL5CR_29_0),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+       /* PORT */
+       GPIO_PORT_ALL(),
+
+       /* IRQ */
+       GPIO_FN(IRQ0_PORT2),    GPIO_FN(IRQ0_PORT13),
+       GPIO_FN(IRQ1),
+       GPIO_FN(IRQ2_PORT11),   GPIO_FN(IRQ2_PORT12),
+       GPIO_FN(IRQ3_PORT10),   GPIO_FN(IRQ3_PORT14),
+       GPIO_FN(IRQ4_PORT15),   GPIO_FN(IRQ4_PORT172),
+       GPIO_FN(IRQ5_PORT0),    GPIO_FN(IRQ5_PORT1),
+       GPIO_FN(IRQ6_PORT121),  GPIO_FN(IRQ6_PORT173),
+       GPIO_FN(IRQ7_PORT120),  GPIO_FN(IRQ7_PORT209),
+       GPIO_FN(IRQ8),
+       GPIO_FN(IRQ9_PORT118),  GPIO_FN(IRQ9_PORT210),
+       GPIO_FN(IRQ10),
+       GPIO_FN(IRQ11),
+       GPIO_FN(IRQ12_PORT42),  GPIO_FN(IRQ12_PORT97),
+       GPIO_FN(IRQ13_PORT64),  GPIO_FN(IRQ13_PORT98),
+       GPIO_FN(IRQ14_PORT63),  GPIO_FN(IRQ14_PORT99),
+       GPIO_FN(IRQ15_PORT62),  GPIO_FN(IRQ15_PORT100),
+       GPIO_FN(IRQ16_PORT68),  GPIO_FN(IRQ16_PORT211),
+       GPIO_FN(IRQ17),
+       GPIO_FN(IRQ18),
+       GPIO_FN(IRQ19),
+       GPIO_FN(IRQ20),
+       GPIO_FN(IRQ21),
+       GPIO_FN(IRQ22),
+       GPIO_FN(IRQ23),
+       GPIO_FN(IRQ24),
+       GPIO_FN(IRQ25),
+       GPIO_FN(IRQ26_PORT58),  GPIO_FN(IRQ26_PORT81),
+       GPIO_FN(IRQ27_PORT57),  GPIO_FN(IRQ27_PORT168),
+       GPIO_FN(IRQ28_PORT56),  GPIO_FN(IRQ28_PORT169),
+       GPIO_FN(IRQ29_PORT50),  GPIO_FN(IRQ29_PORT170),
+       GPIO_FN(IRQ30_PORT49),  GPIO_FN(IRQ30_PORT171),
+       GPIO_FN(IRQ31_PORT41),  GPIO_FN(IRQ31_PORT167),
+
+       /* Function */
+
+       /* DBGT */
+       GPIO_FN(DBGMDT2),       GPIO_FN(DBGMDT1),       GPIO_FN(DBGMDT0),
+       GPIO_FN(DBGMD10),       GPIO_FN(DBGMD11),       GPIO_FN(DBGMD20),
+       GPIO_FN(DBGMD21),
+
+       /* FSI */
+       GPIO_FN(FSIAISLD_PORT0),        /* FSIAISLD Port 0/5 */
+       GPIO_FN(FSIAISLD_PORT5),
+       GPIO_FN(FSIASPDIF_PORT9),       /* FSIASPDIF Port 9/18 */
+       GPIO_FN(FSIASPDIF_PORT18),
+       GPIO_FN(FSIAOSLD1),     GPIO_FN(FSIAOSLD2),     GPIO_FN(FSIAOLR),
+       GPIO_FN(FSIAOBT),       GPIO_FN(FSIAOSLD),      GPIO_FN(FSIAOMC),
+       GPIO_FN(FSIACK),        GPIO_FN(FSIAILR),       GPIO_FN(FSIAIBT),
+
+       /* FMSI */
+       GPIO_FN(FMSISLD_PORT1), /* FMSISLD Port 1/6 */
+       GPIO_FN(FMSISLD_PORT6),
+       GPIO_FN(FMSIILR),       GPIO_FN(FMSIIBT),       GPIO_FN(FMSIOLR),
+       GPIO_FN(FMSIOBT),       GPIO_FN(FMSICK),        GPIO_FN(FMSOILR),
+       GPIO_FN(FMSOIBT),       GPIO_FN(FMSOOLR),       GPIO_FN(FMSOOBT),
+       GPIO_FN(FMSOSLD),       GPIO_FN(FMSOCK),
+
+       /* SCIFA0 */
+       GPIO_FN(SCIFA0_SCK),    GPIO_FN(SCIFA0_CTS),    GPIO_FN(SCIFA0_RTS),
+       GPIO_FN(SCIFA0_RXD),    GPIO_FN(SCIFA0_TXD),
+
+       /* SCIFA1 */
+       GPIO_FN(SCIFA1_CTS),    GPIO_FN(SCIFA1_SCK),
+       GPIO_FN(SCIFA1_RXD),    GPIO_FN(SCIFA1_TXD),    GPIO_FN(SCIFA1_RTS),
+
+       /* SCIFA2 */
+       GPIO_FN(SCIFA2_SCK_PORT22), /* SCIFA2_SCK Port 22/199 */
+       GPIO_FN(SCIFA2_SCK_PORT199),
+       GPIO_FN(SCIFA2_RXD),    GPIO_FN(SCIFA2_TXD),
+       GPIO_FN(SCIFA2_CTS),    GPIO_FN(SCIFA2_RTS),
+
+       /* SCIFA3 */
+       GPIO_FN(SCIFA3_RTS_PORT105), /* MSEL5CR_8_0 */
+       GPIO_FN(SCIFA3_SCK_PORT116),
+       GPIO_FN(SCIFA3_CTS_PORT117),
+       GPIO_FN(SCIFA3_RXD_PORT174),
+       GPIO_FN(SCIFA3_TXD_PORT175),
+
+       GPIO_FN(SCIFA3_RTS_PORT161), /* MSEL5CR_8_1 */
+       GPIO_FN(SCIFA3_SCK_PORT158),
+       GPIO_FN(SCIFA3_CTS_PORT162),
+       GPIO_FN(SCIFA3_RXD_PORT159),
+       GPIO_FN(SCIFA3_TXD_PORT160),
+
+       /* SCIFA4 */
+       GPIO_FN(SCIFA4_RXD_PORT12), /* MSEL5CR[12:11] = 00 */
+       GPIO_FN(SCIFA4_TXD_PORT13),
+
+       GPIO_FN(SCIFA4_RXD_PORT204), /* MSEL5CR[12:11] = 01 */
+       GPIO_FN(SCIFA4_TXD_PORT203),
+
+       GPIO_FN(SCIFA4_RXD_PORT94), /* MSEL5CR[12:11] = 10 */
+       GPIO_FN(SCIFA4_TXD_PORT93),
+
+       GPIO_FN(SCIFA4_SCK_PORT21), /* SCIFA4_SCK Port 21/205 */
+       GPIO_FN(SCIFA4_SCK_PORT205),
+
+       /* SCIFA5 */
+       GPIO_FN(SCIFA5_TXD_PORT20), /* MSEL5CR[15:14] = 00 */
+       GPIO_FN(SCIFA5_RXD_PORT10),
+
+       GPIO_FN(SCIFA5_RXD_PORT207), /* MSEL5CR[15:14] = 01 */
+       GPIO_FN(SCIFA5_TXD_PORT208),
+
+       GPIO_FN(SCIFA5_TXD_PORT91), /* MSEL5CR[15:14] = 10 */
+       GPIO_FN(SCIFA5_RXD_PORT92),
+
+       GPIO_FN(SCIFA5_SCK_PORT23), /* SCIFA5_SCK Port 23/206 */
+       GPIO_FN(SCIFA5_SCK_PORT206),
+
+       /* SCIFA6 */
+       GPIO_FN(SCIFA6_SCK),    GPIO_FN(SCIFA6_RXD),    GPIO_FN(SCIFA6_TXD),
+
+       /* SCIFA7 */
+       GPIO_FN(SCIFA7_TXD),    GPIO_FN(SCIFA7_RXD),
+
+       /* SCIFAB */
+       GPIO_FN(SCIFB_SCK_PORT190), /* MSEL5CR_17_0 */
+       GPIO_FN(SCIFB_RXD_PORT191),
+       GPIO_FN(SCIFB_TXD_PORT192),
+       GPIO_FN(SCIFB_RTS_PORT186),
+       GPIO_FN(SCIFB_CTS_PORT187),
+
+       GPIO_FN(SCIFB_SCK_PORT2), /* MSEL5CR_17_1 */
+       GPIO_FN(SCIFB_RXD_PORT3),
+       GPIO_FN(SCIFB_TXD_PORT4),
+       GPIO_FN(SCIFB_RTS_PORT172),
+       GPIO_FN(SCIFB_CTS_PORT173),
+
+       /* LCD0 */
+       GPIO_FN(LCD0_D0),       GPIO_FN(LCD0_D1),       GPIO_FN(LCD0_D2),
+       GPIO_FN(LCD0_D3),       GPIO_FN(LCD0_D4),       GPIO_FN(LCD0_D5),
+       GPIO_FN(LCD0_D6),       GPIO_FN(LCD0_D7),       GPIO_FN(LCD0_D8),
+       GPIO_FN(LCD0_D9),       GPIO_FN(LCD0_D10),      GPIO_FN(LCD0_D11),
+       GPIO_FN(LCD0_D12),      GPIO_FN(LCD0_D13),      GPIO_FN(LCD0_D14),
+       GPIO_FN(LCD0_D15),      GPIO_FN(LCD0_D16),      GPIO_FN(LCD0_D17),
+       GPIO_FN(LCD0_DON),      GPIO_FN(LCD0_VCPWC),    GPIO_FN(LCD0_VEPWC),
+       GPIO_FN(LCD0_DCK),      GPIO_FN(LCD0_VSYN),
+       GPIO_FN(LCD0_HSYN),     GPIO_FN(LCD0_DISP),
+       GPIO_FN(LCD0_WR),       GPIO_FN(LCD0_RD),
+       GPIO_FN(LCD0_CS),       GPIO_FN(LCD0_RS),
+
+       GPIO_FN(LCD0_D18_PORT163),      GPIO_FN(LCD0_D19_PORT162),
+       GPIO_FN(LCD0_D20_PORT161),      GPIO_FN(LCD0_D21_PORT158),
+       GPIO_FN(LCD0_D22_PORT160),      GPIO_FN(LCD0_D23_PORT159),
+       GPIO_FN(LCD0_LCLK_PORT165),     /* MSEL5CR_6_1 */
+
+       GPIO_FN(LCD0_D18_PORT40),       GPIO_FN(LCD0_D19_PORT4),
+       GPIO_FN(LCD0_D20_PORT3),        GPIO_FN(LCD0_D21_PORT2),
+       GPIO_FN(LCD0_D22_PORT0),        GPIO_FN(LCD0_D23_PORT1),
+       GPIO_FN(LCD0_LCLK_PORT102),     /* MSEL5CR_6_0 */
+
+       /* LCD1 */
+       GPIO_FN(LCD1_D0),       GPIO_FN(LCD1_D1),       GPIO_FN(LCD1_D2),
+       GPIO_FN(LCD1_D3),       GPIO_FN(LCD1_D4),       GPIO_FN(LCD1_D5),
+       GPIO_FN(LCD1_D6),       GPIO_FN(LCD1_D7),       GPIO_FN(LCD1_D8),
+       GPIO_FN(LCD1_D9),       GPIO_FN(LCD1_D10),      GPIO_FN(LCD1_D11),
+       GPIO_FN(LCD1_D12),      GPIO_FN(LCD1_D13),      GPIO_FN(LCD1_D14),
+       GPIO_FN(LCD1_D15),      GPIO_FN(LCD1_D16),      GPIO_FN(LCD1_D17),
+       GPIO_FN(LCD1_D18),      GPIO_FN(LCD1_D19),      GPIO_FN(LCD1_D20),
+       GPIO_FN(LCD1_D21),      GPIO_FN(LCD1_D22),      GPIO_FN(LCD1_D23),
+       GPIO_FN(LCD1_RS),       GPIO_FN(LCD1_RD),       GPIO_FN(LCD1_CS),
+       GPIO_FN(LCD1_WR),       GPIO_FN(LCD1_DCK),      GPIO_FN(LCD1_DON),
+       GPIO_FN(LCD1_VCPWC),    GPIO_FN(LCD1_LCLK),     GPIO_FN(LCD1_HSYN),
+       GPIO_FN(LCD1_VSYN),     GPIO_FN(LCD1_VEPWC),    GPIO_FN(LCD1_DISP),
+
+       /* RSPI */
+       GPIO_FN(RSPI_SSL0_A),   GPIO_FN(RSPI_SSL1_A),   GPIO_FN(RSPI_SSL2_A),
+       GPIO_FN(RSPI_SSL3_A),   GPIO_FN(RSPI_CK_A),     GPIO_FN(RSPI_MOSI_A),
+       GPIO_FN(RSPI_MISO_A),
+
+       /* VIO CKO */
+       GPIO_FN(VIO_CKO1),
+       GPIO_FN(VIO_CKO2),
+       GPIO_FN(VIO_CKO_1),
+       GPIO_FN(VIO_CKO),
+
+       /* VIO0 */
+       GPIO_FN(VIO0_D0),       GPIO_FN(VIO0_D1),       GPIO_FN(VIO0_D2),
+       GPIO_FN(VIO0_D3),       GPIO_FN(VIO0_D4),       GPIO_FN(VIO0_D5),
+       GPIO_FN(VIO0_D6),       GPIO_FN(VIO0_D7),       GPIO_FN(VIO0_D8),
+       GPIO_FN(VIO0_D9),       GPIO_FN(VIO0_D10),      GPIO_FN(VIO0_D11),
+       GPIO_FN(VIO0_D12),      GPIO_FN(VIO0_VD),       GPIO_FN(VIO0_HD),
+       GPIO_FN(VIO0_CLK),      GPIO_FN(VIO0_FIELD),
+
+       GPIO_FN(VIO0_D13_PORT26), /* MSEL5CR_27_0 */
+       GPIO_FN(VIO0_D14_PORT25),
+       GPIO_FN(VIO0_D15_PORT24),
+
+       GPIO_FN(VIO0_D13_PORT22), /* MSEL5CR_27_1 */
+       GPIO_FN(VIO0_D14_PORT95),
+       GPIO_FN(VIO0_D15_PORT96),
+
+       /* VIO1 */
+       GPIO_FN(VIO1_D0),       GPIO_FN(VIO1_D1),       GPIO_FN(VIO1_D2),
+       GPIO_FN(VIO1_D3),       GPIO_FN(VIO1_D4),       GPIO_FN(VIO1_D5),
+       GPIO_FN(VIO1_D6),       GPIO_FN(VIO1_D7),       GPIO_FN(VIO1_VD),
+       GPIO_FN(VIO1_HD),       GPIO_FN(VIO1_CLK),      GPIO_FN(VIO1_FIELD),
+
+       /* TPU0 */
+       GPIO_FN(TPU0TO0),       GPIO_FN(TPU0TO1),       GPIO_FN(TPU0TO3),
+       GPIO_FN(TPU0TO2_PORT66), /* TPU0TO2 Port 66/202 */
+       GPIO_FN(TPU0TO2_PORT202),
+
+       /* SSP1 0 */
+       GPIO_FN(STP0_IPD0),     GPIO_FN(STP0_IPD1),     GPIO_FN(STP0_IPD2),
+       GPIO_FN(STP0_IPD3),     GPIO_FN(STP0_IPD4),     GPIO_FN(STP0_IPD5),
+       GPIO_FN(STP0_IPD6),     GPIO_FN(STP0_IPD7),     GPIO_FN(STP0_IPEN),
+       GPIO_FN(STP0_IPCLK),    GPIO_FN(STP0_IPSYNC),
+
+       /* SSP1 1 */
+       GPIO_FN(STP1_IPD1),     GPIO_FN(STP1_IPD2),     GPIO_FN(STP1_IPD3),
+       GPIO_FN(STP1_IPD4),     GPIO_FN(STP1_IPD5),     GPIO_FN(STP1_IPD6),
+       GPIO_FN(STP1_IPD7),     GPIO_FN(STP1_IPCLK),    GPIO_FN(STP1_IPSYNC),
+
+       GPIO_FN(STP1_IPD0_PORT186), /* MSEL5CR_23_0 */
+       GPIO_FN(STP1_IPEN_PORT187),
+
+       GPIO_FN(STP1_IPD0_PORT194), /* MSEL5CR_23_1 */
+       GPIO_FN(STP1_IPEN_PORT193),
+
+       /* SIM */
+       GPIO_FN(SIM_RST),       GPIO_FN(SIM_CLK),
+       GPIO_FN(SIM_D_PORT22), /* SIM_D  Port 22/199 */
+       GPIO_FN(SIM_D_PORT199),
+
+       /* SDHI0 */
+       GPIO_FN(SDHI0_D0),      GPIO_FN(SDHI0_D1),      GPIO_FN(SDHI0_D2),
+       GPIO_FN(SDHI0_D3),      GPIO_FN(SDHI0_CD),      GPIO_FN(SDHI0_WP),
+       GPIO_FN(SDHI0_CMD),     GPIO_FN(SDHI0_CLK),
+
+       /* SDHI1 */
+       GPIO_FN(SDHI1_D0),      GPIO_FN(SDHI1_D1),      GPIO_FN(SDHI1_D2),
+       GPIO_FN(SDHI1_D3),      GPIO_FN(SDHI1_CD),      GPIO_FN(SDHI1_WP),
+       GPIO_FN(SDHI1_CMD),     GPIO_FN(SDHI1_CLK),
+
+       /* SDHI2 */
+       GPIO_FN(SDHI2_D0),      GPIO_FN(SDHI2_D1),      GPIO_FN(SDHI2_D2),
+       GPIO_FN(SDHI2_D3),      GPIO_FN(SDHI2_CLK),     GPIO_FN(SDHI2_CMD),
+
+       GPIO_FN(SDHI2_CD_PORT24), /* MSEL5CR_19_0 */
+       GPIO_FN(SDHI2_WP_PORT25),
+
+       GPIO_FN(SDHI2_WP_PORT177), /* MSEL5CR_19_1 */
+       GPIO_FN(SDHI2_CD_PORT202),
+
+       /* MSIOF2 */
+       GPIO_FN(MSIOF2_TXD),    GPIO_FN(MSIOF2_RXD),    GPIO_FN(MSIOF2_TSCK),
+       GPIO_FN(MSIOF2_SS2),    GPIO_FN(MSIOF2_TSYNC),  GPIO_FN(MSIOF2_SS1),
+       GPIO_FN(MSIOF2_MCK1),   GPIO_FN(MSIOF2_MCK0),   GPIO_FN(MSIOF2_RSYNC),
+       GPIO_FN(MSIOF2_RSCK),
+
+       /* KEYSC */
+       GPIO_FN(KEYIN4),        GPIO_FN(KEYIN5),
+       GPIO_FN(KEYIN6),        GPIO_FN(KEYIN7),
+       GPIO_FN(KEYOUT0),       GPIO_FN(KEYOUT1),       GPIO_FN(KEYOUT2),
+       GPIO_FN(KEYOUT3),       GPIO_FN(KEYOUT4),       GPIO_FN(KEYOUT5),
+       GPIO_FN(KEYOUT6),       GPIO_FN(KEYOUT7),
+
+       GPIO_FN(KEYIN0_PORT43), /* MSEL4CR_18_0 */
+       GPIO_FN(KEYIN1_PORT44),
+       GPIO_FN(KEYIN2_PORT45),
+       GPIO_FN(KEYIN3_PORT46),
+
+       GPIO_FN(KEYIN0_PORT58), /* MSEL4CR_18_1 */
+       GPIO_FN(KEYIN1_PORT57),
+       GPIO_FN(KEYIN2_PORT56),
+       GPIO_FN(KEYIN3_PORT55),
+
+       /* VOU */
+       GPIO_FN(DV_D0),         GPIO_FN(DV_D1),         GPIO_FN(DV_D2),
+       GPIO_FN(DV_D3),         GPIO_FN(DV_D4),         GPIO_FN(DV_D5),
+       GPIO_FN(DV_D6),         GPIO_FN(DV_D7),         GPIO_FN(DV_D8),
+       GPIO_FN(DV_D9),         GPIO_FN(DV_D10),        GPIO_FN(DV_D11),
+       GPIO_FN(DV_D12),        GPIO_FN(DV_D13),        GPIO_FN(DV_D14),
+       GPIO_FN(DV_D15),        GPIO_FN(DV_CLK),
+       GPIO_FN(DV_VSYNC),      GPIO_FN(DV_HSYNC),
+
+       /* MEMC */
+       GPIO_FN(MEMC_AD0),      GPIO_FN(MEMC_AD1),      GPIO_FN(MEMC_AD2),
+       GPIO_FN(MEMC_AD3),      GPIO_FN(MEMC_AD4),      GPIO_FN(MEMC_AD5),
+       GPIO_FN(MEMC_AD6),      GPIO_FN(MEMC_AD7),      GPIO_FN(MEMC_AD8),
+       GPIO_FN(MEMC_AD9),      GPIO_FN(MEMC_AD10),     GPIO_FN(MEMC_AD11),
+       GPIO_FN(MEMC_AD12),     GPIO_FN(MEMC_AD13),     GPIO_FN(MEMC_AD14),
+       GPIO_FN(MEMC_AD15),     GPIO_FN(MEMC_CS0),      GPIO_FN(MEMC_INT),
+       GPIO_FN(MEMC_NWE),      GPIO_FN(MEMC_NOE),      GPIO_FN(MEMC_CS1),
+       GPIO_FN(MEMC_A1),       GPIO_FN(MEMC_ADV),      GPIO_FN(MEMC_DREQ0),
+       GPIO_FN(MEMC_WAIT),     GPIO_FN(MEMC_DREQ1),    GPIO_FN(MEMC_BUSCLK),
+       GPIO_FN(MEMC_A0),
+
+       /* MMC */
+       GPIO_FN(MMC0_D0_PORT68),        GPIO_FN(MMC0_D1_PORT69),
+       GPIO_FN(MMC0_D2_PORT70),        GPIO_FN(MMC0_D3_PORT71),
+       GPIO_FN(MMC0_D4_PORT72),        GPIO_FN(MMC0_D5_PORT73),
+       GPIO_FN(MMC0_D6_PORT74),        GPIO_FN(MMC0_D7_PORT75),
+       GPIO_FN(MMC0_CLK_PORT66),
+       GPIO_FN(MMC0_CMD_PORT67),       /* MSEL4CR_15_0 */
+
+       GPIO_FN(MMC1_D0_PORT149),       GPIO_FN(MMC1_D1_PORT148),
+       GPIO_FN(MMC1_D2_PORT147),       GPIO_FN(MMC1_D3_PORT146),
+       GPIO_FN(MMC1_D4_PORT145),       GPIO_FN(MMC1_D5_PORT144),
+       GPIO_FN(MMC1_D6_PORT143),       GPIO_FN(MMC1_D7_PORT142),
+       GPIO_FN(MMC1_CLK_PORT103),
+       GPIO_FN(MMC1_CMD_PORT104),      /* MSEL4CR_15_1 */
+
+       /* MSIOF0 */
+       GPIO_FN(MSIOF0_SS1),    GPIO_FN(MSIOF0_SS2),    GPIO_FN(MSIOF0_RXD),
+       GPIO_FN(MSIOF0_TXD),    GPIO_FN(MSIOF0_MCK0),   GPIO_FN(MSIOF0_MCK1),
+       GPIO_FN(MSIOF0_RSYNC),  GPIO_FN(MSIOF0_RSCK),   GPIO_FN(MSIOF0_TSCK),
+       GPIO_FN(MSIOF0_TSYNC),
+
+       /* MSIOF1 */
+       GPIO_FN(MSIOF1_RSCK),   GPIO_FN(MSIOF1_RSYNC),
+       GPIO_FN(MSIOF1_MCK0),   GPIO_FN(MSIOF1_MCK1),
+
+       GPIO_FN(MSIOF1_SS2_PORT116),    GPIO_FN(MSIOF1_SS1_PORT117),
+       GPIO_FN(MSIOF1_RXD_PORT118),    GPIO_FN(MSIOF1_TXD_PORT119),
+       GPIO_FN(MSIOF1_TSYNC_PORT120),
+       GPIO_FN(MSIOF1_TSCK_PORT121),   /* MSEL4CR_10_0 */
+
+       GPIO_FN(MSIOF1_SS1_PORT67),     GPIO_FN(MSIOF1_TSCK_PORT72),
+       GPIO_FN(MSIOF1_TSYNC_PORT73),   GPIO_FN(MSIOF1_TXD_PORT74),
+       GPIO_FN(MSIOF1_RXD_PORT75),
+       GPIO_FN(MSIOF1_SS2_PORT202),    /* MSEL4CR_10_1 */
+
+       /* GPIO */
+       GPIO_FN(GPO0),  GPIO_FN(GPI0),
+       GPIO_FN(GPO1),  GPIO_FN(GPI1),
+
+       /* USB0 */
+       GPIO_FN(USB0_OCI),      GPIO_FN(USB0_PPON),     GPIO_FN(VBUS),
+
+       /* USB1 */
+       GPIO_FN(USB1_OCI),      GPIO_FN(USB1_PPON),
+
+       /* BBIF1 */
+       GPIO_FN(BBIF1_RXD),     GPIO_FN(BBIF1_TXD),     GPIO_FN(BBIF1_TSYNC),
+       GPIO_FN(BBIF1_TSCK),    GPIO_FN(BBIF1_RSCK),    GPIO_FN(BBIF1_RSYNC),
+       GPIO_FN(BBIF1_FLOW),    GPIO_FN(BBIF1_RX_FLOW_N),
+
+       /* BBIF2 */
+       GPIO_FN(BBIF2_TXD2_PORT5), /* MSEL5CR_0_0 */
+       GPIO_FN(BBIF2_RXD2_PORT60),
+       GPIO_FN(BBIF2_TSYNC2_PORT6),
+       GPIO_FN(BBIF2_TSCK2_PORT59),
+
+       GPIO_FN(BBIF2_RXD2_PORT90), /* MSEL5CR_0_1 */
+       GPIO_FN(BBIF2_TXD2_PORT183),
+       GPIO_FN(BBIF2_TSCK2_PORT89),
+       GPIO_FN(BBIF2_TSYNC2_PORT184),
+
+       /* BSC / FLCTL / PCMCIA */
+       GPIO_FN(CS0),   GPIO_FN(CS2),   GPIO_FN(CS4),
+       GPIO_FN(CS5B),  GPIO_FN(CS6A),
+       GPIO_FN(CS5A_PORT105), /* CS5A PORT 19/105 */
+       GPIO_FN(CS5A_PORT19),
+       GPIO_FN(IOIS16), /* ? */
+
+       GPIO_FN(A0),    GPIO_FN(A1),    GPIO_FN(A2),    GPIO_FN(A3),
+       GPIO_FN(A4_FOE),        GPIO_FN(A5_FCDE),       /* share with FLCTL */
+       GPIO_FN(A6),    GPIO_FN(A7),    GPIO_FN(A8),    GPIO_FN(A9),
+       GPIO_FN(A10),   GPIO_FN(A11),   GPIO_FN(A12),   GPIO_FN(A13),
+       GPIO_FN(A14),   GPIO_FN(A15),   GPIO_FN(A16),   GPIO_FN(A17),
+       GPIO_FN(A18),   GPIO_FN(A19),   GPIO_FN(A20),   GPIO_FN(A21),
+       GPIO_FN(A22),   GPIO_FN(A23),   GPIO_FN(A24),   GPIO_FN(A25),
+       GPIO_FN(A26),
+
+       GPIO_FN(D0_NAF0),       GPIO_FN(D1_NAF1),       /* share with FLCTL */
+       GPIO_FN(D2_NAF2),       GPIO_FN(D3_NAF3),       /* share with FLCTL */
+       GPIO_FN(D4_NAF4),       GPIO_FN(D5_NAF5),       /* share with FLCTL */
+       GPIO_FN(D6_NAF6),       GPIO_FN(D7_NAF7),       /* share with FLCTL */
+       GPIO_FN(D8_NAF8),       GPIO_FN(D9_NAF9),       /* share with FLCTL */
+       GPIO_FN(D10_NAF10),     GPIO_FN(D11_NAF11),     /* share with FLCTL */
+       GPIO_FN(D12_NAF12),     GPIO_FN(D13_NAF13),     /* share with FLCTL */
+       GPIO_FN(D14_NAF14),     GPIO_FN(D15_NAF15),     /* share with FLCTL */
+       GPIO_FN(D16),   GPIO_FN(D17),   GPIO_FN(D18),   GPIO_FN(D19),
+       GPIO_FN(D20),   GPIO_FN(D21),   GPIO_FN(D22),   GPIO_FN(D23),
+       GPIO_FN(D24),   GPIO_FN(D25),   GPIO_FN(D26),   GPIO_FN(D27),
+       GPIO_FN(D28),   GPIO_FN(D29),   GPIO_FN(D30),   GPIO_FN(D31),
+
+       GPIO_FN(WE0_FWE),       /* share with FLCTL */
+       GPIO_FN(WE1),
+       GPIO_FN(WE2_ICIORD),    /* share with PCMCIA */
+       GPIO_FN(WE3_ICIOWR),    /* share with PCMCIA */
+       GPIO_FN(CKO),   GPIO_FN(BS),    GPIO_FN(RDWR),
+       GPIO_FN(RD_FSC),        /* share with FLCTL */
+       GPIO_FN(WAIT_PORT177), /* WAIT Port 90/177 */
+       GPIO_FN(WAIT_PORT90),
+
+       GPIO_FN(FCE0),  GPIO_FN(FCE1),  GPIO_FN(FRB), /* FLCTL */
+
+       /* IRDA */
+       GPIO_FN(IRDA_FIRSEL),   GPIO_FN(IRDA_IN),       GPIO_FN(IRDA_OUT),
+
+       /* ATAPI */
+       GPIO_FN(IDE_D0),        GPIO_FN(IDE_D1),        GPIO_FN(IDE_D2),
+       GPIO_FN(IDE_D3),        GPIO_FN(IDE_D4),        GPIO_FN(IDE_D5),
+       GPIO_FN(IDE_D6),        GPIO_FN(IDE_D7),        GPIO_FN(IDE_D8),
+       GPIO_FN(IDE_D9),        GPIO_FN(IDE_D10),       GPIO_FN(IDE_D11),
+       GPIO_FN(IDE_D12),       GPIO_FN(IDE_D13),       GPIO_FN(IDE_D14),
+       GPIO_FN(IDE_D15),       GPIO_FN(IDE_A0),        GPIO_FN(IDE_A1),
+       GPIO_FN(IDE_A2),        GPIO_FN(IDE_CS0),       GPIO_FN(IDE_CS1),
+       GPIO_FN(IDE_IOWR),      GPIO_FN(IDE_IORD),      GPIO_FN(IDE_IORDY),
+       GPIO_FN(IDE_INT),       GPIO_FN(IDE_RST),       GPIO_FN(IDE_DIRECTION),
+       GPIO_FN(IDE_EXBUF_ENB), GPIO_FN(IDE_IODACK),    GPIO_FN(IDE_IODREQ),
+
+       /* RMII */
+       GPIO_FN(RMII_CRS_DV),   GPIO_FN(RMII_RX_ER),    GPIO_FN(RMII_RXD0),
+       GPIO_FN(RMII_RXD1),     GPIO_FN(RMII_TX_EN),    GPIO_FN(RMII_TXD0),
+       GPIO_FN(RMII_MDC),      GPIO_FN(RMII_TXD1),     GPIO_FN(RMII_MDIO),
+       GPIO_FN(RMII_REF50CK),  GPIO_FN(RMII_REF125CK), /* for GMII */
+
+       /* GEther */
+       GPIO_FN(ET_TX_CLK),     GPIO_FN(ET_TX_EN),      GPIO_FN(ET_ETXD0),
+       GPIO_FN(ET_ETXD1),      GPIO_FN(ET_ETXD2),      GPIO_FN(ET_ETXD3),
+       GPIO_FN(ET_ETXD4),      GPIO_FN(ET_ETXD5), /* for GEther */
+       GPIO_FN(ET_ETXD6),      GPIO_FN(ET_ETXD7), /* for GEther */
+       GPIO_FN(ET_COL),        GPIO_FN(ET_TX_ER),      GPIO_FN(ET_RX_CLK),
+       GPIO_FN(ET_RX_DV),      GPIO_FN(ET_ERXD0),      GPIO_FN(ET_ERXD1),
+       GPIO_FN(ET_ERXD2),      GPIO_FN(ET_ERXD3),
+       GPIO_FN(ET_ERXD4),      GPIO_FN(ET_ERXD5), /* for GEther */
+       GPIO_FN(ET_ERXD6),      GPIO_FN(ET_ERXD7), /* for GEther */
+       GPIO_FN(ET_RX_ER),      GPIO_FN(ET_CRS),        GPIO_FN(ET_MDC),
+       GPIO_FN(ET_MDIO),       GPIO_FN(ET_LINK),       GPIO_FN(ET_PHY_INT),
+       GPIO_FN(ET_WOL),        GPIO_FN(ET_GTX_CLK),
+
+       /* DMA0 */
+       GPIO_FN(DREQ0), GPIO_FN(DACK0),
+
+       /* DMA1 */
+       GPIO_FN(DREQ1), GPIO_FN(DACK1),
+
+       /* SYSC */
+       GPIO_FN(RESETOUTS),
+
+       /* IRREM */
+       GPIO_FN(IROUT),
+
+       /* LCDC */
+       GPIO_FN(LCDC0_SELECT),
+       GPIO_FN(LCDC1_SELECT),
+
+       /* SDENC */
+       GPIO_FN(SDENC_CPG),
+       GPIO_FN(SDENC_DV_CLKI),
+
+       /* SYSC */
+       GPIO_FN(RESETP_PULLUP),
+       GPIO_FN(RESETP_PLAIN),
+
+       /* DEBUG */
+       GPIO_FN(EDEBGREQ_PULLDOWN),
+       GPIO_FN(EDEBGREQ_PULLUP),
+
+       GPIO_FN(TRACEAUD_FROM_VIO),
+       GPIO_FN(TRACEAUD_FROM_LCDC0),
+       GPIO_FN(TRACEAUD_FROM_MEMC),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       PORTCR(0,       0xe6050000), /* PORT0CR */
+       PORTCR(1,       0xe6050001), /* PORT1CR */
+       PORTCR(2,       0xe6050002), /* PORT2CR */
+       PORTCR(3,       0xe6050003), /* PORT3CR */
+       PORTCR(4,       0xe6050004), /* PORT4CR */
+       PORTCR(5,       0xe6050005), /* PORT5CR */
+       PORTCR(6,       0xe6050006), /* PORT6CR */
+       PORTCR(7,       0xe6050007), /* PORT7CR */
+       PORTCR(8,       0xe6050008), /* PORT8CR */
+       PORTCR(9,       0xe6050009), /* PORT9CR */
+       PORTCR(10,      0xe605000a), /* PORT10CR */
+       PORTCR(11,      0xe605000b), /* PORT11CR */
+       PORTCR(12,      0xe605000c), /* PORT12CR */
+       PORTCR(13,      0xe605000d), /* PORT13CR */
+       PORTCR(14,      0xe605000e), /* PORT14CR */
+       PORTCR(15,      0xe605000f), /* PORT15CR */
+       PORTCR(16,      0xe6050010), /* PORT16CR */
+       PORTCR(17,      0xe6050011), /* PORT17CR */
+       PORTCR(18,      0xe6050012), /* PORT18CR */
+       PORTCR(19,      0xe6050013), /* PORT19CR */
+       PORTCR(20,      0xe6050014), /* PORT20CR */
+       PORTCR(21,      0xe6050015), /* PORT21CR */
+       PORTCR(22,      0xe6050016), /* PORT22CR */
+       PORTCR(23,      0xe6050017), /* PORT23CR */
+       PORTCR(24,      0xe6050018), /* PORT24CR */
+       PORTCR(25,      0xe6050019), /* PORT25CR */
+       PORTCR(26,      0xe605001a), /* PORT26CR */
+       PORTCR(27,      0xe605001b), /* PORT27CR */
+       PORTCR(28,      0xe605001c), /* PORT28CR */
+       PORTCR(29,      0xe605001d), /* PORT29CR */
+       PORTCR(30,      0xe605001e), /* PORT30CR */
+       PORTCR(31,      0xe605001f), /* PORT31CR */
+       PORTCR(32,      0xe6050020), /* PORT32CR */
+       PORTCR(33,      0xe6050021), /* PORT33CR */
+       PORTCR(34,      0xe6050022), /* PORT34CR */
+       PORTCR(35,      0xe6050023), /* PORT35CR */
+       PORTCR(36,      0xe6050024), /* PORT36CR */
+       PORTCR(37,      0xe6050025), /* PORT37CR */
+       PORTCR(38,      0xe6050026), /* PORT38CR */
+       PORTCR(39,      0xe6050027), /* PORT39CR */
+       PORTCR(40,      0xe6050028), /* PORT40CR */
+       PORTCR(41,      0xe6050029), /* PORT41CR */
+       PORTCR(42,      0xe605002a), /* PORT42CR */
+       PORTCR(43,      0xe605002b), /* PORT43CR */
+       PORTCR(44,      0xe605002c), /* PORT44CR */
+       PORTCR(45,      0xe605002d), /* PORT45CR */
+       PORTCR(46,      0xe605002e), /* PORT46CR */
+       PORTCR(47,      0xe605002f), /* PORT47CR */
+       PORTCR(48,      0xe6050030), /* PORT48CR */
+       PORTCR(49,      0xe6050031), /* PORT49CR */
+       PORTCR(50,      0xe6050032), /* PORT50CR */
+       PORTCR(51,      0xe6050033), /* PORT51CR */
+       PORTCR(52,      0xe6050034), /* PORT52CR */
+       PORTCR(53,      0xe6050035), /* PORT53CR */
+       PORTCR(54,      0xe6050036), /* PORT54CR */
+       PORTCR(55,      0xe6050037), /* PORT55CR */
+       PORTCR(56,      0xe6050038), /* PORT56CR */
+       PORTCR(57,      0xe6050039), /* PORT57CR */
+       PORTCR(58,      0xe605003a), /* PORT58CR */
+       PORTCR(59,      0xe605003b), /* PORT59CR */
+       PORTCR(60,      0xe605003c), /* PORT60CR */
+       PORTCR(61,      0xe605003d), /* PORT61CR */
+       PORTCR(62,      0xe605003e), /* PORT62CR */
+       PORTCR(63,      0xe605003f), /* PORT63CR */
+       PORTCR(64,      0xe6050040), /* PORT64CR */
+       PORTCR(65,      0xe6050041), /* PORT65CR */
+       PORTCR(66,      0xe6050042), /* PORT66CR */
+       PORTCR(67,      0xe6050043), /* PORT67CR */
+       PORTCR(68,      0xe6050044), /* PORT68CR */
+       PORTCR(69,      0xe6050045), /* PORT69CR */
+       PORTCR(70,      0xe6050046), /* PORT70CR */
+       PORTCR(71,      0xe6050047), /* PORT71CR */
+       PORTCR(72,      0xe6050048), /* PORT72CR */
+       PORTCR(73,      0xe6050049), /* PORT73CR */
+       PORTCR(74,      0xe605004a), /* PORT74CR */
+       PORTCR(75,      0xe605004b), /* PORT75CR */
+       PORTCR(76,      0xe605004c), /* PORT76CR */
+       PORTCR(77,      0xe605004d), /* PORT77CR */
+       PORTCR(78,      0xe605004e), /* PORT78CR */
+       PORTCR(79,      0xe605004f), /* PORT79CR */
+       PORTCR(80,      0xe6050050), /* PORT80CR */
+       PORTCR(81,      0xe6050051), /* PORT81CR */
+       PORTCR(82,      0xe6050052), /* PORT82CR */
+       PORTCR(83,      0xe6050053), /* PORT83CR */
+
+       PORTCR(84,      0xe6051054), /* PORT84CR */
+       PORTCR(85,      0xe6051055), /* PORT85CR */
+       PORTCR(86,      0xe6051056), /* PORT86CR */
+       PORTCR(87,      0xe6051057), /* PORT87CR */
+       PORTCR(88,      0xe6051058), /* PORT88CR */
+       PORTCR(89,      0xe6051059), /* PORT89CR */
+       PORTCR(90,      0xe605105a), /* PORT90CR */
+       PORTCR(91,      0xe605105b), /* PORT91CR */
+       PORTCR(92,      0xe605105c), /* PORT92CR */
+       PORTCR(93,      0xe605105d), /* PORT93CR */
+       PORTCR(94,      0xe605105e), /* PORT94CR */
+       PORTCR(95,      0xe605105f), /* PORT95CR */
+       PORTCR(96,      0xe6051060), /* PORT96CR */
+       PORTCR(97,      0xe6051061), /* PORT97CR */
+       PORTCR(98,      0xe6051062), /* PORT98CR */
+       PORTCR(99,      0xe6051063), /* PORT99CR */
+       PORTCR(100,     0xe6051064), /* PORT100CR */
+       PORTCR(101,     0xe6051065), /* PORT101CR */
+       PORTCR(102,     0xe6051066), /* PORT102CR */
+       PORTCR(103,     0xe6051067), /* PORT103CR */
+       PORTCR(104,     0xe6051068), /* PORT104CR */
+       PORTCR(105,     0xe6051069), /* PORT105CR */
+       PORTCR(106,     0xe605106a), /* PORT106CR */
+       PORTCR(107,     0xe605106b), /* PORT107CR */
+       PORTCR(108,     0xe605106c), /* PORT108CR */
+       PORTCR(109,     0xe605106d), /* PORT109CR */
+       PORTCR(110,     0xe605106e), /* PORT110CR */
+       PORTCR(111,     0xe605106f), /* PORT111CR */
+       PORTCR(112,     0xe6051070), /* PORT112CR */
+       PORTCR(113,     0xe6051071), /* PORT113CR */
+       PORTCR(114,     0xe6051072), /* PORT114CR */
+
+       PORTCR(115,     0xe6052073), /* PORT115CR */
+       PORTCR(116,     0xe6052074), /* PORT116CR */
+       PORTCR(117,     0xe6052075), /* PORT117CR */
+       PORTCR(118,     0xe6052076), /* PORT118CR */
+       PORTCR(119,     0xe6052077), /* PORT119CR */
+       PORTCR(120,     0xe6052078), /* PORT120CR */
+       PORTCR(121,     0xe6052079), /* PORT121CR */
+       PORTCR(122,     0xe605207a), /* PORT122CR */
+       PORTCR(123,     0xe605207b), /* PORT123CR */
+       PORTCR(124,     0xe605207c), /* PORT124CR */
+       PORTCR(125,     0xe605207d), /* PORT125CR */
+       PORTCR(126,     0xe605207e), /* PORT126CR */
+       PORTCR(127,     0xe605207f), /* PORT127CR */
+       PORTCR(128,     0xe6052080), /* PORT128CR */
+       PORTCR(129,     0xe6052081), /* PORT129CR */
+       PORTCR(130,     0xe6052082), /* PORT130CR */
+       PORTCR(131,     0xe6052083), /* PORT131CR */
+       PORTCR(132,     0xe6052084), /* PORT132CR */
+       PORTCR(133,     0xe6052085), /* PORT133CR */
+       PORTCR(134,     0xe6052086), /* PORT134CR */
+       PORTCR(135,     0xe6052087), /* PORT135CR */
+       PORTCR(136,     0xe6052088), /* PORT136CR */
+       PORTCR(137,     0xe6052089), /* PORT137CR */
+       PORTCR(138,     0xe605208a), /* PORT138CR */
+       PORTCR(139,     0xe605208b), /* PORT139CR */
+       PORTCR(140,     0xe605208c), /* PORT140CR */
+       PORTCR(141,     0xe605208d), /* PORT141CR */
+       PORTCR(142,     0xe605208e), /* PORT142CR */
+       PORTCR(143,     0xe605208f), /* PORT143CR */
+       PORTCR(144,     0xe6052090), /* PORT144CR */
+       PORTCR(145,     0xe6052091), /* PORT145CR */
+       PORTCR(146,     0xe6052092), /* PORT146CR */
+       PORTCR(147,     0xe6052093), /* PORT147CR */
+       PORTCR(148,     0xe6052094), /* PORT148CR */
+       PORTCR(149,     0xe6052095), /* PORT149CR */
+       PORTCR(150,     0xe6052096), /* PORT150CR */
+       PORTCR(151,     0xe6052097), /* PORT151CR */
+       PORTCR(152,     0xe6052098), /* PORT152CR */
+       PORTCR(153,     0xe6052099), /* PORT153CR */
+       PORTCR(154,     0xe605209a), /* PORT154CR */
+       PORTCR(155,     0xe605209b), /* PORT155CR */
+       PORTCR(156,     0xe605209c), /* PORT156CR */
+       PORTCR(157,     0xe605209d), /* PORT157CR */
+       PORTCR(158,     0xe605209e), /* PORT158CR */
+       PORTCR(159,     0xe605209f), /* PORT159CR */
+       PORTCR(160,     0xe60520a0), /* PORT160CR */
+       PORTCR(161,     0xe60520a1), /* PORT161CR */
+       PORTCR(162,     0xe60520a2), /* PORT162CR */
+       PORTCR(163,     0xe60520a3), /* PORT163CR */
+       PORTCR(164,     0xe60520a4), /* PORT164CR */
+       PORTCR(165,     0xe60520a5), /* PORT165CR */
+       PORTCR(166,     0xe60520a6), /* PORT166CR */
+       PORTCR(167,     0xe60520a7), /* PORT167CR */
+       PORTCR(168,     0xe60520a8), /* PORT168CR */
+       PORTCR(169,     0xe60520a9), /* PORT169CR */
+       PORTCR(170,     0xe60520aa), /* PORT170CR */
+       PORTCR(171,     0xe60520ab), /* PORT171CR */
+       PORTCR(172,     0xe60520ac), /* PORT172CR */
+       PORTCR(173,     0xe60520ad), /* PORT173CR */
+       PORTCR(174,     0xe60520ae), /* PORT174CR */
+       PORTCR(175,     0xe60520af), /* PORT175CR */
+       PORTCR(176,     0xe60520b0), /* PORT176CR */
+       PORTCR(177,     0xe60520b1), /* PORT177CR */
+       PORTCR(178,     0xe60520b2), /* PORT178CR */
+       PORTCR(179,     0xe60520b3), /* PORT179CR */
+       PORTCR(180,     0xe60520b4), /* PORT180CR */
+       PORTCR(181,     0xe60520b5), /* PORT181CR */
+       PORTCR(182,     0xe60520b6), /* PORT182CR */
+       PORTCR(183,     0xe60520b7), /* PORT183CR */
+       PORTCR(184,     0xe60520b8), /* PORT184CR */
+       PORTCR(185,     0xe60520b9), /* PORT185CR */
+       PORTCR(186,     0xe60520ba), /* PORT186CR */
+       PORTCR(187,     0xe60520bb), /* PORT187CR */
+       PORTCR(188,     0xe60520bc), /* PORT188CR */
+       PORTCR(189,     0xe60520bd), /* PORT189CR */
+       PORTCR(190,     0xe60520be), /* PORT190CR */
+       PORTCR(191,     0xe60520bf), /* PORT191CR */
+       PORTCR(192,     0xe60520c0), /* PORT192CR */
+       PORTCR(193,     0xe60520c1), /* PORT193CR */
+       PORTCR(194,     0xe60520c2), /* PORT194CR */
+       PORTCR(195,     0xe60520c3), /* PORT195CR */
+       PORTCR(196,     0xe60520c4), /* PORT196CR */
+       PORTCR(197,     0xe60520c5), /* PORT197CR */
+       PORTCR(198,     0xe60520c6), /* PORT198CR */
+       PORTCR(199,     0xe60520c7), /* PORT199CR */
+       PORTCR(200,     0xe60520c8), /* PORT200CR */
+       PORTCR(201,     0xe60520c9), /* PORT201CR */
+       PORTCR(202,     0xe60520ca), /* PORT202CR */
+       PORTCR(203,     0xe60520cb), /* PORT203CR */
+       PORTCR(204,     0xe60520cc), /* PORT204CR */
+       PORTCR(205,     0xe60520cd), /* PORT205CR */
+       PORTCR(206,     0xe60520ce), /* PORT206CR */
+       PORTCR(207,     0xe60520cf), /* PORT207CR */
+       PORTCR(208,     0xe60520d0), /* PORT208CR */
+       PORTCR(209,     0xe60520d1), /* PORT209CR */
+
+       PORTCR(210,     0xe60530d2), /* PORT210CR */
+       PORTCR(211,     0xe60530d3), /* PORT211CR */
+
+       { PINMUX_CFG_REG("MSEL1CR", 0xe605800c, 32, 1) {
+                       MSEL1CR_31_0,   MSEL1CR_31_1,
+                       MSEL1CR_30_0,   MSEL1CR_30_1,
+                       MSEL1CR_29_0,   MSEL1CR_29_1,
+                       MSEL1CR_28_0,   MSEL1CR_28_1,
+                       MSEL1CR_27_0,   MSEL1CR_27_1,
+                       MSEL1CR_26_0,   MSEL1CR_26_1,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       MSEL1CR_16_0,   MSEL1CR_16_1,
+                       MSEL1CR_15_0,   MSEL1CR_15_1,
+                       MSEL1CR_14_0,   MSEL1CR_14_1,
+                       MSEL1CR_13_0,   MSEL1CR_13_1,
+                       MSEL1CR_12_0,   MSEL1CR_12_1,
+                       0, 0, 0, 0,
+                       MSEL1CR_9_0,    MSEL1CR_9_1,
+                       0, 0,
+                       MSEL1CR_7_0,    MSEL1CR_7_1,
+                       MSEL1CR_6_0,    MSEL1CR_6_1,
+                       MSEL1CR_5_0,    MSEL1CR_5_1,
+                       MSEL1CR_4_0,    MSEL1CR_4_1,
+                       MSEL1CR_3_0,    MSEL1CR_3_1,
+                       MSEL1CR_2_0,    MSEL1CR_2_1,
+                       0, 0,
+                       MSEL1CR_0_0,    MSEL1CR_0_1,
+               }
+       },
+       { PINMUX_CFG_REG("MSEL3CR", 0xE6058020, 32, 1) {
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       MSEL3CR_15_0,   MSEL3CR_15_1,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       MSEL3CR_6_0,    MSEL3CR_6_1,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0,
+                       }
+       },
+       { PINMUX_CFG_REG("MSEL4CR", 0xE6058024, 32, 1) {
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       MSEL4CR_19_0,   MSEL4CR_19_1,
+                       MSEL4CR_18_0,   MSEL4CR_18_1,
+                       0, 0, 0, 0,
+                       MSEL4CR_15_0,   MSEL4CR_15_1,
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       MSEL4CR_10_0,   MSEL4CR_10_1,
+                       0, 0, 0, 0, 0, 0,
+                       MSEL4CR_6_0,    MSEL4CR_6_1,
+                       0, 0,
+                       MSEL4CR_4_0,    MSEL4CR_4_1,
+                       0, 0, 0, 0,
+                       MSEL4CR_1_0,    MSEL4CR_1_1,
+                       0, 0,
+               }
+       },
+       { PINMUX_CFG_REG("MSEL5CR", 0xE6058028, 32, 1) {
+                       MSEL5CR_31_0,   MSEL5CR_31_1,
+                       MSEL5CR_30_0,   MSEL5CR_30_1,
+                       MSEL5CR_29_0,   MSEL5CR_29_1,
+                       0, 0,
+                       MSEL5CR_27_0,   MSEL5CR_27_1,
+                       0, 0,
+                       MSEL5CR_25_0,   MSEL5CR_25_1,
+                       0, 0,
+                       MSEL5CR_23_0,   MSEL5CR_23_1,
+                       0, 0,
+                       MSEL5CR_21_0,   MSEL5CR_21_1,
+                       0, 0,
+                       MSEL5CR_19_0,   MSEL5CR_19_1,
+                       0, 0,
+                       MSEL5CR_17_0,   MSEL5CR_17_1,
+                       0, 0,
+                       MSEL5CR_15_0,   MSEL5CR_15_1,
+                       MSEL5CR_14_0,   MSEL5CR_14_1,
+                       MSEL5CR_13_0,   MSEL5CR_13_1,
+                       MSEL5CR_12_0,   MSEL5CR_12_1,
+                       MSEL5CR_11_0,   MSEL5CR_11_1,
+                       MSEL5CR_10_0,   MSEL5CR_10_1,
+                       0, 0,
+                       MSEL5CR_8_0,    MSEL5CR_8_1,
+                       MSEL5CR_7_0,    MSEL5CR_7_1,
+                       MSEL5CR_6_0,    MSEL5CR_6_1,
+                       MSEL5CR_5_0,    MSEL5CR_5_1,
+                       MSEL5CR_4_0,    MSEL5CR_4_1,
+                       MSEL5CR_3_0,    MSEL5CR_3_1,
+                       MSEL5CR_2_0,    MSEL5CR_2_1,
+                       0, 0,
+                       MSEL5CR_0_0,    MSEL5CR_0_1,
+               }
+       },
+       { },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("PORTL031_000DR", 0xe6054800, 32) {
+               PORT31_DATA,    PORT30_DATA,    PORT29_DATA,    PORT28_DATA,
+               PORT27_DATA,    PORT26_DATA,    PORT25_DATA,    PORT24_DATA,
+               PORT23_DATA,    PORT22_DATA,    PORT21_DATA,    PORT20_DATA,
+               PORT19_DATA,    PORT18_DATA,    PORT17_DATA,    PORT16_DATA,
+               PORT15_DATA,    PORT14_DATA,    PORT13_DATA,    PORT12_DATA,
+               PORT11_DATA,    PORT10_DATA,    PORT9_DATA,     PORT8_DATA,
+               PORT7_DATA,     PORT6_DATA,     PORT5_DATA,     PORT4_DATA,
+               PORT3_DATA,     PORT2_DATA,     PORT1_DATA,     PORT0_DATA }
+       },
+       { PINMUX_DATA_REG("PORTL063_032DR", 0xe6054804, 32) {
+               PORT63_DATA,    PORT62_DATA,    PORT61_DATA,    PORT60_DATA,
+               PORT59_DATA,    PORT58_DATA,    PORT57_DATA,    PORT56_DATA,
+               PORT55_DATA,    PORT54_DATA,    PORT53_DATA,    PORT52_DATA,
+               PORT51_DATA,    PORT50_DATA,    PORT49_DATA,    PORT48_DATA,
+               PORT47_DATA,    PORT46_DATA,    PORT45_DATA,    PORT44_DATA,
+               PORT43_DATA,    PORT42_DATA,    PORT41_DATA,    PORT40_DATA,
+               PORT39_DATA,    PORT38_DATA,    PORT37_DATA,    PORT36_DATA,
+               PORT35_DATA,    PORT34_DATA,    PORT33_DATA,    PORT32_DATA }
+       },
+       { PINMUX_DATA_REG("PORTL095_064DR", 0xe6054808, 32) {
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               PORT83_DATA,    PORT82_DATA,    PORT81_DATA,    PORT80_DATA,
+               PORT79_DATA,    PORT78_DATA,    PORT77_DATA,    PORT76_DATA,
+               PORT75_DATA,    PORT74_DATA,    PORT73_DATA,    PORT72_DATA,
+               PORT71_DATA,    PORT70_DATA,    PORT69_DATA,    PORT68_DATA,
+               PORT67_DATA,    PORT66_DATA,    PORT65_DATA,    PORT64_DATA }
+       },
+       { PINMUX_DATA_REG("PORTD095_064DR", 0xe6055808, 32) {
+               PORT95_DATA,    PORT94_DATA,    PORT93_DATA,    PORT92_DATA,
+               PORT91_DATA,    PORT90_DATA,    PORT89_DATA,    PORT88_DATA,
+               PORT87_DATA,    PORT86_DATA,    PORT85_DATA,    PORT84_DATA,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0 }
+       },
+       { PINMUX_DATA_REG("PORTD127_096DR", 0xe605580c, 32) {
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0,              PORT114_DATA,   PORT113_DATA,   PORT112_DATA,
+               PORT111_DATA,   PORT110_DATA,   PORT109_DATA,   PORT108_DATA,
+               PORT107_DATA,   PORT106_DATA,   PORT105_DATA,   PORT104_DATA,
+               PORT103_DATA,   PORT102_DATA,   PORT101_DATA,   PORT100_DATA,
+               PORT99_DATA,    PORT98_DATA,    PORT97_DATA,    PORT96_DATA }
+       },
+       { PINMUX_DATA_REG("PORTR127_096DR", 0xe605680C, 32) {
+               PORT127_DATA,   PORT126_DATA,   PORT125_DATA,   PORT124_DATA,
+               PORT123_DATA,   PORT122_DATA,   PORT121_DATA,   PORT120_DATA,
+               PORT119_DATA,   PORT118_DATA,   PORT117_DATA,   PORT116_DATA,
+               PORT115_DATA,   0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0 }
+       },
+       { PINMUX_DATA_REG("PORTR159_128DR", 0xe6056810, 32) {
+               PORT159_DATA,   PORT158_DATA,   PORT157_DATA,   PORT156_DATA,
+               PORT155_DATA,   PORT154_DATA,   PORT153_DATA,   PORT152_DATA,
+               PORT151_DATA,   PORT150_DATA,   PORT149_DATA,   PORT148_DATA,
+               PORT147_DATA,   PORT146_DATA,   PORT145_DATA,   PORT144_DATA,
+               PORT143_DATA,   PORT142_DATA,   PORT141_DATA,   PORT140_DATA,
+               PORT139_DATA,   PORT138_DATA,   PORT137_DATA,   PORT136_DATA,
+               PORT135_DATA,   PORT134_DATA,   PORT133_DATA,   PORT132_DATA,
+               PORT131_DATA,   PORT130_DATA,   PORT129_DATA,   PORT128_DATA }
+       },
+       { PINMUX_DATA_REG("PORTR191_160DR", 0xe6056814, 32) {
+               PORT191_DATA,   PORT190_DATA,   PORT189_DATA,   PORT188_DATA,
+               PORT187_DATA,   PORT186_DATA,   PORT185_DATA,   PORT184_DATA,
+               PORT183_DATA,   PORT182_DATA,   PORT181_DATA,   PORT180_DATA,
+               PORT179_DATA,   PORT178_DATA,   PORT177_DATA,   PORT176_DATA,
+               PORT175_DATA,   PORT174_DATA,   PORT173_DATA,   PORT172_DATA,
+               PORT171_DATA,   PORT170_DATA,   PORT169_DATA,   PORT168_DATA,
+               PORT167_DATA,   PORT166_DATA,   PORT165_DATA,   PORT164_DATA,
+               PORT163_DATA,   PORT162_DATA,   PORT161_DATA,   PORT160_DATA }
+       },
+       { PINMUX_DATA_REG("PORTR223_192DR", 0xe6056818, 32) {
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0,                           PORT209_DATA,   PORT208_DATA,
+               PORT207_DATA,   PORT206_DATA,   PORT205_DATA,   PORT204_DATA,
+               PORT203_DATA,   PORT202_DATA,   PORT201_DATA,   PORT200_DATA,
+               PORT199_DATA,   PORT198_DATA,   PORT197_DATA,   PORT196_DATA,
+               PORT195_DATA,   PORT194_DATA,   PORT193_DATA,   PORT192_DATA }
+       },
+       { PINMUX_DATA_REG("PORTU223_192DR", 0xe6057818, 32) {
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               PORT211_DATA,   PORT210_DATA, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0,
+               0, 0, 0, 0 }
+       },
+       { },
+};
+
+static struct pinmux_info r8a7740_pinmux_info = {
+       .name           = "r8a7740_pfc",
+       .reserved_id    = PINMUX_RESERVED,
+       .data           = { PINMUX_DATA_BEGIN,
+                           PINMUX_DATA_END },
+       .input          = { PINMUX_INPUT_BEGIN,
+                           PINMUX_INPUT_END },
+       .input_pu       = { PINMUX_INPUT_PULLUP_BEGIN,
+                           PINMUX_INPUT_PULLUP_END },
+       .input_pd       = { PINMUX_INPUT_PULLDOWN_BEGIN,
+                           PINMUX_INPUT_PULLDOWN_END },
+       .output         = { PINMUX_OUTPUT_BEGIN,
+                           PINMUX_OUTPUT_END },
+       .mark           = { PINMUX_MARK_BEGIN,
+                           PINMUX_MARK_END },
+       .function       = { PINMUX_FUNCTION_BEGIN,
+                           PINMUX_FUNCTION_END },
+
+       .first_gpio     = GPIO_PORT0,
+       .last_gpio      = GPIO_FN_TRACEAUD_FROM_MEMC,
+
+       .gpios          = pinmux_gpios,
+       .cfg_regs       = pinmux_config_regs,
+       .data_regs      = pinmux_data_regs,
+
+       .gpio_data      = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+void r8a7740_pinmux_init(void)
+{
+       register_pinmux(&r8a7740_pinmux_info);
+}
diff --git a/arch/arm/mach-shmobile/pfc-r8a7779.c b/arch/arm/mach-shmobile/pfc-r8a7779.c
new file mode 100644 (file)
index 0000000..963532f
--- /dev/null
@@ -0,0 +1,2645 @@
+/*
+ * r8a7779 processor support - PFC hardware block
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <mach/r8a7779.h>
+
+#define CPU_32_PORT(fn, pfx, sfx)                              \
+       PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx),        \
+       PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx),     \
+       PORT_1(fn, pfx##31, sfx)
+
+#define CPU_32_PORT6(fn, pfx, sfx)                             \
+       PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),       \
+       PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),       \
+       PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),       \
+       PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),       \
+       PORT_1(fn, pfx##8, sfx)
+
+#define CPU_ALL_PORT(fn, pfx, sfx)                             \
+       CPU_32_PORT(fn, pfx##_0_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_1_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_2_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_3_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_4_, sfx),                         \
+       CPU_32_PORT(fn, pfx##_5_, sfx),                         \
+       CPU_32_PORT6(fn, pfx##_6_, sfx)
+
+#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
+#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN,   \
+                                      GP##pfx##_IN, GP##pfx##_OUT)
+
+#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
+#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
+
+#define GP_ALL(str)    CPU_ALL_PORT(_PORT_ALL, GP, str)
+#define PINMUX_GPIO_GP_ALL()   CPU_ALL_PORT(_GP_GPIO, , unused)
+#define PINMUX_DATA_GP_ALL()   CPU_ALL_PORT(_GP_DATA, , unused)
+
+
+#define PORT_10_REV(fn, pfx, sfx)                              \
+       PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx),       \
+       PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx),       \
+       PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx),       \
+       PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx),       \
+       PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+
+#define CPU_32_PORT_REV(fn, pfx, sfx)                                  \
+       PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx),             \
+       PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx),     \
+       PORT_10_REV(fn, pfx, sfx)
+
+#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
+#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
+
+#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
+                                                         FN_##ipsr, FN_##fn)
+
+enum {
+       PINMUX_RESERVED = 0,
+
+       PINMUX_DATA_BEGIN,
+       GP_ALL(DATA), /* GP_0_0_DATA -> GP_6_8_DATA */
+       PINMUX_DATA_END,
+
+       PINMUX_INPUT_BEGIN,
+       GP_ALL(IN), /* GP_0_0_IN -> GP_6_8_IN */
+       PINMUX_INPUT_END,
+
+       PINMUX_OUTPUT_BEGIN,
+       GP_ALL(OUT), /* GP_0_0_OUT -> GP_6_8_OUT */
+       PINMUX_OUTPUT_END,
+
+       PINMUX_FUNCTION_BEGIN,
+       GP_ALL(FN), /* GP_0_0_FN -> GP_6_8_FN */
+
+       /* GPSR0 */
+       FN_AVS1, FN_AVS2, FN_IP0_7_6, FN_A17,
+       FN_A18, FN_A19, FN_IP0_9_8, FN_IP0_11_10,
+       FN_IP0_13_12, FN_IP0_15_14, FN_IP0_18_16, FN_IP0_22_19,
+       FN_IP0_24_23, FN_IP0_25, FN_IP0_27_26, FN_IP1_1_0,
+       FN_IP1_3_2, FN_IP1_6_4, FN_IP1_10_7, FN_IP1_14_11,
+       FN_IP1_18_15, FN_IP0_5_3, FN_IP0_30_28, FN_IP2_18_16,
+       FN_IP2_21_19, FN_IP2_30_28, FN_IP3_2_0, FN_IP3_11_9,
+       FN_IP3_14_12, FN_IP3_22_21, FN_IP3_26_24, FN_IP3_31_29,
+
+       /* GPSR1 */
+       FN_IP4_1_0, FN_IP4_4_2, FN_IP4_7_5, FN_IP4_10_8,
+       FN_IP4_11, FN_IP4_12, FN_IP4_13, FN_IP4_14,
+       FN_IP4_15, FN_IP4_16, FN_IP4_19_17, FN_IP4_22_20,
+       FN_IP4_23, FN_IP4_24, FN_IP4_25, FN_IP4_26,
+       FN_IP4_27, FN_IP4_28, FN_IP4_31_29, FN_IP5_2_0,
+       FN_IP5_3, FN_IP5_4, FN_IP5_5, FN_IP5_6,
+       FN_IP5_7, FN_IP5_8, FN_IP5_10_9, FN_IP5_12_11,
+       FN_IP5_14_13, FN_IP5_16_15, FN_IP5_20_17, FN_IP5_23_21,
+
+       /* GPSR2 */
+       FN_IP5_27_24, FN_IP8_20, FN_IP8_22_21, FN_IP8_24_23,
+       FN_IP8_27_25, FN_IP8_30_28, FN_IP9_1_0, FN_IP9_3_2,
+       FN_IP9_4, FN_IP9_5, FN_IP9_6, FN_IP9_7,
+       FN_IP9_9_8, FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14,
+       FN_IP9_18_16, FN_IP9_21_19, FN_IP9_23_22, FN_IP9_25_24,
+       FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
+       FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_17_15,
+       FN_IP10_20_18, FN_IP10_23_21, FN_IP10_25_24, FN_IP10_28_26,
+
+       /* GPSR3 */
+       FN_IP10_31_29, FN_IP11_2_0, FN_IP11_5_3, FN_IP11_8_6,
+       FN_IP11_11_9, FN_IP11_14_12, FN_IP11_17_15, FN_IP11_20_18,
+       FN_IP11_23_21, FN_IP11_26_24, FN_IP11_29_27, FN_IP12_2_0,
+       FN_IP12_5_3, FN_IP12_8_6, FN_IP12_11_9, FN_IP12_14_12,
+       FN_IP12_17_15, FN_IP7_16_15, FN_IP7_18_17, FN_IP7_28_27,
+       FN_IP7_30_29, FN_IP7_20_19, FN_IP7_22_21, FN_IP7_24_23,
+       FN_IP7_26_25, FN_IP1_20_19, FN_IP1_22_21, FN_IP1_24_23,
+       FN_IP5_28, FN_IP5_30_29, FN_IP6_1_0, FN_IP6_3_2,
+
+       /* GPSR4 */
+       FN_IP6_5_4, FN_IP6_7_6, FN_IP6_8, FN_IP6_11_9,
+       FN_IP6_14_12, FN_IP6_17_15, FN_IP6_19_18, FN_IP6_22_20,
+       FN_IP6_24_23, FN_IP6_26_25, FN_IP6_30_29, FN_IP7_1_0,
+       FN_IP7_3_2, FN_IP7_6_4, FN_IP7_9_7, FN_IP7_12_10,
+       FN_IP7_14_13, FN_IP2_7_4, FN_IP2_11_8, FN_IP2_15_12,
+       FN_IP1_28_25, FN_IP2_3_0, FN_IP8_3_0, FN_IP8_7_4,
+       FN_IP8_11_8, FN_IP8_15_12, FN_PENC0, FN_PENC1,
+       FN_IP0_2_0, FN_IP8_17_16, FN_IP8_18, FN_IP8_19,
+
+       /* GPSR5 */
+       FN_A1, FN_A2, FN_A3, FN_A4,
+       FN_A5, FN_A6, FN_A7, FN_A8,
+       FN_A9, FN_A10, FN_A11, FN_A12,
+       FN_A13, FN_A14, FN_A15, FN_A16,
+       FN_RD, FN_WE0, FN_WE1, FN_EX_WAIT0,
+       FN_IP3_23, FN_IP3_27, FN_IP3_28, FN_IP2_22,
+       FN_IP2_23, FN_IP2_24, FN_IP2_25, FN_IP2_26,
+       FN_IP2_27, FN_IP3_3, FN_IP3_4, FN_IP3_5,
+
+       /* GPSR6 */
+       FN_IP3_6, FN_IP3_7, FN_IP3_8, FN_IP3_15,
+       FN_IP3_16, FN_IP3_17, FN_IP3_18, FN_IP3_19,
+       FN_IP3_20,
+
+       /* IPSR0 */
+       FN_RD_WR, FN_FWE, FN_ATAG0, FN_VI1_R7,
+       FN_HRTS1, FN_RX4_C,
+       FN_CS1_A26, FN_HSPI_TX2, FN_SDSELF_B,
+       FN_CS0, FN_HSPI_CS2_B,
+       FN_CLKOUT, FN_TX3C_IRDA_TX_C, FN_PWM0_B,
+       FN_A25, FN_SD1_WP, FN_MMC0_D5, FN_FD5,
+       FN_HSPI_RX2, FN_VI1_R3, FN_TX5_B, FN_SSI_SDATA7_B,
+       FN_CTS0_B,
+       FN_A24, FN_SD1_CD, FN_MMC0_D4, FN_FD4,
+       FN_HSPI_CS2, FN_VI1_R2, FN_SSI_WS78_B,
+       FN_A23, FN_FCLE, FN_HSPI_CLK2, FN_VI1_R1,
+       FN_A22, FN_RX5_D, FN_HSPI_RX2_B, FN_VI1_R0,
+       FN_A21, FN_SCK5_D, FN_HSPI_CLK2_B,
+       FN_A20, FN_TX5_D, FN_HSPI_TX2_B,
+       FN_A0, FN_SD1_DAT3, FN_MMC0_D3, FN_FD3,
+       FN_BS, FN_SD1_DAT2, FN_MMC0_D2, FN_FD2,
+       FN_ATADIR0, FN_SDSELF, FN_HCTS1, FN_TX4_C,
+       FN_PENC2, FN_SCK0, FN_PWM1, FN_PWMFSW0,
+       FN_SCIF_CLK, FN_TCLK0_C,
+
+       /* IPSR1 */
+       FN_EX_CS0, FN_RX3_C_IRDA_RX_C, FN_MMC0_D6,
+       FN_FD6, FN_EX_CS1, FN_MMC0_D7, FN_FD7,
+       FN_EX_CS2, FN_SD1_CLK, FN_MMC0_CLK, FN_FALE,
+       FN_ATACS00, FN_EX_CS3, FN_SD1_CMD, FN_MMC0_CMD,
+       FN_FRE, FN_ATACS10, FN_VI1_R4, FN_RX5_B,
+       FN_HSCK1, FN_SSI_SDATA8_B, FN_RTS0_B_TANS_B, FN_SSI_SDATA9,
+       FN_EX_CS4, FN_SD1_DAT0, FN_MMC0_D0, FN_FD0,
+       FN_ATARD0, FN_VI1_R5, FN_SCK5_B, FN_HTX1,
+       FN_TX2_E, FN_TX0_B, FN_SSI_SCK9, FN_EX_CS5,
+       FN_SD1_DAT1, FN_MMC0_D1, FN_FD1, FN_ATAWR0,
+       FN_VI1_R6, FN_HRX1, FN_RX2_E, FN_RX0_B,
+       FN_SSI_WS9, FN_MLB_CLK, FN_PWM2, FN_SCK4,
+       FN_MLB_SIG, FN_PWM3, FN_TX4, FN_MLB_DAT,
+       FN_PWM4, FN_RX4, FN_HTX0, FN_TX1,
+       FN_SDATA, FN_CTS0_C, FN_SUB_TCK, FN_CC5_STATE2,
+       FN_CC5_STATE10, FN_CC5_STATE18, FN_CC5_STATE26, FN_CC5_STATE34,
+
+       /* IPSR2 */
+       FN_HRX0, FN_RX1, FN_SCKZ, FN_RTS0_C_TANS_C,
+       FN_SUB_TDI, FN_CC5_STATE3, FN_CC5_STATE11, FN_CC5_STATE19,
+       FN_CC5_STATE27, FN_CC5_STATE35, FN_HSCK0, FN_SCK1,
+       FN_MTS, FN_PWM5, FN_SCK0_C, FN_SSI_SDATA9_B,
+       FN_SUB_TDO, FN_CC5_STATE0, FN_CC5_STATE8, FN_CC5_STATE16,
+       FN_CC5_STATE24, FN_CC5_STATE32, FN_HCTS0, FN_CTS1,
+       FN_STM, FN_PWM0_D, FN_RX0_C, FN_SCIF_CLK_C,
+       FN_SUB_TRST, FN_TCLK1_B, FN_CC5_OSCOUT, FN_HRTS0,
+       FN_RTS1_TANS, FN_MDATA, FN_TX0_C, FN_SUB_TMS,
+       FN_CC5_STATE1, FN_CC5_STATE9, FN_CC5_STATE17, FN_CC5_STATE25,
+       FN_CC5_STATE33, FN_DU0_DR0, FN_LCDOUT0, FN_DREQ0,
+       FN_GPS_CLK_B, FN_AUDATA0, FN_TX5_C, FN_DU0_DR1,
+       FN_LCDOUT1, FN_DACK0, FN_DRACK0, FN_GPS_SIGN_B,
+       FN_AUDATA1, FN_RX5_C, FN_DU0_DR2, FN_LCDOUT2,
+       FN_DU0_DR3, FN_LCDOUT3, FN_DU0_DR4, FN_LCDOUT4,
+       FN_DU0_DR5, FN_LCDOUT5, FN_DU0_DR6, FN_LCDOUT6,
+       FN_DU0_DR7, FN_LCDOUT7, FN_DU0_DG0, FN_LCDOUT8,
+       FN_DREQ1, FN_SCL2, FN_AUDATA2,
+
+       /* IPSR3 */
+       FN_DU0_DG1, FN_LCDOUT9, FN_DACK1, FN_SDA2,
+       FN_AUDATA3, FN_DU0_DG2, FN_LCDOUT10, FN_DU0_DG3,
+       FN_LCDOUT11, FN_DU0_DG4, FN_LCDOUT12, FN_DU0_DG5,
+       FN_LCDOUT13, FN_DU0_DG6, FN_LCDOUT14, FN_DU0_DG7,
+       FN_LCDOUT15, FN_DU0_DB0, FN_LCDOUT16, FN_EX_WAIT1,
+       FN_SCL1, FN_TCLK1, FN_AUDATA4, FN_DU0_DB1,
+       FN_LCDOUT17, FN_EX_WAIT2, FN_SDA1, FN_GPS_MAG_B,
+       FN_AUDATA5, FN_SCK5_C, FN_DU0_DB2, FN_LCDOUT18,
+       FN_DU0_DB3, FN_LCDOUT19, FN_DU0_DB4, FN_LCDOUT20,
+       FN_DU0_DB5, FN_LCDOUT21, FN_DU0_DB6, FN_LCDOUT22,
+       FN_DU0_DB7, FN_LCDOUT23, FN_DU0_DOTCLKIN, FN_QSTVA_QVS,
+       FN_TX3_D_IRDA_TX_D, FN_SCL3_B, FN_DU0_DOTCLKOUT0, FN_QCLK,
+       FN_DU0_DOTCLKOUT1, FN_QSTVB_QVE, FN_RX3_D_IRDA_RX_D, FN_SDA3_B,
+       FN_SDA2_C, FN_DACK0_B, FN_DRACK0_B, FN_DU0_EXHSYNC_DU0_HSYNC,
+       FN_QSTH_QHS, FN_DU0_EXVSYNC_DU0_VSYNC, FN_QSTB_QHE,
+       FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, FN_QCPV_QDE, FN_CAN1_TX,
+       FN_TX2_C, FN_SCL2_C, FN_REMOCON,
+
+       /* IPSR4 */
+       FN_DU0_DISP, FN_QPOLA, FN_CAN_CLK_C, FN_SCK2_C,
+       FN_DU0_CDE, FN_QPOLB, FN_CAN1_RX, FN_RX2_C,
+       FN_DREQ0_B, FN_SSI_SCK78_B, FN_SCK0_B, FN_DU1_DR0,
+       FN_VI2_DATA0_VI2_B0, FN_PWM6, FN_SD3_CLK, FN_TX3_E_IRDA_TX_E,
+       FN_AUDCK, FN_PWMFSW0_B, FN_DU1_DR1, FN_VI2_DATA1_VI2_B1,
+       FN_PWM0, FN_SD3_CMD, FN_RX3_E_IRDA_RX_E, FN_AUDSYNC,
+       FN_CTS0_D, FN_DU1_DR2, FN_VI2_G0, FN_DU1_DR3,
+       FN_VI2_G1, FN_DU1_DR4, FN_VI2_G2, FN_DU1_DR5,
+       FN_VI2_G3, FN_DU1_DR6, FN_VI2_G4, FN_DU1_DR7,
+       FN_VI2_G5, FN_DU1_DG0, FN_VI2_DATA2_VI2_B2, FN_SCL1_B,
+       FN_SD3_DAT2, FN_SCK3_E, FN_AUDATA6, FN_TX0_D,
+       FN_DU1_DG1, FN_VI2_DATA3_VI2_B3, FN_SDA1_B, FN_SD3_DAT3,
+       FN_SCK5, FN_AUDATA7, FN_RX0_D, FN_DU1_DG2,
+       FN_VI2_G6, FN_DU1_DG3, FN_VI2_G7, FN_DU1_DG4,
+       FN_VI2_R0, FN_DU1_DG5, FN_VI2_R1, FN_DU1_DG6,
+       FN_VI2_R2, FN_DU1_DG7, FN_VI2_R3, FN_DU1_DB0,
+       FN_VI2_DATA4_VI2_B4, FN_SCL2_B, FN_SD3_DAT0, FN_TX5,
+       FN_SCK0_D,
+
+       /* IPSR5 */
+       FN_DU1_DB1, FN_VI2_DATA5_VI2_B5, FN_SDA2_B, FN_SD3_DAT1,
+       FN_RX5, FN_RTS0_D_TANS_D, FN_DU1_DB2, FN_VI2_R4,
+       FN_DU1_DB3, FN_VI2_R5, FN_DU1_DB4, FN_VI2_R6,
+       FN_DU1_DB5, FN_VI2_R7, FN_DU1_DB6, FN_SCL2_D,
+       FN_DU1_DB7, FN_SDA2_D, FN_DU1_DOTCLKIN, FN_VI2_CLKENB,
+       FN_HSPI_CS1, FN_SCL1_D, FN_DU1_DOTCLKOUT, FN_VI2_FIELD,
+       FN_SDA1_D, FN_DU1_EXHSYNC_DU1_HSYNC, FN_VI2_HSYNC,
+       FN_VI3_HSYNC, FN_DU1_EXVSYNC_DU1_VSYNC, FN_VI2_VSYNC, FN_VI3_VSYNC,
+       FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_VI2_CLK, FN_TX3_B_IRDA_TX_B,
+       FN_SD3_CD, FN_HSPI_TX1, FN_VI1_CLKENB, FN_VI3_CLKENB,
+       FN_AUDIO_CLKC, FN_TX2_D, FN_SPEEDIN, FN_GPS_SIGN_D,
+       FN_DU1_DISP, FN_VI2_DATA6_VI2_B6, FN_TCLK0, FN_QSTVA_B_QVS_B,
+       FN_HSPI_CLK1, FN_SCK2_D, FN_AUDIO_CLKOUT_B, FN_GPS_MAG_D,
+       FN_DU1_CDE, FN_VI2_DATA7_VI2_B7, FN_RX3_B_IRDA_RX_B,
+       FN_SD3_WP, FN_HSPI_RX1, FN_VI1_FIELD, FN_VI3_FIELD,
+       FN_AUDIO_CLKOUT, FN_RX2_D, FN_GPS_CLK_C, FN_GPS_CLK_D,
+       FN_AUDIO_CLKA, FN_CAN_TXCLK, FN_AUDIO_CLKB, FN_USB_OVC2,
+       FN_CAN_DEBUGOUT0, FN_MOUT0,
+
+       /* IPSR6 */
+       FN_SSI_SCK0129, FN_CAN_DEBUGOUT1, FN_MOUT1, FN_SSI_WS0129,
+       FN_CAN_DEBUGOUT2, FN_MOUT2, FN_SSI_SDATA0, FN_CAN_DEBUGOUT3,
+       FN_MOUT5, FN_SSI_SDATA1, FN_CAN_DEBUGOUT4, FN_MOUT6,
+       FN_SSI_SDATA2, FN_CAN_DEBUGOUT5, FN_SSI_SCK34, FN_CAN_DEBUGOUT6,
+       FN_CAN0_TX_B, FN_IERX, FN_SSI_SCK9_C, FN_SSI_WS34,
+       FN_CAN_DEBUGOUT7, FN_CAN0_RX_B, FN_IETX, FN_SSI_WS9_C,
+       FN_SSI_SDATA3, FN_PWM0_C, FN_CAN_DEBUGOUT8, FN_CAN_CLK_B,
+       FN_IECLK, FN_SCIF_CLK_B, FN_TCLK0_B, FN_SSI_SDATA4,
+       FN_CAN_DEBUGOUT9, FN_SSI_SDATA9_C, FN_SSI_SCK5, FN_ADICLK,
+       FN_CAN_DEBUGOUT10, FN_SCK3, FN_TCLK0_D, FN_SSI_WS5,
+       FN_ADICS_SAMP, FN_CAN_DEBUGOUT11, FN_TX3_IRDA_TX, FN_SSI_SDATA5,
+       FN_ADIDATA, FN_CAN_DEBUGOUT12, FN_RX3_IRDA_RX, FN_SSI_SCK6,
+       FN_ADICHS0, FN_CAN0_TX, FN_IERX_B,
+
+       /* IPSR7 */
+       FN_SSI_WS6, FN_ADICHS1, FN_CAN0_RX, FN_IETX_B,
+       FN_SSI_SDATA6, FN_ADICHS2, FN_CAN_CLK, FN_IECLK_B,
+       FN_SSI_SCK78, FN_CAN_DEBUGOUT13, FN_IRQ0_B, FN_SSI_SCK9_B,
+       FN_HSPI_CLK1_C, FN_SSI_WS78, FN_CAN_DEBUGOUT14, FN_IRQ1_B,
+       FN_SSI_WS9_B, FN_HSPI_CS1_C, FN_SSI_SDATA7, FN_CAN_DEBUGOUT15,
+       FN_IRQ2_B, FN_TCLK1_C, FN_HSPI_TX1_C, FN_SSI_SDATA8,
+       FN_VSP, FN_IRQ3_B, FN_HSPI_RX1_C, FN_SD0_CLK,
+       FN_ATACS01, FN_SCK1_B, FN_SD0_CMD, FN_ATACS11,
+       FN_TX1_B, FN_CC5_TDO, FN_SD0_DAT0, FN_ATADIR1,
+       FN_RX1_B, FN_CC5_TRST, FN_SD0_DAT1, FN_ATAG1,
+       FN_SCK2_B, FN_CC5_TMS, FN_SD0_DAT2, FN_ATARD1,
+       FN_TX2_B, FN_CC5_TCK, FN_SD0_DAT3, FN_ATAWR1,
+       FN_RX2_B, FN_CC5_TDI, FN_SD0_CD, FN_DREQ2,
+       FN_RTS1_B_TANS_B, FN_SD0_WP, FN_DACK2, FN_CTS1_B,
+
+       /* IPSR8 */
+       FN_HSPI_CLK0, FN_CTS0, FN_USB_OVC0, FN_AD_CLK,
+       FN_CC5_STATE4, FN_CC5_STATE12, FN_CC5_STATE20, FN_CC5_STATE28,
+       FN_CC5_STATE36, FN_HSPI_CS0, FN_RTS0_TANS, FN_USB_OVC1,
+       FN_AD_DI, FN_CC5_STATE5, FN_CC5_STATE13, FN_CC5_STATE21,
+       FN_CC5_STATE29, FN_CC5_STATE37, FN_HSPI_TX0, FN_TX0,
+       FN_CAN_DEBUG_HW_TRIGGER, FN_AD_DO, FN_CC5_STATE6, FN_CC5_STATE14,
+       FN_CC5_STATE22, FN_CC5_STATE30, FN_CC5_STATE38, FN_HSPI_RX0,
+       FN_RX0, FN_CAN_STEP0, FN_AD_NCS, FN_CC5_STATE7,
+       FN_CC5_STATE15, FN_CC5_STATE23, FN_CC5_STATE31, FN_CC5_STATE39,
+       FN_FMCLK, FN_RDS_CLK, FN_PCMOE, FN_BPFCLK,
+       FN_PCMWE, FN_FMIN, FN_RDS_DATA, FN_VI0_CLK,
+       FN_MMC1_CLK, FN_VI0_CLKENB, FN_TX1_C, FN_HTX1_B,
+       FN_MT1_SYNC, FN_VI0_FIELD, FN_RX1_C, FN_HRX1_B,
+       FN_VI0_HSYNC, FN_VI0_DATA0_B_VI0_B0_B, FN_CTS1_C, FN_TX4_D,
+       FN_MMC1_CMD, FN_HSCK1_B, FN_VI0_VSYNC, FN_VI0_DATA1_B_VI0_B1_B,
+       FN_RTS1_C_TANS_C, FN_RX4_D, FN_PWMFSW0_C,
+
+       /* IPSR9 */
+       FN_VI0_DATA0_VI0_B0, FN_HRTS1_B, FN_MT1_VCXO, FN_VI0_DATA1_VI0_B1,
+       FN_HCTS1_B, FN_MT1_PWM, FN_VI0_DATA2_VI0_B2, FN_MMC1_D0,
+       FN_VI0_DATA3_VI0_B3, FN_MMC1_D1, FN_VI0_DATA4_VI0_B4, FN_MMC1_D2,
+       FN_VI0_DATA5_VI0_B5, FN_MMC1_D3, FN_VI0_DATA6_VI0_B6, FN_MMC1_D4,
+       FN_ARM_TRACEDATA_0, FN_VI0_DATA7_VI0_B7, FN_MMC1_D5,
+       FN_ARM_TRACEDATA_1, FN_VI0_G0, FN_SSI_SCK78_C, FN_IRQ0,
+       FN_ARM_TRACEDATA_2, FN_VI0_G1, FN_SSI_WS78_C, FN_IRQ1,
+       FN_ARM_TRACEDATA_3, FN_VI0_G2, FN_ETH_TXD1, FN_MMC1_D6,
+       FN_ARM_TRACEDATA_4, FN_TS_SPSYNC0, FN_VI0_G3, FN_ETH_CRS_DV,
+       FN_MMC1_D7, FN_ARM_TRACEDATA_5, FN_TS_SDAT0, FN_VI0_G4,
+       FN_ETH_TX_EN, FN_SD2_DAT0_B, FN_ARM_TRACEDATA_6, FN_VI0_G5,
+       FN_ETH_RX_ER, FN_SD2_DAT1_B, FN_ARM_TRACEDATA_7, FN_VI0_G6,
+       FN_ETH_RXD0, FN_SD2_DAT2_B, FN_ARM_TRACEDATA_8, FN_VI0_G7,
+       FN_ETH_RXD1, FN_SD2_DAT3_B, FN_ARM_TRACEDATA_9,
+
+       /* IPSR10 */
+       FN_VI0_R0, FN_SSI_SDATA7_C, FN_SCK1_C, FN_DREQ1_B,
+       FN_ARM_TRACEDATA_10, FN_DREQ0_C, FN_VI0_R1, FN_SSI_SDATA8_C,
+       FN_DACK1_B, FN_ARM_TRACEDATA_11, FN_DACK0_C, FN_DRACK0_C,
+       FN_VI0_R2, FN_ETH_LINK, FN_SD2_CLK_B, FN_IRQ2,
+       FN_ARM_TRACEDATA_12, FN_VI0_R3, FN_ETH_MAGIC, FN_SD2_CMD_B,
+       FN_IRQ3, FN_ARM_TRACEDATA_13, FN_VI0_R4, FN_ETH_REFCLK,
+       FN_SD2_CD_B, FN_HSPI_CLK1_B, FN_ARM_TRACEDATA_14, FN_MT1_CLK,
+       FN_TS_SCK0, FN_VI0_R5, FN_ETH_TXD0, FN_SD2_WP_B, FN_HSPI_CS1_B,
+       FN_ARM_TRACEDATA_15, FN_MT1_D, FN_TS_SDEN0, FN_VI0_R6,
+       FN_ETH_MDC, FN_DREQ2_C, FN_HSPI_TX1_B, FN_TRACECLK,
+       FN_MT1_BEN, FN_PWMFSW0_D, FN_VI0_R7, FN_ETH_MDIO,
+       FN_DACK2_C, FN_HSPI_RX1_B, FN_SCIF_CLK_D, FN_TRACECTL,
+       FN_MT1_PEN, FN_VI1_CLK, FN_SIM_D, FN_SDA3,
+       FN_VI1_HSYNC, FN_VI3_CLK, FN_SSI_SCK4, FN_GPS_SIGN_C,
+       FN_PWMFSW0_E, FN_VI1_VSYNC, FN_AUDIO_CLKOUT_C, FN_SSI_WS4,
+       FN_SIM_CLK, FN_GPS_MAG_C, FN_SPV_TRST, FN_SCL3,
+
+       /* IPSR11 */
+       FN_VI1_DATA0_VI1_B0, FN_SD2_DAT0, FN_SIM_RST, FN_SPV_TCK,
+       FN_ADICLK_B, FN_VI1_DATA1_VI1_B1, FN_SD2_DAT1, FN_MT0_CLK,
+       FN_SPV_TMS, FN_ADICS_B_SAMP_B, FN_VI1_DATA2_VI1_B2, FN_SD2_DAT2,
+       FN_MT0_D, FN_SPVTDI, FN_ADIDATA_B, FN_VI1_DATA3_VI1_B3,
+       FN_SD2_DAT3, FN_MT0_BEN, FN_SPV_TDO, FN_ADICHS0_B,
+       FN_VI1_DATA4_VI1_B4, FN_SD2_CLK, FN_MT0_PEN, FN_SPA_TRST,
+       FN_HSPI_CLK1_D, FN_ADICHS1_B, FN_VI1_DATA5_VI1_B5, FN_SD2_CMD,
+       FN_MT0_SYNC, FN_SPA_TCK, FN_HSPI_CS1_D, FN_ADICHS2_B,
+       FN_VI1_DATA6_VI1_B6, FN_SD2_CD, FN_MT0_VCXO, FN_SPA_TMS,
+       FN_HSPI_TX1_D, FN_VI1_DATA7_VI1_B7, FN_SD2_WP, FN_MT0_PWM,
+       FN_SPA_TDI, FN_HSPI_RX1_D, FN_VI1_G0, FN_VI3_DATA0,
+       FN_DU1_DOTCLKOUT1, FN_TS_SCK1, FN_DREQ2_B, FN_TX2,
+       FN_SPA_TDO, FN_HCTS0_B, FN_VI1_G1, FN_VI3_DATA1,
+       FN_SSI_SCK1, FN_TS_SDEN1, FN_DACK2_B, FN_RX2, FN_HRTS0_B,
+
+       /* IPSR12 */
+       FN_VI1_G2, FN_VI3_DATA2, FN_SSI_WS1, FN_TS_SPSYNC1,
+       FN_SCK2, FN_HSCK0_B, FN_VI1_G3, FN_VI3_DATA3,
+       FN_SSI_SCK2, FN_TS_SDAT1, FN_SCL1_C, FN_HTX0_B,
+       FN_VI1_G4, FN_VI3_DATA4, FN_SSI_WS2, FN_SDA1_C,
+       FN_SIM_RST_B, FN_HRX0_B, FN_VI1_G5, FN_VI3_DATA5,
+       FN_GPS_CLK, FN_FSE, FN_TX4_B, FN_SIM_D_B,
+       FN_VI1_G6, FN_VI3_DATA6, FN_GPS_SIGN, FN_FRB,
+       FN_RX4_B, FN_SIM_CLK_B, FN_VI1_G7, FN_VI3_DATA7,
+       FN_GPS_MAG, FN_FCE, FN_SCK4_B,
+
+       FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+       FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+       FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
+       FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
+       FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
+       FN_SEL_SCIF2_3, FN_SEL_SCIF2_4,
+       FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
+       FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, FN_SEL_SCIF0_3,
+       FN_SEL_SSI9_0, FN_SEL_SSI9_1, FN_SEL_SSI9_2,
+       FN_SEL_SSI8_0, FN_SEL_SSI8_1, FN_SEL_SSI8_2,
+       FN_SEL_SSI7_0, FN_SEL_SSI7_1, FN_SEL_SSI7_2,
+       FN_SEL_VI0_0, FN_SEL_VI0_1,
+       FN_SEL_SD2_0, FN_SEL_SD2_1,
+       FN_SEL_INT3_0, FN_SEL_INT3_1,
+       FN_SEL_INT2_0, FN_SEL_INT2_1,
+       FN_SEL_INT1_0, FN_SEL_INT1_1,
+       FN_SEL_INT0_0, FN_SEL_INT0_1,
+       FN_SEL_IE_0, FN_SEL_IE_1,
+       FN_SEL_EXBUS2_0, FN_SEL_EXBUS2_1, FN_SEL_EXBUS2_2,
+       FN_SEL_EXBUS1_0, FN_SEL_EXBUS1_1,
+       FN_SEL_EXBUS0_0, FN_SEL_EXBUS0_1, FN_SEL_EXBUS0_2,
+
+       FN_SEL_TMU1_0, FN_SEL_TMU1_1, FN_SEL_TMU1_2,
+       FN_SEL_TMU0_0, FN_SEL_TMU0_1, FN_SEL_TMU0_2, FN_SEL_TMU0_3,
+       FN_SEL_SCIF_0, FN_SEL_SCIF_1, FN_SEL_SCIF_2, FN_SEL_SCIF_3,
+       FN_SEL_CANCLK_0, FN_SEL_CANCLK_1, FN_SEL_CANCLK_2,
+       FN_SEL_CAN0_0, FN_SEL_CAN0_1,
+       FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1,
+       FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1,
+       FN_SEL_PWMFSW_0, FN_SEL_PWMFSW_1, FN_SEL_PWMFSW_2,
+       FN_SEL_PWMFSW_3, FN_SEL_PWMFSW_4,
+       FN_SEL_ADI_0, FN_SEL_ADI_1,
+       FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, FN_SEL_GPS_3,
+       FN_SEL_SIM_0, FN_SEL_SIM_1,
+       FN_SEL_HSPI2_0, FN_SEL_HSPI2_1,
+       FN_SEL_HSPI1_0, FN_SEL_HSPI1_1, FN_SEL_HSPI1_2, FN_SEL_HSPI1_3,
+       FN_SEL_I2C3_0, FN_SEL_I2C3_1,
+       FN_SEL_I2C2_0, FN_SEL_I2C2_1, FN_SEL_I2C2_2, FN_SEL_I2C2_3,
+       FN_SEL_I2C1_0, FN_SEL_I2C1_1, FN_SEL_I2C1_2, FN_SEL_I2C1_3,
+       PINMUX_FUNCTION_END,
+
+       PINMUX_MARK_BEGIN,
+       AVS1_MARK, AVS2_MARK, A17_MARK, A18_MARK,
+       A19_MARK,
+
+       RD_WR_MARK, FWE_MARK, ATAG0_MARK, VI1_R7_MARK,
+       HRTS1_MARK, RX4_C_MARK,
+       CS1_A26_MARK, HSPI_TX2_MARK, SDSELF_B_MARK,
+       CS0_MARK, HSPI_CS2_B_MARK,
+       CLKOUT_MARK, TX3C_IRDA_TX_C_MARK, PWM0_B_MARK,
+       A25_MARK, SD1_WP_MARK, MMC0_D5_MARK, FD5_MARK,
+       HSPI_RX2_MARK, VI1_R3_MARK, TX5_B_MARK, SSI_SDATA7_B_MARK, CTS0_B_MARK,
+       A24_MARK, SD1_CD_MARK, MMC0_D4_MARK, FD4_MARK,
+       HSPI_CS2_MARK, VI1_R2_MARK, SSI_WS78_B_MARK,
+       A23_MARK, FCLE_MARK, HSPI_CLK2_MARK, VI1_R1_MARK,
+       A22_MARK, RX5_D_MARK, HSPI_RX2_B_MARK, VI1_R0_MARK,
+       A21_MARK, SCK5_D_MARK, HSPI_CLK2_B_MARK,
+       A20_MARK, TX5_D_MARK, HSPI_TX2_B_MARK,
+       A0_MARK, SD1_DAT3_MARK, MMC0_D3_MARK, FD3_MARK,
+       BS_MARK, SD1_DAT2_MARK, MMC0_D2_MARK, FD2_MARK,
+       ATADIR0_MARK, SDSELF_MARK, HCTS1_MARK, TX4_C_MARK,
+       PENC2_MARK, SCK0_MARK, PWM1_MARK, PWMFSW0_MARK,
+       SCIF_CLK_MARK, TCLK0_C_MARK,
+
+       EX_CS0_MARK, RX3_C_IRDA_RX_C_MARK, MMC0_D6_MARK,
+       FD6_MARK, EX_CS1_MARK, MMC0_D7_MARK, FD7_MARK,
+       EX_CS2_MARK, SD1_CLK_MARK, MMC0_CLK_MARK, FALE_MARK,
+       ATACS00_MARK, EX_CS3_MARK, SD1_CMD_MARK, MMC0_CMD_MARK,
+       FRE_MARK, ATACS10_MARK, VI1_R4_MARK, RX5_B_MARK,
+       HSCK1_MARK, SSI_SDATA8_B_MARK, RTS0_B_TANS_B_MARK, SSI_SDATA9_MARK,
+       EX_CS4_MARK, SD1_DAT0_MARK, MMC0_D0_MARK, FD0_MARK,
+       ATARD0_MARK, VI1_R5_MARK, SCK5_B_MARK, HTX1_MARK,
+       TX2_E_MARK, TX0_B_MARK, SSI_SCK9_MARK, EX_CS5_MARK,
+       SD1_DAT1_MARK, MMC0_D1_MARK, FD1_MARK, ATAWR0_MARK,
+       VI1_R6_MARK, HRX1_MARK, RX2_E_MARK, RX0_B_MARK,
+       SSI_WS9_MARK, MLB_CLK_MARK, PWM2_MARK, SCK4_MARK,
+       MLB_SIG_MARK, PWM3_MARK, TX4_MARK, MLB_DAT_MARK,
+       PWM4_MARK, RX4_MARK, HTX0_MARK, TX1_MARK,
+       SDATA_MARK, CTS0_C_MARK, SUB_TCK_MARK, CC5_STATE2_MARK,
+       CC5_STATE10_MARK, CC5_STATE18_MARK, CC5_STATE26_MARK, CC5_STATE34_MARK,
+
+       HRX0_MARK, RX1_MARK, SCKZ_MARK, RTS0_C_TANS_C_MARK,
+       SUB_TDI_MARK, CC5_STATE3_MARK, CC5_STATE11_MARK, CC5_STATE19_MARK,
+       CC5_STATE27_MARK, CC5_STATE35_MARK, HSCK0_MARK, SCK1_MARK,
+       MTS_MARK, PWM5_MARK, SCK0_C_MARK, SSI_SDATA9_B_MARK,
+       SUB_TDO_MARK, CC5_STATE0_MARK, CC5_STATE8_MARK, CC5_STATE16_MARK,
+       CC5_STATE24_MARK, CC5_STATE32_MARK, HCTS0_MARK, CTS1_MARK,
+       STM_MARK, PWM0_D_MARK, RX0_C_MARK, SCIF_CLK_C_MARK,
+       SUB_TRST_MARK, TCLK1_B_MARK, CC5_OSCOUT_MARK, HRTS0_MARK,
+       RTS1_TANS_MARK, MDATA_MARK, TX0_C_MARK, SUB_TMS_MARK,
+       CC5_STATE1_MARK, CC5_STATE9_MARK, CC5_STATE17_MARK, CC5_STATE25_MARK,
+       CC5_STATE33_MARK, DU0_DR0_MARK, LCDOUT0_MARK, DREQ0_MARK,
+       GPS_CLK_B_MARK, AUDATA0_MARK, TX5_C_MARK, DU0_DR1_MARK,
+       LCDOUT1_MARK, DACK0_MARK, DRACK0_MARK, GPS_SIGN_B_MARK,
+       AUDATA1_MARK, RX5_C_MARK, DU0_DR2_MARK, LCDOUT2_MARK,
+       DU0_DR3_MARK, LCDOUT3_MARK, DU0_DR4_MARK, LCDOUT4_MARK,
+       DU0_DR5_MARK, LCDOUT5_MARK, DU0_DR6_MARK, LCDOUT6_MARK,
+       DU0_DR7_MARK, LCDOUT7_MARK, DU0_DG0_MARK, LCDOUT8_MARK,
+       DREQ1_MARK, SCL2_MARK, AUDATA2_MARK,
+
+       DU0_DG1_MARK, LCDOUT9_MARK, DACK1_MARK, SDA2_MARK,
+       AUDATA3_MARK, DU0_DG2_MARK, LCDOUT10_MARK, DU0_DG3_MARK,
+       LCDOUT11_MARK, DU0_DG4_MARK, LCDOUT12_MARK, DU0_DG5_MARK,
+       LCDOUT13_MARK, DU0_DG6_MARK, LCDOUT14_MARK, DU0_DG7_MARK,
+       LCDOUT15_MARK, DU0_DB0_MARK, LCDOUT16_MARK, EX_WAIT1_MARK,
+       SCL1_MARK, TCLK1_MARK, AUDATA4_MARK, DU0_DB1_MARK,
+       LCDOUT17_MARK, EX_WAIT2_MARK, SDA1_MARK, GPS_MAG_B_MARK,
+       AUDATA5_MARK, SCK5_C_MARK, DU0_DB2_MARK, LCDOUT18_MARK,
+       DU0_DB3_MARK, LCDOUT19_MARK, DU0_DB4_MARK, LCDOUT20_MARK,
+       DU0_DB5_MARK, LCDOUT21_MARK, DU0_DB6_MARK, LCDOUT22_MARK,
+       DU0_DB7_MARK, LCDOUT23_MARK, DU0_DOTCLKIN_MARK, QSTVA_QVS_MARK,
+       TX3_D_IRDA_TX_D_MARK, SCL3_B_MARK, DU0_DOTCLKOUT0_MARK, QCLK_MARK,
+       DU0_DOTCLKOUT1_MARK, QSTVB_QVE_MARK, RX3_D_IRDA_RX_D_MARK, SDA3_B_MARK,
+       SDA2_C_MARK, DACK0_B_MARK, DRACK0_B_MARK, DU0_EXHSYNC_DU0_HSYNC_MARK,
+       QSTH_QHS_MARK, DU0_EXVSYNC_DU0_VSYNC_MARK, QSTB_QHE_MARK,
+       DU0_EXODDF_DU0_ODDF_DISP_CDE_MARK, QCPV_QDE_MARK, CAN1_TX_MARK,
+       TX2_C_MARK, SCL2_C_MARK, REMOCON_MARK,
+
+       DU0_DISP_MARK, QPOLA_MARK, CAN_CLK_C_MARK, SCK2_C_MARK,
+       DU0_CDE_MARK, QPOLB_MARK, CAN1_RX_MARK, RX2_C_MARK,
+       DREQ0_B_MARK, SSI_SCK78_B_MARK, SCK0_B_MARK, DU1_DR0_MARK,
+       VI2_DATA0_VI2_B0_MARK, PWM6_MARK, SD3_CLK_MARK, TX3_E_IRDA_TX_E_MARK,
+       AUDCK_MARK, PWMFSW0_B_MARK, DU1_DR1_MARK, VI2_DATA1_VI2_B1_MARK,
+       PWM0_MARK, SD3_CMD_MARK, RX3_E_IRDA_RX_E_MARK, AUDSYNC_MARK,
+       CTS0_D_MARK, DU1_DR2_MARK, VI2_G0_MARK, DU1_DR3_MARK,
+       VI2_G1_MARK, DU1_DR4_MARK, VI2_G2_MARK, DU1_DR5_MARK,
+       VI2_G3_MARK, DU1_DR6_MARK, VI2_G4_MARK, DU1_DR7_MARK,
+       VI2_G5_MARK, DU1_DG0_MARK, VI2_DATA2_VI2_B2_MARK, SCL1_B_MARK,
+       SD3_DAT2_MARK, SCK3_E_MARK, AUDATA6_MARK, TX0_D_MARK,
+       DU1_DG1_MARK, VI2_DATA3_VI2_B3_MARK, SDA1_B_MARK, SD3_DAT3_MARK,
+       SCK5_MARK, AUDATA7_MARK, RX0_D_MARK, DU1_DG2_MARK,
+       VI2_G6_MARK, DU1_DG3_MARK, VI2_G7_MARK, DU1_DG4_MARK,
+       VI2_R0_MARK, DU1_DG5_MARK, VI2_R1_MARK, DU1_DG6_MARK,
+       VI2_R2_MARK, DU1_DG7_MARK, VI2_R3_MARK, DU1_DB0_MARK,
+       VI2_DATA4_VI2_B4_MARK, SCL2_B_MARK, SD3_DAT0_MARK, TX5_MARK,
+       SCK0_D_MARK,
+
+       DU1_DB1_MARK, VI2_DATA5_VI2_B5_MARK, SDA2_B_MARK, SD3_DAT1_MARK,
+       RX5_MARK, RTS0_D_TANS_D_MARK, DU1_DB2_MARK, VI2_R4_MARK,
+       DU1_DB3_MARK, VI2_R5_MARK, DU1_DB4_MARK, VI2_R6_MARK,
+       DU1_DB5_MARK, VI2_R7_MARK, DU1_DB6_MARK, SCL2_D_MARK,
+       DU1_DB7_MARK, SDA2_D_MARK, DU1_DOTCLKIN_MARK, VI2_CLKENB_MARK,
+       HSPI_CS1_MARK, SCL1_D_MARK, DU1_DOTCLKOUT_MARK, VI2_FIELD_MARK,
+       SDA1_D_MARK, DU1_EXHSYNC_DU1_HSYNC_MARK, VI2_HSYNC_MARK,
+       VI3_HSYNC_MARK, DU1_EXVSYNC_DU1_VSYNC_MARK, VI2_VSYNC_MARK,
+       VI3_VSYNC_MARK, DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK, VI2_CLK_MARK,
+       TX3_B_IRDA_TX_B_MARK, SD3_CD_MARK, HSPI_TX1_MARK, VI1_CLKENB_MARK,
+       VI3_CLKENB_MARK, AUDIO_CLKC_MARK, TX2_D_MARK, SPEEDIN_MARK,
+       GPS_SIGN_D_MARK, DU1_DISP_MARK, VI2_DATA6_VI2_B6_MARK, TCLK0_MARK,
+       QSTVA_B_QVS_B_MARK, HSPI_CLK1_MARK, SCK2_D_MARK, AUDIO_CLKOUT_B_MARK,
+       GPS_MAG_D_MARK, DU1_CDE_MARK, VI2_DATA7_VI2_B7_MARK,
+       RX3_B_IRDA_RX_B_MARK, SD3_WP_MARK, HSPI_RX1_MARK, VI1_FIELD_MARK,
+       VI3_FIELD_MARK, AUDIO_CLKOUT_MARK, RX2_D_MARK, GPS_CLK_C_MARK,
+       GPS_CLK_D_MARK, AUDIO_CLKA_MARK, CAN_TXCLK_MARK, AUDIO_CLKB_MARK,
+       USB_OVC2_MARK, CAN_DEBUGOUT0_MARK, MOUT0_MARK,
+
+       SSI_SCK0129_MARK, CAN_DEBUGOUT1_MARK, MOUT1_MARK, SSI_WS0129_MARK,
+       CAN_DEBUGOUT2_MARK, MOUT2_MARK, SSI_SDATA0_MARK, CAN_DEBUGOUT3_MARK,
+       MOUT5_MARK, SSI_SDATA1_MARK, CAN_DEBUGOUT4_MARK, MOUT6_MARK,
+       SSI_SDATA2_MARK, CAN_DEBUGOUT5_MARK, SSI_SCK34_MARK,
+       CAN_DEBUGOUT6_MARK, CAN0_TX_B_MARK, IERX_MARK, SSI_SCK9_C_MARK,
+       SSI_WS34_MARK, CAN_DEBUGOUT7_MARK, CAN0_RX_B_MARK, IETX_MARK,
+       SSI_WS9_C_MARK, SSI_SDATA3_MARK, PWM0_C_MARK, CAN_DEBUGOUT8_MARK,
+       CAN_CLK_B_MARK, IECLK_MARK, SCIF_CLK_B_MARK, TCLK0_B_MARK,
+       SSI_SDATA4_MARK, CAN_DEBUGOUT9_MARK, SSI_SDATA9_C_MARK, SSI_SCK5_MARK,
+       ADICLK_MARK, CAN_DEBUGOUT10_MARK, SCK3_MARK, TCLK0_D_MARK,
+       SSI_WS5_MARK, ADICS_SAMP_MARK, CAN_DEBUGOUT11_MARK, TX3_IRDA_TX_MARK,
+       SSI_SDATA5_MARK, ADIDATA_MARK, CAN_DEBUGOUT12_MARK, RX3_IRDA_RX_MARK,
+       SSI_SCK6_MARK, ADICHS0_MARK, CAN0_TX_MARK, IERX_B_MARK,
+
+       SSI_WS6_MARK, ADICHS1_MARK, CAN0_RX_MARK, IETX_B_MARK,
+       SSI_SDATA6_MARK, ADICHS2_MARK, CAN_CLK_MARK, IECLK_B_MARK,
+       SSI_SCK78_MARK, CAN_DEBUGOUT13_MARK, IRQ0_B_MARK, SSI_SCK9_B_MARK,
+       HSPI_CLK1_C_MARK, SSI_WS78_MARK, CAN_DEBUGOUT14_MARK, IRQ1_B_MARK,
+       SSI_WS9_B_MARK, HSPI_CS1_C_MARK, SSI_SDATA7_MARK, CAN_DEBUGOUT15_MARK,
+       IRQ2_B_MARK, TCLK1_C_MARK, HSPI_TX1_C_MARK, SSI_SDATA8_MARK,
+       VSP_MARK, IRQ3_B_MARK, HSPI_RX1_C_MARK, SD0_CLK_MARK,
+       ATACS01_MARK, SCK1_B_MARK, SD0_CMD_MARK, ATACS11_MARK,
+       TX1_B_MARK, CC5_TDO_MARK, SD0_DAT0_MARK, ATADIR1_MARK,
+       RX1_B_MARK, CC5_TRST_MARK, SD0_DAT1_MARK, ATAG1_MARK,
+       SCK2_B_MARK, CC5_TMS_MARK, SD0_DAT2_MARK, ATARD1_MARK,
+       TX2_B_MARK, CC5_TCK_MARK, SD0_DAT3_MARK, ATAWR1_MARK,
+       RX2_B_MARK, CC5_TDI_MARK, SD0_CD_MARK, DREQ2_MARK,
+       RTS1_B_TANS_B_MARK, SD0_WP_MARK, DACK2_MARK, CTS1_B_MARK,
+
+       HSPI_CLK0_MARK, CTS0_MARK, USB_OVC0_MARK, AD_CLK_MARK,
+       CC5_STATE4_MARK, CC5_STATE12_MARK, CC5_STATE20_MARK, CC5_STATE28_MARK,
+       CC5_STATE36_MARK, HSPI_CS0_MARK, RTS0_TANS_MARK, USB_OVC1_MARK,
+       AD_DI_MARK, CC5_STATE5_MARK, CC5_STATE13_MARK, CC5_STATE21_MARK,
+       CC5_STATE29_MARK, CC5_STATE37_MARK, HSPI_TX0_MARK, TX0_MARK,
+       CAN_DEBUG_HW_TRIGGER_MARK, AD_DO_MARK, CC5_STATE6_MARK,
+       CC5_STATE14_MARK, CC5_STATE22_MARK, CC5_STATE30_MARK,
+       CC5_STATE38_MARK, HSPI_RX0_MARK, RX0_MARK, CAN_STEP0_MARK,
+       AD_NCS_MARK, CC5_STATE7_MARK, CC5_STATE15_MARK, CC5_STATE23_MARK,
+       CC5_STATE31_MARK, CC5_STATE39_MARK, FMCLK_MARK, RDS_CLK_MARK,
+       PCMOE_MARK, BPFCLK_MARK, PCMWE_MARK, FMIN_MARK, RDS_DATA_MARK,
+       VI0_CLK_MARK, MMC1_CLK_MARK, VI0_CLKENB_MARK, TX1_C_MARK, HTX1_B_MARK,
+       MT1_SYNC_MARK, VI0_FIELD_MARK, RX1_C_MARK, HRX1_B_MARK,
+       VI0_HSYNC_MARK, VI0_DATA0_B_VI0_B0_B_MARK, CTS1_C_MARK, TX4_D_MARK,
+       MMC1_CMD_MARK, HSCK1_B_MARK, VI0_VSYNC_MARK, VI0_DATA1_B_VI0_B1_B_MARK,
+       RTS1_C_TANS_C_MARK, RX4_D_MARK, PWMFSW0_C_MARK,
+
+       VI0_DATA0_VI0_B0_MARK, HRTS1_B_MARK, MT1_VCXO_MARK,
+       VI0_DATA1_VI0_B1_MARK, HCTS1_B_MARK, MT1_PWM_MARK,
+       VI0_DATA2_VI0_B2_MARK, MMC1_D0_MARK, VI0_DATA3_VI0_B3_MARK,
+       MMC1_D1_MARK, VI0_DATA4_VI0_B4_MARK, MMC1_D2_MARK,
+       VI0_DATA5_VI0_B5_MARK, MMC1_D3_MARK, VI0_DATA6_VI0_B6_MARK,
+       MMC1_D4_MARK, ARM_TRACEDATA_0_MARK, VI0_DATA7_VI0_B7_MARK,
+       MMC1_D5_MARK, ARM_TRACEDATA_1_MARK, VI0_G0_MARK, SSI_SCK78_C_MARK,
+       IRQ0_MARK, ARM_TRACEDATA_2_MARK, VI0_G1_MARK, SSI_WS78_C_MARK,
+       IRQ1_MARK, ARM_TRACEDATA_3_MARK, VI0_G2_MARK, ETH_TXD1_MARK,
+       MMC1_D6_MARK, ARM_TRACEDATA_4_MARK, TS_SPSYNC0_MARK, VI0_G3_MARK,
+       ETH_CRS_DV_MARK, MMC1_D7_MARK, ARM_TRACEDATA_5_MARK, TS_SDAT0_MARK,
+       VI0_G4_MARK, ETH_TX_EN_MARK, SD2_DAT0_B_MARK, ARM_TRACEDATA_6_MARK,
+       VI0_G5_MARK, ETH_RX_ER_MARK, SD2_DAT1_B_MARK, ARM_TRACEDATA_7_MARK,
+       VI0_G6_MARK, ETH_RXD0_MARK, SD2_DAT2_B_MARK, ARM_TRACEDATA_8_MARK,
+       VI0_G7_MARK, ETH_RXD1_MARK, SD2_DAT3_B_MARK, ARM_TRACEDATA_9_MARK,
+
+       VI0_R0_MARK, SSI_SDATA7_C_MARK, SCK1_C_MARK, DREQ1_B_MARK,
+       ARM_TRACEDATA_10_MARK, DREQ0_C_MARK, VI0_R1_MARK, SSI_SDATA8_C_MARK,
+       DACK1_B_MARK, ARM_TRACEDATA_11_MARK, DACK0_C_MARK, DRACK0_C_MARK,
+       VI0_R2_MARK, ETH_LINK_MARK, SD2_CLK_B_MARK, IRQ2_MARK,
+       ARM_TRACEDATA_12_MARK, VI0_R3_MARK, ETH_MAGIC_MARK, SD2_CMD_B_MARK,
+       IRQ3_MARK, ARM_TRACEDATA_13_MARK, VI0_R4_MARK, ETH_REFCLK_MARK,
+       SD2_CD_B_MARK, HSPI_CLK1_B_MARK, ARM_TRACEDATA_14_MARK, MT1_CLK_MARK,
+       TS_SCK0_MARK, VI0_R5_MARK, ETH_TXD0_MARK, SD2_WP_B_MARK,
+       HSPI_CS1_B_MARK, ARM_TRACEDATA_15_MARK, MT1_D_MARK, TS_SDEN0_MARK,
+       VI0_R6_MARK, ETH_MDC_MARK, DREQ2_C_MARK, HSPI_TX1_B_MARK,
+       TRACECLK_MARK, MT1_BEN_MARK, PWMFSW0_D_MARK, VI0_R7_MARK,
+       ETH_MDIO_MARK, DACK2_C_MARK, HSPI_RX1_B_MARK, SCIF_CLK_D_MARK,
+       TRACECTL_MARK, MT1_PEN_MARK, VI1_CLK_MARK, SIM_D_MARK, SDA3_MARK,
+       VI1_HSYNC_MARK, VI3_CLK_MARK, SSI_SCK4_MARK, GPS_SIGN_C_MARK,
+       PWMFSW0_E_MARK, VI1_VSYNC_MARK, AUDIO_CLKOUT_C_MARK, SSI_WS4_MARK,
+       SIM_CLK_MARK, GPS_MAG_C_MARK, SPV_TRST_MARK, SCL3_MARK,
+
+       VI1_DATA0_VI1_B0_MARK, SD2_DAT0_MARK, SIM_RST_MARK, SPV_TCK_MARK,
+       ADICLK_B_MARK, VI1_DATA1_VI1_B1_MARK, SD2_DAT1_MARK, MT0_CLK_MARK,
+       SPV_TMS_MARK, ADICS_B_SAMP_B_MARK, VI1_DATA2_VI1_B2_MARK,
+       SD2_DAT2_MARK, MT0_D_MARK, SPVTDI_MARK, ADIDATA_B_MARK,
+       VI1_DATA3_VI1_B3_MARK, SD2_DAT3_MARK, MT0_BEN_MARK, SPV_TDO_MARK,
+       ADICHS0_B_MARK, VI1_DATA4_VI1_B4_MARK, SD2_CLK_MARK, MT0_PEN_MARK,
+       SPA_TRST_MARK, HSPI_CLK1_D_MARK, ADICHS1_B_MARK,
+       VI1_DATA5_VI1_B5_MARK, SD2_CMD_MARK, MT0_SYNC_MARK, SPA_TCK_MARK,
+       HSPI_CS1_D_MARK, ADICHS2_B_MARK, VI1_DATA6_VI1_B6_MARK, SD2_CD_MARK,
+       MT0_VCXO_MARK, SPA_TMS_MARK, HSPI_TX1_D_MARK, VI1_DATA7_VI1_B7_MARK,
+       SD2_WP_MARK, MT0_PWM_MARK, SPA_TDI_MARK, HSPI_RX1_D_MARK,
+       VI1_G0_MARK, VI3_DATA0_MARK, DU1_DOTCLKOUT1_MARK, TS_SCK1_MARK,
+       DREQ2_B_MARK, TX2_MARK, SPA_TDO_MARK, HCTS0_B_MARK,
+       VI1_G1_MARK, VI3_DATA1_MARK, SSI_SCK1_MARK, TS_SDEN1_MARK,
+       DACK2_B_MARK, RX2_MARK, HRTS0_B_MARK,
+
+       VI1_G2_MARK, VI3_DATA2_MARK, SSI_WS1_MARK, TS_SPSYNC1_MARK,
+       SCK2_MARK, HSCK0_B_MARK, VI1_G3_MARK, VI3_DATA3_MARK,
+       SSI_SCK2_MARK, TS_SDAT1_MARK, SCL1_C_MARK, HTX0_B_MARK,
+       VI1_G4_MARK, VI3_DATA4_MARK, SSI_WS2_MARK, SDA1_C_MARK,
+       SIM_RST_B_MARK, HRX0_B_MARK, VI1_G5_MARK, VI3_DATA5_MARK,
+       GPS_CLK_MARK, FSE_MARK, TX4_B_MARK, SIM_D_B_MARK,
+       VI1_G6_MARK, VI3_DATA6_MARK, GPS_SIGN_MARK, FRB_MARK,
+       RX4_B_MARK, SIM_CLK_B_MARK, VI1_G7_MARK, VI3_DATA7_MARK,
+       GPS_MAG_MARK, FCE_MARK, SCK4_B_MARK,
+       PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+       PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+       PINMUX_DATA(AVS1_MARK, FN_AVS1),
+       PINMUX_DATA(AVS1_MARK, FN_AVS1),
+       PINMUX_DATA(A17_MARK, FN_A17),
+       PINMUX_DATA(A18_MARK, FN_A18),
+       PINMUX_DATA(A19_MARK, FN_A19),
+
+       PINMUX_IPSR_DATA(IP0_2_0, PENC2),
+       PINMUX_IPSR_MODSEL_DATA(IP0_2_0, SCK0, SEL_SCIF0_0),
+       PINMUX_IPSR_DATA(IP0_2_0, PWM1),
+       PINMUX_IPSR_MODSEL_DATA(IP0_2_0, PWMFSW0, SEL_PWMFSW_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_2_0, SCIF_CLK, SEL_SCIF_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_2_0, TCLK0_C, SEL_TMU0_2),
+       PINMUX_IPSR_DATA(IP0_5_3, BS),
+       PINMUX_IPSR_DATA(IP0_5_3, SD1_DAT2),
+       PINMUX_IPSR_DATA(IP0_5_3, MMC0_D2),
+       PINMUX_IPSR_DATA(IP0_5_3, FD2),
+       PINMUX_IPSR_DATA(IP0_5_3, ATADIR0),
+       PINMUX_IPSR_DATA(IP0_5_3, SDSELF),
+       PINMUX_IPSR_MODSEL_DATA(IP0_5_3, HCTS1, SEL_HSCIF1_0),
+       PINMUX_IPSR_DATA(IP0_5_3, TX4_C),
+       PINMUX_IPSR_DATA(IP0_7_6, A0),
+       PINMUX_IPSR_DATA(IP0_7_6, SD1_DAT3),
+       PINMUX_IPSR_DATA(IP0_7_6, MMC0_D3),
+       PINMUX_IPSR_DATA(IP0_7_6, FD3),
+       PINMUX_IPSR_DATA(IP0_9_8, A20),
+       PINMUX_IPSR_DATA(IP0_9_8, TX5_D),
+       PINMUX_IPSR_DATA(IP0_9_8, HSPI_TX2_B),
+       PINMUX_IPSR_DATA(IP0_11_10, A21),
+       PINMUX_IPSR_MODSEL_DATA(IP0_11_10, SCK5_D, SEL_SCIF5_3),
+       PINMUX_IPSR_MODSEL_DATA(IP0_11_10, HSPI_CLK2_B, SEL_HSPI2_1),
+       PINMUX_IPSR_DATA(IP0_13_12, A22),
+       PINMUX_IPSR_MODSEL_DATA(IP0_13_12, RX5_D, SEL_SCIF5_3),
+       PINMUX_IPSR_MODSEL_DATA(IP0_13_12, HSPI_RX2_B, SEL_HSPI2_1),
+       PINMUX_IPSR_DATA(IP0_13_12, VI1_R0),
+       PINMUX_IPSR_DATA(IP0_15_14, A23),
+       PINMUX_IPSR_DATA(IP0_15_14, FCLE),
+       PINMUX_IPSR_MODSEL_DATA(IP0_15_14, HSPI_CLK2, SEL_HSPI2_0),
+       PINMUX_IPSR_DATA(IP0_15_14, VI1_R1),
+       PINMUX_IPSR_DATA(IP0_18_16, A24),
+       PINMUX_IPSR_DATA(IP0_18_16, SD1_CD),
+       PINMUX_IPSR_DATA(IP0_18_16, MMC0_D4),
+       PINMUX_IPSR_DATA(IP0_18_16, FD4),
+       PINMUX_IPSR_MODSEL_DATA(IP0_18_16, HSPI_CS2, SEL_HSPI2_0),
+       PINMUX_IPSR_DATA(IP0_18_16, VI1_R2),
+       PINMUX_IPSR_MODSEL_DATA(IP0_18_16, SSI_WS78_B, SEL_SSI7_1),
+       PINMUX_IPSR_DATA(IP0_22_19, A25),
+       PINMUX_IPSR_DATA(IP0_22_19, SD1_WP),
+       PINMUX_IPSR_DATA(IP0_22_19, MMC0_D5),
+       PINMUX_IPSR_DATA(IP0_22_19, FD5),
+       PINMUX_IPSR_MODSEL_DATA(IP0_22_19, HSPI_RX2, SEL_HSPI2_0),
+       PINMUX_IPSR_DATA(IP0_22_19, VI1_R3),
+       PINMUX_IPSR_DATA(IP0_22_19, TX5_B),
+       PINMUX_IPSR_MODSEL_DATA(IP0_22_19, SSI_SDATA7_B, SEL_SSI7_1),
+       PINMUX_IPSR_MODSEL_DATA(IP0_22_19, CTS0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_DATA(IP0_24_23, CLKOUT),
+       PINMUX_IPSR_DATA(IP0_24_23, TX3C_IRDA_TX_C),
+       PINMUX_IPSR_DATA(IP0_24_23, PWM0_B),
+       PINMUX_IPSR_DATA(IP0_25, CS0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_25, HSPI_CS2_B, SEL_HSPI2_1),
+       PINMUX_IPSR_DATA(IP0_27_26, CS1_A26),
+       PINMUX_IPSR_DATA(IP0_27_26, HSPI_TX2),
+       PINMUX_IPSR_DATA(IP0_27_26, SDSELF_B),
+       PINMUX_IPSR_DATA(IP0_30_28, RD_WR),
+       PINMUX_IPSR_DATA(IP0_30_28, FWE),
+       PINMUX_IPSR_DATA(IP0_30_28, ATAG0),
+       PINMUX_IPSR_DATA(IP0_30_28, VI1_R7),
+       PINMUX_IPSR_MODSEL_DATA(IP0_30_28, HRTS1, SEL_HSCIF1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP0_30_28, RX4_C, SEL_SCIF4_2),
+
+       PINMUX_IPSR_DATA(IP1_1_0, EX_CS0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_1_0, RX3_C_IRDA_RX_C, SEL_SCIF3_2),
+       PINMUX_IPSR_DATA(IP1_1_0, MMC0_D6),
+       PINMUX_IPSR_DATA(IP1_1_0, FD6),
+       PINMUX_IPSR_DATA(IP1_3_2, EX_CS1),
+       PINMUX_IPSR_DATA(IP1_3_2, MMC0_D7),
+       PINMUX_IPSR_DATA(IP1_3_2, FD7),
+       PINMUX_IPSR_DATA(IP1_6_4, EX_CS2),
+       PINMUX_IPSR_DATA(IP1_6_4, SD1_CLK),
+       PINMUX_IPSR_DATA(IP1_6_4, MMC0_CLK),
+       PINMUX_IPSR_DATA(IP1_6_4, FALE),
+       PINMUX_IPSR_DATA(IP1_6_4, ATACS00),
+       PINMUX_IPSR_DATA(IP1_10_7, EX_CS3),
+       PINMUX_IPSR_DATA(IP1_10_7, SD1_CMD),
+       PINMUX_IPSR_DATA(IP1_10_7, MMC0_CMD),
+       PINMUX_IPSR_DATA(IP1_10_7, FRE),
+       PINMUX_IPSR_DATA(IP1_10_7, ATACS10),
+       PINMUX_IPSR_DATA(IP1_10_7, VI1_R4),
+       PINMUX_IPSR_MODSEL_DATA(IP1_10_7, RX5_B, SEL_SCIF5_1),
+       PINMUX_IPSR_MODSEL_DATA(IP1_10_7, HSCK1, SEL_HSCIF1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_10_7, SSI_SDATA8_B, SEL_SSI8_1),
+       PINMUX_IPSR_MODSEL_DATA(IP1_10_7, RTS0_B_TANS_B, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP1_10_7, SSI_SDATA9, SEL_SSI9_0),
+       PINMUX_IPSR_DATA(IP1_14_11, EX_CS4),
+       PINMUX_IPSR_DATA(IP1_14_11, SD1_DAT0),
+       PINMUX_IPSR_DATA(IP1_14_11, MMC0_D0),
+       PINMUX_IPSR_DATA(IP1_14_11, FD0),
+       PINMUX_IPSR_DATA(IP1_14_11, ATARD0),
+       PINMUX_IPSR_DATA(IP1_14_11, VI1_R5),
+       PINMUX_IPSR_MODSEL_DATA(IP1_14_11, SCK5_B, SEL_SCIF5_1),
+       PINMUX_IPSR_DATA(IP1_14_11, HTX1),
+       PINMUX_IPSR_DATA(IP1_14_11, TX2_E),
+       PINMUX_IPSR_DATA(IP1_14_11, TX0_B),
+       PINMUX_IPSR_MODSEL_DATA(IP1_14_11, SSI_SCK9, SEL_SSI9_0),
+       PINMUX_IPSR_DATA(IP1_18_15, EX_CS5),
+       PINMUX_IPSR_DATA(IP1_18_15, SD1_DAT1),
+       PINMUX_IPSR_DATA(IP1_18_15, MMC0_D1),
+       PINMUX_IPSR_DATA(IP1_18_15, FD1),
+       PINMUX_IPSR_DATA(IP1_18_15, ATAWR0),
+       PINMUX_IPSR_DATA(IP1_18_15, VI1_R6),
+       PINMUX_IPSR_MODSEL_DATA(IP1_18_15, HRX1, SEL_HSCIF1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP1_18_15, RX2_E, SEL_SCIF2_4),
+       PINMUX_IPSR_MODSEL_DATA(IP1_18_15, RX0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP1_18_15, SSI_WS9, SEL_SSI9_0),
+       PINMUX_IPSR_DATA(IP1_20_19, MLB_CLK),
+       PINMUX_IPSR_DATA(IP1_20_19, PWM2),
+       PINMUX_IPSR_MODSEL_DATA(IP1_20_19, SCK4, SEL_SCIF4_0),
+       PINMUX_IPSR_DATA(IP1_22_21, MLB_SIG),
+       PINMUX_IPSR_DATA(IP1_22_21, PWM3),
+       PINMUX_IPSR_DATA(IP1_22_21, TX4),
+       PINMUX_IPSR_DATA(IP1_24_23, MLB_DAT),
+       PINMUX_IPSR_DATA(IP1_24_23, PWM4),
+       PINMUX_IPSR_MODSEL_DATA(IP1_24_23, RX4, SEL_SCIF4_0),
+       PINMUX_IPSR_DATA(IP1_28_25, HTX0),
+       PINMUX_IPSR_DATA(IP1_28_25, TX1),
+       PINMUX_IPSR_DATA(IP1_28_25, SDATA),
+       PINMUX_IPSR_MODSEL_DATA(IP1_28_25, CTS0_C, SEL_SCIF0_2),
+       PINMUX_IPSR_DATA(IP1_28_25, SUB_TCK),
+       PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE2),
+       PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE10),
+       PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE18),
+       PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE26),
+       PINMUX_IPSR_DATA(IP1_28_25, CC5_STATE34),
+
+       PINMUX_IPSR_MODSEL_DATA(IP2_3_0, HRX0, SEL_HSCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_3_0, RX1, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP2_3_0, SCKZ),
+       PINMUX_IPSR_MODSEL_DATA(IP2_3_0, RTS0_C_TANS_C, SEL_SCIF0_2),
+       PINMUX_IPSR_DATA(IP2_3_0, SUB_TDI),
+       PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE3),
+       PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE11),
+       PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE19),
+       PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE27),
+       PINMUX_IPSR_DATA(IP2_3_0, CC5_STATE35),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_4, HSCK0, SEL_HSCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_4, SCK1, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP2_7_4, MTS),
+       PINMUX_IPSR_DATA(IP2_7_4, PWM5),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_4, SCK0_C, SEL_SCIF0_2),
+       PINMUX_IPSR_MODSEL_DATA(IP2_7_4, SSI_SDATA9_B, SEL_SSI9_1),
+       PINMUX_IPSR_DATA(IP2_7_4, SUB_TDO),
+       PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE0),
+       PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE8),
+       PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE16),
+       PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE24),
+       PINMUX_IPSR_DATA(IP2_7_4, CC5_STATE32),
+       PINMUX_IPSR_MODSEL_DATA(IP2_11_8, HCTS0, SEL_HSCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_11_8, CTS1, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP2_11_8, STM),
+       PINMUX_IPSR_DATA(IP2_11_8, PWM0_D),
+       PINMUX_IPSR_MODSEL_DATA(IP2_11_8, RX0_C, SEL_SCIF0_2),
+       PINMUX_IPSR_MODSEL_DATA(IP2_11_8, SCIF_CLK_C, SEL_SCIF_2),
+       PINMUX_IPSR_DATA(IP2_11_8, SUB_TRST),
+       PINMUX_IPSR_MODSEL_DATA(IP2_11_8, TCLK1_B, SEL_TMU1_1),
+       PINMUX_IPSR_DATA(IP2_11_8, CC5_OSCOUT),
+       PINMUX_IPSR_MODSEL_DATA(IP2_15_12, HRTS0, SEL_HSCIF0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_15_12, RTS1_TANS, SEL_SCIF1_0),
+       PINMUX_IPSR_DATA(IP2_15_12, MDATA),
+       PINMUX_IPSR_DATA(IP2_15_12, TX0_C),
+       PINMUX_IPSR_DATA(IP2_15_12, SUB_TMS),
+       PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE1),
+       PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE9),
+       PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE17),
+       PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE25),
+       PINMUX_IPSR_DATA(IP2_15_12, CC5_STATE33),
+       PINMUX_IPSR_DATA(IP2_18_16, DU0_DR0),
+       PINMUX_IPSR_DATA(IP2_18_16, LCDOUT0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_18_16, DREQ0, SEL_EXBUS0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_18_16, GPS_CLK_B, SEL_GPS_1),
+       PINMUX_IPSR_DATA(IP2_18_16, AUDATA0),
+       PINMUX_IPSR_DATA(IP2_18_16, TX5_C),
+       PINMUX_IPSR_DATA(IP2_21_19, DU0_DR1),
+       PINMUX_IPSR_DATA(IP2_21_19, LCDOUT1),
+       PINMUX_IPSR_DATA(IP2_21_19, DACK0),
+       PINMUX_IPSR_DATA(IP2_21_19, DRACK0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_21_19, GPS_SIGN_B, SEL_GPS_1),
+       PINMUX_IPSR_DATA(IP2_21_19, AUDATA1),
+       PINMUX_IPSR_MODSEL_DATA(IP2_21_19, RX5_C, SEL_SCIF5_2),
+       PINMUX_IPSR_DATA(IP2_22, DU0_DR2),
+       PINMUX_IPSR_DATA(IP2_22, LCDOUT2),
+       PINMUX_IPSR_DATA(IP2_23, DU0_DR3),
+       PINMUX_IPSR_DATA(IP2_23, LCDOUT3),
+       PINMUX_IPSR_DATA(IP2_24, DU0_DR4),
+       PINMUX_IPSR_DATA(IP2_24, LCDOUT4),
+       PINMUX_IPSR_DATA(IP2_25, DU0_DR5),
+       PINMUX_IPSR_DATA(IP2_25, LCDOUT5),
+       PINMUX_IPSR_DATA(IP2_26, DU0_DR6),
+       PINMUX_IPSR_DATA(IP2_26, LCDOUT6),
+       PINMUX_IPSR_DATA(IP2_27, DU0_DR7),
+       PINMUX_IPSR_DATA(IP2_27, LCDOUT7),
+       PINMUX_IPSR_DATA(IP2_30_28, DU0_DG0),
+       PINMUX_IPSR_DATA(IP2_30_28, LCDOUT8),
+       PINMUX_IPSR_MODSEL_DATA(IP2_30_28, DREQ1, SEL_EXBUS1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP2_30_28, SCL2, SEL_I2C2_0),
+       PINMUX_IPSR_DATA(IP2_30_28, AUDATA2),
+
+       PINMUX_IPSR_DATA(IP3_2_0, DU0_DG1),
+       PINMUX_IPSR_DATA(IP3_2_0, LCDOUT9),
+       PINMUX_IPSR_DATA(IP3_2_0, DACK1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_2_0, SDA2, SEL_I2C2_0),
+       PINMUX_IPSR_DATA(IP3_2_0, AUDATA3),
+       PINMUX_IPSR_DATA(IP3_3, DU0_DG2),
+       PINMUX_IPSR_DATA(IP3_3, LCDOUT10),
+       PINMUX_IPSR_DATA(IP3_4, DU0_DG3),
+       PINMUX_IPSR_DATA(IP3_4, LCDOUT11),
+       PINMUX_IPSR_DATA(IP3_5, DU0_DG4),
+       PINMUX_IPSR_DATA(IP3_5, LCDOUT12),
+       PINMUX_IPSR_DATA(IP3_6, DU0_DG5),
+       PINMUX_IPSR_DATA(IP3_6, LCDOUT13),
+       PINMUX_IPSR_DATA(IP3_7, DU0_DG6),
+       PINMUX_IPSR_DATA(IP3_7, LCDOUT14),
+       PINMUX_IPSR_DATA(IP3_8, DU0_DG7),
+       PINMUX_IPSR_DATA(IP3_8, LCDOUT15),
+       PINMUX_IPSR_DATA(IP3_11_9, DU0_DB0),
+       PINMUX_IPSR_DATA(IP3_11_9, LCDOUT16),
+       PINMUX_IPSR_DATA(IP3_11_9, EX_WAIT1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SCL1, SEL_I2C1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_11_9, TCLK1, SEL_TMU1_0),
+       PINMUX_IPSR_DATA(IP3_11_9, AUDATA4),
+       PINMUX_IPSR_DATA(IP3_14_12, DU0_DB1),
+       PINMUX_IPSR_DATA(IP3_14_12, LCDOUT17),
+       PINMUX_IPSR_DATA(IP3_14_12, EX_WAIT2),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SDA1, SEL_I2C1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, GPS_MAG_B, SEL_GPS_1),
+       PINMUX_IPSR_DATA(IP3_14_12, AUDATA5),
+       PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SCK5_C, SEL_SCIF5_2),
+       PINMUX_IPSR_DATA(IP3_15, DU0_DB2),
+       PINMUX_IPSR_DATA(IP3_15, LCDOUT18),
+       PINMUX_IPSR_DATA(IP3_16, DU0_DB3),
+       PINMUX_IPSR_DATA(IP3_16, LCDOUT19),
+       PINMUX_IPSR_DATA(IP3_17, DU0_DB4),
+       PINMUX_IPSR_DATA(IP3_17, LCDOUT20),
+       PINMUX_IPSR_DATA(IP3_18, DU0_DB5),
+       PINMUX_IPSR_DATA(IP3_18, LCDOUT21),
+       PINMUX_IPSR_DATA(IP3_19, DU0_DB6),
+       PINMUX_IPSR_DATA(IP3_19, LCDOUT22),
+       PINMUX_IPSR_DATA(IP3_20, DU0_DB7),
+       PINMUX_IPSR_DATA(IP3_20, LCDOUT23),
+       PINMUX_IPSR_DATA(IP3_22_21, DU0_DOTCLKIN),
+       PINMUX_IPSR_DATA(IP3_22_21, QSTVA_QVS),
+       PINMUX_IPSR_DATA(IP3_22_21, TX3_D_IRDA_TX_D),
+       PINMUX_IPSR_MODSEL_DATA(IP3_22_21, SCL3_B, SEL_I2C3_1),
+       PINMUX_IPSR_DATA(IP3_23, DU0_DOTCLKOUT0),
+       PINMUX_IPSR_DATA(IP3_23, QCLK),
+       PINMUX_IPSR_DATA(IP3_26_24, DU0_DOTCLKOUT1),
+       PINMUX_IPSR_DATA(IP3_26_24, QSTVB_QVE),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, RX3_D_IRDA_RX_D, SEL_SCIF3_3),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SDA3_B, SEL_I2C3_1),
+       PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SDA2_C, SEL_I2C2_2),
+       PINMUX_IPSR_DATA(IP3_26_24, DACK0_B),
+       PINMUX_IPSR_DATA(IP3_26_24, DRACK0_B),
+       PINMUX_IPSR_DATA(IP3_27, DU0_EXHSYNC_DU0_HSYNC),
+       PINMUX_IPSR_DATA(IP3_27, QSTH_QHS),
+       PINMUX_IPSR_DATA(IP3_28, DU0_EXVSYNC_DU0_VSYNC),
+       PINMUX_IPSR_DATA(IP3_28, QSTB_QHE),
+       PINMUX_IPSR_DATA(IP3_31_29, DU0_EXODDF_DU0_ODDF_DISP_CDE),
+       PINMUX_IPSR_DATA(IP3_31_29, QCPV_QDE),
+       PINMUX_IPSR_DATA(IP3_31_29, CAN1_TX),
+       PINMUX_IPSR_DATA(IP3_31_29, TX2_C),
+       PINMUX_IPSR_MODSEL_DATA(IP3_31_29, SCL2_C, SEL_I2C2_2),
+       PINMUX_IPSR_DATA(IP3_31_29, REMOCON),
+
+       PINMUX_IPSR_DATA(IP4_1_0, DU0_DISP),
+       PINMUX_IPSR_DATA(IP4_1_0, QPOLA),
+       PINMUX_IPSR_MODSEL_DATA(IP4_1_0, CAN_CLK_C, SEL_CANCLK_2),
+       PINMUX_IPSR_MODSEL_DATA(IP4_1_0, SCK2_C, SEL_SCIF2_2),
+       PINMUX_IPSR_DATA(IP4_4_2, DU0_CDE),
+       PINMUX_IPSR_DATA(IP4_4_2, QPOLB),
+       PINMUX_IPSR_DATA(IP4_4_2, CAN1_RX),
+       PINMUX_IPSR_MODSEL_DATA(IP4_4_2, RX2_C, SEL_SCIF2_2),
+       PINMUX_IPSR_MODSEL_DATA(IP4_4_2, DREQ0_B, SEL_EXBUS0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SSI_SCK78_B, SEL_SSI7_1),
+       PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SCK0_B, SEL_SCIF0_1),
+       PINMUX_IPSR_DATA(IP4_7_5, DU1_DR0),
+       PINMUX_IPSR_DATA(IP4_7_5, VI2_DATA0_VI2_B0),
+       PINMUX_IPSR_DATA(IP4_7_5, PWM6),
+       PINMUX_IPSR_DATA(IP4_7_5, SD3_CLK),
+       PINMUX_IPSR_DATA(IP4_7_5, TX3_E_IRDA_TX_E),
+       PINMUX_IPSR_DATA(IP4_7_5, AUDCK),
+       PINMUX_IPSR_MODSEL_DATA(IP4_7_5, PWMFSW0_B, SEL_PWMFSW_1),
+       PINMUX_IPSR_DATA(IP4_10_8, DU1_DR1),
+       PINMUX_IPSR_DATA(IP4_10_8, VI2_DATA1_VI2_B1),
+       PINMUX_IPSR_DATA(IP4_10_8, PWM0),
+       PINMUX_IPSR_DATA(IP4_10_8, SD3_CMD),
+       PINMUX_IPSR_MODSEL_DATA(IP4_10_8, RX3_E_IRDA_RX_E, SEL_SCIF3_4),
+       PINMUX_IPSR_DATA(IP4_10_8, AUDSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP4_10_8, CTS0_D, SEL_SCIF0_3),
+       PINMUX_IPSR_DATA(IP4_11, DU1_DR2),
+       PINMUX_IPSR_DATA(IP4_11, VI2_G0),
+       PINMUX_IPSR_DATA(IP4_12, DU1_DR3),
+       PINMUX_IPSR_DATA(IP4_12, VI2_G1),
+       PINMUX_IPSR_DATA(IP4_13, DU1_DR4),
+       PINMUX_IPSR_DATA(IP4_13, VI2_G2),
+       PINMUX_IPSR_DATA(IP4_14, DU1_DR5),
+       PINMUX_IPSR_DATA(IP4_14, VI2_G3),
+       PINMUX_IPSR_DATA(IP4_15, DU1_DR6),
+       PINMUX_IPSR_DATA(IP4_15, VI2_G4),
+       PINMUX_IPSR_DATA(IP4_16, DU1_DR7),
+       PINMUX_IPSR_DATA(IP4_16, VI2_G5),
+       PINMUX_IPSR_DATA(IP4_19_17, DU1_DG0),
+       PINMUX_IPSR_DATA(IP4_19_17, VI2_DATA2_VI2_B2),
+       PINMUX_IPSR_MODSEL_DATA(IP4_19_17, SCL1_B, SEL_I2C1_1),
+       PINMUX_IPSR_DATA(IP4_19_17, SD3_DAT2),
+       PINMUX_IPSR_MODSEL_DATA(IP4_19_17, SCK3_E, SEL_SCIF3_4),
+       PINMUX_IPSR_DATA(IP4_19_17, AUDATA6),
+       PINMUX_IPSR_DATA(IP4_19_17, TX0_D),
+       PINMUX_IPSR_DATA(IP4_22_20, DU1_DG1),
+       PINMUX_IPSR_DATA(IP4_22_20, VI2_DATA3_VI2_B3),
+       PINMUX_IPSR_MODSEL_DATA(IP4_22_20, SDA1_B, SEL_I2C1_1),
+       PINMUX_IPSR_DATA(IP4_22_20, SD3_DAT3),
+       PINMUX_IPSR_MODSEL_DATA(IP4_22_20, SCK5, SEL_SCIF5_0),
+       PINMUX_IPSR_DATA(IP4_22_20, AUDATA7),
+       PINMUX_IPSR_MODSEL_DATA(IP4_22_20, RX0_D, SEL_SCIF0_3),
+       PINMUX_IPSR_DATA(IP4_23, DU1_DG2),
+       PINMUX_IPSR_DATA(IP4_23, VI2_G6),
+       PINMUX_IPSR_DATA(IP4_24, DU1_DG3),
+       PINMUX_IPSR_DATA(IP4_24, VI2_G7),
+       PINMUX_IPSR_DATA(IP4_25, DU1_DG4),
+       PINMUX_IPSR_DATA(IP4_25, VI2_R0),
+       PINMUX_IPSR_DATA(IP4_26, DU1_DG5),
+       PINMUX_IPSR_DATA(IP4_26, VI2_R1),
+       PINMUX_IPSR_DATA(IP4_27, DU1_DG6),
+       PINMUX_IPSR_DATA(IP4_27, VI2_R2),
+       PINMUX_IPSR_DATA(IP4_28, DU1_DG7),
+       PINMUX_IPSR_DATA(IP4_28, VI2_R3),
+       PINMUX_IPSR_DATA(IP4_31_29, DU1_DB0),
+       PINMUX_IPSR_DATA(IP4_31_29, VI2_DATA4_VI2_B4),
+       PINMUX_IPSR_MODSEL_DATA(IP4_31_29, SCL2_B, SEL_I2C2_1),
+       PINMUX_IPSR_DATA(IP4_31_29, SD3_DAT0),
+       PINMUX_IPSR_DATA(IP4_31_29, TX5),
+       PINMUX_IPSR_MODSEL_DATA(IP4_31_29, SCK0_D, SEL_SCIF0_3),
+
+       PINMUX_IPSR_DATA(IP5_2_0, DU1_DB1),
+       PINMUX_IPSR_DATA(IP5_2_0, VI2_DATA5_VI2_B5),
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SDA2_B, SEL_I2C2_1),
+       PINMUX_IPSR_DATA(IP5_2_0, SD3_DAT1),
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX5, SEL_SCIF5_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RTS0_D_TANS_D, SEL_SCIF0_3),
+       PINMUX_IPSR_DATA(IP5_3, DU1_DB2),
+       PINMUX_IPSR_DATA(IP5_3, VI2_R4),
+       PINMUX_IPSR_DATA(IP5_4, DU1_DB3),
+       PINMUX_IPSR_DATA(IP5_4, VI2_R5),
+       PINMUX_IPSR_DATA(IP5_5, DU1_DB4),
+       PINMUX_IPSR_DATA(IP5_5, VI2_R6),
+       PINMUX_IPSR_DATA(IP5_6, DU1_DB5),
+       PINMUX_IPSR_DATA(IP5_6, VI2_R7),
+       PINMUX_IPSR_DATA(IP5_7, DU1_DB6),
+       PINMUX_IPSR_MODSEL_DATA(IP5_7, SCL2_D, SEL_I2C2_3),
+       PINMUX_IPSR_DATA(IP5_8, DU1_DB7),
+       PINMUX_IPSR_MODSEL_DATA(IP5_8, SDA2_D, SEL_I2C2_3),
+       PINMUX_IPSR_DATA(IP5_10_9, DU1_DOTCLKIN),
+       PINMUX_IPSR_DATA(IP5_10_9, VI2_CLKENB),
+       PINMUX_IPSR_MODSEL_DATA(IP5_10_9, HSPI_CS1, SEL_HSPI1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_10_9, SCL1_D, SEL_I2C1_3),
+       PINMUX_IPSR_DATA(IP5_12_11, DU1_DOTCLKOUT),
+       PINMUX_IPSR_DATA(IP5_12_11, VI2_FIELD),
+       PINMUX_IPSR_MODSEL_DATA(IP5_12_11, SDA1_D, SEL_I2C1_3),
+       PINMUX_IPSR_DATA(IP5_14_13, DU1_EXHSYNC_DU1_HSYNC),
+       PINMUX_IPSR_DATA(IP5_14_13, VI2_HSYNC),
+       PINMUX_IPSR_DATA(IP5_14_13, VI3_HSYNC),
+       PINMUX_IPSR_DATA(IP5_16_15, DU1_EXVSYNC_DU1_VSYNC),
+       PINMUX_IPSR_DATA(IP5_16_15, VI2_VSYNC),
+       PINMUX_IPSR_DATA(IP5_16_15, VI3_VSYNC),
+       PINMUX_IPSR_DATA(IP5_20_17, DU1_EXODDF_DU1_ODDF_DISP_CDE),
+       PINMUX_IPSR_DATA(IP5_20_17, VI2_CLK),
+       PINMUX_IPSR_DATA(IP5_20_17, TX3_B_IRDA_TX_B),
+       PINMUX_IPSR_DATA(IP5_20_17, SD3_CD),
+       PINMUX_IPSR_DATA(IP5_20_17, HSPI_TX1),
+       PINMUX_IPSR_DATA(IP5_20_17, VI1_CLKENB),
+       PINMUX_IPSR_DATA(IP5_20_17, VI3_CLKENB),
+       PINMUX_IPSR_DATA(IP5_20_17, AUDIO_CLKC),
+       PINMUX_IPSR_DATA(IP5_20_17, TX2_D),
+       PINMUX_IPSR_DATA(IP5_20_17, SPEEDIN),
+       PINMUX_IPSR_MODSEL_DATA(IP5_20_17, GPS_SIGN_D, SEL_GPS_3),
+       PINMUX_IPSR_DATA(IP5_23_21, DU1_DISP),
+       PINMUX_IPSR_DATA(IP5_23_21, VI2_DATA6_VI2_B6),
+       PINMUX_IPSR_MODSEL_DATA(IP5_23_21, TCLK0, SEL_TMU0_0),
+       PINMUX_IPSR_DATA(IP5_23_21, QSTVA_B_QVS_B),
+       PINMUX_IPSR_MODSEL_DATA(IP5_23_21, HSPI_CLK1, SEL_HSPI1_0),
+       PINMUX_IPSR_MODSEL_DATA(IP5_23_21, SCK2_D, SEL_SCIF2_3),
+       PINMUX_IPSR_DATA(IP5_23_21, AUDIO_CLKOUT_B),
+       PINMUX_IPSR_MODSEL_DATA(IP5_23_21, GPS_MAG_D, SEL_GPS_3),
+       PINMUX_IPSR_DATA(IP5_27_24, DU1_CDE),
+       PINMUX_IPSR_DATA(IP5_27_24, VI2_DATA7_VI2_B7),
+       PINMUX_IPSR_MODSEL_DATA(IP5_27_24, RX3_B_IRDA_RX_B, SEL_SCIF3_1),
+       PINMUX_IPSR_DATA(IP5_27_24, SD3_WP),
+       PINMUX_IPSR_MODSEL_DATA(IP5_27_24, HSPI_RX1, SEL_HSPI1_0),
+       PINMUX_IPSR_DATA(IP5_27_24, VI1_FIELD),
+       PINMUX_IPSR_DATA(IP5_27_24, VI3_FIELD),
+       PINMUX_IPSR_DATA(IP5_27_24, AUDIO_CLKOUT),
+       PINMUX_IPSR_MODSEL_DATA(IP5_27_24, RX2_D, SEL_SCIF2_3),
+       PINMUX_IPSR_MODSEL_DATA(IP5_27_24, GPS_CLK_C, SEL_GPS_2),
+       PINMUX_IPSR_MODSEL_DATA(IP5_27_24, GPS_CLK_D, SEL_GPS_3),
+       PINMUX_IPSR_DATA(IP5_28, AUDIO_CLKA),
+       PINMUX_IPSR_DATA(IP5_28, CAN_TXCLK),
+       PINMUX_IPSR_DATA(IP5_30_29, AUDIO_CLKB),
+       PINMUX_IPSR_DATA(IP5_30_29, USB_OVC2),
+       PINMUX_IPSR_DATA(IP5_30_29, CAN_DEBUGOUT0),
+       PINMUX_IPSR_DATA(IP5_30_29, MOUT0),
+
+       PINMUX_IPSR_DATA(IP6_1_0, SSI_SCK0129),
+       PINMUX_IPSR_DATA(IP6_1_0, CAN_DEBUGOUT1),
+       PINMUX_IPSR_DATA(IP6_1_0, MOUT1),
+       PINMUX_IPSR_DATA(IP6_3_2, SSI_WS0129),
+       PINMUX_IPSR_DATA(IP6_3_2, CAN_DEBUGOUT2),
+       PINMUX_IPSR_DATA(IP6_3_2, MOUT2),
+       PINMUX_IPSR_DATA(IP6_5_4, SSI_SDATA0),
+       PINMUX_IPSR_DATA(IP6_5_4, CAN_DEBUGOUT3),
+       PINMUX_IPSR_DATA(IP6_5_4, MOUT5),
+       PINMUX_IPSR_DATA(IP6_7_6, SSI_SDATA1),
+       PINMUX_IPSR_DATA(IP6_7_6, CAN_DEBUGOUT4),
+       PINMUX_IPSR_DATA(IP6_7_6, MOUT6),
+       PINMUX_IPSR_DATA(IP6_8, SSI_SDATA2),
+       PINMUX_IPSR_DATA(IP6_8, CAN_DEBUGOUT5),
+       PINMUX_IPSR_DATA(IP6_11_9, SSI_SCK34),
+       PINMUX_IPSR_DATA(IP6_11_9, CAN_DEBUGOUT6),
+       PINMUX_IPSR_DATA(IP6_11_9, CAN0_TX_B),
+       PINMUX_IPSR_MODSEL_DATA(IP6_11_9, IERX, SEL_IE_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_11_9, SSI_SCK9_C, SEL_SSI9_2),
+       PINMUX_IPSR_DATA(IP6_14_12, SSI_WS34),
+       PINMUX_IPSR_DATA(IP6_14_12, CAN_DEBUGOUT7),
+       PINMUX_IPSR_MODSEL_DATA(IP6_14_12, CAN0_RX_B, SEL_CAN0_1),
+       PINMUX_IPSR_DATA(IP6_14_12, IETX),
+       PINMUX_IPSR_MODSEL_DATA(IP6_14_12, SSI_WS9_C, SEL_SSI9_2),
+       PINMUX_IPSR_DATA(IP6_17_15, SSI_SDATA3),
+       PINMUX_IPSR_DATA(IP6_17_15, PWM0_C),
+       PINMUX_IPSR_DATA(IP6_17_15, CAN_DEBUGOUT8),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_15, CAN_CLK_B, SEL_CANCLK_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_15, IECLK, SEL_IE_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_15, SCIF_CLK_B, SEL_SCIF_1),
+       PINMUX_IPSR_MODSEL_DATA(IP6_17_15, TCLK0_B, SEL_TMU0_1),
+       PINMUX_IPSR_DATA(IP6_19_18, SSI_SDATA4),
+       PINMUX_IPSR_DATA(IP6_19_18, CAN_DEBUGOUT9),
+       PINMUX_IPSR_MODSEL_DATA(IP6_19_18, SSI_SDATA9_C, SEL_SSI9_2),
+       PINMUX_IPSR_DATA(IP6_22_20, SSI_SCK5),
+       PINMUX_IPSR_DATA(IP6_22_20, ADICLK),
+       PINMUX_IPSR_DATA(IP6_22_20, CAN_DEBUGOUT10),
+       PINMUX_IPSR_MODSEL_DATA(IP6_22_20, SCK3, SEL_SCIF3_0),
+       PINMUX_IPSR_MODSEL_DATA(IP6_22_20, TCLK0_D, SEL_TMU0_3),
+       PINMUX_IPSR_DATA(IP6_24_23, SSI_WS5),
+       PINMUX_IPSR_MODSEL_DATA(IP6_24_23, ADICS_SAMP, SEL_ADI_0),
+       PINMUX_IPSR_DATA(IP6_24_23, CAN_DEBUGOUT11),
+       PINMUX_IPSR_DATA(IP6_24_23, TX3_IRDA_TX),
+       PINMUX_IPSR_DATA(IP6_26_25, SSI_SDATA5),
+       PINMUX_IPSR_MODSEL_DATA(IP6_26_25, ADIDATA, SEL_ADI_0),
+       PINMUX_IPSR_DATA(IP6_26_25, CAN_DEBUGOUT12),
+       PINMUX_IPSR_MODSEL_DATA(IP6_26_25, RX3_IRDA_RX, SEL_SCIF3_0),
+       PINMUX_IPSR_DATA(IP6_30_29, SSI_SCK6),
+       PINMUX_IPSR_DATA(IP6_30_29, ADICHS0),
+       PINMUX_IPSR_DATA(IP6_30_29, CAN0_TX),
+       PINMUX_IPSR_MODSEL_DATA(IP6_30_29, IERX_B, SEL_IE_1),
+
+       PINMUX_IPSR_DATA(IP7_1_0, SSI_WS6),
+       PINMUX_IPSR_DATA(IP7_1_0, ADICHS1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_1_0, CAN0_RX, SEL_CAN0_0),
+       PINMUX_IPSR_DATA(IP7_1_0, IETX_B),
+       PINMUX_IPSR_DATA(IP7_3_2, SSI_SDATA6),
+       PINMUX_IPSR_DATA(IP7_3_2, ADICHS2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_3_2, CAN_CLK, SEL_CANCLK_0),
+       PINMUX_IPSR_MODSEL_DATA(IP7_3_2, IECLK_B, SEL_IE_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_6_4, SSI_SCK78, SEL_SSI7_0),
+       PINMUX_IPSR_DATA(IP7_6_4, CAN_DEBUGOUT13),
+       PINMUX_IPSR_MODSEL_DATA(IP7_6_4, IRQ0_B, SEL_INT0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_6_4, SSI_SCK9_B, SEL_SSI9_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_6_4, HSPI_CLK1_C, SEL_HSPI1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_9_7, SSI_WS78, SEL_SSI7_0),
+       PINMUX_IPSR_DATA(IP7_9_7, CAN_DEBUGOUT14),
+       PINMUX_IPSR_MODSEL_DATA(IP7_9_7, IRQ1_B, SEL_INT1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_9_7, SSI_WS9_B, SEL_SSI9_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_9_7, HSPI_CS1_C, SEL_HSPI1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_12_10, SSI_SDATA7, SEL_SSI7_0),
+       PINMUX_IPSR_DATA(IP7_12_10, CAN_DEBUGOUT15),
+       PINMUX_IPSR_MODSEL_DATA(IP7_12_10, IRQ2_B, SEL_INT2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_12_10, TCLK1_C, SEL_TMU1_2),
+       PINMUX_IPSR_DATA(IP7_12_10, HSPI_TX1_C),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_13, SSI_SDATA8, SEL_SSI8_0),
+       PINMUX_IPSR_DATA(IP7_14_13, VSP),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_13, IRQ3_B, SEL_INT3_1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_14_13, HSPI_RX1_C, SEL_HSPI1_2),
+       PINMUX_IPSR_DATA(IP7_16_15, SD0_CLK),
+       PINMUX_IPSR_DATA(IP7_16_15, ATACS01),
+       PINMUX_IPSR_MODSEL_DATA(IP7_16_15, SCK1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP7_18_17, SD0_CMD),
+       PINMUX_IPSR_DATA(IP7_18_17, ATACS11),
+       PINMUX_IPSR_DATA(IP7_18_17, TX1_B),
+       PINMUX_IPSR_DATA(IP7_18_17, CC5_TDO),
+       PINMUX_IPSR_DATA(IP7_20_19, SD0_DAT0),
+       PINMUX_IPSR_DATA(IP7_20_19, ATADIR1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_20_19, RX1_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP7_20_19, CC5_TRST),
+       PINMUX_IPSR_DATA(IP7_22_21, SD0_DAT1),
+       PINMUX_IPSR_DATA(IP7_22_21, ATAG1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_22_21, SCK2_B, SEL_SCIF2_1),
+       PINMUX_IPSR_DATA(IP7_22_21, CC5_TMS),
+       PINMUX_IPSR_DATA(IP7_24_23, SD0_DAT2),
+       PINMUX_IPSR_DATA(IP7_24_23, ATARD1),
+       PINMUX_IPSR_DATA(IP7_24_23, TX2_B),
+       PINMUX_IPSR_DATA(IP7_24_23, CC5_TCK),
+       PINMUX_IPSR_DATA(IP7_26_25, SD0_DAT3),
+       PINMUX_IPSR_DATA(IP7_26_25, ATAWR1),
+       PINMUX_IPSR_MODSEL_DATA(IP7_26_25, RX2_B, SEL_SCIF2_1),
+       PINMUX_IPSR_DATA(IP7_26_25, CC5_TDI),
+       PINMUX_IPSR_DATA(IP7_28_27, SD0_CD),
+       PINMUX_IPSR_MODSEL_DATA(IP7_28_27, DREQ2, SEL_EXBUS2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP7_28_27, RTS1_B_TANS_B, SEL_SCIF1_1),
+       PINMUX_IPSR_DATA(IP7_30_29, SD0_WP),
+       PINMUX_IPSR_DATA(IP7_30_29, DACK2),
+       PINMUX_IPSR_MODSEL_DATA(IP7_30_29, CTS1_B, SEL_SCIF1_1),
+
+       PINMUX_IPSR_DATA(IP8_3_0, HSPI_CLK0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_3_0, CTS0, SEL_SCIF0_0),
+       PINMUX_IPSR_DATA(IP8_3_0, USB_OVC0),
+       PINMUX_IPSR_DATA(IP8_3_0, AD_CLK),
+       PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE4),
+       PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE12),
+       PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE20),
+       PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE28),
+       PINMUX_IPSR_DATA(IP8_3_0, CC5_STATE36),
+       PINMUX_IPSR_DATA(IP8_7_4, HSPI_CS0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_7_4, RTS0_TANS, SEL_SCIF0_0),
+       PINMUX_IPSR_DATA(IP8_7_4, USB_OVC1),
+       PINMUX_IPSR_DATA(IP8_7_4, AD_DI),
+       PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE5),
+       PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE13),
+       PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE21),
+       PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE29),
+       PINMUX_IPSR_DATA(IP8_7_4, CC5_STATE37),
+       PINMUX_IPSR_DATA(IP8_11_8, HSPI_TX0),
+       PINMUX_IPSR_DATA(IP8_11_8, TX0),
+       PINMUX_IPSR_DATA(IP8_11_8, CAN_DEBUG_HW_TRIGGER),
+       PINMUX_IPSR_DATA(IP8_11_8, AD_DO),
+       PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE6),
+       PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE14),
+       PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE22),
+       PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE30),
+       PINMUX_IPSR_DATA(IP8_11_8, CC5_STATE38),
+       PINMUX_IPSR_DATA(IP8_15_12, HSPI_RX0),
+       PINMUX_IPSR_MODSEL_DATA(IP8_15_12, RX0, SEL_SCIF0_0),
+       PINMUX_IPSR_DATA(IP8_15_12, CAN_STEP0),
+       PINMUX_IPSR_DATA(IP8_15_12, AD_NCS),
+       PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE7),
+       PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE15),
+       PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE23),
+       PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE31),
+       PINMUX_IPSR_DATA(IP8_15_12, CC5_STATE39),
+       PINMUX_IPSR_DATA(IP8_17_16, FMCLK),
+       PINMUX_IPSR_DATA(IP8_17_16, RDS_CLK),
+       PINMUX_IPSR_DATA(IP8_17_16, PCMOE),
+       PINMUX_IPSR_DATA(IP8_18, BPFCLK),
+       PINMUX_IPSR_DATA(IP8_18, PCMWE),
+       PINMUX_IPSR_DATA(IP8_19, FMIN),
+       PINMUX_IPSR_DATA(IP8_19, RDS_DATA),
+       PINMUX_IPSR_DATA(IP8_20, VI0_CLK),
+       PINMUX_IPSR_DATA(IP8_20, MMC1_CLK),
+       PINMUX_IPSR_DATA(IP8_22_21, VI0_CLKENB),
+       PINMUX_IPSR_DATA(IP8_22_21, TX1_C),
+       PINMUX_IPSR_DATA(IP8_22_21, HTX1_B),
+       PINMUX_IPSR_DATA(IP8_22_21, MT1_SYNC),
+       PINMUX_IPSR_DATA(IP8_24_23, VI0_FIELD),
+       PINMUX_IPSR_MODSEL_DATA(IP8_24_23, RX1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_24_23, HRX1_B, SEL_HSCIF1_1),
+       PINMUX_IPSR_DATA(IP8_27_25, VI0_HSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_25, VI0_DATA0_B_VI0_B0_B, SEL_VI0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_25, CTS1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_DATA(IP8_27_25, TX4_D),
+       PINMUX_IPSR_DATA(IP8_27_25, MMC1_CMD),
+       PINMUX_IPSR_MODSEL_DATA(IP8_27_25, HSCK1_B, SEL_HSCIF1_1),
+       PINMUX_IPSR_DATA(IP8_30_28, VI0_VSYNC),
+       PINMUX_IPSR_MODSEL_DATA(IP8_30_28, VI0_DATA1_B_VI0_B1_B, SEL_VI0_1),
+       PINMUX_IPSR_MODSEL_DATA(IP8_30_28, RTS1_C_TANS_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP8_30_28, RX4_D, SEL_SCIF4_3),
+       PINMUX_IPSR_MODSEL_DATA(IP8_30_28, PWMFSW0_C, SEL_PWMFSW_2),
+
+       PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI0_DATA0_VI0_B0, SEL_VI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_1_0, HRTS1_B, SEL_HSCIF1_1),
+       PINMUX_IPSR_DATA(IP9_1_0, MT1_VCXO),
+       PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI0_DATA1_VI0_B1, SEL_VI0_0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_3_2, HCTS1_B, SEL_HSCIF1_1),
+       PINMUX_IPSR_DATA(IP9_3_2, MT1_PWM),
+       PINMUX_IPSR_DATA(IP9_4, VI0_DATA2_VI0_B2),
+       PINMUX_IPSR_DATA(IP9_4, MMC1_D0),
+       PINMUX_IPSR_DATA(IP9_5, VI0_DATA3_VI0_B3),
+       PINMUX_IPSR_DATA(IP9_5, MMC1_D1),
+       PINMUX_IPSR_DATA(IP9_6, VI0_DATA4_VI0_B4),
+       PINMUX_IPSR_DATA(IP9_6, MMC1_D2),
+       PINMUX_IPSR_DATA(IP9_7, VI0_DATA5_VI0_B5),
+       PINMUX_IPSR_DATA(IP9_7, MMC1_D3),
+       PINMUX_IPSR_DATA(IP9_9_8, VI0_DATA6_VI0_B6),
+       PINMUX_IPSR_DATA(IP9_9_8, MMC1_D4),
+       PINMUX_IPSR_DATA(IP9_9_8, ARM_TRACEDATA_0),
+       PINMUX_IPSR_DATA(IP9_11_10, VI0_DATA7_VI0_B7),
+       PINMUX_IPSR_DATA(IP9_11_10, MMC1_D5),
+       PINMUX_IPSR_DATA(IP9_11_10, ARM_TRACEDATA_1),
+       PINMUX_IPSR_DATA(IP9_13_12, VI0_G0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_13_12, SSI_SCK78_C, SEL_SSI7_2),
+       PINMUX_IPSR_MODSEL_DATA(IP9_13_12, IRQ0, SEL_INT0_0),
+       PINMUX_IPSR_DATA(IP9_13_12, ARM_TRACEDATA_2),
+       PINMUX_IPSR_DATA(IP9_15_14, VI0_G1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_15_14, SSI_WS78_C, SEL_SSI7_2),
+       PINMUX_IPSR_MODSEL_DATA(IP9_15_14, IRQ1, SEL_INT1_0),
+       PINMUX_IPSR_DATA(IP9_15_14, ARM_TRACEDATA_3),
+       PINMUX_IPSR_DATA(IP9_18_16, VI0_G2),
+       PINMUX_IPSR_DATA(IP9_18_16, ETH_TXD1),
+       PINMUX_IPSR_DATA(IP9_18_16, MMC1_D6),
+       PINMUX_IPSR_DATA(IP9_18_16, ARM_TRACEDATA_4),
+       PINMUX_IPSR_DATA(IP9_18_16, TS_SPSYNC0),
+       PINMUX_IPSR_DATA(IP9_21_19, VI0_G3),
+       PINMUX_IPSR_DATA(IP9_21_19, ETH_CRS_DV),
+       PINMUX_IPSR_DATA(IP9_21_19, MMC1_D7),
+       PINMUX_IPSR_DATA(IP9_21_19, ARM_TRACEDATA_5),
+       PINMUX_IPSR_DATA(IP9_21_19, TS_SDAT0),
+       PINMUX_IPSR_DATA(IP9_23_22, VI0_G4),
+       PINMUX_IPSR_DATA(IP9_23_22, ETH_TX_EN),
+       PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SD2_DAT0_B, SEL_SD2_1),
+       PINMUX_IPSR_DATA(IP9_23_22, ARM_TRACEDATA_6),
+       PINMUX_IPSR_DATA(IP9_25_24, VI0_G5),
+       PINMUX_IPSR_DATA(IP9_25_24, ETH_RX_ER),
+       PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SD2_DAT1_B, SEL_SD2_1),
+       PINMUX_IPSR_DATA(IP9_25_24, ARM_TRACEDATA_7),
+       PINMUX_IPSR_DATA(IP9_27_26, VI0_G6),
+       PINMUX_IPSR_DATA(IP9_27_26, ETH_RXD0),
+       PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SD2_DAT2_B, SEL_SD2_1),
+       PINMUX_IPSR_DATA(IP9_27_26, ARM_TRACEDATA_8),
+       PINMUX_IPSR_DATA(IP9_29_28, VI0_G7),
+       PINMUX_IPSR_DATA(IP9_29_28, ETH_RXD1),
+       PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SD2_DAT3_B, SEL_SD2_1),
+       PINMUX_IPSR_DATA(IP9_29_28, ARM_TRACEDATA_9),
+
+       PINMUX_IPSR_DATA(IP10_2_0, VI0_R0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SSI_SDATA7_C, SEL_SSI7_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SCK1_C, SEL_SCIF1_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, DREQ1_B, SEL_EXBUS1_0),
+       PINMUX_IPSR_DATA(IP10_2_0, ARM_TRACEDATA_10),
+       PINMUX_IPSR_MODSEL_DATA(IP10_2_0, DREQ0_C, SEL_EXBUS0_2),
+       PINMUX_IPSR_DATA(IP10_5_3, VI0_R1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_5_3, SSI_SDATA8_C, SEL_SSI8_2),
+       PINMUX_IPSR_DATA(IP10_5_3, DACK1_B),
+       PINMUX_IPSR_DATA(IP10_5_3, ARM_TRACEDATA_11),
+       PINMUX_IPSR_DATA(IP10_5_3, DACK0_C),
+       PINMUX_IPSR_DATA(IP10_5_3, DRACK0_C),
+       PINMUX_IPSR_DATA(IP10_8_6, VI0_R2),
+       PINMUX_IPSR_DATA(IP10_8_6, ETH_LINK),
+       PINMUX_IPSR_DATA(IP10_8_6, SD2_CLK_B),
+       PINMUX_IPSR_MODSEL_DATA(IP10_8_6, IRQ2, SEL_INT2_0),
+       PINMUX_IPSR_DATA(IP10_8_6, ARM_TRACEDATA_12),
+       PINMUX_IPSR_DATA(IP10_11_9, VI0_R3),
+       PINMUX_IPSR_DATA(IP10_11_9, ETH_MAGIC),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, SD2_CMD_B, SEL_SD2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_11_9, IRQ3, SEL_INT3_0),
+       PINMUX_IPSR_DATA(IP10_11_9, ARM_TRACEDATA_13),
+       PINMUX_IPSR_DATA(IP10_14_12, VI0_R4),
+       PINMUX_IPSR_DATA(IP10_14_12, ETH_REFCLK),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SD2_CD_B, SEL_SD2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_14_12, HSPI_CLK1_B, SEL_HSPI1_1),
+       PINMUX_IPSR_DATA(IP10_14_12, ARM_TRACEDATA_14),
+       PINMUX_IPSR_DATA(IP10_14_12, MT1_CLK),
+       PINMUX_IPSR_DATA(IP10_14_12, TS_SCK0),
+       PINMUX_IPSR_DATA(IP10_17_15, VI0_R5),
+       PINMUX_IPSR_DATA(IP10_17_15, ETH_TXD0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_17_15, SD2_WP_B, SEL_SD2_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_17_15, HSPI_CS1_B, SEL_HSPI1_1),
+       PINMUX_IPSR_DATA(IP10_17_15, ARM_TRACEDATA_15),
+       PINMUX_IPSR_DATA(IP10_17_15, MT1_D),
+       PINMUX_IPSR_DATA(IP10_17_15, TS_SDEN0),
+       PINMUX_IPSR_DATA(IP10_20_18, VI0_R6),
+       PINMUX_IPSR_DATA(IP10_20_18, ETH_MDC),
+       PINMUX_IPSR_MODSEL_DATA(IP10_20_18, DREQ2_C, SEL_EXBUS2_2),
+       PINMUX_IPSR_DATA(IP10_20_18, HSPI_TX1_B),
+       PINMUX_IPSR_DATA(IP10_20_18, TRACECLK),
+       PINMUX_IPSR_DATA(IP10_20_18, MT1_BEN),
+       PINMUX_IPSR_MODSEL_DATA(IP10_20_18, PWMFSW0_D, SEL_PWMFSW_3),
+       PINMUX_IPSR_DATA(IP10_23_21, VI0_R7),
+       PINMUX_IPSR_DATA(IP10_23_21, ETH_MDIO),
+       PINMUX_IPSR_DATA(IP10_23_21, DACK2_C),
+       PINMUX_IPSR_MODSEL_DATA(IP10_23_21, HSPI_RX1_B, SEL_HSPI1_1),
+       PINMUX_IPSR_MODSEL_DATA(IP10_23_21, SCIF_CLK_D, SEL_SCIF_3),
+       PINMUX_IPSR_DATA(IP10_23_21, TRACECTL),
+       PINMUX_IPSR_DATA(IP10_23_21, MT1_PEN),
+       PINMUX_IPSR_DATA(IP10_25_24, VI1_CLK),
+       PINMUX_IPSR_MODSEL_DATA(IP10_25_24, SIM_D, SEL_SIM_0),
+       PINMUX_IPSR_MODSEL_DATA(IP10_25_24, SDA3, SEL_I2C3_0),
+       PINMUX_IPSR_DATA(IP10_28_26, VI1_HSYNC),
+       PINMUX_IPSR_DATA(IP10_28_26, VI3_CLK),
+       PINMUX_IPSR_DATA(IP10_28_26, SSI_SCK4),
+       PINMUX_IPSR_MODSEL_DATA(IP10_28_26, GPS_SIGN_C, SEL_GPS_2),
+       PINMUX_IPSR_MODSEL_DATA(IP10_28_26, PWMFSW0_E, SEL_PWMFSW_4),
+       PINMUX_IPSR_DATA(IP10_31_29, VI1_VSYNC),
+       PINMUX_IPSR_DATA(IP10_31_29, AUDIO_CLKOUT_C),
+       PINMUX_IPSR_DATA(IP10_31_29, SSI_WS4),
+       PINMUX_IPSR_DATA(IP10_31_29, SIM_CLK),
+       PINMUX_IPSR_MODSEL_DATA(IP10_31_29, GPS_MAG_C, SEL_GPS_2),
+       PINMUX_IPSR_DATA(IP10_31_29, SPV_TRST),
+       PINMUX_IPSR_MODSEL_DATA(IP10_31_29, SCL3, SEL_I2C3_0),
+
+       PINMUX_IPSR_DATA(IP11_2_0, VI1_DATA0_VI1_B0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_2_0, SD2_DAT0, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_2_0, SIM_RST),
+       PINMUX_IPSR_DATA(IP11_2_0, SPV_TCK),
+       PINMUX_IPSR_DATA(IP11_2_0, ADICLK_B),
+       PINMUX_IPSR_DATA(IP11_5_3, VI1_DATA1_VI1_B1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_5_3, SD2_DAT1, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_5_3, MT0_CLK),
+       PINMUX_IPSR_DATA(IP11_5_3, SPV_TMS),
+       PINMUX_IPSR_MODSEL_DATA(IP11_5_3, ADICS_B_SAMP_B, SEL_ADI_1),
+       PINMUX_IPSR_DATA(IP11_8_6, VI1_DATA2_VI1_B2),
+       PINMUX_IPSR_MODSEL_DATA(IP11_8_6, SD2_DAT2, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_8_6, MT0_D),
+       PINMUX_IPSR_DATA(IP11_8_6, SPVTDI),
+       PINMUX_IPSR_MODSEL_DATA(IP11_8_6, ADIDATA_B, SEL_ADI_1),
+       PINMUX_IPSR_DATA(IP11_11_9, VI1_DATA3_VI1_B3),
+       PINMUX_IPSR_MODSEL_DATA(IP11_11_9, SD2_DAT3, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_11_9, MT0_BEN),
+       PINMUX_IPSR_DATA(IP11_11_9, SPV_TDO),
+       PINMUX_IPSR_DATA(IP11_11_9, ADICHS0_B),
+       PINMUX_IPSR_DATA(IP11_14_12, VI1_DATA4_VI1_B4),
+       PINMUX_IPSR_DATA(IP11_14_12, SD2_CLK),
+       PINMUX_IPSR_DATA(IP11_14_12, MT0_PEN),
+       PINMUX_IPSR_DATA(IP11_14_12, SPA_TRST),
+       PINMUX_IPSR_MODSEL_DATA(IP11_14_12, HSPI_CLK1_D, SEL_HSPI1_3),
+       PINMUX_IPSR_DATA(IP11_14_12, ADICHS1_B),
+       PINMUX_IPSR_DATA(IP11_17_15, VI1_DATA5_VI1_B5),
+       PINMUX_IPSR_MODSEL_DATA(IP11_17_15, SD2_CMD, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_17_15, MT0_SYNC),
+       PINMUX_IPSR_DATA(IP11_17_15, SPA_TCK),
+       PINMUX_IPSR_MODSEL_DATA(IP11_17_15, HSPI_CS1_D, SEL_HSPI1_3),
+       PINMUX_IPSR_DATA(IP11_17_15, ADICHS2_B),
+       PINMUX_IPSR_DATA(IP11_20_18, VI1_DATA6_VI1_B6),
+       PINMUX_IPSR_MODSEL_DATA(IP11_20_18, SD2_CD, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_20_18, MT0_VCXO),
+       PINMUX_IPSR_DATA(IP11_20_18, SPA_TMS),
+       PINMUX_IPSR_DATA(IP11_20_18, HSPI_TX1_D),
+       PINMUX_IPSR_DATA(IP11_23_21, VI1_DATA7_VI1_B7),
+       PINMUX_IPSR_MODSEL_DATA(IP11_23_21, SD2_WP, SEL_SD2_0),
+       PINMUX_IPSR_DATA(IP11_23_21, MT0_PWM),
+       PINMUX_IPSR_DATA(IP11_23_21, SPA_TDI),
+       PINMUX_IPSR_MODSEL_DATA(IP11_23_21, HSPI_RX1_D, SEL_HSPI1_3),
+       PINMUX_IPSR_DATA(IP11_26_24, VI1_G0),
+       PINMUX_IPSR_DATA(IP11_26_24, VI3_DATA0),
+       PINMUX_IPSR_DATA(IP11_26_24, DU1_DOTCLKOUT1),
+       PINMUX_IPSR_DATA(IP11_26_24, TS_SCK1),
+       PINMUX_IPSR_MODSEL_DATA(IP11_26_24, DREQ2_B, SEL_EXBUS2_1),
+       PINMUX_IPSR_DATA(IP11_26_24, TX2),
+       PINMUX_IPSR_DATA(IP11_26_24, SPA_TDO),
+       PINMUX_IPSR_MODSEL_DATA(IP11_26_24, HCTS0_B, SEL_HSCIF0_1),
+       PINMUX_IPSR_DATA(IP11_29_27, VI1_G1),
+       PINMUX_IPSR_DATA(IP11_29_27, VI3_DATA1),
+       PINMUX_IPSR_DATA(IP11_29_27, SSI_SCK1),
+       PINMUX_IPSR_DATA(IP11_29_27, TS_SDEN1),
+       PINMUX_IPSR_DATA(IP11_29_27, DACK2_B),
+       PINMUX_IPSR_MODSEL_DATA(IP11_29_27, RX2, SEL_SCIF2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP11_29_27, HRTS0_B, SEL_HSCIF0_1),
+
+       PINMUX_IPSR_DATA(IP12_2_0, VI1_G2),
+       PINMUX_IPSR_DATA(IP12_2_0, VI3_DATA2),
+       PINMUX_IPSR_DATA(IP12_2_0, SSI_WS1),
+       PINMUX_IPSR_DATA(IP12_2_0, TS_SPSYNC1),
+       PINMUX_IPSR_MODSEL_DATA(IP12_2_0, SCK2, SEL_SCIF2_0),
+       PINMUX_IPSR_MODSEL_DATA(IP12_2_0, HSCK0_B, SEL_HSCIF0_1),
+       PINMUX_IPSR_DATA(IP12_5_3, VI1_G3),
+       PINMUX_IPSR_DATA(IP12_5_3, VI3_DATA3),
+       PINMUX_IPSR_DATA(IP12_5_3, SSI_SCK2),
+       PINMUX_IPSR_DATA(IP12_5_3, TS_SDAT1),
+       PINMUX_IPSR_MODSEL_DATA(IP12_5_3, SCL1_C, SEL_I2C1_2),
+       PINMUX_IPSR_DATA(IP12_5_3, HTX0_B),
+       PINMUX_IPSR_DATA(IP12_8_6, VI1_G4),
+       PINMUX_IPSR_DATA(IP12_8_6, VI3_DATA4),
+       PINMUX_IPSR_DATA(IP12_8_6, SSI_WS2),
+       PINMUX_IPSR_MODSEL_DATA(IP12_8_6, SDA1_C, SEL_I2C1_2),
+       PINMUX_IPSR_DATA(IP12_8_6, SIM_RST_B),
+       PINMUX_IPSR_MODSEL_DATA(IP12_8_6, HRX0_B, SEL_HSCIF0_1),
+       PINMUX_IPSR_DATA(IP12_11_9, VI1_G5),
+       PINMUX_IPSR_DATA(IP12_11_9, VI3_DATA5),
+       PINMUX_IPSR_MODSEL_DATA(IP12_11_9, GPS_CLK, SEL_GPS_0),
+       PINMUX_IPSR_DATA(IP12_11_9, FSE),
+       PINMUX_IPSR_DATA(IP12_11_9, TX4_B),
+       PINMUX_IPSR_MODSEL_DATA(IP12_11_9, SIM_D_B, SEL_SIM_1),
+       PINMUX_IPSR_DATA(IP12_14_12, VI1_G6),
+       PINMUX_IPSR_DATA(IP12_14_12, VI3_DATA6),
+       PINMUX_IPSR_MODSEL_DATA(IP12_14_12, GPS_SIGN, SEL_GPS_0),
+       PINMUX_IPSR_DATA(IP12_14_12, FRB),
+       PINMUX_IPSR_MODSEL_DATA(IP12_14_12, RX4_B, SEL_SCIF4_1),
+       PINMUX_IPSR_DATA(IP12_14_12, SIM_CLK_B),
+       PINMUX_IPSR_DATA(IP12_17_15, VI1_G7),
+       PINMUX_IPSR_DATA(IP12_17_15, VI3_DATA7),
+       PINMUX_IPSR_MODSEL_DATA(IP12_17_15, GPS_MAG, SEL_GPS_0),
+       PINMUX_IPSR_DATA(IP12_17_15, FCE),
+       PINMUX_IPSR_MODSEL_DATA(IP12_17_15, SCK4_B, SEL_SCIF4_1),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+       PINMUX_GPIO_GP_ALL(),
+       GPIO_FN(AVS1), GPIO_FN(AVS2), GPIO_FN(A17), GPIO_FN(A18),
+       GPIO_FN(A19),
+
+       /* IPSR0 */
+       GPIO_FN(PENC2), GPIO_FN(SCK0), GPIO_FN(PWM1), GPIO_FN(PWMFSW0),
+       GPIO_FN(SCIF_CLK), GPIO_FN(TCLK0_C), GPIO_FN(BS), GPIO_FN(SD1_DAT2),
+       GPIO_FN(MMC0_D2), GPIO_FN(FD2), GPIO_FN(ATADIR0), GPIO_FN(SDSELF),
+       GPIO_FN(HCTS1), GPIO_FN(TX4_C), GPIO_FN(A0), GPIO_FN(SD1_DAT3),
+       GPIO_FN(MMC0_D3), GPIO_FN(FD3), GPIO_FN(A20), GPIO_FN(TX5_D),
+       GPIO_FN(HSPI_TX2_B), GPIO_FN(A21), GPIO_FN(SCK5_D),
+       GPIO_FN(HSPI_CLK2_B), GPIO_FN(A22), GPIO_FN(RX5_D),
+       GPIO_FN(HSPI_RX2_B), GPIO_FN(VI1_R0), GPIO_FN(A23), GPIO_FN(FCLE),
+       GPIO_FN(HSPI_CLK2), GPIO_FN(VI1_R1), GPIO_FN(A24), GPIO_FN(SD1_CD),
+       GPIO_FN(MMC0_D4), GPIO_FN(FD4), GPIO_FN(HSPI_CS2), GPIO_FN(VI1_R2),
+       GPIO_FN(SSI_WS78_B), GPIO_FN(A25), GPIO_FN(SD1_WP), GPIO_FN(MMC0_D5),
+       GPIO_FN(FD5), GPIO_FN(HSPI_RX2), GPIO_FN(VI1_R3), GPIO_FN(TX5_B),
+       GPIO_FN(SSI_SDATA7_B), GPIO_FN(CTS0_B), GPIO_FN(CLKOUT),
+       GPIO_FN(TX3C_IRDA_TX_C), GPIO_FN(PWM0_B), GPIO_FN(CS0),
+       GPIO_FN(HSPI_CS2_B), GPIO_FN(CS1_A26), GPIO_FN(HSPI_TX2),
+       GPIO_FN(SDSELF_B), GPIO_FN(RD_WR), GPIO_FN(FWE), GPIO_FN(ATAG0),
+       GPIO_FN(VI1_R7), GPIO_FN(HRTS1), GPIO_FN(RX4_C),
+
+       /* IPSR1 */
+       GPIO_FN(EX_CS0), GPIO_FN(RX3_C_IRDA_RX_C), GPIO_FN(MMC0_D6),
+       GPIO_FN(FD6), GPIO_FN(EX_CS1), GPIO_FN(MMC0_D7), GPIO_FN(FD7),
+       GPIO_FN(EX_CS2), GPIO_FN(SD1_CLK), GPIO_FN(MMC0_CLK), GPIO_FN(FALE),
+       GPIO_FN(ATACS00), GPIO_FN(EX_CS3), GPIO_FN(SD1_CMD), GPIO_FN(MMC0_CMD),
+       GPIO_FN(FRE), GPIO_FN(ATACS10), GPIO_FN(VI1_R4), GPIO_FN(RX5_B),
+       GPIO_FN(HSCK1), GPIO_FN(SSI_SDATA8_B), GPIO_FN(RTS0_B_TANS_B),
+       GPIO_FN(SSI_SDATA9), GPIO_FN(EX_CS4), GPIO_FN(SD1_DAT0),
+       GPIO_FN(MMC0_D0), GPIO_FN(FD0), GPIO_FN(ATARD0), GPIO_FN(VI1_R5),
+       GPIO_FN(SCK5_B), GPIO_FN(HTX1), GPIO_FN(TX2_E), GPIO_FN(TX0_B),
+       GPIO_FN(SSI_SCK9), GPIO_FN(EX_CS5), GPIO_FN(SD1_DAT1),
+       GPIO_FN(MMC0_D1), GPIO_FN(FD1), GPIO_FN(ATAWR0), GPIO_FN(VI1_R6),
+       GPIO_FN(HRX1), GPIO_FN(RX2_E), GPIO_FN(RX0_B), GPIO_FN(SSI_WS9),
+       GPIO_FN(MLB_CLK), GPIO_FN(PWM2), GPIO_FN(SCK4), GPIO_FN(MLB_SIG),
+       GPIO_FN(PWM3), GPIO_FN(TX4), GPIO_FN(MLB_DAT), GPIO_FN(PWM4),
+       GPIO_FN(RX4), GPIO_FN(HTX0), GPIO_FN(TX1), GPIO_FN(SDATA),
+       GPIO_FN(CTS0_C), GPIO_FN(SUB_TCK), GPIO_FN(CC5_STATE2),
+       GPIO_FN(CC5_STATE10), GPIO_FN(CC5_STATE18), GPIO_FN(CC5_STATE26),
+       GPIO_FN(CC5_STATE34),
+
+       /* IPSR2 */
+       GPIO_FN(HRX0), GPIO_FN(RX1), GPIO_FN(SCKZ), GPIO_FN(RTS0_C_TANS_C),
+       GPIO_FN(SUB_TDI), GPIO_FN(CC5_STATE3), GPIO_FN(CC5_STATE11),
+       GPIO_FN(CC5_STATE19), GPIO_FN(CC5_STATE27), GPIO_FN(CC5_STATE35),
+       GPIO_FN(HSCK0), GPIO_FN(SCK1), GPIO_FN(MTS), GPIO_FN(PWM5),
+       GPIO_FN(SCK0_C), GPIO_FN(SSI_SDATA9_B), GPIO_FN(SUB_TDO),
+       GPIO_FN(CC5_STATE0), GPIO_FN(CC5_STATE8), GPIO_FN(CC5_STATE16),
+       GPIO_FN(CC5_STATE24), GPIO_FN(CC5_STATE32), GPIO_FN(HCTS0),
+       GPIO_FN(CTS1), GPIO_FN(STM), GPIO_FN(PWM0_D), GPIO_FN(RX0_C),
+       GPIO_FN(SCIF_CLK_C), GPIO_FN(SUB_TRST), GPIO_FN(TCLK1_B),
+       GPIO_FN(CC5_OSCOUT), GPIO_FN(HRTS0), GPIO_FN(RTS1_TANS),
+       GPIO_FN(MDATA), GPIO_FN(TX0_C), GPIO_FN(SUB_TMS), GPIO_FN(CC5_STATE1),
+       GPIO_FN(CC5_STATE9), GPIO_FN(CC5_STATE17), GPIO_FN(CC5_STATE25),
+       GPIO_FN(CC5_STATE33), GPIO_FN(DU0_DR0), GPIO_FN(LCDOUT0),
+       GPIO_FN(DREQ0), GPIO_FN(GPS_CLK_B), GPIO_FN(AUDATA0),
+       GPIO_FN(TX5_C), GPIO_FN(DU0_DR1), GPIO_FN(LCDOUT1), GPIO_FN(DACK0),
+       GPIO_FN(DRACK0), GPIO_FN(GPS_SIGN_B), GPIO_FN(AUDATA1), GPIO_FN(RX5_C),
+       GPIO_FN(DU0_DR2), GPIO_FN(LCDOUT2), GPIO_FN(DU0_DR3), GPIO_FN(LCDOUT3),
+       GPIO_FN(DU0_DR4), GPIO_FN(LCDOUT4), GPIO_FN(DU0_DR5), GPIO_FN(LCDOUT5),
+       GPIO_FN(DU0_DR6), GPIO_FN(LCDOUT6), GPIO_FN(DU0_DR7), GPIO_FN(LCDOUT7),
+       GPIO_FN(DU0_DG0), GPIO_FN(LCDOUT8), GPIO_FN(DREQ1), GPIO_FN(SCL2),
+       GPIO_FN(AUDATA2),
+
+       /* IPSR3 */
+       GPIO_FN(DU0_DG1), GPIO_FN(LCDOUT9), GPIO_FN(DACK1), GPIO_FN(SDA2),
+       GPIO_FN(AUDATA3), GPIO_FN(DU0_DG2), GPIO_FN(LCDOUT10),
+       GPIO_FN(DU0_DG3), GPIO_FN(LCDOUT11), GPIO_FN(DU0_DG4),
+       GPIO_FN(LCDOUT12), GPIO_FN(DU0_DG5), GPIO_FN(LCDOUT13),
+       GPIO_FN(DU0_DG6), GPIO_FN(LCDOUT14), GPIO_FN(DU0_DG7),
+       GPIO_FN(LCDOUT15), GPIO_FN(DU0_DB0), GPIO_FN(LCDOUT16),
+       GPIO_FN(EX_WAIT1), GPIO_FN(SCL1), GPIO_FN(TCLK1), GPIO_FN(AUDATA4),
+       GPIO_FN(DU0_DB1), GPIO_FN(LCDOUT17), GPIO_FN(EX_WAIT2), GPIO_FN(SDA1),
+       GPIO_FN(GPS_MAG_B), GPIO_FN(AUDATA5), GPIO_FN(SCK5_C),
+       GPIO_FN(DU0_DB2), GPIO_FN(LCDOUT18), GPIO_FN(DU0_DB3),
+       GPIO_FN(LCDOUT19), GPIO_FN(DU0_DB4), GPIO_FN(LCDOUT20),
+       GPIO_FN(DU0_DB5), GPIO_FN(LCDOUT21), GPIO_FN(DU0_DB6),
+       GPIO_FN(LCDOUT22), GPIO_FN(DU0_DB7), GPIO_FN(LCDOUT23),
+       GPIO_FN(DU0_DOTCLKIN), GPIO_FN(QSTVA_QVS), GPIO_FN(TX3_D_IRDA_TX_D),
+       GPIO_FN(SCL3_B), GPIO_FN(DU0_DOTCLKOUT0), GPIO_FN(QCLK),
+       GPIO_FN(DU0_DOTCLKOUT1), GPIO_FN(QSTVB_QVE), GPIO_FN(RX3_D_IRDA_RX_D),
+       GPIO_FN(SDA3_B), GPIO_FN(SDA2_C), GPIO_FN(DACK0_B), GPIO_FN(DRACK0_B),
+       GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(QSTH_QHS),
+       GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(QSTB_QHE),
+       GPIO_FN(DU0_EXODDF_DU0_ODDF_DISP_CDE), GPIO_FN(QCPV_QDE),
+       GPIO_FN(CAN1_TX), GPIO_FN(TX2_C), GPIO_FN(SCL2_C), GPIO_FN(REMOCON),
+
+       /* IPSR4 */
+       GPIO_FN(DU0_DISP), GPIO_FN(QPOLA), GPIO_FN(CAN_CLK_C), GPIO_FN(SCK2_C),
+       GPIO_FN(DU0_CDE), GPIO_FN(QPOLB), GPIO_FN(CAN1_RX), GPIO_FN(RX2_C),
+       GPIO_FN(DREQ0_B), GPIO_FN(SSI_SCK78_B), GPIO_FN(SCK0_B),
+       GPIO_FN(DU1_DR0), GPIO_FN(VI2_DATA0_VI2_B0), GPIO_FN(PWM6),
+       GPIO_FN(SD3_CLK), GPIO_FN(TX3_E_IRDA_TX_E), GPIO_FN(AUDCK),
+       GPIO_FN(PWMFSW0_B), GPIO_FN(DU1_DR1), GPIO_FN(VI2_DATA1_VI2_B1),
+       GPIO_FN(PWM0), GPIO_FN(SD3_CMD), GPIO_FN(RX3_E_IRDA_RX_E),
+       GPIO_FN(AUDSYNC), GPIO_FN(CTS0_D), GPIO_FN(DU1_DR2), GPIO_FN(VI2_G0),
+       GPIO_FN(DU1_DR3), GPIO_FN(VI2_G1), GPIO_FN(DU1_DR4), GPIO_FN(VI2_G2),
+       GPIO_FN(DU1_DR5), GPIO_FN(VI2_G3), GPIO_FN(DU1_DR6), GPIO_FN(VI2_G4),
+       GPIO_FN(DU1_DR7), GPIO_FN(VI2_G5), GPIO_FN(DU1_DG0),
+       GPIO_FN(VI2_DATA2_VI2_B2), GPIO_FN(SCL1_B), GPIO_FN(SD3_DAT2),
+       GPIO_FN(SCK3_E), GPIO_FN(AUDATA6), GPIO_FN(TX0_D), GPIO_FN(DU1_DG1),
+       GPIO_FN(VI2_DATA3_VI2_B3), GPIO_FN(SDA1_B), GPIO_FN(SD3_DAT3),
+       GPIO_FN(SCK5), GPIO_FN(AUDATA7), GPIO_FN(RX0_D), GPIO_FN(DU1_DG2),
+       GPIO_FN(VI2_G6), GPIO_FN(DU1_DG3), GPIO_FN(VI2_G7), GPIO_FN(DU1_DG4),
+       GPIO_FN(VI2_R0), GPIO_FN(DU1_DG5), GPIO_FN(VI2_R1), GPIO_FN(DU1_DG6),
+       GPIO_FN(VI2_R2), GPIO_FN(DU1_DG7), GPIO_FN(VI2_R3), GPIO_FN(DU1_DB0),
+       GPIO_FN(VI2_DATA4_VI2_B4), GPIO_FN(SCL2_B), GPIO_FN(SD3_DAT0),
+       GPIO_FN(TX5), GPIO_FN(SCK0_D),
+
+       /* IPSR5 */
+       GPIO_FN(DU1_DB1), GPIO_FN(VI2_DATA5_VI2_B5), GPIO_FN(SDA2_B),
+       GPIO_FN(SD3_DAT1), GPIO_FN(RX5), GPIO_FN(RTS0_D_TANS_D),
+       GPIO_FN(DU1_DB2), GPIO_FN(VI2_R4), GPIO_FN(DU1_DB3), GPIO_FN(VI2_R5),
+       GPIO_FN(DU1_DB4), GPIO_FN(VI2_R6), GPIO_FN(DU1_DB5), GPIO_FN(VI2_R7),
+       GPIO_FN(DU1_DB6), GPIO_FN(SCL2_D), GPIO_FN(DU1_DB7), GPIO_FN(SDA2_D),
+       GPIO_FN(DU1_DOTCLKIN), GPIO_FN(VI2_CLKENB), GPIO_FN(HSPI_CS1),
+       GPIO_FN(SCL1_D), GPIO_FN(DU1_DOTCLKOUT), GPIO_FN(VI2_FIELD),
+       GPIO_FN(SDA1_D), GPIO_FN(DU1_EXHSYNC_DU1_HSYNC), GPIO_FN(VI2_HSYNC),
+       GPIO_FN(VI3_HSYNC), GPIO_FN(DU1_EXVSYNC_DU1_VSYNC), GPIO_FN(VI2_VSYNC),
+       GPIO_FN(VI3_VSYNC), GPIO_FN(DU1_EXODDF_DU1_ODDF_DISP_CDE),
+       GPIO_FN(VI2_CLK), GPIO_FN(TX3_B_IRDA_TX_B), GPIO_FN(SD3_CD),
+       GPIO_FN(HSPI_TX1), GPIO_FN(VI1_CLKENB), GPIO_FN(VI3_CLKENB),
+       GPIO_FN(AUDIO_CLKC), GPIO_FN(TX2_D), GPIO_FN(SPEEDIN),
+       GPIO_FN(GPS_SIGN_D), GPIO_FN(DU1_DISP), GPIO_FN(VI2_DATA6_VI2_B6),
+       GPIO_FN(TCLK0), GPIO_FN(QSTVA_B_QVS_B), GPIO_FN(HSPI_CLK1),
+       GPIO_FN(SCK2_D), GPIO_FN(AUDIO_CLKOUT_B), GPIO_FN(GPS_MAG_D),
+       GPIO_FN(DU1_CDE), GPIO_FN(VI2_DATA7_VI2_B7), GPIO_FN(RX3_B_IRDA_RX_B),
+       GPIO_FN(SD3_WP), GPIO_FN(HSPI_RX1), GPIO_FN(VI1_FIELD),
+       GPIO_FN(VI3_FIELD), GPIO_FN(AUDIO_CLKOUT), GPIO_FN(RX2_D),
+       GPIO_FN(GPS_CLK_C), GPIO_FN(GPS_CLK_D), GPIO_FN(AUDIO_CLKA),
+       GPIO_FN(CAN_TXCLK), GPIO_FN(AUDIO_CLKB), GPIO_FN(USB_OVC2),
+       GPIO_FN(CAN_DEBUGOUT0), GPIO_FN(MOUT0),
+
+       /* IPSR6 */
+       GPIO_FN(SSI_SCK0129), GPIO_FN(CAN_DEBUGOUT1), GPIO_FN(MOUT1),
+       GPIO_FN(SSI_WS0129), GPIO_FN(CAN_DEBUGOUT2), GPIO_FN(MOUT2),
+       GPIO_FN(SSI_SDATA0), GPIO_FN(CAN_DEBUGOUT3), GPIO_FN(MOUT5),
+       GPIO_FN(SSI_SDATA1), GPIO_FN(CAN_DEBUGOUT4), GPIO_FN(MOUT6),
+       GPIO_FN(SSI_SDATA2), GPIO_FN(CAN_DEBUGOUT5), GPIO_FN(SSI_SCK34),
+       GPIO_FN(CAN_DEBUGOUT6), GPIO_FN(CAN0_TX_B), GPIO_FN(IERX),
+       GPIO_FN(SSI_SCK9_C), GPIO_FN(SSI_WS34), GPIO_FN(CAN_DEBUGOUT7),
+       GPIO_FN(CAN0_RX_B), GPIO_FN(IETX), GPIO_FN(SSI_WS9_C),
+       GPIO_FN(SSI_SDATA3), GPIO_FN(PWM0_C), GPIO_FN(CAN_DEBUGOUT8),
+       GPIO_FN(CAN_CLK_B), GPIO_FN(IECLK), GPIO_FN(SCIF_CLK_B),
+       GPIO_FN(TCLK0_B), GPIO_FN(SSI_SDATA4), GPIO_FN(CAN_DEBUGOUT9),
+       GPIO_FN(SSI_SDATA9_C), GPIO_FN(SSI_SCK5), GPIO_FN(ADICLK),
+       GPIO_FN(CAN_DEBUGOUT10), GPIO_FN(SCK3), GPIO_FN(TCLK0_D),
+       GPIO_FN(SSI_WS5), GPIO_FN(ADICS_SAMP), GPIO_FN(CAN_DEBUGOUT11),
+       GPIO_FN(TX3_IRDA_TX), GPIO_FN(SSI_SDATA5), GPIO_FN(ADIDATA),
+       GPIO_FN(CAN_DEBUGOUT12), GPIO_FN(RX3_IRDA_RX), GPIO_FN(SSI_SCK6),
+       GPIO_FN(ADICHS0), GPIO_FN(CAN0_TX), GPIO_FN(IERX_B),
+
+       /* IPSR7 */
+       GPIO_FN(SSI_WS6), GPIO_FN(ADICHS1), GPIO_FN(CAN0_RX), GPIO_FN(IETX_B),
+       GPIO_FN(SSI_SDATA6), GPIO_FN(ADICHS2), GPIO_FN(CAN_CLK),
+       GPIO_FN(IECLK_B), GPIO_FN(SSI_SCK78), GPIO_FN(CAN_DEBUGOUT13),
+       GPIO_FN(IRQ0_B), GPIO_FN(SSI_SCK9_B), GPIO_FN(HSPI_CLK1_C),
+       GPIO_FN(SSI_WS78), GPIO_FN(CAN_DEBUGOUT14), GPIO_FN(IRQ1_B),
+       GPIO_FN(SSI_WS9_B), GPIO_FN(HSPI_CS1_C), GPIO_FN(SSI_SDATA7),
+       GPIO_FN(CAN_DEBUGOUT15), GPIO_FN(IRQ2_B), GPIO_FN(TCLK1_C),
+       GPIO_FN(HSPI_TX1_C), GPIO_FN(SSI_SDATA8), GPIO_FN(VSP),
+       GPIO_FN(IRQ3_B), GPIO_FN(HSPI_RX1_C), GPIO_FN(SD0_CLK),
+       GPIO_FN(ATACS01), GPIO_FN(SCK1_B), GPIO_FN(SD0_CMD), GPIO_FN(ATACS11),
+       GPIO_FN(TX1_B), GPIO_FN(CC5_TDO), GPIO_FN(SD0_DAT0), GPIO_FN(ATADIR1),
+       GPIO_FN(RX1_B), GPIO_FN(CC5_TRST), GPIO_FN(SD0_DAT1), GPIO_FN(ATAG1),
+       GPIO_FN(SCK2_B), GPIO_FN(CC5_TMS), GPIO_FN(SD0_DAT2), GPIO_FN(ATARD1),
+       GPIO_FN(TX2_B), GPIO_FN(CC5_TCK), GPIO_FN(SD0_DAT3), GPIO_FN(ATAWR1),
+       GPIO_FN(RX2_B), GPIO_FN(CC5_TDI), GPIO_FN(SD0_CD), GPIO_FN(DREQ2),
+       GPIO_FN(RTS1_B_TANS_B), GPIO_FN(SD0_WP), GPIO_FN(DACK2),
+       GPIO_FN(CTS1_B),
+
+       /* IPSR8 */
+       GPIO_FN(HSPI_CLK0), GPIO_FN(CTS0), GPIO_FN(USB_OVC0), GPIO_FN(AD_CLK),
+       GPIO_FN(CC5_STATE4), GPIO_FN(CC5_STATE12), GPIO_FN(CC5_STATE20),
+       GPIO_FN(CC5_STATE28), GPIO_FN(CC5_STATE36), GPIO_FN(HSPI_CS0),
+       GPIO_FN(RTS0_TANS), GPIO_FN(USB_OVC1), GPIO_FN(AD_DI),
+       GPIO_FN(CC5_STATE5), GPIO_FN(CC5_STATE13), GPIO_FN(CC5_STATE21),
+       GPIO_FN(CC5_STATE29), GPIO_FN(CC5_STATE37), GPIO_FN(HSPI_TX0),
+       GPIO_FN(TX0), GPIO_FN(CAN_DEBUG_HW_TRIGGER), GPIO_FN(AD_DO),
+       GPIO_FN(CC5_STATE6), GPIO_FN(CC5_STATE14), GPIO_FN(CC5_STATE22),
+       GPIO_FN(CC5_STATE30), GPIO_FN(CC5_STATE38), GPIO_FN(HSPI_RX0),
+       GPIO_FN(RX0), GPIO_FN(CAN_STEP0), GPIO_FN(AD_NCS), GPIO_FN(CC5_STATE7),
+       GPIO_FN(CC5_STATE15), GPIO_FN(CC5_STATE23), GPIO_FN(CC5_STATE31),
+       GPIO_FN(CC5_STATE39), GPIO_FN(FMCLK), GPIO_FN(RDS_CLK), GPIO_FN(PCMOE),
+       GPIO_FN(BPFCLK), GPIO_FN(PCMWE), GPIO_FN(FMIN), GPIO_FN(RDS_DATA),
+       GPIO_FN(VI0_CLK), GPIO_FN(MMC1_CLK), GPIO_FN(VI0_CLKENB),
+       GPIO_FN(TX1_C), GPIO_FN(HTX1_B), GPIO_FN(MT1_SYNC),
+       GPIO_FN(VI0_FIELD), GPIO_FN(RX1_C), GPIO_FN(HRX1_B),
+       GPIO_FN(VI0_HSYNC), GPIO_FN(VI0_DATA0_B_VI0_B0_B), GPIO_FN(CTS1_C),
+       GPIO_FN(TX4_D), GPIO_FN(MMC1_CMD), GPIO_FN(HSCK1_B),
+       GPIO_FN(VI0_VSYNC), GPIO_FN(VI0_DATA1_B_VI0_B1_B),
+       GPIO_FN(RTS1_C_TANS_C), GPIO_FN(RX4_D), GPIO_FN(PWMFSW0_C),
+
+       /* IPSR9 */
+       GPIO_FN(VI0_DATA0_VI0_B0), GPIO_FN(HRTS1_B), GPIO_FN(MT1_VCXO),
+       GPIO_FN(VI0_DATA1_VI0_B1), GPIO_FN(HCTS1_B), GPIO_FN(MT1_PWM),
+       GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(MMC1_D0), GPIO_FN(VI0_DATA3_VI0_B3),
+       GPIO_FN(MMC1_D1), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(MMC1_D2),
+       GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(MMC1_D3), GPIO_FN(VI0_DATA6_VI0_B6),
+       GPIO_FN(MMC1_D4), GPIO_FN(ARM_TRACEDATA_0), GPIO_FN(VI0_DATA7_VI0_B7),
+       GPIO_FN(MMC1_D5), GPIO_FN(ARM_TRACEDATA_1), GPIO_FN(VI0_G0),
+       GPIO_FN(SSI_SCK78_C), GPIO_FN(IRQ0), GPIO_FN(ARM_TRACEDATA_2),
+       GPIO_FN(VI0_G1), GPIO_FN(SSI_WS78_C), GPIO_FN(IRQ1),
+       GPIO_FN(ARM_TRACEDATA_3), GPIO_FN(VI0_G2), GPIO_FN(ETH_TXD1),
+       GPIO_FN(MMC1_D6), GPIO_FN(ARM_TRACEDATA_4), GPIO_FN(TS_SPSYNC0),
+       GPIO_FN(VI0_G3), GPIO_FN(ETH_CRS_DV), GPIO_FN(MMC1_D7),
+       GPIO_FN(ARM_TRACEDATA_5), GPIO_FN(TS_SDAT0), GPIO_FN(VI0_G4),
+       GPIO_FN(ETH_TX_EN), GPIO_FN(SD2_DAT0_B), GPIO_FN(ARM_TRACEDATA_6),
+       GPIO_FN(VI0_G5), GPIO_FN(ETH_RX_ER), GPIO_FN(SD2_DAT1_B),
+       GPIO_FN(ARM_TRACEDATA_7), GPIO_FN(VI0_G6), GPIO_FN(ETH_RXD0),
+       GPIO_FN(SD2_DAT2_B), GPIO_FN(ARM_TRACEDATA_8), GPIO_FN(VI0_G7),
+       GPIO_FN(ETH_RXD1), GPIO_FN(SD2_DAT3_B), GPIO_FN(ARM_TRACEDATA_9),
+
+       /* IPSR10 */
+       GPIO_FN(VI0_R0), GPIO_FN(SSI_SDATA7_C), GPIO_FN(SCK1_C),
+       GPIO_FN(DREQ1_B), GPIO_FN(ARM_TRACEDATA_10), GPIO_FN(DREQ0_C),
+       GPIO_FN(VI0_R1), GPIO_FN(SSI_SDATA8_C), GPIO_FN(DACK1_B),
+       GPIO_FN(ARM_TRACEDATA_11), GPIO_FN(DACK0_C), GPIO_FN(DRACK0_C),
+       GPIO_FN(VI0_R2), GPIO_FN(ETH_LINK), GPIO_FN(SD2_CLK_B), GPIO_FN(IRQ2),
+       GPIO_FN(ARM_TRACEDATA_12), GPIO_FN(VI0_R3), GPIO_FN(ETH_MAGIC),
+       GPIO_FN(SD2_CMD_B), GPIO_FN(IRQ3), GPIO_FN(ARM_TRACEDATA_13),
+       GPIO_FN(VI0_R4), GPIO_FN(ETH_REFCLK), GPIO_FN(SD2_CD_B),
+       GPIO_FN(HSPI_CLK1_B), GPIO_FN(ARM_TRACEDATA_14), GPIO_FN(MT1_CLK),
+       GPIO_FN(TS_SCK0), GPIO_FN(VI0_R5), GPIO_FN(ETH_TXD0),
+       GPIO_FN(SD2_WP_B), GPIO_FN(HSPI_CS1_B), GPIO_FN(ARM_TRACEDATA_15),
+       GPIO_FN(MT1_D), GPIO_FN(TS_SDEN0), GPIO_FN(VI0_R6), GPIO_FN(ETH_MDC),
+       GPIO_FN(DREQ2_C), GPIO_FN(HSPI_TX1_B), GPIO_FN(TRACECLK),
+       GPIO_FN(MT1_BEN), GPIO_FN(PWMFSW0_D), GPIO_FN(VI0_R7),
+       GPIO_FN(ETH_MDIO), GPIO_FN(DACK2_C), GPIO_FN(HSPI_RX1_B),
+       GPIO_FN(SCIF_CLK_D), GPIO_FN(TRACECTL), GPIO_FN(MT1_PEN),
+       GPIO_FN(VI1_CLK), GPIO_FN(SIM_D), GPIO_FN(SDA3), GPIO_FN(VI1_HSYNC),
+       GPIO_FN(VI3_CLK), GPIO_FN(SSI_SCK4), GPIO_FN(GPS_SIGN_C),
+       GPIO_FN(PWMFSW0_E), GPIO_FN(VI1_VSYNC), GPIO_FN(AUDIO_CLKOUT_C),
+       GPIO_FN(SSI_WS4), GPIO_FN(SIM_CLK), GPIO_FN(GPS_MAG_C),
+       GPIO_FN(SPV_TRST), GPIO_FN(SCL3),
+
+       /* IPSR11 */
+       GPIO_FN(VI1_DATA0_VI1_B0), GPIO_FN(SD2_DAT0), GPIO_FN(SIM_RST),
+       GPIO_FN(SPV_TCK), GPIO_FN(ADICLK_B), GPIO_FN(VI1_DATA1_VI1_B1),
+       GPIO_FN(SD2_DAT1), GPIO_FN(MT0_CLK), GPIO_FN(SPV_TMS),
+       GPIO_FN(ADICS_B_SAMP_B), GPIO_FN(VI1_DATA2_VI1_B2), GPIO_FN(SD2_DAT2),
+       GPIO_FN(MT0_D), GPIO_FN(SPVTDI), GPIO_FN(ADIDATA_B),
+       GPIO_FN(VI1_DATA3_VI1_B3), GPIO_FN(SD2_DAT3), GPIO_FN(MT0_BEN),
+       GPIO_FN(SPV_TDO), GPIO_FN(ADICHS0_B), GPIO_FN(VI1_DATA4_VI1_B4),
+       GPIO_FN(SD2_CLK), GPIO_FN(MT0_PEN), GPIO_FN(SPA_TRST),
+       GPIO_FN(HSPI_CLK1_D), GPIO_FN(ADICHS1_B), GPIO_FN(VI1_DATA5_VI1_B5),
+       GPIO_FN(SD2_CMD), GPIO_FN(MT0_SYNC), GPIO_FN(SPA_TCK),
+       GPIO_FN(HSPI_CS1_D), GPIO_FN(ADICHS2_B), GPIO_FN(VI1_DATA6_VI1_B6),
+       GPIO_FN(SD2_CD), GPIO_FN(MT0_VCXO), GPIO_FN(SPA_TMS),
+       GPIO_FN(HSPI_TX1_D), GPIO_FN(VI1_DATA7_VI1_B7), GPIO_FN(SD2_WP),
+       GPIO_FN(MT0_PWM), GPIO_FN(SPA_TDI), GPIO_FN(HSPI_RX1_D),
+       GPIO_FN(VI1_G0), GPIO_FN(VI3_DATA0), GPIO_FN(DU1_DOTCLKOUT1),
+       GPIO_FN(TS_SCK1), GPIO_FN(DREQ2_B), GPIO_FN(TX2), GPIO_FN(SPA_TDO),
+       GPIO_FN(HCTS0_B), GPIO_FN(VI1_G1), GPIO_FN(VI3_DATA1),
+       GPIO_FN(SSI_SCK1), GPIO_FN(TS_SDEN1), GPIO_FN(DACK2_B), GPIO_FN(RX2),
+       GPIO_FN(HRTS0_B),
+
+       /* IPSR12 */
+       GPIO_FN(VI1_G2), GPIO_FN(VI3_DATA2), GPIO_FN(SSI_WS1),
+       GPIO_FN(TS_SPSYNC1), GPIO_FN(SCK2), GPIO_FN(HSCK0_B), GPIO_FN(VI1_G3),
+       GPIO_FN(VI3_DATA3), GPIO_FN(SSI_SCK2), GPIO_FN(TS_SDAT1),
+       GPIO_FN(SCL1_C), GPIO_FN(HTX0_B), GPIO_FN(VI1_G4), GPIO_FN(VI3_DATA4),
+       GPIO_FN(SSI_WS2), GPIO_FN(SDA1_C), GPIO_FN(SIM_RST_B),
+       GPIO_FN(HRX0_B), GPIO_FN(VI1_G5), GPIO_FN(VI3_DATA5),
+       GPIO_FN(GPS_CLK), GPIO_FN(FSE), GPIO_FN(TX4_B), GPIO_FN(SIM_D_B),
+       GPIO_FN(VI1_G6), GPIO_FN(VI3_DATA6), GPIO_FN(GPS_SIGN), GPIO_FN(FRB),
+       GPIO_FN(RX4_B), GPIO_FN(SIM_CLK_B), GPIO_FN(VI1_G7),
+       GPIO_FN(VI3_DATA7), GPIO_FN(GPS_MAG), GPIO_FN(FCE), GPIO_FN(SCK4_B),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+       { PINMUX_CFG_REG("GPSR0", 0xfffc0004, 32, 1) {
+               GP_0_31_FN, FN_IP3_31_29,
+               GP_0_30_FN, FN_IP3_26_24,
+               GP_0_29_FN, FN_IP3_22_21,
+               GP_0_28_FN, FN_IP3_14_12,
+               GP_0_27_FN, FN_IP3_11_9,
+               GP_0_26_FN, FN_IP3_2_0,
+               GP_0_25_FN, FN_IP2_30_28,
+               GP_0_24_FN, FN_IP2_21_19,
+               GP_0_23_FN, FN_IP2_18_16,
+               GP_0_22_FN, FN_IP0_30_28,
+               GP_0_21_FN, FN_IP0_5_3,
+               GP_0_20_FN, FN_IP1_18_15,
+               GP_0_19_FN, FN_IP1_14_11,
+               GP_0_18_FN, FN_IP1_10_7,
+               GP_0_17_FN, FN_IP1_6_4,
+               GP_0_16_FN, FN_IP1_3_2,
+               GP_0_15_FN, FN_IP1_1_0,
+               GP_0_14_FN, FN_IP0_27_26,
+               GP_0_13_FN, FN_IP0_25,
+               GP_0_12_FN, FN_IP0_24_23,
+               GP_0_11_FN, FN_IP0_22_19,
+               GP_0_10_FN, FN_IP0_18_16,
+               GP_0_9_FN, FN_IP0_15_14,
+               GP_0_8_FN, FN_IP0_13_12,
+               GP_0_7_FN, FN_IP0_11_10,
+               GP_0_6_FN, FN_IP0_9_8,
+               GP_0_5_FN, FN_A19,
+               GP_0_4_FN, FN_A18,
+               GP_0_3_FN, FN_A17,
+               GP_0_2_FN, FN_IP0_7_6,
+               GP_0_1_FN, FN_AVS2,
+               GP_0_0_FN, FN_AVS1 }
+       },
+       { PINMUX_CFG_REG("GPSR1", 0xfffc0008, 32, 1) {
+               GP_1_31_FN, FN_IP5_23_21,
+               GP_1_30_FN, FN_IP5_20_17,
+               GP_1_29_FN, FN_IP5_16_15,
+               GP_1_28_FN, FN_IP5_14_13,
+               GP_1_27_FN, FN_IP5_12_11,
+               GP_1_26_FN, FN_IP5_10_9,
+               GP_1_25_FN, FN_IP5_8,
+               GP_1_24_FN, FN_IP5_7,
+               GP_1_23_FN, FN_IP5_6,
+               GP_1_22_FN, FN_IP5_5,
+               GP_1_21_FN, FN_IP5_4,
+               GP_1_20_FN, FN_IP5_3,
+               GP_1_19_FN, FN_IP5_2_0,
+               GP_1_18_FN, FN_IP4_31_29,
+               GP_1_17_FN, FN_IP4_28,
+               GP_1_16_FN, FN_IP4_27,
+               GP_1_15_FN, FN_IP4_26,
+               GP_1_14_FN, FN_IP4_25,
+               GP_1_13_FN, FN_IP4_24,
+               GP_1_12_FN, FN_IP4_23,
+               GP_1_11_FN, FN_IP4_22_20,
+               GP_1_10_FN, FN_IP4_19_17,
+               GP_1_9_FN, FN_IP4_16,
+               GP_1_8_FN, FN_IP4_15,
+               GP_1_7_FN, FN_IP4_14,
+               GP_1_6_FN, FN_IP4_13,
+               GP_1_5_FN, FN_IP4_12,
+               GP_1_4_FN, FN_IP4_11,
+               GP_1_3_FN, FN_IP4_10_8,
+               GP_1_2_FN, FN_IP4_7_5,
+               GP_1_1_FN, FN_IP4_4_2,
+               GP_1_0_FN, FN_IP4_1_0 }
+       },
+       { PINMUX_CFG_REG("GPSR2", 0xfffc000c, 32, 1) {
+               GP_2_31_FN, FN_IP10_28_26,
+               GP_2_30_FN, FN_IP10_25_24,
+               GP_2_29_FN, FN_IP10_23_21,
+               GP_2_28_FN, FN_IP10_20_18,
+               GP_2_27_FN, FN_IP10_17_15,
+               GP_2_26_FN, FN_IP10_14_12,
+               GP_2_25_FN, FN_IP10_11_9,
+               GP_2_24_FN, FN_IP10_8_6,
+               GP_2_23_FN, FN_IP10_5_3,
+               GP_2_22_FN, FN_IP10_2_0,
+               GP_2_21_FN, FN_IP9_29_28,
+               GP_2_20_FN, FN_IP9_27_26,
+               GP_2_19_FN, FN_IP9_25_24,
+               GP_2_18_FN, FN_IP9_23_22,
+               GP_2_17_FN, FN_IP9_21_19,
+               GP_2_16_FN, FN_IP9_18_16,
+               GP_2_15_FN, FN_IP9_15_14,
+               GP_2_14_FN, FN_IP9_13_12,
+               GP_2_13_FN, FN_IP9_11_10,
+               GP_2_12_FN, FN_IP9_9_8,
+               GP_2_11_FN, FN_IP9_7,
+               GP_2_10_FN, FN_IP9_6,
+               GP_2_9_FN, FN_IP9_5,
+               GP_2_8_FN, FN_IP9_4,
+               GP_2_7_FN, FN_IP9_3_2,
+               GP_2_6_FN, FN_IP9_1_0,
+               GP_2_5_FN, FN_IP8_30_28,
+               GP_2_4_FN, FN_IP8_27_25,
+               GP_2_3_FN, FN_IP8_24_23,
+               GP_2_2_FN, FN_IP8_22_21,
+               GP_2_1_FN, FN_IP8_20,
+               GP_2_0_FN, FN_IP5_27_24 }
+       },
+       { PINMUX_CFG_REG("GPSR3", 0xfffc0010, 32, 1) {
+               GP_3_31_FN, FN_IP6_3_2,
+               GP_3_30_FN, FN_IP6_1_0,
+               GP_3_29_FN, FN_IP5_30_29,
+               GP_3_28_FN, FN_IP5_28,
+               GP_3_27_FN, FN_IP1_24_23,
+               GP_3_26_FN, FN_IP1_22_21,
+               GP_3_25_FN, FN_IP1_20_19,
+               GP_3_24_FN, FN_IP7_26_25,
+               GP_3_23_FN, FN_IP7_24_23,
+               GP_3_22_FN, FN_IP7_22_21,
+               GP_3_21_FN, FN_IP7_20_19,
+               GP_3_20_FN, FN_IP7_30_29,
+               GP_3_19_FN, FN_IP7_28_27,
+               GP_3_18_FN, FN_IP7_18_17,
+               GP_3_17_FN, FN_IP7_16_15,
+               GP_3_16_FN, FN_IP12_17_15,
+               GP_3_15_FN, FN_IP12_14_12,
+               GP_3_14_FN, FN_IP12_11_9,
+               GP_3_13_FN, FN_IP12_8_6,
+               GP_3_12_FN, FN_IP12_5_3,
+               GP_3_11_FN, FN_IP12_2_0,
+               GP_3_10_FN, FN_IP11_29_27,
+               GP_3_9_FN, FN_IP11_26_24,
+               GP_3_8_FN, FN_IP11_23_21,
+               GP_3_7_FN, FN_IP11_20_18,
+               GP_3_6_FN, FN_IP11_17_15,
+               GP_3_5_FN, FN_IP11_14_12,
+               GP_3_4_FN, FN_IP11_11_9,
+               GP_3_3_FN, FN_IP11_8_6,
+               GP_3_2_FN, FN_IP11_5_3,
+               GP_3_1_FN, FN_IP11_2_0,
+               GP_3_0_FN, FN_IP10_31_29 }
+       },
+       { PINMUX_CFG_REG("GPSR4", 0xfffc0014, 32, 1) {
+               GP_4_31_FN, FN_IP8_19,
+               GP_4_30_FN, FN_IP8_18,
+               GP_4_29_FN, FN_IP8_17_16,
+               GP_4_28_FN, FN_IP0_2_0,
+               GP_4_27_FN, FN_PENC1,
+               GP_4_26_FN, FN_PENC0,
+               GP_4_25_FN, FN_IP8_15_12,
+               GP_4_24_FN, FN_IP8_11_8,
+               GP_4_23_FN, FN_IP8_7_4,
+               GP_4_22_FN, FN_IP8_3_0,
+               GP_4_21_FN, FN_IP2_3_0,
+               GP_4_20_FN, FN_IP1_28_25,
+               GP_4_19_FN, FN_IP2_15_12,
+               GP_4_18_FN, FN_IP2_11_8,
+               GP_4_17_FN, FN_IP2_7_4,
+               GP_4_16_FN, FN_IP7_14_13,
+               GP_4_15_FN, FN_IP7_12_10,
+               GP_4_14_FN, FN_IP7_9_7,
+               GP_4_13_FN, FN_IP7_6_4,
+               GP_4_12_FN, FN_IP7_3_2,
+               GP_4_11_FN, FN_IP7_1_0,
+               GP_4_10_FN, FN_IP6_30_29,
+               GP_4_9_FN, FN_IP6_26_25,
+               GP_4_8_FN, FN_IP6_24_23,
+               GP_4_7_FN, FN_IP6_22_20,
+               GP_4_6_FN, FN_IP6_19_18,
+               GP_4_5_FN, FN_IP6_17_15,
+               GP_4_4_FN, FN_IP6_14_12,
+               GP_4_3_FN, FN_IP6_11_9,
+               GP_4_2_FN, FN_IP6_8,
+               GP_4_1_FN, FN_IP6_7_6,
+               GP_4_0_FN, FN_IP6_5_4 }
+       },
+       { PINMUX_CFG_REG("GPSR5", 0xfffc0018, 32, 1) {
+               GP_5_31_FN, FN_IP3_5,
+               GP_5_30_FN, FN_IP3_4,
+               GP_5_29_FN, FN_IP3_3,
+               GP_5_28_FN, FN_IP2_27,
+               GP_5_27_FN, FN_IP2_26,
+               GP_5_26_FN, FN_IP2_25,
+               GP_5_25_FN, FN_IP2_24,
+               GP_5_24_FN, FN_IP2_23,
+               GP_5_23_FN, FN_IP2_22,
+               GP_5_22_FN, FN_IP3_28,
+               GP_5_21_FN, FN_IP3_27,
+               GP_5_20_FN, FN_IP3_23,
+               GP_5_19_FN, FN_EX_WAIT0,
+               GP_5_18_FN, FN_WE1,
+               GP_5_17_FN, FN_WE0,
+               GP_5_16_FN, FN_RD,
+               GP_5_15_FN, FN_A16,
+               GP_5_14_FN, FN_A15,
+               GP_5_13_FN, FN_A14,
+               GP_5_12_FN, FN_A13,
+               GP_5_11_FN, FN_A12,
+               GP_5_10_FN, FN_A11,
+               GP_5_9_FN, FN_A10,
+               GP_5_8_FN, FN_A9,
+               GP_5_7_FN, FN_A8,
+               GP_5_6_FN, FN_A7,
+               GP_5_5_FN, FN_A6,
+               GP_5_4_FN, FN_A5,
+               GP_5_3_FN, FN_A4,
+               GP_5_2_FN, FN_A3,
+               GP_5_1_FN, FN_A2,
+               GP_5_0_FN, FN_A1 }
+       },
+       { PINMUX_CFG_REG("GPSR6", 0xfffc001c, 32, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               GP_6_8_FN, FN_IP3_20,
+               GP_6_7_FN, FN_IP3_19,
+               GP_6_6_FN, FN_IP3_18,
+               GP_6_5_FN, FN_IP3_17,
+               GP_6_4_FN, FN_IP3_16,
+               GP_6_3_FN, FN_IP3_15,
+               GP_6_2_FN, FN_IP3_8,
+               GP_6_1_FN, FN_IP3_7,
+               GP_6_0_FN, FN_IP3_6 }
+       },
+
+       { PINMUX_CFG_REG_VAR("IPSR0", 0xfffc0020, 32,
+                            1, 3, 2, 1, 2, 4, 3, 2, 2, 2, 2, 2, 3, 3) {
+               /* IP0_31 [1] */
+               0, 0,
+               /* IP0_30_28 [3] */
+               FN_RD_WR, FN_FWE, FN_ATAG0, FN_VI1_R7,
+               FN_HRTS1, FN_RX4_C, 0, 0,
+               /* IP0_27_26 [2] */
+               FN_CS1_A26, FN_HSPI_TX2, FN_SDSELF_B, 0,
+               /* IP0_25 [1] */
+               FN_CS0, FN_HSPI_CS2_B,
+               /* IP0_24_23 [2] */
+               FN_CLKOUT, FN_TX3C_IRDA_TX_C, FN_PWM0_B, 0,
+               /* IP0_22_19 [4] */
+               FN_A25, FN_SD1_WP, FN_MMC0_D5, FN_FD5,
+               FN_HSPI_RX2, FN_VI1_R3, FN_TX5_B, FN_SSI_SDATA7_B,
+               FN_CTS0_B, 0, 0, 0,
+               0, 0, 0, 0,
+               /* IP0_18_16 [3] */
+               FN_A24, FN_SD1_CD, FN_MMC0_D4, FN_FD4,
+               FN_HSPI_CS2, FN_VI1_R2, FN_SSI_WS78_B, 0,
+               /* IP0_15_14 [2] */
+               FN_A23, FN_FCLE, FN_HSPI_CLK2, FN_VI1_R1,
+               /* IP0_13_12 [2] */
+               FN_A22, FN_RX5_D, FN_HSPI_RX2_B, FN_VI1_R0,
+               /* IP0_11_10 [2] */
+               FN_A21, FN_SCK5_D, FN_HSPI_CLK2_B, 0,
+               /* IP0_9_8 [2] */
+               FN_A20, FN_TX5_D, FN_HSPI_TX2_B, 0,
+               /* IP0_7_6 [2] */
+               FN_A0, FN_SD1_DAT3, FN_MMC0_D3, FN_FD3,
+               /* IP0_5_3 [3] */
+               FN_BS, FN_SD1_DAT2, FN_MMC0_D2, FN_FD2,
+               FN_ATADIR0, FN_SDSELF, FN_HCTS1, FN_TX4_C,
+               /* IP0_2_0 [3] */
+               FN_PENC2, FN_SCK0, FN_PWM1, FN_PWMFSW0,
+               FN_SCIF_CLK, FN_TCLK0_C, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR1", 0xfffc0024, 32,
+                            3, 4, 2, 2, 2, 4, 4, 4, 3, 2, 2) {
+               /* IP1_31_29 [3] */
+               0, 0, 0, 0, 0, 0, 0, 0,
+               /* IP1_28_25 [4] */
+               FN_HTX0, FN_TX1, FN_SDATA, FN_CTS0_C,
+               FN_SUB_TCK, FN_CC5_STATE2, FN_CC5_STATE10, FN_CC5_STATE18,
+               FN_CC5_STATE26, FN_CC5_STATE34, 0, 0,
+               0, 0, 0, 0,
+               /* IP1_24_23 [2] */
+               FN_MLB_DAT, FN_PWM4, FN_RX4, 0,
+               /* IP1_22_21 [2] */
+               FN_MLB_SIG, FN_PWM3, FN_TX4, 0,
+               /* IP1_20_19 [2] */
+               FN_MLB_CLK, FN_PWM2, FN_SCK4, 0,
+               /* IP1_18_15 [4] */
+               FN_EX_CS5, FN_SD1_DAT1, FN_MMC0_D1, FN_FD1,
+               FN_ATAWR0, FN_VI1_R6, FN_HRX1, FN_RX2_E,
+               FN_RX0_B, FN_SSI_WS9, 0, 0,
+               0, 0, 0, 0,
+               /* IP1_14_11 [4] */
+               FN_EX_CS4, FN_SD1_DAT0, FN_MMC0_D0, FN_FD0,
+               FN_ATARD0, FN_VI1_R5, FN_SCK5_B, FN_HTX1,
+               FN_TX2_E, FN_TX0_B, FN_SSI_SCK9, 0,
+               0, 0, 0, 0,
+               /* IP1_10_7 [4] */
+               FN_EX_CS3, FN_SD1_CMD, FN_MMC0_CMD, FN_FRE,
+               FN_ATACS10, FN_VI1_R4, FN_RX5_B, FN_HSCK1,
+               FN_SSI_SDATA8_B, FN_RTS0_B_TANS_B, FN_SSI_SDATA9, 0,
+               0, 0, 0, 0,
+               /* IP1_6_4 [3] */
+               FN_EX_CS2, FN_SD1_CLK, FN_MMC0_CLK, FN_FALE,
+               FN_ATACS00, 0, 0, 0,
+               /* IP1_3_2 [2] */
+               FN_EX_CS1, FN_MMC0_D7, FN_FD7, 0,
+               /* IP1_1_0 [2] */
+               FN_EX_CS0, FN_RX3_C_IRDA_RX_C, FN_MMC0_D6, FN_FD6 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR2", 0xfffc0028, 32,
+                            1, 3, 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 4) {
+               /* IP2_31 [1] */
+               0, 0,
+               /* IP2_30_28 [3] */
+               FN_DU0_DG0, FN_LCDOUT8, FN_DREQ1, FN_SCL2,
+               FN_AUDATA2, 0, 0, 0,
+               /* IP2_27 [1] */
+               FN_DU0_DR7, FN_LCDOUT7,
+               /* IP2_26 [1] */
+               FN_DU0_DR6, FN_LCDOUT6,
+               /* IP2_25 [1] */
+               FN_DU0_DR5, FN_LCDOUT5,
+               /* IP2_24 [1] */
+               FN_DU0_DR4, FN_LCDOUT4,
+               /* IP2_23 [1] */
+               FN_DU0_DR3, FN_LCDOUT3,
+               /* IP2_22 [1] */
+               FN_DU0_DR2, FN_LCDOUT2,
+               /* IP2_21_19 [3] */
+               FN_DU0_DR1, FN_LCDOUT1, FN_DACK0, FN_DRACK0,
+               FN_GPS_SIGN_B, FN_AUDATA1, FN_RX5_C, 0,
+               /* IP2_18_16 [3] */
+               FN_DU0_DR0, FN_LCDOUT0, FN_DREQ0, FN_GPS_CLK_B,
+               FN_AUDATA0, FN_TX5_C, 0, 0,
+               /* IP2_15_12 [4] */
+               FN_HRTS0, FN_RTS1_TANS, FN_MDATA, FN_TX0_C,
+               FN_SUB_TMS, FN_CC5_STATE1, FN_CC5_STATE9, FN_CC5_STATE17,
+               FN_CC5_STATE25, FN_CC5_STATE33, 0, 0,
+               0, 0, 0, 0,
+               /* IP2_11_8 [4] */
+               FN_HCTS0, FN_CTS1, FN_STM, FN_PWM0_D,
+               FN_RX0_C, FN_SCIF_CLK_C, FN_SUB_TRST, FN_TCLK1_B,
+               FN_CC5_OSCOUT, 0, 0, 0,
+               0, 0, 0, 0,
+               /* IP2_7_4 [4] */
+               FN_HSCK0, FN_SCK1, FN_MTS, FN_PWM5,
+               FN_SCK0_C, FN_SSI_SDATA9_B, FN_SUB_TDO, FN_CC5_STATE0,
+               FN_CC5_STATE8, FN_CC5_STATE16, FN_CC5_STATE24, FN_CC5_STATE32,
+               0, 0, 0, 0,
+               /* IP2_3_0 [4] */
+               FN_HRX0, FN_RX1, FN_SCKZ, FN_RTS0_C_TANS_C,
+               FN_SUB_TDI, FN_CC5_STATE3, FN_CC5_STATE11, FN_CC5_STATE19,
+               FN_CC5_STATE27, FN_CC5_STATE35, 0, 0,
+               0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR3", 0xfffc002c, 32,
+                            3, 1, 1, 3, 1, 2, 1, 1, 1, 1, 1,
+                            1, 3, 3, 1, 1, 1, 1, 1, 1, 3) {
+           /* IP3_31_29 [3] */
+           FN_DU0_EXODDF_DU0_ODDF_DISP_CDE, FN_QCPV_QDE, FN_CAN1_TX, FN_TX2_C,
+           FN_SCL2_C, FN_REMOCON, 0, 0,
+           /* IP3_28 [1] */
+           FN_DU0_EXVSYNC_DU0_VSYNC, FN_QSTB_QHE,
+           /* IP3_27 [1] */
+           FN_DU0_EXHSYNC_DU0_HSYNC, FN_QSTH_QHS,
+           /* IP3_26_24 [3] */
+           FN_DU0_DOTCLKOUT1, FN_QSTVB_QVE, FN_RX3_D_IRDA_RX_D, FN_SDA3_B,
+           FN_SDA2_C, FN_DACK0_B, FN_DRACK0_B, 0,
+           /* IP3_23 [1] */
+           FN_DU0_DOTCLKOUT0, FN_QCLK,
+           /* IP3_22_21 [2] */
+           FN_DU0_DOTCLKIN, FN_QSTVA_QVS, FN_TX3_D_IRDA_TX_D, FN_SCL3_B,
+           /* IP3_20 [1] */
+           FN_DU0_DB7, FN_LCDOUT23,
+           /* IP3_19 [1] */
+           FN_DU0_DB6, FN_LCDOUT22,
+           /* IP3_18 [1] */
+           FN_DU0_DB5, FN_LCDOUT21,
+           /* IP3_17 [1] */
+           FN_DU0_DB4, FN_LCDOUT20,
+           /* IP3_16 [1] */
+           FN_DU0_DB3, FN_LCDOUT19,
+           /* IP3_15 [1] */
+           FN_DU0_DB2, FN_LCDOUT18,
+           /* IP3_14_12 [3] */
+           FN_DU0_DB1, FN_LCDOUT17, FN_EX_WAIT2, FN_SDA1,
+           FN_GPS_MAG_B, FN_AUDATA5, FN_SCK5_C, 0,
+           /* IP3_11_9 [3] */
+           FN_DU0_DB0, FN_LCDOUT16, FN_EX_WAIT1, FN_SCL1,
+           FN_TCLK1, FN_AUDATA4, 0, 0,
+           /* IP3_8 [1] */
+           FN_DU0_DG7, FN_LCDOUT15,
+           /* IP3_7 [1] */
+           FN_DU0_DG6, FN_LCDOUT14,
+           /* IP3_6 [1] */
+           FN_DU0_DG5, FN_LCDOUT13,
+           /* IP3_5 [1] */
+           FN_DU0_DG4, FN_LCDOUT12,
+           /* IP3_4 [1] */
+           FN_DU0_DG3, FN_LCDOUT11,
+           /* IP3_3 [1] */
+           FN_DU0_DG2, FN_LCDOUT10,
+           /* IP3_2_0 [3] */
+           FN_DU0_DG1, FN_LCDOUT9, FN_DACK1, FN_SDA2,
+           FN_AUDATA3, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR4", 0xfffc0030, 32,
+                            3, 1, 1, 1, 1, 1, 1, 3, 3, 1,
+                            1, 1, 1, 1, 1, 1, 3, 3, 3, 2) {
+           /* IP4_31_29 [3] */
+           FN_DU1_DB0, FN_VI2_DATA4_VI2_B4, FN_SCL2_B, FN_SD3_DAT0,
+           FN_TX5, FN_SCK0_D, 0, 0,
+           /* IP4_28 [1] */
+           FN_DU1_DG7, FN_VI2_R3,
+           /* IP4_27 [1] */
+           FN_DU1_DG6, FN_VI2_R2,
+           /* IP4_26 [1] */
+           FN_DU1_DG5, FN_VI2_R1,
+           /* IP4_25 [1] */
+           FN_DU1_DG4, FN_VI2_R0,
+           /* IP4_24 [1] */
+           FN_DU1_DG3, FN_VI2_G7,
+           /* IP4_23 [1] */
+           FN_DU1_DG2, FN_VI2_G6,
+           /* IP4_22_20 [3] */
+           FN_DU1_DG1, FN_VI2_DATA3_VI2_B3, FN_SDA1_B, FN_SD3_DAT3,
+           FN_SCK5, FN_AUDATA7, FN_RX0_D, 0,
+           /* IP4_19_17 [3] */
+           FN_DU1_DG0, FN_VI2_DATA2_VI2_B2, FN_SCL1_B, FN_SD3_DAT2,
+           FN_SCK3_E, FN_AUDATA6, FN_TX0_D, 0,
+           /* IP4_16 [1] */
+           FN_DU1_DR7, FN_VI2_G5,
+           /* IP4_15 [1] */
+           FN_DU1_DR6, FN_VI2_G4,
+           /* IP4_14 [1] */
+           FN_DU1_DR5, FN_VI2_G3,
+           /* IP4_13 [1] */
+           FN_DU1_DR4, FN_VI2_G2,
+           /* IP4_12 [1] */
+           FN_DU1_DR3, FN_VI2_G1,
+           /* IP4_11 [1] */
+           FN_DU1_DR2, FN_VI2_G0,
+           /* IP4_10_8 [3] */
+           FN_DU1_DR1, FN_VI2_DATA1_VI2_B1, FN_PWM0, FN_SD3_CMD,
+           FN_RX3_E_IRDA_RX_E, FN_AUDSYNC, FN_CTS0_D, 0,
+           /* IP4_7_5 [3] */
+           FN_DU1_DR0, FN_VI2_DATA0_VI2_B0, FN_PWM6, FN_SD3_CLK,
+           FN_TX3_E_IRDA_TX_E, FN_AUDCK, FN_PWMFSW0_B, 0,
+           /* IP4_4_2 [3] */
+           FN_DU0_CDE, FN_QPOLB, FN_CAN1_RX, FN_RX2_C,
+           FN_DREQ0_B, FN_SSI_SCK78_B, FN_SCK0_B, 0,
+           /* IP4_1_0 [2] */
+           FN_DU0_DISP, FN_QPOLA, FN_CAN_CLK_C, FN_SCK2_C }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR5", 0xfffc0034, 32,
+                            1, 2, 1, 4, 3, 4, 2, 2,
+                            2, 2, 1, 1, 1, 1, 1, 1, 3) {
+           /* IP5_31 [1] */
+           0, 0,
+           /* IP5_30_29 [2] */
+           FN_AUDIO_CLKB, FN_USB_OVC2, FN_CAN_DEBUGOUT0, FN_MOUT0,
+           /* IP5_28 [1] */
+           FN_AUDIO_CLKA, FN_CAN_TXCLK,
+           /* IP5_27_24 [4] */
+           FN_DU1_CDE, FN_VI2_DATA7_VI2_B7, FN_RX3_B_IRDA_RX_B, FN_SD3_WP,
+           FN_HSPI_RX1, FN_VI1_FIELD, FN_VI3_FIELD, FN_AUDIO_CLKOUT,
+           FN_RX2_D, FN_GPS_CLK_C, FN_GPS_CLK_D, 0,
+           0, 0, 0, 0,
+           /* IP5_23_21 [3] */
+           FN_DU1_DISP, FN_VI2_DATA6_VI2_B6, FN_TCLK0, FN_QSTVA_B_QVS_B,
+           FN_HSPI_CLK1, FN_SCK2_D, FN_AUDIO_CLKOUT_B, FN_GPS_MAG_D,
+           /* IP5_20_17 [4] */
+           FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_VI2_CLK, FN_TX3_B_IRDA_TX_B,
+           FN_SD3_CD, FN_HSPI_TX1, FN_VI1_CLKENB, FN_VI3_CLKENB,
+           FN_AUDIO_CLKC, FN_TX2_D, FN_SPEEDIN, FN_GPS_SIGN_D, 0,
+           0, 0, 0, 0,
+           /* IP5_16_15 [2] */
+           FN_DU1_EXVSYNC_DU1_VSYNC, FN_VI2_VSYNC, FN_VI3_VSYNC, 0,
+           /* IP5_14_13 [2] */
+           FN_DU1_EXHSYNC_DU1_HSYNC, FN_VI2_HSYNC, FN_VI3_HSYNC, 0,
+           /* IP5_12_11 [2] */
+           FN_DU1_DOTCLKOUT, FN_VI2_FIELD, FN_SDA1_D, 0,
+           /* IP5_10_9 [2] */
+           FN_DU1_DOTCLKIN, FN_VI2_CLKENB, FN_HSPI_CS1, FN_SCL1_D,
+           /* IP5_8 [1] */
+           FN_DU1_DB7, FN_SDA2_D,
+           /* IP5_7 [1] */
+           FN_DU1_DB6, FN_SCL2_D,
+           /* IP5_6 [1] */
+           FN_DU1_DB5, FN_VI2_R7,
+           /* IP5_5 [1] */
+           FN_DU1_DB4, FN_VI2_R6,
+           /* IP5_4 [1] */
+           FN_DU1_DB3, FN_VI2_R5,
+           /* IP5_3 [1] */
+           FN_DU1_DB2, FN_VI2_R4,
+           /* IP5_2_0 [3] */
+           FN_DU1_DB1, FN_VI2_DATA5_VI2_B5, FN_SDA2_B, FN_SD3_DAT1,
+           FN_RX5, FN_RTS0_D_TANS_D, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR6", 0xfffc0038, 32,
+                            1, 2, 2, 2, 2, 3, 2, 3, 3, 3, 1, 2, 2, 2, 2) {
+           /* IP6_31 [1] */
+           0, 0,
+           /* IP6_30_29 [2] */
+           FN_SSI_SCK6, FN_ADICHS0, FN_CAN0_TX, FN_IERX_B,
+           /* IP_28_27 [2] */
+           0, 0, 0, 0,
+           /* IP6_26_25 [2] */
+           FN_SSI_SDATA5, FN_ADIDATA, FN_CAN_DEBUGOUT12, FN_RX3_IRDA_RX,
+           /* IP6_24_23 [2] */
+           FN_SSI_WS5, FN_ADICS_SAMP, FN_CAN_DEBUGOUT11, FN_TX3_IRDA_TX,
+           /* IP6_22_20 [3] */
+           FN_SSI_SCK5, FN_ADICLK, FN_CAN_DEBUGOUT10, FN_SCK3,
+           FN_TCLK0_D, 0, 0, 0,
+           /* IP6_19_18 [2] */
+           FN_SSI_SDATA4, FN_CAN_DEBUGOUT9, FN_SSI_SDATA9_C, 0,
+           /* IP6_17_15 [3] */
+           FN_SSI_SDATA3, FN_PWM0_C, FN_CAN_DEBUGOUT8, FN_CAN_CLK_B,
+           FN_IECLK, FN_SCIF_CLK_B, FN_TCLK0_B, 0,
+           /* IP6_14_12 [3] */
+           FN_SSI_WS34, FN_CAN_DEBUGOUT7, FN_CAN0_RX_B, FN_IETX,
+           FN_SSI_WS9_C, 0, 0, 0,
+           /* IP6_11_9 [3] */
+           FN_SSI_SCK34, FN_CAN_DEBUGOUT6, FN_CAN0_TX_B, FN_IERX,
+           FN_SSI_SCK9_C, 0, 0, 0,
+           /* IP6_8 [1] */
+           FN_SSI_SDATA2, FN_CAN_DEBUGOUT5,
+           /* IP6_7_6 [2] */
+           FN_SSI_SDATA1, FN_CAN_DEBUGOUT4, FN_MOUT6, 0,
+           /* IP6_5_4 [2] */
+           FN_SSI_SDATA0, FN_CAN_DEBUGOUT3, FN_MOUT5, 0,
+           /* IP6_3_2 [2] */
+           FN_SSI_WS0129, FN_CAN_DEBUGOUT2, FN_MOUT2, 0,
+           /* IP6_1_0 [2] */
+           FN_SSI_SCK0129, FN_CAN_DEBUGOUT1, FN_MOUT1, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR7", 0xfffc003c, 32,
+                            1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2) {
+           /* IP7_31 [1] */
+           0, 0,
+           /* IP7_30_29 [2] */
+           FN_SD0_WP, FN_DACK2, FN_CTS1_B, 0,
+           /* IP7_28_27 [2] */
+           FN_SD0_CD, FN_DREQ2, FN_RTS1_B_TANS_B, 0,
+           /* IP7_26_25 [2] */
+           FN_SD0_DAT3, FN_ATAWR1, FN_RX2_B, FN_CC5_TDI,
+           /* IP7_24_23 [2] */
+           FN_SD0_DAT2, FN_ATARD1, FN_TX2_B, FN_CC5_TCK,
+           /* IP7_22_21 [2] */
+           FN_SD0_DAT1, FN_ATAG1, FN_SCK2_B, FN_CC5_TMS,
+           /* IP7_20_19 [2] */
+           FN_SD0_DAT0, FN_ATADIR1, FN_RX1_B, FN_CC5_TRST,
+           /* IP7_18_17 [2] */
+           FN_SD0_CMD, FN_ATACS11, FN_TX1_B, FN_CC5_TDO,
+           /* IP7_16_15 [2] */
+           FN_SD0_CLK, FN_ATACS01, FN_SCK1_B, 0,
+           /* IP7_14_13 [2] */
+           FN_SSI_SDATA8, FN_VSP, FN_IRQ3_B, FN_HSPI_RX1_C,
+           /* IP7_12_10 [3] */
+           FN_SSI_SDATA7, FN_CAN_DEBUGOUT15, FN_IRQ2_B, FN_TCLK1_C,
+           FN_HSPI_TX1_C, 0, 0, 0,
+           /* IP7_9_7 [3] */
+           FN_SSI_WS78, FN_CAN_DEBUGOUT14, FN_IRQ1_B, FN_SSI_WS9_B,
+           FN_HSPI_CS1_C, 0, 0, 0,
+           /* IP7_6_4 [3] */
+           FN_SSI_SCK78, FN_CAN_DEBUGOUT13, FN_IRQ0_B, FN_SSI_SCK9_B,
+           FN_HSPI_CLK1_C, 0, 0, 0,
+           /* IP7_3_2 [2] */
+           FN_SSI_SDATA6, FN_ADICHS2, FN_CAN_CLK, FN_IECLK_B,
+           /* IP7_1_0 [2] */
+           FN_SSI_WS6, FN_ADICHS1, FN_CAN0_RX, FN_IETX_B }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR8", 0xfffc0040, 32,
+                            1, 3, 3, 2, 2, 1, 1, 1, 2, 4, 4, 4, 4) {
+           /* IP8_31 [1] */
+           0, 0,
+           /* IP8_30_28 [3] */
+           FN_VI0_VSYNC, FN_VI0_DATA1_B_VI0_B1_B, FN_RTS1_C_TANS_C, FN_RX4_D,
+           FN_PWMFSW0_C, 0, 0, 0,
+           /* IP8_27_25 [3] */
+           FN_VI0_HSYNC, FN_VI0_DATA0_B_VI0_B0_B, FN_CTS1_C, FN_TX4_D,
+           FN_MMC1_CMD, FN_HSCK1_B, 0, 0,
+           /* IP8_24_23 [2] */
+           FN_VI0_FIELD, FN_RX1_C, FN_HRX1_B, 0,
+           /* IP8_22_21 [2] */
+           FN_VI0_CLKENB, FN_TX1_C, FN_HTX1_B, FN_MT1_SYNC,
+           /* IP8_20 [1] */
+           FN_VI0_CLK, FN_MMC1_CLK,
+           /* IP8_19 [1] */
+           FN_FMIN, FN_RDS_DATA,
+           /* IP8_18 [1] */
+           FN_BPFCLK, FN_PCMWE,
+           /* IP8_17_16 [2] */
+           FN_FMCLK, FN_RDS_CLK, FN_PCMOE, 0,
+           /* IP8_15_12 [4] */
+           FN_HSPI_RX0, FN_RX0, FN_CAN_STEP0, FN_AD_NCS,
+           FN_CC5_STATE7, FN_CC5_STATE15, FN_CC5_STATE23, FN_CC5_STATE31,
+           FN_CC5_STATE39, 0, 0, 0,
+           0, 0, 0, 0,
+           /* IP8_11_8 [4] */
+           FN_HSPI_TX0, FN_TX0, FN_CAN_DEBUG_HW_TRIGGER, FN_AD_DO,
+           FN_CC5_STATE6, FN_CC5_STATE14, FN_CC5_STATE22, FN_CC5_STATE30,
+           FN_CC5_STATE38, 0, 0, 0,
+           0, 0, 0, 0,
+           /* IP8_7_4 [4] */
+           FN_HSPI_CS0, FN_RTS0_TANS, FN_USB_OVC1, FN_AD_DI,
+           FN_CC5_STATE5, FN_CC5_STATE13, FN_CC5_STATE21, FN_CC5_STATE29,
+           FN_CC5_STATE37, 0, 0, 0,
+           0, 0, 0, 0,
+           /* IP8_3_0 [4] */
+           FN_HSPI_CLK0, FN_CTS0, FN_USB_OVC0, FN_AD_CLK,
+           FN_CC5_STATE4, FN_CC5_STATE12, FN_CC5_STATE20, FN_CC5_STATE28,
+           FN_CC5_STATE36, 0, 0, 0,
+           0, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR9", 0xfffc0044, 32,
+                            2, 2, 2, 2, 2, 3, 3, 2, 2,
+                            2, 2, 1, 1, 1, 1, 2, 2) {
+           /* IP9_31_30 [2] */
+           0, 0, 0, 0,
+           /* IP9_29_28 [2] */
+           FN_VI0_G7, FN_ETH_RXD1, FN_SD2_DAT3_B, FN_ARM_TRACEDATA_9,
+           /* IP9_27_26 [2] */
+           FN_VI0_G6, FN_ETH_RXD0, FN_SD2_DAT2_B, FN_ARM_TRACEDATA_8,
+           /* IP9_25_24 [2] */
+           FN_VI0_G5, FN_ETH_RX_ER, FN_SD2_DAT1_B, FN_ARM_TRACEDATA_7,
+           /* IP9_23_22 [2] */
+           FN_VI0_G4, FN_ETH_TX_EN, FN_SD2_DAT0_B, FN_ARM_TRACEDATA_6,
+           /* IP9_21_19 [3] */
+           FN_VI0_G3, FN_ETH_CRS_DV, FN_MMC1_D7, FN_ARM_TRACEDATA_5,
+           FN_TS_SDAT0, 0, 0, 0,
+           /* IP9_18_16 [3] */
+           FN_VI0_G2, FN_ETH_TXD1, FN_MMC1_D6, FN_ARM_TRACEDATA_4,
+           FN_TS_SPSYNC0, 0, 0, 0,
+           /* IP9_15_14 [2] */
+           FN_VI0_G1, FN_SSI_WS78_C, FN_IRQ1, FN_ARM_TRACEDATA_3,
+           /* IP9_13_12 [2] */
+           FN_VI0_G0, FN_SSI_SCK78_C, FN_IRQ0, FN_ARM_TRACEDATA_2,
+           /* IP9_11_10 [2] */
+           FN_VI0_DATA7_VI0_B7, FN_MMC1_D5, FN_ARM_TRACEDATA_1, 0,
+           /* IP9_9_8 [2] */
+           FN_VI0_DATA6_VI0_B6, FN_MMC1_D4, FN_ARM_TRACEDATA_0, 0,
+           /* IP9_7 [1] */
+           FN_VI0_DATA5_VI0_B5, FN_MMC1_D3,
+           /* IP9_6 [1] */
+           FN_VI0_DATA4_VI0_B4, FN_MMC1_D2,
+           /* IP9_5 [1] */
+           FN_VI0_DATA3_VI0_B3, FN_MMC1_D1,
+           /* IP9_4 [1] */
+           FN_VI0_DATA2_VI0_B2, FN_MMC1_D0,
+           /* IP9_3_2 [2] */
+           FN_VI0_DATA1_VI0_B1, FN_HCTS1_B, FN_MT1_PWM, 0,
+           /* IP9_1_0 [2] */
+           FN_VI0_DATA0_VI0_B0, FN_HRTS1_B, FN_MT1_VCXO, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR10", 0xfffc0048, 32,
+                            3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3) {
+           /* IP10_31_29 [3] */
+           FN_VI1_VSYNC, FN_AUDIO_CLKOUT_C, FN_SSI_WS4, FN_SIM_CLK,
+           FN_GPS_MAG_C, FN_SPV_TRST, FN_SCL3, 0,
+           /* IP10_28_26 [3] */
+           FN_VI1_HSYNC, FN_VI3_CLK, FN_SSI_SCK4, FN_GPS_SIGN_C,
+           FN_PWMFSW0_E, 0, 0, 0,
+           /* IP10_25_24 [2] */
+           FN_VI1_CLK, FN_SIM_D, FN_SDA3, 0,
+           /* IP10_23_21 [3] */
+           FN_VI0_R7, FN_ETH_MDIO, FN_DACK2_C, FN_HSPI_RX1_B,
+           FN_SCIF_CLK_D, FN_TRACECTL, FN_MT1_PEN, 0,
+           /* IP10_20_18 [3] */
+           FN_VI0_R6, FN_ETH_MDC, FN_DREQ2_C, FN_HSPI_TX1_B,
+           FN_TRACECLK, FN_MT1_BEN, FN_PWMFSW0_D, 0,
+           /* IP10_17_15 [3] */
+           FN_VI0_R5, FN_ETH_TXD0, FN_SD2_WP_B, FN_HSPI_CS1_B,
+           FN_ARM_TRACEDATA_15, FN_MT1_D, FN_TS_SDEN0, 0,
+           /* IP10_14_12 [3] */
+           FN_VI0_R4, FN_ETH_REFCLK, FN_SD2_CD_B, FN_HSPI_CLK1_B,
+           FN_ARM_TRACEDATA_14, FN_MT1_CLK, FN_TS_SCK0, 0,
+           /* IP10_11_9 [3] */
+           FN_VI0_R3, FN_ETH_MAGIC, FN_SD2_CMD_B, FN_IRQ3,
+           FN_ARM_TRACEDATA_13, 0, 0, 0,
+           /* IP10_8_6 [3] */
+           FN_VI0_R2, FN_ETH_LINK, FN_SD2_CLK_B, FN_IRQ2,
+           FN_ARM_TRACEDATA_12, 0, 0, 0,
+           /* IP10_5_3 [3] */
+           FN_VI0_R1, FN_SSI_SDATA8_C, FN_DACK1_B, FN_ARM_TRACEDATA_11,
+           FN_DACK0_C, FN_DRACK0_C, 0, 0,
+           /* IP10_2_0 [3] */
+           FN_VI0_R0, FN_SSI_SDATA7_C, FN_SCK1_C, FN_DREQ1_B,
+           FN_ARM_TRACEDATA_10, FN_DREQ0_C, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR11", 0xfffc004c, 32,
+                            2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+           /* IP11_31_30 [2] */
+           0, 0, 0, 0,
+           /* IP11_29_27 [3] */
+           FN_VI1_G1, FN_VI3_DATA1, FN_SSI_SCK1, FN_TS_SDEN1,
+           FN_DACK2_B, FN_RX2, FN_HRTS0_B, 0,
+           /* IP11_26_24 [3] */
+           FN_VI1_G0, FN_VI3_DATA0, FN_DU1_DOTCLKOUT1, FN_TS_SCK1,
+           FN_DREQ2_B, FN_TX2, FN_SPA_TDO, FN_HCTS0_B,
+           /* IP11_23_21 [3] */
+           FN_VI1_DATA7_VI1_B7, FN_SD2_WP, FN_MT0_PWM, FN_SPA_TDI,
+           FN_HSPI_RX1_D, 0, 0, 0,
+           /* IP11_20_18 [3] */
+           FN_VI1_DATA6_VI1_B6, FN_SD2_CD, FN_MT0_VCXO, FN_SPA_TMS,
+           FN_HSPI_TX1_D, 0, 0, 0,
+           /* IP11_17_15 [3] */
+           FN_VI1_DATA5_VI1_B5, FN_SD2_CMD, FN_MT0_SYNC, FN_SPA_TCK,
+           FN_HSPI_CS1_D, FN_ADICHS2_B, 0, 0,
+           /* IP11_14_12 [3] */
+           FN_VI1_DATA4_VI1_B4, FN_SD2_CLK, FN_MT0_PEN, FN_SPA_TRST,
+           FN_HSPI_CLK1_D, FN_ADICHS1_B, 0, 0,
+           /* IP11_11_9 [3] */
+           FN_VI1_DATA3_VI1_B3, FN_SD2_DAT3, FN_MT0_BEN, FN_SPV_TDO,
+           FN_ADICHS0_B, 0, 0, 0,
+           /* IP11_8_6 [3] */
+           FN_VI1_DATA2_VI1_B2, FN_SD2_DAT2, FN_MT0_D, FN_SPVTDI,
+           FN_ADIDATA_B, 0, 0, 0,
+           /* IP11_5_3 [3] */
+           FN_VI1_DATA1_VI1_B1, FN_SD2_DAT1, FN_MT0_CLK, FN_SPV_TMS,
+           FN_ADICS_B_SAMP_B, 0, 0, 0,
+           /* IP11_2_0 [3] */
+           FN_VI1_DATA0_VI1_B0, FN_SD2_DAT0, FN_SIM_RST, FN_SPV_TCK,
+           FN_ADICLK_B, 0, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("IPSR12", 0xfffc0050, 32,
+                            4, 4, 4, 2, 3, 3, 3, 3, 3, 3) {
+           /* IP12_31_28 [4] */
+           0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0,
+           /* IP12_27_24 [4] */
+           0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0,
+           /* IP12_23_20 [4] */
+           0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, 0, 0,
+           /* IP12_19_18 [2] */
+           0, 0, 0, 0,
+           /* IP12_17_15 [3] */
+           FN_VI1_G7, FN_VI3_DATA7, FN_GPS_MAG, FN_FCE,
+           FN_SCK4_B, 0, 0, 0,
+           /* IP12_14_12 [3] */
+           FN_VI1_G6, FN_VI3_DATA6, FN_GPS_SIGN, FN_FRB,
+           FN_RX4_B, FN_SIM_CLK_B, 0, 0,
+           /* IP12_11_9 [3] */
+           FN_VI1_G5, FN_VI3_DATA5, FN_GPS_CLK, FN_FSE,
+           FN_TX4_B, FN_SIM_D_B, 0, 0,
+           /* IP12_8_6 [3] */
+           FN_VI1_G4, FN_VI3_DATA4, FN_SSI_WS2, FN_SDA1_C,
+           FN_SIM_RST_B, FN_HRX0_B, 0, 0,
+           /* IP12_5_3 [3] */
+           FN_VI1_G3, FN_VI3_DATA3, FN_SSI_SCK2, FN_TS_SDAT1,
+           FN_SCL1_C, FN_HTX0_B, 0, 0,
+           /* IP12_2_0 [3] */
+           FN_VI1_G2, FN_VI3_DATA2, FN_SSI_WS1, FN_TS_SPSYNC1,
+           FN_SCK2, FN_HSCK0_B, 0, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL", 0xfffc0090, 32,
+                            2, 2, 3, 3, 2, 2, 2, 2, 2,
+                            1, 1, 1, 1, 1, 1, 1, 2, 1, 2) {
+           /* SEL_SCIF5 [2] */
+           FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+           /* SEL_SCIF4 [2] */
+           FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+           /* SEL_SCIF3 [3] */
+           FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
+           FN_SEL_SCIF3_4, 0, 0, 0,
+           /* SEL_SCIF2 [3] */
+           FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
+           FN_SEL_SCIF2_4, 0, 0, 0,
+           /* SEL_SCIF1 [2] */
+           FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, 0,
+           /* SEL_SCIF0 [2] */
+           FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, FN_SEL_SCIF0_3,
+           /* SEL_SSI9 [2] */
+           FN_SEL_SSI9_0, FN_SEL_SSI9_1, FN_SEL_SSI9_2, 0,
+           /* SEL_SSI8 [2] */
+           FN_SEL_SSI8_0, FN_SEL_SSI8_1, FN_SEL_SSI8_2, 0,
+           /* SEL_SSI7 [2] */
+           FN_SEL_SSI7_0, FN_SEL_SSI7_1, FN_SEL_SSI7_2, 0,
+           /* SEL_VI0 [1] */
+           FN_SEL_VI0_0, FN_SEL_VI0_1,
+           /* SEL_SD2 [1] */
+           FN_SEL_SD2_0, FN_SEL_SD2_1,
+           /* SEL_INT3 [1] */
+           FN_SEL_INT3_0, FN_SEL_INT3_1,
+           /* SEL_INT2 [1] */
+           FN_SEL_INT2_0, FN_SEL_INT2_1,
+           /* SEL_INT1 [1] */
+           FN_SEL_INT1_0, FN_SEL_INT1_1,
+           /* SEL_INT0 [1] */
+           FN_SEL_INT0_0, FN_SEL_INT0_1,
+           /* SEL_IE [1] */
+           FN_SEL_IE_0, FN_SEL_IE_1,
+           /* SEL_EXBUS2 [2] */
+           FN_SEL_EXBUS2_0, FN_SEL_EXBUS2_1, FN_SEL_EXBUS2_2, 0,
+           /* SEL_EXBUS1 [1] */
+           FN_SEL_EXBUS1_0, FN_SEL_EXBUS1_1,
+           /* SEL_EXBUS0 [2] */
+           FN_SEL_EXBUS0_0, FN_SEL_EXBUS0_1, FN_SEL_EXBUS0_2, 0 }
+       },
+       { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xfffc0094, 32,
+                            2, 2, 2, 2, 1, 1, 1, 3, 1,
+                            2, 2, 2, 2, 1, 1, 2, 1, 2, 2) {
+           /* SEL_TMU1 [2] */
+           FN_SEL_TMU1_0, FN_SEL_TMU1_1, FN_SEL_TMU1_2, 0,
+           /* SEL_TMU0 [2] */
+           FN_SEL_TMU0_0, FN_SEL_TMU0_1, FN_SEL_TMU0_2, FN_SEL_TMU0_3,
+           /* SEL_SCIF [2] */
+           FN_SEL_SCIF_0, FN_SEL_SCIF_1, FN_SEL_SCIF_2, FN_SEL_SCIF_3,
+           /* SEL_CANCLK [2] */
+           FN_SEL_CANCLK_0, FN_SEL_CANCLK_1, FN_SEL_CANCLK_2,
+           /* SEL_CAN0 [1] */
+           FN_SEL_CAN0_0, FN_SEL_CAN0_1,
+           /* SEL_HSCIF1 [1] */
+           FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1,
+           /* SEL_HSCIF0 [1] */
+           FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1,
+           /* SEL_PWMFSW [3] */
+           FN_SEL_PWMFSW_0, FN_SEL_PWMFSW_1, FN_SEL_PWMFSW_2,
+           FN_SEL_PWMFSW_3, FN_SEL_PWMFSW_4, 0, 0, 0,
+           /* SEL_ADI [1] */
+           FN_SEL_ADI_0, FN_SEL_ADI_1,
+           /* [2] */
+           0, 0, 0, 0,
+           /* [2] */
+           0, 0, 0, 0,
+           /* [2] */
+           0, 0, 0, 0,
+           /* SEL_GPS [2] */
+           FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, FN_SEL_GPS_3,
+           /* SEL_SIM [1] */
+           FN_SEL_SIM_0, FN_SEL_SIM_1,
+           /* SEL_HSPI2 [1] */
+           FN_SEL_HSPI2_0, FN_SEL_HSPI2_1,
+           /* SEL_HSPI1 [2] */
+           FN_SEL_HSPI1_0, FN_SEL_HSPI1_1, FN_SEL_HSPI1_2, FN_SEL_HSPI1_3,
+           /* SEL_I2C3 [1] */
+           FN_SEL_I2C3_0, FN_SEL_I2C3_1,
+           /* SEL_I2C2 [2] */
+           FN_SEL_I2C2_0, FN_SEL_I2C2_1, FN_SEL_I2C2_2, FN_SEL_I2C2_3,
+           /* SEL_I2C1 [2] */
+           FN_SEL_I2C1_0, FN_SEL_I2C1_1, FN_SEL_I2C1_2, FN_SEL_I2C1_3 }
+       },
+       { PINMUX_CFG_REG("INOUTSEL0", 0xffc40004, 32, 1) { GP_INOUTSEL(0) } },
+       { PINMUX_CFG_REG("INOUTSEL1", 0xffc41004, 32, 1) { GP_INOUTSEL(1) } },
+       { PINMUX_CFG_REG("INOUTSEL2", 0xffc42004, 32, 1) { GP_INOUTSEL(2) } },
+       { PINMUX_CFG_REG("INOUTSEL3", 0xffc43004, 32, 1) { GP_INOUTSEL(3) } },
+       { PINMUX_CFG_REG("INOUTSEL4", 0xffc44004, 32, 1) { GP_INOUTSEL(4) } },
+       { PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) { GP_INOUTSEL(5) } },
+       { PINMUX_CFG_REG("INOUTSEL6", 0xffc46004, 32, 1) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0,
+               0, 0,
+               0, 0,
+               GP_6_8_IN, GP_6_8_OUT,
+               GP_6_7_IN, GP_6_7_OUT,
+               GP_6_6_IN, GP_6_6_OUT,
+               GP_6_5_IN, GP_6_5_OUT,
+               GP_6_4_IN, GP_6_4_OUT,
+               GP_6_3_IN, GP_6_3_OUT,
+               GP_6_2_IN, GP_6_2_OUT,
+               GP_6_1_IN, GP_6_1_OUT,
+               GP_6_0_IN, GP_6_0_OUT, }
+       },
+       { },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+       { PINMUX_DATA_REG("INDT0", 0xffc40008, 32) { GP_INDT(0) } },
+       { PINMUX_DATA_REG("INDT1", 0xffc41008, 32) { GP_INDT(1) } },
+       { PINMUX_DATA_REG("INDT2", 0xffc42008, 32) { GP_INDT(2) } },
+       { PINMUX_DATA_REG("INDT3", 0xffc43008, 32) { GP_INDT(3) } },
+       { PINMUX_DATA_REG("INDT4", 0xffc44008, 32) { GP_INDT(4) } },
+       { PINMUX_DATA_REG("INDT5", 0xffc45008, 32) { GP_INDT(5) } },
+       { PINMUX_DATA_REG("INDT6", 0xffc46008, 32) {
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, GP_6_8_DATA,
+               GP_6_7_DATA, GP_6_6_DATA, GP_6_5_DATA, GP_6_4_DATA,
+               GP_6_3_DATA, GP_6_2_DATA, GP_6_1_DATA, GP_6_0_DATA }
+       },
+       { },
+};
+
+static struct resource r8a7779_pfc_resources[] = {
+       [0] = {
+               .start  = 0xfffc0000,
+               .end    = 0xfffc023b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0xffc40000,
+               .end    = 0xffc46fff,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct pinmux_info r8a7779_pinmux_info = {
+       .name = "r8a7779_pfc",
+
+       .resource = r8a7779_pfc_resources,
+       .num_resources = ARRAY_SIZE(r8a7779_pfc_resources),
+
+       .unlock_reg = 0xfffc0000, /* PMMR */
+
+       .reserved_id = PINMUX_RESERVED,
+       .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+       .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+       .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+       .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+       .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+       .first_gpio = GPIO_GP_0_0,
+       .last_gpio = GPIO_FN_SCK4_B,
+
+       .gpios = pinmux_gpios,
+       .cfg_regs = pinmux_config_regs,
+       .data_regs = pinmux_data_regs,
+
+       .gpio_data = pinmux_data,
+       .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+void r8a7779_pinmux_init(void)
+{
+       register_pinmux(&r8a7779_pinmux_info);
+}
index c49a833bf9bbf123d0313390b65ba85c9a9f669c..993381257f69a6352adcc7e61df3d92d65b88643 100644 (file)
 #include <mach/common.h>
 
 #define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
+#define is_r8a7779() machine_is_marzen()
 
 static unsigned int __init shmobile_smp_get_core_count(void)
 {
        if (is_sh73a0())
                return sh73a0_get_core_count();
 
+       if (is_r8a7779())
+               return r8a7779_get_core_count();
+
        return 1;
 }
 
@@ -35,6 +39,17 @@ static void __init shmobile_smp_prepare_cpus(void)
 {
        if (is_sh73a0())
                sh73a0_smp_prepare_cpus();
+
+       if (is_r8a7779())
+               r8a7779_smp_prepare_cpus();
+}
+
+int shmobile_platform_cpu_kill(unsigned int cpu)
+{
+       if (is_r8a7779())
+               return r8a7779_platform_cpu_kill(cpu);
+
+       return 1;
 }
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -43,6 +58,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
 
        if (is_sh73a0())
                sh73a0_secondary_init(cpu);
+
+       if (is_r8a7779())
+               r8a7779_secondary_init(cpu);
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -50,6 +68,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
        if (is_sh73a0())
                return sh73a0_boot_secondary(cpu);
 
+       if (is_r8a7779())
+               return r8a7779_boot_secondary(cpu);
+
        return -ENOSYS;
 }
 
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c
new file mode 100644 (file)
index 0000000..c38ba7b
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * r8a7779 Power management support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/err.h>
+#include <linux/pm_clock.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <mach/common.h>
+#include <mach/r8a7779.h>
+
+static void __iomem *r8a7779_sysc_base;
+
+/* SYSC */
+#define SYSCSR 0x00
+#define SYSCISR 0x04
+#define SYSCISCR 0x08
+#define SYSCIER 0x0c
+#define SYSCIMR 0x10
+#define PWRSR0 0x40
+#define PWRSR1 0x80
+#define PWRSR2 0xc0
+#define PWRSR3 0x100
+#define PWRSR4 0x140
+
+#define PWRSR_OFFS 0x00
+#define PWROFFCR_OFFS 0x04
+#define PWRONCR_OFFS 0x0c
+#define PWRER_OFFS 0x14
+
+#define SYSCSR_RETRIES 100
+#define SYSCSR_DELAY_US 1
+
+#define SYSCISR_RETRIES 1000
+#define SYSCISR_DELAY_US 1
+
+#if defined(CONFIG_PM) || defined(CONFIG_SMP)
+
+static DEFINE_SPINLOCK(r8a7779_sysc_lock); /* SMP CPUs + I/O devices */
+
+static int r8a7779_sysc_pwr_on_off(struct r8a7779_pm_ch *r8a7779_ch,
+                                  int sr_bit, int reg_offs)
+{
+       int k;
+
+       for (k = 0; k < SYSCSR_RETRIES; k++) {
+               if (ioread32(r8a7779_sysc_base + SYSCSR) & (1 << sr_bit))
+                       break;
+               udelay(SYSCSR_DELAY_US);
+       }
+
+       if (k == SYSCSR_RETRIES)
+               return -EAGAIN;
+
+       iowrite32(1 << r8a7779_ch->chan_bit,
+                 r8a7779_sysc_base + r8a7779_ch->chan_offs + reg_offs);
+
+       return 0;
+}
+
+static int r8a7779_sysc_pwr_off(struct r8a7779_pm_ch *r8a7779_ch)
+{
+       return r8a7779_sysc_pwr_on_off(r8a7779_ch, 0, PWROFFCR_OFFS);
+}
+
+static int r8a7779_sysc_pwr_on(struct r8a7779_pm_ch *r8a7779_ch)
+{
+       return r8a7779_sysc_pwr_on_off(r8a7779_ch, 1, PWRONCR_OFFS);
+}
+
+static int r8a7779_sysc_update(struct r8a7779_pm_ch *r8a7779_ch,
+                              int (*on_off_fn)(struct r8a7779_pm_ch *))
+{
+       unsigned int isr_mask = 1 << r8a7779_ch->isr_bit;
+       unsigned int chan_mask = 1 << r8a7779_ch->chan_bit;
+       unsigned int status;
+       unsigned long flags;
+       int ret = 0;
+       int k;
+
+       spin_lock_irqsave(&r8a7779_sysc_lock, flags);
+
+       iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR);
+
+       do {
+               ret = on_off_fn(r8a7779_ch);
+               if (ret)
+                       goto out;
+
+               status = ioread32(r8a7779_sysc_base +
+                                 r8a7779_ch->chan_offs + PWRER_OFFS);
+       } while (status & chan_mask);
+
+       for (k = 0; k < SYSCISR_RETRIES; k++) {
+               if (ioread32(r8a7779_sysc_base + SYSCISR) & isr_mask)
+                       break;
+               udelay(SYSCISR_DELAY_US);
+       }
+
+       if (k == SYSCISR_RETRIES)
+               ret = -EIO;
+
+       iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR);
+
+ out:
+       spin_unlock_irqrestore(&r8a7779_sysc_lock, flags);
+
+       pr_debug("r8a7779 power domain %d: %02x %02x %02x %02x %02x -> %d\n",
+                r8a7779_ch->isr_bit, ioread32(r8a7779_sysc_base + PWRSR0),
+                ioread32(r8a7779_sysc_base + PWRSR1),
+                ioread32(r8a7779_sysc_base + PWRSR2),
+                ioread32(r8a7779_sysc_base + PWRSR3),
+                ioread32(r8a7779_sysc_base + PWRSR4), ret);
+       return ret;
+}
+
+int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch)
+{
+       return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_off);
+}
+
+int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch)
+{
+       return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_on);
+}
+
+static void __init r8a7779_sysc_init(void)
+{
+       r8a7779_sysc_base = ioremap_nocache(0xffd85000, PAGE_SIZE);
+       if (!r8a7779_sysc_base)
+               panic("unable to ioremap r8a7779 SYSC hardware block\n");
+
+       /* enable all interrupt sources, but do not use interrupt handler */
+       iowrite32(0x0131000e, r8a7779_sysc_base + SYSCIER);
+       iowrite32(0, r8a7779_sysc_base + SYSCIMR);
+}
+
+#else /* CONFIG_PM || CONFIG_SMP */
+
+static inline void r8a7779_sysc_init(void) {}
+
+#endif /* CONFIG_PM || CONFIG_SMP */
+
+#ifdef CONFIG_PM
+
+static int pd_power_down(struct generic_pm_domain *genpd)
+{
+       return r8a7779_sysc_power_down(to_r8a7779_ch(genpd));
+}
+
+static int pd_power_up(struct generic_pm_domain *genpd)
+{
+       return r8a7779_sysc_power_up(to_r8a7779_ch(genpd));
+}
+
+static bool pd_is_off(struct generic_pm_domain *genpd)
+{
+       struct r8a7779_pm_ch *r8a7779_ch = to_r8a7779_ch(genpd);
+       unsigned int st;
+
+       st = ioread32(r8a7779_sysc_base + r8a7779_ch->chan_offs + PWRSR_OFFS);
+       if (st & (1 << r8a7779_ch->chan_bit))
+               return true;
+
+       return false;
+}
+
+static bool pd_active_wakeup(struct device *dev)
+{
+       return true;
+}
+
+void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
+{
+       struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
+
+       pm_genpd_init(genpd, NULL, false);
+       genpd->dev_ops.stop = pm_clk_suspend;
+       genpd->dev_ops.start = pm_clk_resume;
+       genpd->dev_ops.active_wakeup = pd_active_wakeup;
+       genpd->dev_irq_safe = true;
+       genpd->power_off = pd_power_down;
+       genpd->power_on = pd_power_up;
+
+       if (pd_is_off(&r8a7779_pd->genpd))
+               pd_power_up(&r8a7779_pd->genpd);
+}
+
+void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
+                                struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       pm_genpd_add_device(&r8a7779_pd->genpd, dev);
+       if (pm_clk_no_clocks(dev))
+               pm_clk_add(dev, NULL);
+}
+
+struct r8a7779_pm_domain r8a7779_sh4a = {
+       .ch = {
+               .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
+               .isr_bit = 16, /* SH4A */
+       }
+};
+
+struct r8a7779_pm_domain r8a7779_sgx = {
+       .ch = {
+               .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
+               .isr_bit = 20, /* SGX */
+       }
+};
+
+struct r8a7779_pm_domain r8a7779_vdp1 = {
+       .ch = {
+               .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
+               .isr_bit = 21, /* VDP */
+       }
+};
+
+struct r8a7779_pm_domain r8a7779_impx3 = {
+       .ch = {
+               .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
+               .isr_bit = 24, /* IMP */
+       }
+};
+
+#endif /* CONFIG_PM */
+
+void __init r8a7779_pm_init(void)
+{
+       static int once;
+
+       if (!once++)
+               r8a7779_sysc_init();
+}
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
new file mode 100644 (file)
index 0000000..986dca6
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * R8A7740 processor support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <mach/r8a7740.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+/* SCIFA0 */
+static struct plat_sci_port scif0_platform_data = {
+       .mapbase        = 0xe6c40000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c00)),
+};
+
+static struct platform_device scif0_device = {
+       .name           = "sh-sci",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &scif0_platform_data,
+       },
+};
+
+/* SCIFA1 */
+static struct plat_sci_port scif1_platform_data = {
+       .mapbase        = 0xe6c50000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c20)),
+};
+
+static struct platform_device scif1_device = {
+       .name           = "sh-sci",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &scif1_platform_data,
+       },
+};
+
+/* SCIFA2 */
+static struct plat_sci_port scif2_platform_data = {
+       .mapbase        = 0xe6c60000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c40)),
+};
+
+static struct platform_device scif2_device = {
+       .name           = "sh-sci",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &scif2_platform_data,
+       },
+};
+
+/* SCIFA3 */
+static struct plat_sci_port scif3_platform_data = {
+       .mapbase        = 0xe6c70000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c60)),
+};
+
+static struct platform_device scif3_device = {
+       .name           = "sh-sci",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &scif3_platform_data,
+       },
+};
+
+/* SCIFA4 */
+static struct plat_sci_port scif4_platform_data = {
+       .mapbase        = 0xe6c80000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d20)),
+};
+
+static struct platform_device scif4_device = {
+       .name           = "sh-sci",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &scif4_platform_data,
+       },
+};
+
+/* SCIFA5 */
+static struct plat_sci_port scif5_platform_data = {
+       .mapbase        = 0xe6cb0000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d40)),
+};
+
+static struct platform_device scif5_device = {
+       .name           = "sh-sci",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &scif5_platform_data,
+       },
+};
+
+/* SCIFA6 */
+static struct plat_sci_port scif6_platform_data = {
+       .mapbase        = 0xe6cc0000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x04c0)),
+};
+
+static struct platform_device scif6_device = {
+       .name           = "sh-sci",
+       .id             = 6,
+       .dev            = {
+               .platform_data  = &scif6_platform_data,
+       },
+};
+
+/* SCIFA7 */
+static struct plat_sci_port scif7_platform_data = {
+       .mapbase        = 0xe6cd0000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFA,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x04e0)),
+};
+
+static struct platform_device scif7_device = {
+       .name           = "sh-sci",
+       .id             = 7,
+       .dev            = {
+               .platform_data  = &scif7_platform_data,
+       },
+};
+
+/* SCIFB */
+static struct plat_sci_port scifb_platform_data = {
+       .mapbase        = 0xe6c30000,
+       .flags          = UPF_BOOT_AUTOCONF,
+       .scscr          = SCSCR_RE | SCSCR_TE,
+       .scbrr_algo_id  = SCBRR_ALGO_4,
+       .type           = PORT_SCIFB,
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d60)),
+};
+
+static struct platform_device scifb_device = {
+       .name           = "sh-sci",
+       .id             = 8,
+       .dev            = {
+               .platform_data  = &scifb_platform_data,
+       },
+};
+
+/* CMT */
+static struct sh_timer_config cmt10_platform_data = {
+       .name = "CMT10",
+       .channel_offset = 0x10,
+       .timer_bit = 0,
+       .clockevent_rating = 125,
+       .clocksource_rating = 125,
+};
+
+static struct resource cmt10_resources[] = {
+       [0] = {
+               .name   = "CMT10",
+               .start  = 0xe6138010,
+               .end    = 0xe613801b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x0b00),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device cmt10_device = {
+       .name           = "sh_cmt",
+       .id             = 10,
+       .dev = {
+               .platform_data  = &cmt10_platform_data,
+       },
+       .resource       = cmt10_resources,
+       .num_resources  = ARRAY_SIZE(cmt10_resources),
+};
+
+static struct platform_device *r8a7740_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &scif6_device,
+       &scif7_device,
+       &scifb_device,
+       &cmt10_device,
+};
+
+/* I2C */
+static struct resource i2c0_resources[] = {
+       [0] = {
+               .name   = "IIC0",
+               .start  = 0xfff20000,
+               .end    = 0xfff20425 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0xe00),
+               .end    = intcs_evt2irq(0xe60),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource i2c1_resources[] = {
+       [0] = {
+               .name   = "IIC1",
+               .start  = 0xe6c20000,
+               .end    = 0xe6c20425 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x780), /* IIC1_ALI1 */
+               .end    = evt2irq(0x7e0), /* IIC1_DTEI1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device i2c0_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 0,
+       .resource       = i2c0_resources,
+       .num_resources  = ARRAY_SIZE(i2c0_resources),
+};
+
+static struct platform_device i2c1_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 1,
+       .resource       = i2c1_resources,
+       .num_resources  = ARRAY_SIZE(i2c1_resources),
+};
+
+static struct platform_device *r8a7740_late_devices[] __initdata = {
+       &i2c0_device,
+       &i2c1_device,
+};
+
+#define ICCR   0x0004
+#define ICSTART        0x0070
+
+#define i2c_read(reg, offset)          ioread8(reg + offset)
+#define i2c_write(reg, offset, data)   iowrite8(data, reg + offset)
+
+/*
+ * r8a7740 chip has lasting errata on I2C I/O pad reset.
+ * this is work-around for it.
+ */
+static void r8a7740_i2c_workaround(struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *reg;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               pr_err("r8a7740 i2c workaround fail (cannot find resource)\n");
+               return;
+       }
+
+       reg = ioremap(res->start, resource_size(res));
+       if (unlikely(!reg)) {
+               pr_err("r8a7740 i2c workaround fail (cannot map IO)\n");
+               return;
+       }
+
+       i2c_write(reg, ICCR, i2c_read(reg, ICCR) | 0x80);
+       i2c_read(reg, ICCR); /* dummy read */
+
+       i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
+       i2c_read(reg, ICSTART); /* dummy read */
+
+       mdelay(100);
+
+       i2c_write(reg, ICCR, 0x01);
+       i2c_read(reg, ICCR);
+       i2c_write(reg, ICSTART, 0x00);
+       i2c_read(reg, ICSTART);
+
+       i2c_write(reg, ICCR, 0x10);
+       mdelay(100);
+       i2c_write(reg, ICCR, 0x00);
+       mdelay(100);
+       i2c_write(reg, ICCR, 0x10);
+       mdelay(100);
+
+       iounmap(reg);
+}
+
+void __init r8a7740_add_standard_devices(void)
+{
+       /* I2C work-around */
+       r8a7740_i2c_workaround(&i2c0_device);
+       r8a7740_i2c_workaround(&i2c1_device);
+
+       platform_add_devices(r8a7740_early_devices,
+                           ARRAY_SIZE(r8a7740_early_devices));
+       platform_add_devices(r8a7740_late_devices,
+                            ARRAY_SIZE(r8a7740_late_devices));
+}
+
+void __init r8a7740_add_early_devices(void)
+{
+       early_platform_add_devices(r8a7740_early_devices,
+                                  ARRAY_SIZE(r8a7740_early_devices));
+}
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
new file mode 100644 (file)
index 0000000..4725663
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * r8a7779 processor support
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_intc.h>
+#include <linux/sh_timer.h>
+#include <mach/hardware.h>
+#include <mach/r8a7779.h>
+#include <mach/common.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct plat_sci_port scif0_platform_data = {
+       .mapbase        = 0xffe40000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(88), gic_spi(88),
+                           gic_spi(88), gic_spi(88) },
+};
+
+static struct platform_device scif0_device = {
+       .name           = "sh-sci",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &scif0_platform_data,
+       },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+       .mapbase        = 0xffe41000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(89), gic_spi(89),
+                           gic_spi(89), gic_spi(89) },
+};
+
+static struct platform_device scif1_device = {
+       .name           = "sh-sci",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &scif1_platform_data,
+       },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+       .mapbase        = 0xffe42000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(90), gic_spi(90),
+                           gic_spi(90), gic_spi(90) },
+};
+
+static struct platform_device scif2_device = {
+       .name           = "sh-sci",
+       .id             = 2,
+       .dev            = {
+               .platform_data  = &scif2_platform_data,
+       },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+       .mapbase        = 0xffe43000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(91), gic_spi(91),
+                           gic_spi(91), gic_spi(91) },
+};
+
+static struct platform_device scif3_device = {
+       .name           = "sh-sci",
+       .id             = 3,
+       .dev            = {
+               .platform_data  = &scif3_platform_data,
+       },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+       .mapbase        = 0xffe44000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(92), gic_spi(92),
+                           gic_spi(92), gic_spi(92) },
+};
+
+static struct platform_device scif4_device = {
+       .name           = "sh-sci",
+       .id             = 4,
+       .dev            = {
+               .platform_data  = &scif4_platform_data,
+       },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+       .mapbase        = 0xffe45000,
+       .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+       .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
+       .scbrr_algo_id  = SCBRR_ALGO_2,
+       .type           = PORT_SCIF,
+       .irqs           = { gic_spi(93), gic_spi(93),
+                           gic_spi(93), gic_spi(93) },
+};
+
+static struct platform_device scif5_device = {
+       .name           = "sh-sci",
+       .id             = 5,
+       .dev            = {
+               .platform_data  = &scif5_platform_data,
+       },
+};
+
+/* TMU */
+static struct sh_timer_config tmu00_platform_data = {
+       .name = "TMU00",
+       .channel_offset = 0x4,
+       .timer_bit = 0,
+       .clockevent_rating = 200,
+};
+
+static struct resource tmu00_resources[] = {
+       [0] = {
+               .name   = "TMU00",
+               .start  = 0xffd80008,
+               .end    = 0xffd80013,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(32),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu00_device = {
+       .name           = "sh_tmu",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &tmu00_platform_data,
+       },
+       .resource       = tmu00_resources,
+       .num_resources  = ARRAY_SIZE(tmu00_resources),
+};
+
+static struct sh_timer_config tmu01_platform_data = {
+       .name = "TMU01",
+       .channel_offset = 0x10,
+       .timer_bit = 1,
+       .clocksource_rating = 200,
+};
+
+static struct resource tmu01_resources[] = {
+       [0] = {
+               .name   = "TMU01",
+               .start  = 0xffd80014,
+               .end    = 0xffd8001f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(33),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tmu01_device = {
+       .name           = "sh_tmu",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &tmu01_platform_data,
+       },
+       .resource       = tmu01_resources,
+       .num_resources  = ARRAY_SIZE(tmu01_resources),
+};
+
+static struct platform_device *r8a7779_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+       &scif2_device,
+       &scif3_device,
+       &scif4_device,
+       &scif5_device,
+       &tmu00_device,
+       &tmu01_device,
+};
+
+static struct platform_device *r8a7779_late_devices[] __initdata = {
+};
+
+void __init r8a7779_add_standard_devices(void)
+{
+       r8a7779_pm_init();
+
+       r8a7779_init_pm_domain(&r8a7779_sh4a);
+       r8a7779_init_pm_domain(&r8a7779_sgx);
+       r8a7779_init_pm_domain(&r8a7779_vdp1);
+       r8a7779_init_pm_domain(&r8a7779_impx3);
+
+       platform_add_devices(r8a7779_early_devices,
+                           ARRAY_SIZE(r8a7779_early_devices));
+       platform_add_devices(r8a7779_late_devices,
+                           ARRAY_SIZE(r8a7779_late_devices));
+}
+
+void __init r8a7779_add_early_devices(void)
+{
+       early_platform_add_devices(r8a7779_early_devices,
+                                  ARRAY_SIZE(r8a7779_early_devices));
+}
index c197f9d29d04cc6b920ffe109e4178a5c22d7700..1ea89be63e29e1d13e7783d0d7f2ff31f64057a9 100644 (file)
@@ -504,7 +504,7 @@ static struct resource sh7372_dmae0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = evt2irq(0x20c0),
                .end    = evt2irq(0x20c0),
                .flags  = IORESOURCE_IRQ,
@@ -532,7 +532,7 @@ static struct resource sh7372_dmae1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = evt2irq(0x21c0),
                .end    = evt2irq(0x21c0),
                .flags  = IORESOURCE_IRQ,
@@ -560,7 +560,7 @@ static struct resource sh7372_dmae2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = evt2irq(0x22c0),
                .end    = evt2irq(0x22c0),
                .flags  = IORESOURCE_IRQ,
index e46821c0a62ef6a08aa06d6a390a9db884276861..20e71e5cace4723dabc8276f47d3e1cfef8daf64 100644 (file)
@@ -607,7 +607,7 @@ static struct resource sh73a0_dmae_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = gic_spi(129),
                .end    = gic_spi(129),
                .flags  = IORESOURCE_IRQ,
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
new file mode 100644 (file)
index 0000000..cc97ef8
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * SMP support for R-Mobile / SH-Mobile - r8a7779 portion
+ *
+ * Copyright (C) 2011  Renesas Solutions Corp.
+ * Copyright (C) 2011  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/common.h>
+#include <mach/r8a7779.h>
+#include <asm/smp_scu.h>
+#include <asm/smp_twd.h>
+#include <asm/hardware/gic.h>
+
+#define AVECR 0xfe700040
+
+static struct r8a7779_pm_ch r8a7779_ch_cpu1 = {
+       .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
+       .chan_bit = 1, /* ARM1 */
+       .isr_bit = 1, /* ARM1 */
+};
+
+static struct r8a7779_pm_ch r8a7779_ch_cpu2 = {
+       .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
+       .chan_bit = 2, /* ARM2 */
+       .isr_bit = 2, /* ARM2 */
+};
+
+static struct r8a7779_pm_ch r8a7779_ch_cpu3 = {
+       .chan_offs = 0x40, /* PWRSR0 .. PWRER0 */
+       .chan_bit = 3, /* ARM3 */
+       .isr_bit = 3, /* ARM3 */
+};
+
+static struct r8a7779_pm_ch *r8a7779_ch_cpu[4] = {
+       [1] = &r8a7779_ch_cpu1,
+       [2] = &r8a7779_ch_cpu2,
+       [3] = &r8a7779_ch_cpu3,
+};
+
+static void __iomem *scu_base_addr(void)
+{
+       return (void __iomem *)0xf0000000;
+}
+
+static DEFINE_SPINLOCK(scu_lock);
+static unsigned long tmp;
+
+static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
+{
+       void __iomem *scu_base = scu_base_addr();
+
+       spin_lock(&scu_lock);
+       tmp = __raw_readl(scu_base + 8);
+       tmp &= ~clr;
+       tmp |= set;
+       spin_unlock(&scu_lock);
+
+       /* disable cache coherency after releasing the lock */
+       __raw_writel(tmp, scu_base + 8);
+}
+
+unsigned int __init r8a7779_get_core_count(void)
+{
+       void __iomem *scu_base = scu_base_addr();
+
+#ifdef CONFIG_HAVE_ARM_TWD
+       /* twd_base needs to be initialized before percpu_timer_setup() */
+       twd_base = (void __iomem *)0xf0000600;
+#endif
+
+       return scu_get_core_count(scu_base);
+}
+
+int r8a7779_platform_cpu_kill(unsigned int cpu)
+{
+       struct r8a7779_pm_ch *ch = NULL;
+       int ret = -EIO;
+
+       cpu = cpu_logical_map(cpu);
+
+       /* disable cache coherency */
+       modify_scu_cpu_psr(3 << (cpu * 8), 0);
+
+       if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
+               ch = r8a7779_ch_cpu[cpu];
+
+       if (ch)
+               ret = r8a7779_sysc_power_down(ch);
+
+       return ret ? ret : 1;
+}
+
+void __cpuinit r8a7779_secondary_init(unsigned int cpu)
+{
+       gic_secondary_init(0);
+}
+
+int __cpuinit r8a7779_boot_secondary(unsigned int cpu)
+{
+       struct r8a7779_pm_ch *ch = NULL;
+       int ret = -EIO;
+
+       cpu = cpu_logical_map(cpu);
+
+       /* enable cache coherency */
+       modify_scu_cpu_psr(0, 3 << (cpu * 8));
+
+       if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
+               ch = r8a7779_ch_cpu[cpu];
+
+       if (ch)
+               ret = r8a7779_sysc_power_up(ch);
+
+       return ret;
+}
+
+void __init r8a7779_smp_prepare_cpus(void)
+{
+       int cpu = cpu_logical_map(0);
+
+       scu_enable(scu_base_addr());
+
+       /* Map the reset vector (in headsmp.S) */
+       __raw_writel(__pa(shmobile_secondary_vector), __io(AVECR));
+
+       /* enable cache coherency on CPU0 */
+       modify_scu_cpu_psr(0, 3 << (cpu * 8));
+
+       r8a7779_pm_init();
+
+       /* power off secondary CPUs */
+       r8a7779_platform_cpu_kill(1);
+       r8a7779_platform_cpu_kill(2);
+       r8a7779_platform_cpu_kill(3);
+}
index a0f9634f672703b648a399666e467b6f7b9b9d10..789bdc9e8f913ddb26e46e1a4b827a2b0b6f51fa 100644 (file)
@@ -90,11 +90,11 @@ static struct wm8903_platform_data harmony_wm8903_pdata = {
        .micdet_delay = 100,
        .gpio_base = HARMONY_GPIO_WM8903(0),
        .gpio_cfg = {
-               WM8903_GPIO_NO_CONFIG,
-               WM8903_GPIO_NO_CONFIG,
                0,
-               WM8903_GPIO_NO_CONFIG,
-               WM8903_GPIO_NO_CONFIG,
+               0,
+               WM8903_GPIO_CONFIG_ZERO,
+               0,
+               0,
        },
 };
 
index cfc74d46a09e40d30caaf5a8dac712a733c8cc48..ebac65f52510d4c4eb65093ab0fa79210e83940a 100644 (file)
@@ -172,11 +172,11 @@ static struct wm8903_platform_data wm8903_pdata = {
        .micdet_delay = 100,
        .gpio_base = SEABOARD_GPIO_WM8903(0),
        .gpio_cfg = {
-               WM8903_GPIO_NO_CONFIG,
-               WM8903_GPIO_NO_CONFIG,
                0,
-               WM8903_GPIO_NO_CONFIG,
-               WM8903_GPIO_NO_CONFIG,
+               0,
+               WM8903_GPIO_CONFIG_ZERO,
+               0,
+               0,
        },
 };
 
index ec63c6b2b6b536c1d32939f1df14c443a3ef562d..af8b634357278b5682955d7eca3f4a3f946e0895 100644 (file)
@@ -408,7 +408,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[0].flags = IORESOURCE_IO;
        if (request_resource(&ioport_resource, &pp->res[0]))
                panic("Request PCIe IO resource failed\n");
-       sys->resource[0] = &pp->res[0];
+       pci_add_resource(&sys->resources, &pp->res[0]);
 
        /*
         * IORESOURCE_MEM
@@ -427,7 +427,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[1].flags = IORESOURCE_MEM;
        if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe Memory resource failed\n");
-       sys->resource[1] = &pp->res[1];
+       pci_add_resource(&sys->resources, &pp->res[1]);
 
        /*
         * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -446,7 +446,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
        if (request_resource(&iomem_resource, &pp->res[2]))
                panic("Request PCIe Prefetch Memory resource failed\n");
-       sys->resource[2] = &pp->res[2];
+       pci_add_resource(&sys->resources, &pp->res[2]);
 
        return 1;
 }
@@ -467,7 +467,8 @@ static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
        pp = tegra_pcie.port + nr;
        pp->root_bus_nr = sys->busnr;
 
-       return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &tegra_pcie_ops, sys,
+                                &sys->resources);
 }
 
 static struct hw_pci tegra_pcie_hw __initdata = {
index 9361a5290177d11a26d9190e328147e497ec686a..5c00712907d18ef715a74fa3caa27b38fba095f6 100644 (file)
 #include <linux/amba/pl022.h>
 #include <linux/amba/serial.h>
 #include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
 #include <linux/mfd/tc3589x.h>
 #include <linux/mfd/tps6105x.h>
-#include <linux/mfd/ab8500/gpio.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
 #include <linux/leds-lp5521.h>
 #include <linux/input.h>
 #include <linux/smsc911x.h>
index fe1569b67c9182cea704dab1fc4ddd1145388dbe..9de9e9c4dbbbcf2322e0fbaf3140537e31b89d4a 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/amba/bus.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
-#include <linux/mfd/ab5500/ab5500.h>
+#include <linux/mfd/abx500/ab5500.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/arch.h>
index 47969909836c9bb1441b7143dc5c4e156915267f..d2d4131435a680b61fcb6f84f6b092affe72f5cd 100644 (file)
@@ -9,7 +9,7 @@
 #define __MACH_IRQS_BOARD_MOP500_H
 
 /* Number of AB8500 irqs is taken from header file */
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 #define MOP500_AB8500_IRQ_BASE         IRQ_BOARD_START
 #define MOP500_AB8500_IRQ_END          (MOP500_AB8500_IRQ_BASE \
index c898deb3ada01f2b5dacd1cd93e3e99dd8a7e3a7..90069bce23bc3c4b2b1d88096e0eca5e8dde9841 100644 (file)
@@ -191,7 +191,7 @@ static struct resource pre_mem = {
        .flags  = IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-static int __init pci_versatile_setup_resources(struct resource **resource)
+static int __init pci_versatile_setup_resources(struct list_head *resources)
 {
        int ret = 0;
 
@@ -215,13 +215,13 @@ static int __init pci_versatile_setup_resources(struct resource **resource)
        }
 
        /*
-        * bus->resource[0] is the IO resource for this bus
-        * bus->resource[1] is the mem resource for this bus
-        * bus->resource[2] is the prefetch mem resource for this bus
+        * the IO resource for this bus
+        * the mem resource for this bus
+        * the prefetch mem resource for this bus
         */
-       resource[0] = &io_mem;
-       resource[1] = &non_mem;
-       resource[2] = &pre_mem;
+       pci_add_resource(resources, &io_mem);
+       pci_add_resource(resources, &non_mem);
+       pci_add_resource(resources, &pre_mem);
 
        goto out;
 
@@ -250,7 +250,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 
        if (nr == 0) {
                sys->mem_offset = 0;
-               ret = pci_versatile_setup_resources(sys->resource);
+               ret = pci_versatile_setup_resources(&sys->resources);
                if (ret < 0) {
                        printk("pci_versatile_setup: resources... oops?\n");
                        goto out;
@@ -306,7 +306,8 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 
 struct pci_bus * __init pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &pci_versatile_ops, sys,
+                                &sys->resources);
 }
 
 void __init pci_versatile_preinit(void)
index 430df1a5978d04d198a88f2448c8a2de67c7e963..e62956e1203094bc6daa022486b93bd490c70057 100644 (file)
@@ -35,27 +35,6 @@ EXPORT_SYMBOL(pcibios_min_mem);
 unsigned int pci_flags = PCI_REASSIGN_ALL_RSRC;
 EXPORT_SYMBOL(pci_flags);
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len   = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        if ((unsigned long)addr >= VMALLOC_START &&
index 845549cbbb2766fc5ef3f79e9409c78c35730a92..f4d40a27111e57328739f9ac3111564dbcda8395 100644 (file)
@@ -215,16 +215,16 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
        sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
        sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-       sys->resource[0] = &res[0];
-       sys->resource[1] = &res[1];
-       sys->resource[2] = NULL;
+       pci_add_resource(&sys->resources, &res[0]);
+       pci_add_resource(&sys->resources, &res[1]);
 
        return 1;
 }
 
 struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
 {
-       return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
+       return pci_scan_root_bus(NULL, sys->busnr, &iop3xx_ops, sys,
+                                &sys->resources);
 }
 
 void __init iop3xx_atu_setup(void)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
deleted file mode 100644 (file)
index da4f68d..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- *  linux/arch/arm/plat-omap/cpu-omap.c
- *
- *  CPU frequency scaling for OMAP
- *
- *  Copyright (C) 2005 Nokia Corporation
- *  Written by Tony Lindgren <tony@atomide.com>
- *
- *  Based on cpu-sa1110.c, Copyright (C) 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/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <plat/clock.h>
-#include <asm/system.h>
-
-#define VERY_HI_RATE   900000000
-
-static struct cpufreq_frequency_table *freq_table;
-
-#ifdef CONFIG_ARCH_OMAP1
-#define MPU_CLK                "mpu"
-#else
-#define MPU_CLK                "virt_prcm_set"
-#endif
-
-static struct clk *mpu_clk;
-
-/* TODO: Add support for SDRAM timing changes */
-
-static int omap_verify_speed(struct cpufreq_policy *policy)
-{
-       if (freq_table)
-               return cpufreq_frequency_table_verify(policy, freq_table);
-
-       if (policy->cpu)
-               return -EINVAL;
-
-       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
-                                    policy->cpuinfo.max_freq);
-
-       policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
-       policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
-       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
-                                    policy->cpuinfo.max_freq);
-       return 0;
-}
-
-static unsigned int omap_getspeed(unsigned int cpu)
-{
-       unsigned long rate;
-
-       if (cpu)
-               return 0;
-
-       rate = clk_get_rate(mpu_clk) / 1000;
-       return rate;
-}
-
-static int omap_target(struct cpufreq_policy *policy,
-                      unsigned int target_freq,
-                      unsigned int relation)
-{
-       struct cpufreq_freqs freqs;
-       int ret = 0;
-
-       /* Ensure desired rate is within allowed range.  Some govenors
-        * (ondemand) will just pass target_freq=0 to get the minimum. */
-       if (target_freq < policy->min)
-               target_freq = policy->min;
-       if (target_freq > policy->max)
-               target_freq = policy->max;
-
-       freqs.old = omap_getspeed(0);
-       freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
-       freqs.cpu = 0;
-
-       if (freqs.old == freqs.new)
-               return ret;
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#ifdef CONFIG_CPU_FREQ_DEBUG
-       printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
-              freqs.old, freqs.new);
-#endif
-       ret = clk_set_rate(mpu_clk, freqs.new * 1000);
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-       return ret;
-}
-
-static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
-{
-       int result = 0;
-
-       mpu_clk = clk_get(NULL, MPU_CLK);
-       if (IS_ERR(mpu_clk))
-               return PTR_ERR(mpu_clk);
-
-       if (policy->cpu != 0)
-               return -EINVAL;
-
-       policy->cur = policy->min = policy->max = omap_getspeed(0);
-
-       clk_init_cpufreq_table(&freq_table);
-       if (freq_table) {
-               result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
-               if (!result)
-                       cpufreq_frequency_table_get_attr(freq_table,
-                                                       policy->cpu);
-       } else {
-               policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
-               policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
-                                                       VERY_HI_RATE) / 1000;
-       }
-
-       /* FIXME: what's the actual transition time? */
-       policy->cpuinfo.transition_latency = 300 * 1000;
-
-       return 0;
-}
-
-static int omap_cpu_exit(struct cpufreq_policy *policy)
-{
-       clk_exit_cpufreq_table(&freq_table);
-       clk_put(mpu_clk);
-       return 0;
-}
-
-static struct freq_attr *omap_cpufreq_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-
-static struct cpufreq_driver omap_driver = {
-       .flags          = CPUFREQ_STICKY,
-       .verify         = omap_verify_speed,
-       .target         = omap_target,
-       .get            = omap_getspeed,
-       .init           = omap_cpu_init,
-       .exit           = omap_cpu_exit,
-       .name           = "omap",
-       .attr           = omap_cpufreq_attr,
-};
-
-static int __init omap_cpufreq_init(void)
-{
-       return cpufreq_register_driver(&omap_driver);
-}
-
-arch_initcall(omap_cpufreq_init);
-
-/*
- * if ever we want to remove this, upon cleanup call:
- *
- * cpufreq_unregister_driver()
- * cpufreq_frequency_table_put_attr()
- */
-
index 656dc00d30edde87d8d44ed6dada500672355394..f82f888b91a95bb0a238975b4c575408728eb1e9 100644 (file)
@@ -63,6 +63,7 @@ enum clk_types {
 struct s3c_sdhci_platdata {
        unsigned int    max_width;
        unsigned int    host_caps;
+       unsigned int    pm_caps;
        enum cd_types   cd_type;
        enum clk_types  clk_type;
 
index ceb9fa3a80c0768a10411740547a42dd0fbcceb1..0f707184eae0b0d07cb7cecc2e3d5464182ee4ce 100644 (file)
@@ -53,6 +53,8 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd,
                set->cfg_gpio = pd->cfg_gpio;
        if (pd->host_caps)
                set->host_caps |= pd->host_caps;
+       if (pd->pm_caps)
+               set->pm_caps |= pd->pm_caps;
        if (pd->clk_type)
                set->clk_type = pd->clk_type;
 }
index 9702c2213e1e74d979fb914b286cfbfac8c1609d..62d9ded016357bc6e6a6534d56cd154694b9692a 100644 (file)
@@ -169,7 +169,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
 struct pt_regs;
-void NORET_TYPE die(const char *str, struct pt_regs *regs, long err);
+void die(const char *str, struct pt_regs *regs, long err);
 void _exception(long signr, struct pt_regs *regs, int code,
                unsigned long addr);
 
index 7aa25756412f16299b69cccfcd1d1c9851aaaec7..3d760c06f02481851e6ab27e57e819a376dcb6d5 100644 (file)
@@ -24,7 +24,7 @@
 
 static DEFINE_SPINLOCK(die_lock);
 
-void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
+void die(const char *str, struct pt_regs *regs, long err)
 {
        static int die_counter;
 
index 5edcb58d6f737f49a69a8dcf9784c2c2935e1dea..0b7039cf07ff18b665e868bb7dc0015e519b930c 100644 (file)
@@ -80,7 +80,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 2e549572d4f59c5ff73ab137c56fd13a4b312dd2..5553205d7cbe962f8aee6d386383e3f28b3cdf24 100644 (file)
@@ -97,7 +97,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_WATCHDOG=y
index ad0881ba30af0ec5bc90974d4c518249b72d33df..d95658fc31276d61d99d9da002fdd0cab45dba74 100644 (file)
@@ -68,7 +68,7 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=400
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 8465b3e6b8628a23b5961471c46de0adf617d1db..498f64a87050fd2572b1fa29f14042bc5477ba1e 100644 (file)
@@ -105,7 +105,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 5e7321b26040665fb4a6a3b74db5c82208af2107..72e0317565ef407bbd613e3057717482f0ba089d 100644 (file)
@@ -99,7 +99,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index a7eb54bf3089916359b3f178a3e26fc5980df1be..2f075e0b26244ea9b3a136377b11580f9999f20b 100644 (file)
@@ -81,7 +81,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index b90d3792ed5209a46b2cd4342398d18e28bf531f..ab38a82597b2868ebe129b416f632554c24cbcac 100644 (file)
@@ -84,7 +84,7 @@ CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_GPIO=m
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 005362537a7b4c3f4d70dc46f864bd78feafcbf3..5c802d6bbbc00f54d86306378e983af9c8c9cc23 100644 (file)
@@ -94,7 +94,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_BLACKFIN_TWI=m
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 580bf4296a1456ef7869a8884ebd49e40c1b1351..972aa6263ad0a9e7163c7b3b191afceef4282d70 100644 (file)
@@ -101,7 +101,7 @@ CONFIG_I2C=m
 CONFIG_I2C_BLACKFIN_TWI=m
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 0e6d841b5d0147d21344e2fe4ce8dad446df05ea..7a1e3bf2b04f97c78f1e984a04c74feaeb6c0e75 100644 (file)
@@ -113,7 +113,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 77a27e31d6d1d93dc3fd5b499b4f136dd787b0a9..0fdc4ecaa5317a4de2f1850251c3d618db03a96e 100644 (file)
@@ -85,7 +85,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_PCA_PLATFORM=y
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
index f5ed34e12e0ca9928e3b7b1a9bcbd339a076e6bd..78adbbf3982619b1309eb9bff3571593399d4317 100644 (file)
@@ -84,7 +84,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index d7ff2aee3fbc62f73f855875611728ebbf3295f6..d3cd0f561c842cb6f3307580c40a1c63eb5ecdce 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 85014319672c1fb04bae3de7dc7b9a8c7efbb101..7b982d0502adddfb1f8142f9550944985b5725c8 100644 (file)
@@ -80,7 +80,7 @@ CONFIG_I2C=m
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_GPIO=m
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_SPI_SPIDEV=m
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
index dbf750cd2db85bf3c3713bde6f36d61108cb8d73..c280a50e79435a8a590631e915008c0036146324 100644 (file)
@@ -88,7 +88,7 @@ CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_BLACKFIN_TWI=m
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_WATCHDOG=y
index 07ffbdae34eeda1e3f3b1c5be68c30d67ddfdf20..c940a1e3ab3685fa85f6db0fd132a5d928d484f8 100644 (file)
@@ -57,7 +57,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 # CONFIG_HWMON is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
index 707cbf8a25903b008b306616405255f5100c8f26..2e47df77490f29c3f42add408b847ada13da4370 100644 (file)
@@ -78,7 +78,7 @@ CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_USB_GADGET=m
index 4596935eadacc3e1f420a68188ea74cd1f17e8f3..6da629ffc2f10954ffdca933bacd690a08819fef 100644 (file)
@@ -72,7 +72,7 @@ CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_USB_GADGET=y
index 9f1d08401fcaacdf6d53f661da44e2cee641b66e..349922be01f35c489deacff6ac6cb9b22cc3259a 100644 (file)
@@ -89,7 +89,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_BFIN_WDT=y
index 6c7b21585a43d33032b43ee9421186245122d5df..0456deaa2d6fbc94b62bb7e6a5feb4b815e9a07f 100644 (file)
@@ -78,7 +78,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_USB_GADGET=m
index b192acfae38609d51e8834f19037dca3168d4de0..89162d0fff9ea6325be99d8a45a21f0d8c45c224 100644 (file)
@@ -78,7 +78,7 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
index 06e9f497faed2f0a7f68ec61cd6c8ca74f9527e5..a26436bf50fff23db967e47b2e2ba3c5c765d5df 100644 (file)
@@ -68,7 +68,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_SPI_SPIDEV=y
 CONFIG_WATCHDOG=y
 CONFIG_SOUND=m
index 5e797cf72043f757be28f019a62a1ed669688e9f..647991514ac9b8fc98065b1a6878b1b7c7e72908 100644 (file)
@@ -70,7 +70,7 @@ CONFIG_SERIAL_BFIN_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_HW_RANDOM=y
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_USB=y
index a566a2fe6b9b7478176629d37a9786dc5b2547ab..8fd9b446d6583f595e2b44ec57a7c6f771581c9f 100644 (file)
@@ -84,7 +84,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
index 12e66cd7cdaad79907e6187ad27cd46fed62e9ab..0520c160230de103d8b85b907c48f64abab4e2b3 100644 (file)
@@ -71,7 +71,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_HWMON=m
 CONFIG_WATCHDOG=y
 CONFIG_BFIN_WDT=y
index d496ae9a39b0c9f1f2c0339e124fc52f4721b2d5..e4ed865b885e3a0279f53250afe78f17dcfefd35 100644 (file)
@@ -92,7 +92,7 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
index 65f642167a50351bf95fa68e4481465ebf76efc2..c1f45f15295cdf5c9fbf47c1f945d10cfe29f15c 100644 (file)
@@ -70,7 +70,7 @@ CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_SPI=y
-CONFIG_SPI_BFIN=y
+CONFIG_SPI_BFIN5XX=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_BFIN_WDT=y
index ecacdf34768b593b0e43e91c2314927cde723e83..68bcc3d119b678fac2a9f579bb5f4cce7127769e 100644 (file)
@@ -51,9 +51,6 @@ struct bfin_serial_port {
 #elif ANOMALY_05000363
        unsigned int anomaly_threshold;
 #endif
-#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
-       int scts;
-#endif
 #if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
        defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
        int cts_pin;
index 05043786da2199cbb302563a0c1e3e62295852c2..e349631c8299fa87f7bfca5fca507d0520718de8 100644 (file)
@@ -14,6 +14,9 @@ struct blackfin_cpudata {
        struct cpu cpu;
        unsigned int imemctl;
        unsigned int dmemctl;
+#ifdef CONFIG_SMP
+       struct task_struct *idle;
+#endif
 };
 
 DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data);
index 99cae2e3bac702259b9dc4c469b2eeb85890f2b3..74352c4597d92f5802531ac0ca86c08766b6a62f 100644 (file)
 #define PCIBIOS_MIN_IO 0x00001000
 #define PCIBIOS_MIN_MEM 0x10000000
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
 static inline void pcibios_penalize_isa_irq(int irq)
 {
        /* We don't do dynamic PCI IRQ allocation */
index af6c0aa79bae9435ea5dff4f92f2c945051352aa..dc3d144b4bb5930a396f73d9bce48f67ca1c6365 100644 (file)
@@ -37,7 +37,7 @@ extern unsigned long dcache_invld_count[NR_CPUS];
 #endif
 
 void smp_icache_flush_range_others(unsigned long start,
-                                  unsigned long end);
+                                       unsigned long end);
 #ifdef CONFIG_HOTPLUG_CPU
 void coreb_die(void);
 void cpu_die(void);
@@ -46,4 +46,7 @@ int __cpu_disable(void);
 int __cpu_die(unsigned int cpu);
 #endif
 
+void smp_timer_broadcast(const struct cpumask *mask);
+
+
 #endif /* !__ASM_BLACKFIN_SMP_H */
index dfa2525a442d76318044acc65f51bb07b683b863..d6102c86d037601adcb96d6745d5dc8eadfcf624 100644 (file)
@@ -828,10 +828,18 @@ static inline int __init get_mem_size(void)
        u32 ddrctl = bfin_read_EBIU_DDRCTL1();
        int ret = 0;
        switch (ddrctl & 0xc0000) {
-               case DEVSZ_64:  ret = 64 / 8;
-               case DEVSZ_128: ret = 128 / 8;
-               case DEVSZ_256: ret = 256 / 8;
-               case DEVSZ_512: ret = 512 / 8;
+       case DEVSZ_64:
+               ret = 64 / 8;
+               break;
+       case DEVSZ_128:
+               ret = 128 / 8;
+               break;
+       case DEVSZ_256:
+               ret = 256 / 8;
+               break;
+       case DEVSZ_512:
+               ret = 512 / 8;
+               break;
        }
        switch (ddrctl & 0x30000) {
                case DEVWD_4:  ret *= 2;
index 1bcf3a3c57d83db8b17875a65a5bb9e5b3f7a331..d98f2d69b0c4a3d29dd812c1112a192e66721940 100644 (file)
@@ -219,7 +219,7 @@ static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt)
 
 #if defined(CONFIG_TICKSOURCE_CORETMR)
 /* per-cpu local core timer */
-static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
+DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
 
 static int bfin_coretmr_set_next_event(unsigned long cycles,
                                struct clock_event_device *evt)
@@ -281,6 +281,7 @@ void bfin_coretmr_init(void)
 #ifdef CONFIG_CORE_TIMER_IRQ_L1
 __attribute__((l1_text))
 #endif
+
 irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
 {
        int cpu = smp_processor_id();
@@ -306,6 +307,11 @@ void bfin_coretmr_clockevent_init(void)
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
 
+#ifdef CONFIG_SMP
+       evt->broadcast = smp_timer_broadcast;
+#endif
+
+
        evt->name = "bfin_core_timer";
        evt->rating = 350;
        evt->irq = -1;
index d1c0c0cff3efdb2f68b91edb6a6ad892f10d0a33..a2d96d31bbf16a0764b066d7d08a2201374c5fd9 100644 (file)
@@ -61,7 +61,7 @@ static struct physmap_flash_data ezbrd_flash_data = {
 
 static struct resource ezbrd_flash_resource = {
        .start = 0x20000000,
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        .end   = 0x202fffff,
 #else
        .end   = 0x203fffff,
@@ -122,6 +122,8 @@ static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
 #if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
        .phy_mask = 0xfff7, /* Only probe the port phy connect to the on chip MAC */
 #endif
+       .vlan1_mask = 1,
+       .vlan2_mask = 2,
 };
 
 static struct platform_device bfin_mii_bus = {
@@ -292,7 +294,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 };
 
 /* SPI controller data */
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = 6,
@@ -715,7 +717,7 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
        &bfin_spi1_device,
 #endif
@@ -777,7 +779,7 @@ static int __init ezbrd_init(void)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
        /* setup BF518-EZBRD GPIO pin PG11 to AMS2, PG15 to AMS3. */
        peripheral_request(P_AMS2, "ParaFlash");
-#if !defined(CONFIG_SPI_BFIN) && !defined(CONFIG_SPI_BFIN_MODULE)
+#if !defined(CONFIG_SPI_BFIN5XX) && !defined(CONFIG_SPI_BFIN5XX_MODULE)
        peripheral_request(P_AMS3, "ParaFlash");
 #endif
        return 0;
index 5470bf89e52e1147dcfcec19542dd18d2df7716d..f271310f739d4107241245218aeebaad21dd4308 100644 (file)
@@ -228,7 +228,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 };
 
 /* SPI controller data */
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = 6,
@@ -635,7 +635,7 @@ static struct platform_device *tcm_devices[] __initdata = {
        &bfin_mac_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
        &bfin_spi1_device,
 #endif
index 5bc6938157ad831638ca4661cb61b68c18339e36..c8d5d2b7c732fd78f2a678d2fd09315d3b1968f7 100644 (file)
@@ -334,7 +334,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
@@ -744,7 +744,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_mac_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index cd289698b4dd73575682260b10ba615bf35bb71e..7330607856e96061e9badb1ea24b712b1d1d14da 100644 (file)
@@ -444,7 +444,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = 8,
@@ -893,7 +893,7 @@ static struct platform_device *cmbf527_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index 9f792eafd1ccf604c7b7177d3b5766e691b0c4e2..db3ecfce8306c08fb3b660be5ff509a4b2fdfc4b 100644 (file)
@@ -371,7 +371,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = 8,
@@ -776,7 +776,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_mac_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index 3ecafff5d2ef753416692b623324e800e0925437..dfdd8e6bac7296d02f09ff6a0b6f19ea4f42caf2 100644 (file)
@@ -664,7 +664,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = 8,
@@ -1189,7 +1189,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index 3a92c4318d2deaa392b2cef5693b4dd46f67170a..360e97fc529363d53193c34decc623d27b31a34e 100644 (file)
@@ -448,7 +448,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = EXP_GPIO_SPISEL_BASE + 8 + MAX_CTRL_CS,
@@ -831,7 +831,7 @@ static struct platform_device *tll6527m_devices[] __initdata = {
        &bfin_mac_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index 47cadd316e764484ac9e728d84ccfead6ee5b53f..6cb7b3ed9b3de48d276324ee81d9277d7102a72e 100644 (file)
@@ -125,7 +125,7 @@ static struct platform_device net2272_bfin_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
@@ -398,7 +398,7 @@ static struct platform_device *h8606_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -428,7 +428,7 @@ static int __init H8606_init(void)
        printk(KERN_INFO "HV Sistemas H8606 board support by http://www.hvsistemas.com\n");
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(h8606_devices, ARRAY_SIZE(h8606_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
        return 0;
index 18817d57c7a15b5cf0e36bc806ef2752e91746fe..de44a3765e595ea4aeb58ce922d3248a299cacc6 100644 (file)
@@ -146,7 +146,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -422,7 +422,7 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index 2c8f30ef6a7b2ab4b749c337814010cd9dc2fe10..fe47e048c4e673c7a055b02304270e199c2ec7a5 100644 (file)
@@ -29,7 +29,7 @@
  */
 const char bfin_board_name[] = "Bluetechnix CM BF533";
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
 static struct mtd_partition bfin_spi_flash_partitions[] = {
@@ -536,7 +536,7 @@ static struct platform_device *cm_bf533_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -549,7 +549,7 @@ static int __init cm_bf533_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
        return 0;
index 144556e14499e6fc0a7141b8d368cd29650b5b15..07811c209b9d38f020180d44045ef497a2f4095c 100644 (file)
@@ -245,7 +245,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -484,7 +484,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &smc91x_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index b597d4e50d58e74e7c29e4fd2b37658bbd12ec49..e303dae4e2d96abb8c8f0a86a0f66670ab4c6b5f 100644 (file)
@@ -104,7 +104,7 @@ static struct platform_device dm9000_device2 = {
 #endif
 
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
@@ -270,7 +270,7 @@ static struct platform_device *ip0x_devices[] __initdata = {
 #endif
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &spi_bfin_master_device,
 #endif
 
index 2afd02e14bd1f317b053f0296b35161d4b71d4d3..ce88a7165b62a99dfbea8adcfbe59bc356760209 100644 (file)
@@ -219,9 +219,10 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 
-#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
        {
-               .modalias = "ad183x",
+               .modalias = "ad1836",
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0,
                .chip_select = 4,
@@ -251,7 +252,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -471,7 +472,7 @@ static struct i2c_gpio_platform_data i2c_gpio_data = {
        .scl_pin                = GPIO_PF3,
        .sda_is_open_drain      = 0,
        .scl_is_open_drain      = 0,
-       .udelay                 = 40,
+       .udelay                 = 10,
 };
 
 static struct platform_device i2c_gpio_device = {
@@ -540,27 +541,150 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) \
+       || defined(CONFIG_SND_BF5XX_AC97) || \
+       defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#include <asm/bfin_sport.h>
+
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+               P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+       SPORT_REQ(0),
+       SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s_pcm = {
+       .name = "bfin-i2s-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm_pcm = {
+       .name = "bfin-tdm-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97_pcm = {
+       .name = "bfin-ac97-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static const unsigned ad73311_gpio[] = {
+       GPIO_PF4,
+};
+
+static struct platform_device bfin_ad73311_machine = {
+       .name = "bfin-snd-ad73311",
+       .id = 1,
+       .dev = {
+               .platform_data = (void *)ad73311_gpio,
+       },
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_AD73311) || defined(CONFIG_SND_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+       .name = "ad73311",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_SOC_AD74111) || defined(CONFIG_SND_SOC_AD74111_MODULE)
+static struct platform_device bfin_ad74111_codec_device = {
+       .name = "ad74111",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || \
+       defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources =
+               ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
+       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources =
+               ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
+       defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources =
+               ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -580,7 +704,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -596,7 +720,8 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 #endif
 
-#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || \
+       defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 #ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
        &bfin_sport0_uart_device,
 #endif
@@ -618,14 +743,42 @@ static struct platform_device *stamp_devices[] __initdata = {
 #endif
 
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
-       &bfin_i2s,
+       &bfin_i2s_pcm,
 #endif
 
 #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-       &bfin_tdm,
+       &bfin_tdm_pcm,
 #endif
 
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_ac97_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+       &bfin_ad73311_machine,
+#endif
+
+#if defined(CONFIG_SND_SOC_AD73311) || defined(CONFIG_SND_SOC_AD73311_MODULE)
+       &bfin_ad73311_codec_device,
+#endif
+
+#if defined(CONFIG_SND_SOC_AD74111) || defined(CONFIG_SND_SOC_AD74111_MODULE)
+       &bfin_ad74111_codec_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || \
+       defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
+       &bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
+       defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
+       &bfin_tdm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
+       defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
 #endif
 };
index 604a430038e153c73360987a5e763ee7a4af38dc..0d4a2f61a973a94399a93aeac18ff86935810b1f 100644 (file)
@@ -31,7 +31,7 @@
  */
 const char bfin_board_name[] = "Bluetechnix CM BF537E";
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
@@ -735,7 +735,7 @@ static struct platform_device *cm_bf537e_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -770,7 +770,7 @@ static int __init cm_bf537e_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf537e_devices, ARRAY_SIZE(cm_bf537e_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
 
index d916b46a44fe9334bf49fb51b940aa2889c3245a..f5536982706c702137fbd4cda636affac68b8eec 100644 (file)
@@ -32,7 +32,7 @@
  */
 const char bfin_board_name[] = "Bluetechnix CM BF537U";
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
@@ -700,7 +700,7 @@ static struct platform_device *cm_bf537u_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -747,7 +747,7 @@ static int __init cm_bf537u_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf537u_devices, ARRAY_SIZE(cm_bf537u_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
 
index 5f307228be63b7b78108c9fcc19136b01e636bf1..11dadeb33d79af0dd63118bbce90f794b89d3a48 100644 (file)
@@ -125,7 +125,7 @@ static struct platform_device asmb_flash_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
 
@@ -370,7 +370,7 @@ static struct platform_device *dnp5370_devices[] __initdata = {
        &bfin_mac_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &spi_bfin_master_device,
 #endif
 
index 3901dd093b9044fad71e1a7da5480273677db7cf..d2d71282618fb9b512371c0626d7ae5937eaf28f 100644 (file)
@@ -121,7 +121,7 @@ static struct platform_device net2272_bfin_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) \
@@ -496,7 +496,7 @@ static struct platform_device *minotaur_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -537,7 +537,7 @@ static int __init minotaur_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(minotaur_devices, ARRAY_SIZE(minotaur_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info,
                                ARRAY_SIZE(bfin_spi_board_info));
 #endif
index aebd31c845f008995c90424a5b053767a3058c78..6fd84709fc68c08c786018f2b4c63590c639d232 100644 (file)
@@ -154,7 +154,7 @@ static struct platform_device net2272_bfin_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) \
@@ -477,7 +477,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -508,7 +508,7 @@ static int __init pnav_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info,
                                ARRAY_SIZE(bfin_spi_board_info));
 #endif
index 7fbb0bbf86762c3fd40336cb765c1f746b90cab6..2221173e489e5294f9c788ea33db0a9e9389e6dd 100644 (file)
@@ -1420,7 +1420,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #endif
 };
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
        .num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
@@ -1462,7 +1462,7 @@ static struct platform_device bfin_spi0_device = {
 
 /* SPORT SPI controller data */
 static struct bfin5xx_spi_master bfin_sport_spi0_info = {
-       .num_chipselect = 1, /* master only supports one device */
+       .num_chipselect = MAX_BLACKFIN_GPIOS,
        .enable_dma = 0,  /* master don't support DMA */
        .pin_req = {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_DRPRI,
                P_SPORT0_RSCLK, P_SPORT0_TFS, P_SPORT0_RFS, 0},
@@ -1492,7 +1492,7 @@ static struct platform_device bfin_sport_spi0_device = {
 };
 
 static struct bfin5xx_spi_master bfin_sport_spi1_info = {
-       .num_chipselect = 1, /* master only supports one device */
+       .num_chipselect = MAX_BLACKFIN_GPIOS,
        .enable_dma = 0,  /* master don't support DMA */
        .pin_req = {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_DRPRI,
                P_SPORT1_RSCLK, P_SPORT1_TFS, P_SPORT1_RFS, 0},
@@ -1558,6 +1558,71 @@ static struct platform_device bfin_lq035q1_device = {
 };
 #endif
 
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+#include <linux/videodev2.h>
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+static const unsigned short ppi_req[] = {
+       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+       0,
+};
+
+static const struct ppi_info ppi_info = {
+       .type = PPI_TYPE_PPI,
+       .dma_ch = CH_PPI,
+       .irq_err = IRQ_PPI_ERROR,
+       .base = (void __iomem *)PPI_CONTROL,
+       .pin_req = ppi_req,
+};
+
+#if defined(CONFIG_VIDEO_VS6624) \
+       || defined(CONFIG_VIDEO_VS6624_MODULE)
+static struct v4l2_input vs6624_inputs[] = {
+       {
+               .index = 0,
+               .name = "Camera",
+               .type = V4L2_INPUT_TYPE_CAMERA,
+               .std = V4L2_STD_UNKNOWN,
+       },
+};
+
+static struct bcap_route vs6624_routes[] = {
+       {
+               .input = 0,
+               .output = 0,
+       },
+};
+
+static const unsigned vs6624_ce_pin = GPIO_PF10;
+
+static struct bfin_capture_config bfin_capture_data = {
+       .card_name = "BF537",
+       .inputs = vs6624_inputs,
+       .num_inputs = ARRAY_SIZE(vs6624_inputs),
+       .routes = vs6624_routes,
+       .i2c_adapter_id = 0,
+       .board_info = {
+               .type = "vs6624",
+               .addr = 0x10,
+               .platform_data = (void *)&vs6624_ce_pin,
+       },
+       .ppi_info = &ppi_info,
+       .ppi_control = (PACK_EN | DLEN_8 | XFR_TYPE | 0x0020),
+};
+#endif
+
+static struct platform_device bfin_capture_device = {
+       .name = "bfin_capture",
+       .dev = {
+               .platform_data = &bfin_capture_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 #ifdef CONFIG_SERIAL_BFIN_UART0
 static struct resource bfin_uart0_resources[] = {
@@ -2716,7 +2781,7 @@ static struct platform_device *stamp_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -2733,6 +2798,11 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_lq035q1_device,
 #endif
 
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+       &bfin_capture_device,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
 #ifdef CONFIG_SERIAL_BFIN_UART0
        &bfin_uart0_device,
index 6917ce2fa55ef4f61568263462e05c1cd733aa18..988517671a5dbd91ac12b3fd028dc156eb0a25af 100644 (file)
@@ -32,7 +32,7 @@
  */
 const char bfin_board_name[] = "Bluetechnix TCM BF537";
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
@@ -702,7 +702,7 @@ static struct platform_device *cm_bf537_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -737,7 +737,7 @@ static int __init tcm_bf537_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
 
index 8356eb599f1937cb37b552c36a91c70bf0c0b4b9..1633a6f306c0e1390fedf5dd12dd805c5ac9c704 100644 (file)
@@ -490,7 +490,7 @@ static struct platform_device smc91x_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -874,7 +874,7 @@ static struct platform_device *cm_bf538_devices[] __initdata = {
 #endif
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bf538_spi_master0,
        &bf538_spi_master1,
        &bf538_spi_master2,
@@ -938,7 +938,7 @@ static int __init ezkit_init(void)
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf538_devices, ARRAY_SIZE(cm_bf538_devices));
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bf538_spi_board_info,
                        ARRAY_SIZE(bf538_spi_board_info));
 #endif
index 0350eacec21b96785f2eda1cc933cca52bbde572..68af594db48e638c8ad29bc1a504aaa560382d5b 100644 (file)
@@ -854,7 +854,7 @@ static struct platform_device para_flash_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -1175,7 +1175,7 @@ static struct platform_device *cm_bf548_devices[] __initdata = {
        &bf54x_sdh_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bf54x_spi_master0,
        &bf54x_spi_master1,
 #endif
@@ -1210,7 +1210,7 @@ static int __init cm_bf548_init(void)
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf548_devices, ARRAY_SIZE(cm_bf548_devices));
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bf54x_spi_board_info,
                        ARRAY_SIZE(bf54x_spi_board_info));
 #endif
index bb868ac0fe2dbdf5063034be857f5ece7a9c82a4..3ea45f8bd61c162a1f723a08f068f2972184a0c5 100644 (file)
@@ -1110,7 +1110,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
        },
 #endif
 };
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -1183,6 +1183,71 @@ static struct platform_device bf54x_spi_master1 = {
 };
 #endif  /* spi master and devices */
 
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+#include <linux/videodev2.h>
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+static const unsigned short ppi_req[] = {
+       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
+       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
+       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
+       0,
+};
+
+static const struct ppi_info ppi_info = {
+       .type = PPI_TYPE_EPPI,
+       .dma_ch = CH_EPPI1,
+       .irq_err = IRQ_EPPI1_ERROR,
+       .base = (void __iomem *)EPPI1_STATUS,
+       .pin_req = ppi_req,
+};
+
+#if defined(CONFIG_VIDEO_VS6624) \
+       || defined(CONFIG_VIDEO_VS6624_MODULE)
+static struct v4l2_input vs6624_inputs[] = {
+       {
+               .index = 0,
+               .name = "Camera",
+               .type = V4L2_INPUT_TYPE_CAMERA,
+               .std = V4L2_STD_UNKNOWN,
+       },
+};
+
+static struct bcap_route vs6624_routes[] = {
+       {
+               .input = 0,
+               .output = 0,
+       },
+};
+
+static const unsigned vs6624_ce_pin = GPIO_PG6;
+
+static struct bfin_capture_config bfin_capture_data = {
+       .card_name = "BF548",
+       .inputs = vs6624_inputs,
+       .num_inputs = ARRAY_SIZE(vs6624_inputs),
+       .routes = vs6624_routes,
+       .i2c_adapter_id = 0,
+       .board_info = {
+               .type = "vs6624",
+               .addr = 0x10,
+               .platform_data = (void *)&vs6624_ce_pin,
+       },
+       .ppi_info = &ppi_info,
+       .ppi_control = (POLC | PACKEN | DLEN_8 | XFR_TYPE | 0x20),
+};
+#endif
+
+static struct platform_device bfin_capture_device = {
+       .name = "bfin_capture",
+       .dev = {
+               .platform_data = &bfin_capture_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
        [0] = {
@@ -1502,10 +1567,14 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bf54x_sdh_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bf54x_spi_master0,
        &bf54x_spi_master1,
 #endif
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+       &bfin_capture_device,
+#endif
 
 #if defined(CONFIG_KEYBOARD_BFIN) || defined(CONFIG_KEYBOARD_BFIN_MODULE)
        &bf54x_kpad_device,
index b1b7339b6ba776a321d0614c091fe035508d63b7..f6ffd6f054c398201dfea4e21aaf4c3b6d044719 100644 (file)
@@ -372,7 +372,7 @@ static struct bfin5xx_spi_chip data_flash_chip_info = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -475,7 +475,7 @@ static struct platform_device bfin_dpmc = {
 static struct platform_device *acvilon_devices[] __initdata = {
        &bfin_dpmc,
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
index c017cf07ed4e2960f032f9d8b0c81a0a60e657de..d81450f635df13f2777b9b7587fc9f5db6260b54 100644 (file)
@@ -29,7 +29,7 @@
  */
 const char bfin_board_name[] = "Bluetechnix CM BF561";
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* all SPI peripherals info goes here */
 
 #if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
@@ -488,7 +488,7 @@ static struct platform_device *cm_bf561_devices[] __initdata = {
        &net2272_bfin_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -523,7 +523,7 @@ static int __init cm_bf561_init(void)
 {
        printk(KERN_INFO "%s(): registering device resources\n", __func__);
        platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices));
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 #endif
 
index 27f22ed381d99767b0bda919964fed021f7d3cb5..838978808a15a4414410301b2ba464604eae5f36 100644 (file)
@@ -291,7 +291,7 @@ static struct platform_device ezkit_flash_device = {
 };
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
 /* SPI (0) */
 static struct resource bfin_spi0_resource[] = {
        [0] = {
@@ -383,7 +383,7 @@ static struct i2c_gpio_platform_data i2c_gpio_data = {
        .scl_pin                = GPIO_PF0,
        .sda_is_open_drain      = 0,
        .scl_is_open_drain      = 0,
-       .udelay                 = 40,
+       .udelay                 = 10,
 };
 
 static struct platform_device i2c_gpio_device = {
@@ -422,6 +422,96 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+#include <linux/videodev2.h>
+#include <media/blackfin/bfin_capture.h>
+#include <media/blackfin/ppi.h>
+
+static const unsigned short ppi_req[] = {
+       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+       0,
+};
+
+static const struct ppi_info ppi_info = {
+       .type = PPI_TYPE_PPI,
+       .dma_ch = CH_PPI0,
+       .irq_err = IRQ_PPI1_ERROR,
+       .base = (void __iomem *)PPI0_CONTROL,
+       .pin_req = ppi_req,
+};
+
+#if defined(CONFIG_VIDEO_ADV7183) \
+       || defined(CONFIG_VIDEO_ADV7183_MODULE)
+#include <media/adv7183.h>
+static struct v4l2_input adv7183_inputs[] = {
+       {
+               .index = 0,
+               .name = "Composite",
+               .type = V4L2_INPUT_TYPE_CAMERA,
+               .std = V4L2_STD_ALL,
+       },
+       {
+               .index = 1,
+               .name = "S-Video",
+               .type = V4L2_INPUT_TYPE_CAMERA,
+               .std = V4L2_STD_ALL,
+       },
+       {
+               .index = 2,
+               .name = "Component",
+               .type = V4L2_INPUT_TYPE_CAMERA,
+               .std = V4L2_STD_ALL,
+       },
+};
+
+static struct bcap_route adv7183_routes[] = {
+       {
+               .input = ADV7183_COMPOSITE4,
+               .output = ADV7183_8BIT_OUT,
+       },
+       {
+               .input = ADV7183_SVIDEO0,
+               .output = ADV7183_8BIT_OUT,
+       },
+       {
+               .input = ADV7183_COMPONENT0,
+               .output = ADV7183_8BIT_OUT,
+       },
+};
+
+
+static const unsigned adv7183_gpio[] = {
+       GPIO_PF13, /* reset pin */
+       GPIO_PF2,  /* output enable pin */
+};
+
+static struct bfin_capture_config bfin_capture_data = {
+       .card_name = "BF561",
+       .inputs = adv7183_inputs,
+       .num_inputs = ARRAY_SIZE(adv7183_inputs),
+       .routes = adv7183_routes,
+       .i2c_adapter_id = 0,
+       .board_info = {
+               .type = "adv7183",
+               .addr = 0x20,
+               .platform_data = (void *)adv7183_gpio,
+       },
+       .ppi_info = &ppi_info,
+       .ppi_control = (PACK_EN | DLEN_8 | DMA32 | FLD_SEL),
+};
+#endif
+
+static struct platform_device bfin_capture_device = {
+       .name = "bfin_capture",
+       .dev = {
+               .platform_data = &bfin_capture_data,
+       },
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
@@ -462,7 +552,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &bfin_isp1760_device,
 #endif
 
-#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+#if defined(CONFIG_SPI_BFIN5XX) || defined(CONFIG_SPI_BFIN5XX_MODULE)
        &bfin_spi0_device,
 #endif
 
@@ -494,6 +584,11 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &ezkit_flash_device,
 #endif
 
+#if defined(CONFIG_VIDEO_BLACKFIN_CAPTURE) \
+       || defined(CONFIG_VIDEO_BLACKFIN_CAPTURE_MODULE)
+       &bfin_capture_device,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
index 7977db2f1c1268d15d0f0b7092401f32abd41db3..00bdacee9cc2ec96607a1a4a15d0ddd29196391b 100644 (file)
@@ -16,6 +16,7 @@
 #include <mach/irq.h>
 
 #define SUPPLE_0_WAKEUP ((IRQ_SUPPLE_0 - (IRQ_CORETMR + 1)) % 32)
+#define SUPPLE_1_WAKEUP ((IRQ_SUPPLE_1 - (IRQ_CORETMR + 1)) % 32)
 
 static inline void
 bfin_iwr_restore(unsigned long iwr0, unsigned long iwr1, unsigned long iwr2)
@@ -42,7 +43,8 @@ bfin_iwr_save(unsigned long niwr0, unsigned long niwr1, unsigned long niwr2,
 static inline void
 bfin_iwr_set_sup0(unsigned long *iwr0, unsigned long *iwr1, unsigned long *iwr2)
 {
-       bfin_iwr_save(0, IWR_ENABLE(SUPPLE_0_WAKEUP), 0, iwr0, iwr1, iwr2);
+       bfin_iwr_save(0, IWR_ENABLE(SUPPLE_0_WAKEUP) |
+                       IWR_ENABLE(SUPPLE_1_WAKEUP), 0, iwr0, iwr1, iwr2);
 }
 
 #endif
index db22401e760589f59834302423bbca6cc9466855..ab1c617b9cfc9e646b4366e8fa34bd8c058defa1 100644 (file)
@@ -84,7 +84,7 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
 
        if ((bfin_read_SYSCR() & COREB_SRAM_INIT) == 0) {
                /* CoreB already running, sending ipi to wakeup it */
-               platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
+               smp_send_reschedule(cpu);
        } else {
                /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
                bfin_write_SYSCR(bfin_read_SYSCR() & ~COREB_SRAM_INIT);
@@ -114,7 +114,8 @@ void __init platform_request_ipi(int irq, void *handler)
        int ret;
        const char *name = (irq == IRQ_SUPPLE_0) ? supple0 : supple1;
 
-       ret = request_irq(irq, handler, IRQF_PERCPU, name, handler);
+       ret = request_irq(irq, handler, IRQF_PERCPU | IRQF_NO_SUSPEND |
+                       IRQF_FORCE_RESUME, name, handler);
        if (ret)
                panic("Cannot request %s for IPI service", name);
 }
index 0784a52389c8e4ebe398d1740cd948fbe36e1391..ac8f8a43158c5b85b5524d15bd3a74b8d5de0507 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/cache.h>
+#include <linux/clockchips.h>
 #include <linux/profile.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
@@ -47,9 +48,10 @@ unsigned long blackfin_iflush_l1_entry[NR_CPUS];
 
 struct blackfin_initial_pda __cpuinitdata initial_pda_coreb;
 
-#define BFIN_IPI_RESCHEDULE   0
-#define BFIN_IPI_CALL_FUNC    1
-#define BFIN_IPI_CPU_STOP     2
+#define BFIN_IPI_TIMER       0
+#define BFIN_IPI_RESCHEDULE   1
+#define BFIN_IPI_CALL_FUNC    2
+#define BFIN_IPI_CPU_STOP     3
 
 struct blackfin_flush_data {
        unsigned long start;
@@ -160,6 +162,14 @@ static irqreturn_t ipi_handler_int0(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
+DECLARE_PER_CPU(struct clock_event_device, coretmr_events);
+void ipi_timer(void)
+{
+       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
+       evt->event_handler(evt);
+}
+
 static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
 {
        struct ipi_message *msg;
@@ -176,18 +186,17 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
        while (msg_queue->count) {
                msg = &msg_queue->ipi_message[msg_queue->head];
                switch (msg->type) {
+               case BFIN_IPI_TIMER:
+                       ipi_timer();
+                       break;
                case BFIN_IPI_RESCHEDULE:
                        scheduler_ipi();
                        break;
                case BFIN_IPI_CALL_FUNC:
-                       spin_unlock_irqrestore(&msg_queue->lock, flags);
                        ipi_call_function(cpu, msg);
-                       spin_lock_irqsave(&msg_queue->lock, flags);
                        break;
                case BFIN_IPI_CPU_STOP:
-                       spin_unlock_irqrestore(&msg_queue->lock, flags);
                        ipi_cpu_stop(cpu);
-                       spin_lock_irqsave(&msg_queue->lock, flags);
                        break;
                default:
                        printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%lx\n",
@@ -297,8 +306,6 @@ void smp_send_reschedule(int cpu)
 {
        cpumask_t callmap;
        /* simply trigger an ipi */
-       if (cpu_is_offline(cpu))
-               return;
 
        cpumask_clear(&callmap);
        cpumask_set_cpu(cpu, &callmap);
@@ -308,6 +315,16 @@ void smp_send_reschedule(int cpu)
        return;
 }
 
+void smp_send_msg(const struct cpumask *mask, unsigned long type)
+{
+       smp_send_message(*mask, type, NULL, NULL, 0);
+}
+
+void smp_timer_broadcast(const struct cpumask *mask)
+{
+       smp_send_msg(mask, BFIN_IPI_TIMER);
+}
+
 void smp_send_stop(void)
 {
        cpumask_t callmap;
@@ -326,17 +343,24 @@ void smp_send_stop(void)
 int __cpuinit __cpu_up(unsigned int cpu)
 {
        int ret;
-       static struct task_struct *idle;
+       struct blackfin_cpudata *ci = &per_cpu(cpu_data, cpu);
+       struct task_struct *idle = ci->idle;
 
-       if (idle)
+       if (idle) {
                free_task(idle);
-
-       idle = fork_idle(cpu);
-       if (IS_ERR(idle)) {
-               printk(KERN_ERR "CPU%u: fork() failed\n", cpu);
-               return PTR_ERR(idle);
+               idle = NULL;
        }
 
+       if (!idle) {
+               idle = fork_idle(cpu);
+               if (IS_ERR(idle)) {
+                       printk(KERN_ERR "CPU%u: fork() failed\n", cpu);
+                       return PTR_ERR(idle);
+               }
+               ci->idle = idle;
+       } else {
+               init_idle(idle, cpu);
+       }
        secondary_stack = task_stack_page(idle) + THREAD_SIZE;
 
        ret = platform_boot_secondary(cpu, idle);
@@ -411,6 +435,7 @@ void __cpuinit secondary_start_kernel(void)
 
        bfin_setup_caches(cpu);
 
+       notify_cpu_starting(cpu);
        /*
         * Calibrate loops per jiffy value.
         * IRQs need to be enabled here - D-cache can be invalidated
@@ -453,8 +478,10 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end)
        smp_flush_data.start = start;
        smp_flush_data.end = end;
 
-       if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 0))
+       preempt_disable();
+       if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1))
                printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n");
+       preempt_enable();
 }
 EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
 
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
new file mode 100644 (file)
index 0000000..26e67f0
--- /dev/null
@@ -0,0 +1,174 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+config TMS320C6X
+       def_bool y
+       select CLKDEV_LOOKUP
+       select GENERIC_IRQ_SHOW
+       select HAVE_ARCH_TRACEHOOK
+       select HAVE_DMA_API_DEBUG
+       select HAVE_GENERIC_HARDIRQS
+       select HAVE_MEMBLOCK
+       select HAVE_SPARSE_IRQ
+       select OF
+       select OF_EARLY_FLATTREE
+
+config MMU
+       def_bool n
+
+config ZONE_DMA
+       def_bool y
+
+config FPU
+       def_bool n
+
+config HIGHMEM
+       def_bool n
+
+config NUMA
+       def_bool n
+
+config RWSEM_GENERIC_SPINLOCK
+       def_bool y
+
+config RWSEM_XCHGADD_ALGORITHM
+       def_bool n
+
+config GENERIC_CALIBRATE_DELAY
+       def_bool y
+
+config GENERIC_HWEIGHT
+       def_bool y
+
+config GENERIC_CLOCKEVENTS
+       def_bool y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+
+config GENERIC_BUG
+       def_bool y
+
+config COMMON_CLKDEV
+       def_bool y
+
+config C6X_BIG_KERNEL
+       bool "Build a big kernel"
+       help
+         The C6X function call instruction has a limited range of +/- 2MiB.
+         This is sufficient for most kernels, but some kernel configurations
+         with lots of compiled-in functionality may require a larger range
+         for function calls. Use this option to have the compiler generate
+         function calls with 32-bit range. This will make the kernel both
+         larger and slower.
+
+         If unsure, say N.
+
+source "init/Kconfig"
+
+# Use the generic interrupt handling code in kernel/irq/
+
+source "kernel/Kconfig.freezer"
+
+config CMDLINE_BOOL
+       bool "Default bootloader kernel arguments"
+
+config CMDLINE
+       string "Kernel command line"
+       depends on CMDLINE_BOOL
+       default "console=ttyS0,57600"
+       help
+         On some architectures there is currently no way for the boot loader
+         to pass arguments to the kernel. For these architectures, you should
+         supply some command-line options at build time by entering them
+         here.
+
+config CMDLINE_FORCE
+       bool "Force default kernel command string"
+       depends on CMDLINE_BOOL
+       default n
+       help
+         Set this to have arguments from the default kernel command string
+         override those passed by the boot loader.
+
+config CPU_BIG_ENDIAN
+       bool "Build big-endian kernel"
+       default n
+       help
+         Say Y if you plan on running a kernel in big-endian mode.
+         Note that your board must be properly built and your board
+         port must properly enable any big-endian related features
+         of your chipset/board/processor.
+
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order"
+       default "13"
+       help
+         The kernel memory allocator divides physically contiguous memory
+         blocks into "zones", where each zone is a power of two number of
+         pages.  This option selects the largest power of two that the kernel
+         keeps in the memory allocator.  If you need to allocate very large
+         blocks of physically contiguous memory, then you may need to
+         increase this value.
+
+         This config option is actually maximum order plus one. For example,
+         a value of 11 means that the largest free memory block is 2^10 pages.
+
+menu "Processor type and features"
+
+source "arch/c6x/platforms/Kconfig"
+
+config TMS320C6X_CACHES_ON
+       bool "L2 cache support"
+       default y
+
+config KERNEL_RAM_BASE_ADDRESS
+       hex "Virtual address of memory base"
+       default 0xe0000000 if SOC_TMS320C6455
+       default 0xe0000000 if SOC_TMS320C6457
+       default 0xe0000000 if SOC_TMS320C6472
+       default 0x80000000
+
+source "mm/Kconfig"
+
+source "kernel/Kconfig.preempt"
+
+source "kernel/Kconfig.hz"
+source "kernel/time/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config ACCESS_CHECK
+       bool "Check the user pointer address"
+       default y
+       help
+         Usually the pointer transfer from user space is checked to see if its
+         address is in the kernel space.
+
+         Say N here to disable that check to improve the performance.
+
+endmenu
diff --git a/arch/c6x/Makefile b/arch/c6x/Makefile
new file mode 100644 (file)
index 0000000..1d08dd0
--- /dev/null
@@ -0,0 +1,60 @@
+#
+# linux/arch/c6x/Makefile
+#
+# 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.
+#
+
+cflags-y += -mno-dsbt -msdata=none
+
+cflags-$(CONFIG_C6X_BIG_KERNEL) += -mlong-calls
+
+CFLAGS_MODULE   += -mlong-calls -mno-dsbt -msdata=none
+
+CHECKFLAGS      +=
+
+KBUILD_CFLAGS   += $(cflags-y)
+KBUILD_AFLAGS   += $(cflags-y)
+
+ifdef CONFIG_CPU_BIG_ENDIAN
+KBUILD_CFLAGS   += -mbig-endian
+KBUILD_AFLAGS   += -mbig-endian
+LINKFLAGS       += -mbig-endian
+KBUILD_LDFLAGS  += -mbig-endian
+LDFLAGS += -EB
+endif
+
+head-y          := arch/c6x/kernel/head.o
+core-y          += arch/c6x/kernel/ arch/c6x/mm/ arch/c6x/platforms/
+libs-y          += arch/c6x/lib/
+
+# Default to vmlinux.bin, override when needed
+all: vmlinux.bin
+
+boot := arch/$(ARCH)/boot
+
+# Are we making a dtbImage.<boardname> target? If so, crack out the boardname
+DTB:=$(subst dtbImage.,,$(filter dtbImage.%, $(MAKECMDGOALS)))
+export DTB
+
+ifneq ($(DTB),)
+core-y += $(boot)/
+endif
+
+# With make 3.82 we cannot mix normal and wildcard targets
+
+vmlinux.bin: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
+
+dtbImage.%: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
+
+archclean:
+       $(Q)$(MAKE) $(clean)=$(boot)
+
+define archhelp
+  @echo '  vmlinux.bin     - Binary kernel image (arch/$(ARCH)/boot/vmlinux.bin)'
+  @echo '  dtbImage.<dt>   - ELF image with $(arch)/boot/dts/<dt>.dts linked in'
+  @echo '                  - stripped elf with fdt blob'
+endef
diff --git a/arch/c6x/boot/Makefile b/arch/c6x/boot/Makefile
new file mode 100644 (file)
index 0000000..ecca820
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# Makefile for bootable kernel images
+#
+
+OBJCOPYFLAGS_vmlinux.bin := -O binary
+$(obj)/vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+DTC_FLAGS ?= -p 1024
+
+ifneq ($(DTB),)
+obj-y += linked_dtb.o
+endif
+
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call cmd,dtc)
+
+quiet_cmd_cp = CP      $< $@$2
+       cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false)
+
+# Generate builtin.dtb from $(DTB).dtb
+$(obj)/builtin.dtb: $(obj)/$(DTB).dtb
+       $(call if_changed,cp)
+
+$(obj)/linked_dtb.o: $(obj)/builtin.dtb
+
+$(obj)/dtbImage.%: vmlinux
+       $(call if_changed,objcopy)
+
+clean-files := $(obj)/*.dtb
diff --git a/arch/c6x/boot/dts/dsk6455.dts b/arch/c6x/boot/dts/dsk6455.dts
new file mode 100644 (file)
index 0000000..2b71f80
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/c6x/boot/dts/dsk6455.dts
+ *
+ * DSK6455 Evaluation Platform For TMS320C6455
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Author: Mark Salter <msalter@redhat.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.
+ *
+ */
+
+/dts-v1/;
+
+/include/ "tms320c6455.dtsi"
+
+/ {
+       model = "Spectrum Digital DSK6455";
+       compatible = "spectrum-digital,dsk6455";
+
+       chosen {
+               bootargs = "root=/dev/nfs ip=dhcp rw";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0xE0000000 0x08000000>;
+       };
+
+       soc {
+               megamod_pic: interrupt-controller@1800000 {
+                       interrupts = < 12 13 14 15 >;
+               };
+
+               emifa@70000000 {
+                       flash@3,0 {
+                                 #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "cfi-flash";
+                               reg = <0x3 0x0 0x400000>;
+                               bank-width = <1>;
+                               device-width = <1>;
+                               partition@0 {
+                                       reg = <0x0 0x400000>;
+                                       label = "NOR";
+                               };
+                       };
+               };
+
+               timer1: timer@2980000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 69 >;
+               };
+
+               clock-controller@029a0000 {
+                       clock-frequency = <50000000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/evmc6457.dts b/arch/c6x/boot/dts/evmc6457.dts
new file mode 100644 (file)
index 0000000..0301eb9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * arch/c6x/boot/dts/evmc6457.dts
+ *
+ * EVMC6457 Evaluation Platform For TMS320C6457
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Author: Mark Salter <msalter@redhat.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.
+ *
+ */
+
+/dts-v1/;
+
+/include/ "tms320c6457.dtsi"
+
+/ {
+       model = "eInfochips EVMC6457";
+       compatible = "einfochips,evmc6457";
+
+       chosen {
+               bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0xE0000000 0x10000000>;
+       };
+
+       soc {
+               megamod_pic: interrupt-controller@1800000 {
+                      interrupts = < 12 13 14 15 >;
+               };
+
+               timer0: timer@2940000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 67 >;
+               };
+
+               clock-controller@29a0000 {
+                       clock-frequency = <60000000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/evmc6472.dts b/arch/c6x/boot/dts/evmc6472.dts
new file mode 100644 (file)
index 0000000..3e207b4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * arch/c6x/boot/dts/evmc6472.dts
+ *
+ * EVMC6472 Evaluation Platform For TMS320C6472
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Author: Mark Salter <msalter@redhat.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.
+ *
+ */
+
+/dts-v1/;
+
+/include/ "tms320c6472.dtsi"
+
+/ {
+       model = "eInfochips EVMC6472";
+       compatible = "einfochips,evmc6472";
+
+       chosen {
+               bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0xE0000000 0x10000000>;
+       };
+
+       soc {
+               megamod_pic: interrupt-controller@1800000 {
+                      interrupts = < 12 13 14 15 >;
+               };
+
+               timer0: timer@25e0000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               timer1: timer@25f0000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               timer2: timer@2600000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               timer3: timer@2610000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               timer4: timer@2620000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               timer5: timer@2630000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 16 >;
+               };
+
+               clock-controller@29a0000 {
+                       clock-frequency = <25000000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/evmc6474.dts b/arch/c6x/boot/dts/evmc6474.dts
new file mode 100644 (file)
index 0000000..4dc2912
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * arch/c6x/boot/dts/evmc6474.dts
+ *
+ * EVMC6474 Evaluation Platform For TMS320C6474
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Author: Mark Salter <msalter@redhat.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.
+ *
+ */
+
+/dts-v1/;
+
+/include/ "tms320c6474.dtsi"
+
+/ {
+       model = "Spectrum Digital EVMC6474";
+       compatible = "spectrum-digital,evmc6474";
+
+       chosen {
+               bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x08000000>;
+       };
+
+       soc {
+               megamod_pic: interrupt-controller@1800000 {
+                      interrupts = < 12 13 14 15 >;
+               };
+
+               timer3: timer@2940000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 39 >;
+               };
+
+               timer4: timer@2950000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 41 >;
+               };
+
+               timer5: timer@2960000 {
+                       interrupt-parent = <&megamod_pic>;
+                       interrupts = < 43 >;
+               };
+
+               clock-controller@29a0000 {
+                       clock-frequency = <50000000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/tms320c6455.dtsi b/arch/c6x/boot/dts/tms320c6455.dtsi
new file mode 100644 (file)
index 0000000..a804ec1
--- /dev/null
@@ -0,0 +1,96 @@
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "ti,c64x+";
+                       reg = <0>;
+               };
+       };
+
+       soc {
+               compatible = "simple-bus";
+               model = "tms320c6455";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               core_pic: interrupt-controller {
+                         interrupt-controller;
+                         #interrupt-cells = <1>;
+                         compatible = "ti,c64x+core-pic";
+               };
+
+               /*
+                * Megamodule interrupt controller
+                */
+               megamod_pic: interrupt-controller@1800000 {
+                      compatible = "ti,c64x+megamod-pic";
+                      interrupt-controller;
+                      #interrupt-cells = <1>;
+                      reg = <0x1800000 0x1000>;
+                      interrupt-parent = <&core_pic>;
+               };
+
+               cache-controller@1840000 {
+                       compatible = "ti,c64x+cache";
+                       reg = <0x01840000 0x8400>;
+               };
+
+               emifa@70000000 {
+                       compatible = "ti,c64x+emifa", "simple-bus";
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+                       reg = <0x70000000 0x100>;
+                       ranges = <0x2 0x0 0xa0000000 0x00000008
+                                 0x3 0x0 0xb0000000 0x00400000
+                                 0x4 0x0 0xc0000000 0x10000000
+                                 0x5 0x0 0xD0000000 0x10000000>;
+
+                       ti,dscr-dev-enable = <13>;
+                       ti,emifa-burst-priority = <255>;
+                       ti,emifa-ce-config = <0x00240120
+                                             0x00240120
+                                             0x00240122
+                                             0x00240122>;
+               };
+
+               timer1: timer@2980000 {
+                       compatible = "ti,c64x+timer64";
+                       reg = <0x2980000 0x40>;
+                       ti,dscr-dev-enable = <4>;
+               };
+
+               clock-controller@029a0000 {
+                       compatible = "ti,c6455-pll", "ti,c64x+pll";
+                       reg = <0x029a0000 0x200>;
+                       ti,c64x+pll-bypass-delay = <1440>;
+                       ti,c64x+pll-reset-delay = <15360>;
+                       ti,c64x+pll-lock-delay = <24000>;
+               };
+
+               device-state-config-regs@2a80000 {
+                       compatible = "ti,c64x+dscr";
+                       reg = <0x02a80000 0x41000>;
+
+                       ti,dscr-devstat = <0>;
+                       ti,dscr-silicon-rev = <8 28 0xf>;
+                       ti,dscr-rmii-resets = <0 0x40020 0x00040000>;
+
+                       ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
+                       ti,dscr-devstate-ctl-regs =
+                                <0 12 0x40008 1 0  0  2
+                                 12 1 0x40008 3 0 30  2
+                                 13 2 0x4002c 1 0xffffffff 0 1>;
+                       ti,dscr-devstate-stat-regs =
+                               <0 10 0x40014 1 0  0  3
+                                10 2 0x40018 1 0  0  3>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/tms320c6457.dtsi b/arch/c6x/boot/dts/tms320c6457.dtsi
new file mode 100644 (file)
index 0000000..35f4070
--- /dev/null
@@ -0,0 +1,68 @@
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "ti,c64x+";
+                       reg = <0>;
+               };
+       };
+
+       soc {
+               compatible = "simple-bus";
+               model = "tms320c6457";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               core_pic: interrupt-controller {
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       compatible = "ti,c64x+core-pic";
+               };
+
+               megamod_pic: interrupt-controller@1800000 {
+                       compatible = "ti,c64x+megamod-pic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&core_pic>;
+                       reg = <0x1800000 0x1000>;
+               };
+
+               cache-controller@1840000 {
+                       compatible = "ti,c64x+cache";
+                       reg = <0x01840000 0x8400>;
+               };
+
+               device-state-controller@2880800 {
+                       compatible = "ti,c64x+dscr";
+                       reg = <0x02880800 0x400>;
+
+                       ti,dscr-devstat = <0x20>;
+                       ti,dscr-silicon-rev = <0x18 28 0xf>;
+                       ti,dscr-mac-fuse-regs = <0x114 3 4 5 6
+                                                0x118 0 0 1 2>;
+                       ti,dscr-kick-regs = <0x38 0x83E70B13
+                                            0x3c 0x95A4F1E0>;
+               };
+
+               timer0: timer@2940000 {
+                       compatible = "ti,c64x+timer64";
+                       reg = <0x2940000 0x40>;
+               };
+
+               clock-controller@29a0000 {
+                       compatible = "ti,c6457-pll", "ti,c64x+pll";
+                       reg = <0x029a0000 0x200>;
+                       ti,c64x+pll-bypass-delay = <300>;
+                       ti,c64x+pll-reset-delay = <24000>;
+                       ti,c64x+pll-lock-delay = <50000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/tms320c6472.dtsi b/arch/c6x/boot/dts/tms320c6472.dtsi
new file mode 100644 (file)
index 0000000..b488aae
--- /dev/null
@@ -0,0 +1,134 @@
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       model = "ti,c64x+";
+               };
+               cpu@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       model = "ti,c64x+";
+               };
+               cpu@2 {
+                       device_type = "cpu";
+                       reg = <2>;
+                       model = "ti,c64x+";
+               };
+               cpu@3 {
+                       device_type = "cpu";
+                       reg = <3>;
+                       model = "ti,c64x+";
+               };
+               cpu@4 {
+                       device_type = "cpu";
+                       reg = <4>;
+                       model = "ti,c64x+";
+               };
+               cpu@5 {
+                       device_type = "cpu";
+                       reg = <5>;
+                       model = "ti,c64x+";
+               };
+       };
+
+       soc {
+               compatible = "simple-bus";
+               model = "tms320c6472";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               core_pic: interrupt-controller {
+                       compatible = "ti,c64x+core-pic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               megamod_pic: interrupt-controller@1800000 {
+                      compatible = "ti,c64x+megamod-pic";
+                      interrupt-controller;
+                      #interrupt-cells = <1>;
+                      reg = <0x1800000 0x1000>;
+                      interrupt-parent = <&core_pic>;
+               };
+
+               cache-controller@1840000 {
+                       compatible = "ti,c64x+cache";
+                       reg = <0x01840000 0x8400>;
+               };
+
+               timer0: timer@25e0000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x01 >;
+                       reg = <0x25e0000 0x40>;
+               };
+
+               timer1: timer@25f0000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x02 >;
+                       reg = <0x25f0000 0x40>;
+               };
+
+               timer2: timer@2600000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x04 >;
+                       reg = <0x2600000 0x40>;
+               };
+
+               timer3: timer@2610000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x08 >;
+                       reg = <0x2610000 0x40>;
+               };
+
+               timer4: timer@2620000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x10 >;
+                       reg = <0x2620000 0x40>;
+               };
+
+               timer5: timer@2630000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x20 >;
+                       reg = <0x2630000 0x40>;
+               };
+
+               clock-controller@29a0000 {
+                       compatible = "ti,c6472-pll", "ti,c64x+pll";
+                       reg = <0x029a0000 0x200>;
+                       ti,c64x+pll-bypass-delay = <200>;
+                       ti,c64x+pll-reset-delay = <12000>;
+                       ti,c64x+pll-lock-delay = <80000>;
+               };
+
+               device-state-controller@2a80000 {
+                       compatible = "ti,c64x+dscr";
+                       reg = <0x02a80000 0x1000>;
+
+                       ti,dscr-devstat = <0>;
+                       ti,dscr-silicon-rev = <0x70c 16 0xff>;
+
+                       ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
+                                                0x704 5 6 0 0>;
+
+                       ti,dscr-rmii-resets = <0x208 1
+                                              0x20c 1>;
+
+                       ti,dscr-locked-regs = <0x200 0x204 0x0a1e183a
+                                              0x40c 0x420 0xbea7
+                                              0x41c 0x420 0xbea7>;
+
+                       ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
+
+                       ti,dscr-devstate-ctl-regs = <0 13 0x200 1 0 0 1>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/dts/tms320c6474.dtsi b/arch/c6x/boot/dts/tms320c6474.dtsi
new file mode 100644 (file)
index 0000000..cc601bf
--- /dev/null
@@ -0,0 +1,89 @@
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       model = "ti,c64x+";
+               };
+               cpu@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       model = "ti,c64x+";
+               };
+               cpu@2 {
+                       device_type = "cpu";
+                       reg = <2>;
+                       model = "ti,c64x+";
+               };
+       };
+
+       soc {
+               compatible = "simple-bus";
+               model = "tms320c6474";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               core_pic: interrupt-controller {
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       compatible = "ti,c64x+core-pic";
+               };
+
+               megamod_pic: interrupt-controller@1800000 {
+                      compatible = "ti,c64x+megamod-pic";
+                      interrupt-controller;
+                      #interrupt-cells = <1>;
+                      reg = <0x1800000 0x1000>;
+                      interrupt-parent = <&core_pic>;
+               };
+
+               cache-controller@1840000 {
+                       compatible = "ti,c64x+cache";
+                       reg = <0x01840000 0x8400>;
+               };
+
+               timer3: timer@2940000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x04 >;
+                       reg = <0x2940000 0x40>;
+               };
+
+               timer4: timer@2950000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x02 >;
+                       reg = <0x2950000 0x40>;
+               };
+
+               timer5: timer@2960000 {
+                       compatible = "ti,c64x+timer64";
+                       ti,core-mask = < 0x01 >;
+                       reg = <0x2960000 0x40>;
+               };
+
+               device-state-controller@2880800 {
+                       compatible = "ti,c64x+dscr";
+                       reg = <0x02880800 0x400>;
+
+                       ti,dscr-devstat = <0x004>;
+                       ti,dscr-silicon-rev = <0x014 28 0xf>;
+                       ti,dscr-mac-fuse-regs = <0x34 3 4 5 6
+                                                0x38 0 0 1 2>;
+               };
+
+               clock-controller@29a0000 {
+                       compatible = "ti,c6474-pll", "ti,c64x+pll";
+                       reg = <0x029a0000 0x200>;
+                       ti,c64x+pll-bypass-delay = <120>;
+                       ti,c64x+pll-reset-delay = <30000>;
+                       ti,c64x+pll-lock-delay = <60000>;
+               };
+       };
+};
diff --git a/arch/c6x/boot/linked_dtb.S b/arch/c6x/boot/linked_dtb.S
new file mode 100644 (file)
index 0000000..57a4454
--- /dev/null
@@ -0,0 +1,2 @@
+.section __fdt_blob,"a"
+.incbin "arch/c6x/boot/builtin.dtb"
diff --git a/arch/c6x/configs/dsk6455_defconfig b/arch/c6x/configs/dsk6455_defconfig
new file mode 100644 (file)
index 0000000..4663487
--- /dev/null
@@ -0,0 +1,44 @@
+CONFIG_SOC_TMS320C6455=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=17000
+CONFIG_MISC_DEVICES=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_CRC16=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_MTD=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
diff --git a/arch/c6x/configs/evmc6457_defconfig b/arch/c6x/configs/evmc6457_defconfig
new file mode 100644 (file)
index 0000000..bba40e1
--- /dev/null
@@ -0,0 +1,41 @@
+CONFIG_SOC_TMS320C6457=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_BOARD_EVM6457=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=17000
+CONFIG_MISC_DEVICES=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_CRC16=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/configs/evmc6472_defconfig b/arch/c6x/configs/evmc6472_defconfig
new file mode 100644 (file)
index 0000000..8c46155
--- /dev/null
@@ -0,0 +1,42 @@
+CONFIG_SOC_TMS320C6472=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_FORCE is not set
+CONFIG_BOARD_EVM6472=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=17000
+CONFIG_MISC_DEVICES=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_CRC16=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/configs/evmc6474_defconfig b/arch/c6x/configs/evmc6474_defconfig
new file mode 100644 (file)
index 0000000..15533f6
--- /dev/null
@@ -0,0 +1,42 @@
+CONFIG_SOC_TMS320C6474=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EXPERT=y
+# CONFIG_FUTEX is not set
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+# CONFIG_CMDLINE_FORCE is not set
+CONFIG_BOARD_EVM6474=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=17000
+CONFIG_MISC_DEVICES=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_CRC16=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
new file mode 100644 (file)
index 0000000..13dcf78
--- /dev/null
@@ -0,0 +1,54 @@
+include include/asm-generic/Kbuild.asm
+
+generic-y += atomic.h
+generic-y += auxvec.h
+generic-y += bitsperlong.h
+generic-y += bug.h
+generic-y += bugs.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += futex.h
+generic-y += hw_irq.h
+generic-y += io.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += local.h
+generic-y += mman.h
+generic-y += mmu_context.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += pgalloc.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += segment.h
+generic-y += sembuf.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += tlbflush.h
+generic-y += topology.h
+generic-y += types.h
+generic-y += ucontext.h
+generic-y += user.h
+generic-y += vga.h
diff --git a/arch/c6x/include/asm/asm-offsets.h b/arch/c6x/include/asm/asm-offsets.h
new file mode 100644 (file)
index 0000000..d370ee3
--- /dev/null
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/c6x/include/asm/bitops.h b/arch/c6x/include/asm/bitops.h
new file mode 100644 (file)
index 0000000..39ab7e8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_BITOPS_H
+#define _ASM_C6X_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit() barrier()
+#define smp_mb__after_clear_bit()  barrier()
+
+/*
+ * We are lucky, DSP is perfect for bitops: do it in 3 cycles
+ */
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ * Note __ffs(0) = undef, __ffs(1) = 0, __ffs(0x80000000) = 31.
+ *
+ */
+static inline unsigned long __ffs(unsigned long x)
+{
+       asm (" bitr  .M1  %0,%0\n"
+            " nop\n"
+            " lmbd  .L1  1,%0,%0\n"
+            : "+a"(x));
+
+       return x;
+}
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+#define ffz(x) __ffs(~(x))
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static inline int fls(int x)
+{
+       if (!x)
+               return 0;
+
+       asm (" lmbd  .L1  1,%0,%0\n" : "+a"(x));
+
+       return 32 - x;
+}
+
+/**
+ * ffs - find first bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ * Note ffs(0) = 0, ffs(1) = 1, ffs(0x80000000) = 32.
+ */
+static inline int ffs(int x)
+{
+       if (!x)
+               return 0;
+
+       return __ffs(x) + 1;
+}
+
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/find.h>
+
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/lock.h>
+
+#include <asm-generic/bitops/atomic.h>
+#include <asm-generic/bitops/non-atomic.h>
+#include <asm-generic/bitops/le.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_C6X_BITOPS_H */
diff --git a/arch/c6x/include/asm/byteorder.h b/arch/c6x/include/asm/byteorder.h
new file mode 100644 (file)
index 0000000..166038d
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_C6X_BYTEORDER_H
+#define _ASM_C6X_BYTEORDER_H
+
+#include <asm/types.h>
+
+#ifdef _BIG_ENDIAN
+#include <linux/byteorder/big_endian.h>
+#else /* _BIG_ENDIAN */
+#include <linux/byteorder/little_endian.h>
+#endif /* _BIG_ENDIAN */
+
+#endif /* _ASM_BYTEORDER_H */
diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h
new file mode 100644 (file)
index 0000000..6d521d9
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_CACHE_H
+#define _ASM_C6X_CACHE_H
+
+#include <linux/irqflags.h>
+
+/*
+ * Cache line size
+ */
+#define L1D_CACHE_BYTES   64
+#define L1P_CACHE_BYTES   32
+#define L2_CACHE_BYTES   128
+
+/*
+ * L2 used as cache
+ */
+#define L2MODE_SIZE      L2MODE_256K_CACHE
+
+/*
+ * For practical reasons the L1_CACHE_BYTES defines should not be smaller than
+ * the L2 line size
+ */
+#define L1_CACHE_BYTES        L2_CACHE_BYTES
+
+#define L2_CACHE_ALIGN_LOW(x) \
+       (((x) & ~(L2_CACHE_BYTES - 1)))
+#define L2_CACHE_ALIGN_UP(x) \
+       (((x) + (L2_CACHE_BYTES - 1)) & ~(L2_CACHE_BYTES - 1))
+#define L2_CACHE_ALIGN_CNT(x) \
+       (((x) + (sizeof(int) - 1)) & ~(sizeof(int) - 1))
+
+#define ARCH_DMA_MINALIGN      L1_CACHE_BYTES
+#define ARCH_SLAB_MINALIGN     L1_CACHE_BYTES
+
+/*
+ * This is the granularity of hardware cacheability control.
+ */
+#define CACHEABILITY_ALIGN     0x01000000
+
+/*
+ * Align a physical address to MAR regions
+ */
+#define CACHE_REGION_START(v) \
+       (((u32) (v)) & ~(CACHEABILITY_ALIGN - 1))
+#define CACHE_REGION_END(v) \
+       (((u32) (v) + (CACHEABILITY_ALIGN - 1)) & ~(CACHEABILITY_ALIGN - 1))
+
+extern void __init c6x_cache_init(void);
+
+extern void enable_caching(unsigned long start, unsigned long end);
+extern void disable_caching(unsigned long start, unsigned long end);
+
+extern void L1_cache_off(void);
+extern void L1_cache_on(void);
+
+extern void L1P_cache_global_invalidate(void);
+extern void L1D_cache_global_invalidate(void);
+extern void L1D_cache_global_writeback(void);
+extern void L1D_cache_global_writeback_invalidate(void);
+extern void L2_cache_set_mode(unsigned int mode);
+extern void L2_cache_global_writeback_invalidate(void);
+extern void L2_cache_global_writeback(void);
+
+extern void L1P_cache_block_invalidate(unsigned int start, unsigned int end);
+extern void L1D_cache_block_invalidate(unsigned int start, unsigned int end);
+extern void L1D_cache_block_writeback_invalidate(unsigned int start,
+                                                unsigned int end);
+extern void L1D_cache_block_writeback(unsigned int start, unsigned int end);
+extern void L2_cache_block_invalidate(unsigned int start, unsigned int end);
+extern void L2_cache_block_writeback(unsigned int start, unsigned int end);
+extern void L2_cache_block_writeback_invalidate(unsigned int start,
+                                               unsigned int end);
+extern void L2_cache_block_invalidate_nowait(unsigned int start,
+                                            unsigned int end);
+extern void L2_cache_block_writeback_nowait(unsigned int start,
+                                           unsigned int end);
+
+extern void L2_cache_block_writeback_invalidate_nowait(unsigned int start,
+                                                      unsigned int end);
+
+#endif /* _ASM_C6X_CACHE_H */
diff --git a/arch/c6x/include/asm/cacheflush.h b/arch/c6x/include/asm/cacheflush.h
new file mode 100644 (file)
index 0000000..df5db90
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_CACHEFLUSH_H
+#define _ASM_C6X_CACHEFLUSH_H
+
+#include <linux/spinlock.h>
+
+#include <asm/setup.h>
+#include <asm/cache.h>
+#include <asm/mman.h>
+#include <asm/page.h>
+#include <asm/string.h>
+
+/*
+ * virtually-indexed cache management (our cache is physically indexed)
+ */
+#define flush_cache_all()                      do {} while (0)
+#define flush_cache_mm(mm)                     do {} while (0)
+#define flush_cache_dup_mm(mm)                 do {} while (0)
+#define flush_cache_range(mm, start, end)      do {} while (0)
+#define flush_cache_page(vma, vmaddr, pfn)     do {} while (0)
+#define flush_cache_vmap(start, end)           do {} while (0)
+#define flush_cache_vunmap(start, end)         do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+#define flush_dcache_page(page)                        do {} while (0)
+#define flush_dcache_mmap_lock(mapping)                do {} while (0)
+#define flush_dcache_mmap_unlock(mapping)      do {} while (0)
+
+/*
+ * physically-indexed cache management
+ */
+#define flush_icache_range(s, e)                                 \
+do {                                                             \
+               L1D_cache_block_writeback((s), (e));              \
+               L1P_cache_block_invalidate((s), (e));             \
+} while (0)
+
+#define flush_icache_page(vma, page)                                     \
+do {                                                             \
+       if ((vma)->vm_flags & PROT_EXEC)                                  \
+               L1D_cache_block_writeback_invalidate(page_address(page),  \
+                       (unsigned long) page_address(page) + PAGE_SIZE)); \
+               L1P_cache_block_invalidate(page_address(page),            \
+                       (unsigned long) page_address(page) + PAGE_SIZE)); \
+} while (0)
+
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+do {                                                \
+       memcpy(dst, src, len);                       \
+       flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
+} while (0)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+
+#endif /* _ASM_C6X_CACHEFLUSH_H */
diff --git a/arch/c6x/include/asm/checksum.h b/arch/c6x/include/asm/checksum.h
new file mode 100644 (file)
index 0000000..7246816
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_CHECKSUM_H
+#define _ASM_C6X_CHECKSUM_H
+
+static inline __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+                  unsigned short proto, __wsum sum)
+{
+       unsigned long long tmp;
+
+       asm ("add     .d1   %1,%5,%1\n"
+            "|| addu .l1   %3,%4,%0\n"
+            "addu    .l1   %2,%0,%0\n"
+#ifndef CONFIG_CPU_BIG_ENDIAN
+            "|| shl  .s1   %1,8,%1\n"
+#endif
+            "addu    .l1   %1,%0,%0\n"
+            "add     .l1   %P0,%p0,%2\n"
+            : "=&a"(tmp), "+a"(len), "+a"(sum)
+            : "a" (saddr), "a" (daddr), "a" (proto));
+       return sum;
+}
+#define csum_tcpudp_nofold csum_tcpudp_nofold
+
+#include <asm-generic/checksum.h>
+
+#endif /* _ASM_C6X_CHECKSUM_H */
diff --git a/arch/c6x/include/asm/clkdev.h b/arch/c6x/include/asm/clkdev.h
new file mode 100644 (file)
index 0000000..76a070b
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _ASM_CLKDEV_H
+#define _ASM_CLKDEV_H
+
+#include <linux/slab.h>
+
+struct clk;
+
+static inline int __clk_get(struct clk *clk)
+{
+       return 1;
+}
+
+static inline void __clk_put(struct clk *clk)
+{
+}
+
+static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
+{
+       return kzalloc(size, GFP_KERNEL);
+}
+
+#endif /* _ASM_CLKDEV_H */
diff --git a/arch/c6x/include/asm/clock.h b/arch/c6x/include/asm/clock.h
new file mode 100644 (file)
index 0000000..bcf42b2
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * TI C64X clock definitions
+ *
+ * Copyright (C) 2010, 2011 Texas Instruments.
+ * Contributed by: Mark Salter <msalter@redhat.com>
+ *
+ * Copied heavily from arm/mach-davinci/clock.h, so:
+ *
+ * Copyright (C) 2006-2007 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * This program is free software; you can 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_C6X_CLOCK_H
+#define _ASM_C6X_CLOCK_H
+
+#ifndef __ASSEMBLER__
+
+#include <linux/list.h>
+
+/* PLL/Reset register offsets */
+#define PLLCTL         0x100
+#define PLLM           0x110
+#define PLLPRE         0x114
+#define PLLDIV1                0x118
+#define PLLDIV2                0x11c
+#define PLLDIV3                0x120
+#define PLLPOST                0x128
+#define PLLCMD         0x138
+#define PLLSTAT                0x13c
+#define PLLALNCTL      0x140
+#define PLLDCHANGE     0x144
+#define PLLCKEN                0x148
+#define PLLCKSTAT      0x14c
+#define PLLSYSTAT      0x150
+#define PLLDIV4                0x160
+#define PLLDIV5                0x164
+#define PLLDIV6                0x168
+#define PLLDIV7                0x16c
+#define PLLDIV8                0x170
+#define PLLDIV9                0x174
+#define PLLDIV10       0x178
+#define PLLDIV11       0x17c
+#define PLLDIV12       0x180
+#define PLLDIV13       0x184
+#define PLLDIV14       0x188
+#define PLLDIV15       0x18c
+#define PLLDIV16       0x190
+
+/* PLLM register bits */
+#define PLLM_PLLM_MASK 0xff
+#define PLLM_VAL(x)    ((x) - 1)
+
+/* PREDIV register bits */
+#define PLLPREDIV_EN   BIT(15)
+#define PLLPREDIV_VAL(x) ((x) - 1)
+
+/* PLLCTL register bits */
+#define PLLCTL_PLLEN   BIT(0)
+#define PLLCTL_PLLPWRDN        BIT(1)
+#define PLLCTL_PLLRST  BIT(3)
+#define PLLCTL_PLLDIS  BIT(4)
+#define PLLCTL_PLLENSRC        BIT(5)
+#define PLLCTL_CLKMODE BIT(8)
+
+/* PLLCMD register bits */
+#define PLLCMD_GOSTAT  BIT(0)
+
+/* PLLSTAT register bits */
+#define PLLSTAT_GOSTAT BIT(0)
+
+/* PLLDIV register bits */
+#define PLLDIV_EN      BIT(15)
+#define PLLDIV_RATIO_MASK 0x1f
+#define PLLDIV_RATIO(x) ((x) - 1)
+
+struct pll_data;
+
+struct clk {
+       struct list_head        node;
+       struct module           *owner;
+       const char              *name;
+       unsigned long           rate;
+       int                     usecount;
+       u32                     flags;
+       struct clk              *parent;
+       struct list_head        children;       /* list of children */
+       struct list_head        childnode;      /* parent's child list node */
+       struct pll_data         *pll_data;
+       u32                     div;
+       unsigned long (*recalc) (struct clk *);
+       int (*set_rate) (struct clk *clk, unsigned long rate);
+       int (*round_rate) (struct clk *clk, unsigned long rate);
+};
+
+/* Clock flags: SoC-specific flags start at BIT(16) */
+#define ALWAYS_ENABLED         BIT(1)
+#define CLK_PLL                        BIT(2) /* PLL-derived clock */
+#define PRE_PLL                        BIT(3) /* source is before PLL mult/div */
+#define FIXED_DIV_PLL          BIT(4) /* fixed divisor from PLL */
+#define FIXED_RATE_PLL         BIT(5) /* fixed ouput rate PLL */
+
+#define MAX_PLL_SYSCLKS 16
+
+struct pll_data {
+       void __iomem *base;
+       u32 num;
+       u32 flags;
+       u32 input_rate;
+       u32 bypass_delay; /* in loops */
+       u32 reset_delay;  /* in loops */
+       u32 lock_delay;   /* in loops */
+       struct clk sysclks[MAX_PLL_SYSCLKS + 1];
+};
+
+/* pll_data flag bit */
+#define PLL_HAS_PRE    BIT(0)
+#define PLL_HAS_MUL    BIT(1)
+#define PLL_HAS_POST   BIT(2)
+
+#define CLK(dev, con, ck)      \
+       {                       \
+               .dev_id = dev,  \
+               .con_id = con,  \
+               .clk = ck,      \
+       }                       \
+
+extern void c6x_clks_init(struct clk_lookup *clocks);
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
+extern void c64x_setup_clocks(void);
+
+extern struct pll_data c6x_soc_pll1;
+
+extern struct clk clkin1;
+extern struct clk c6x_core_clk;
+extern struct clk c6x_i2c_clk;
+extern struct clk c6x_watchdog_clk;
+extern struct clk c6x_mcbsp1_clk;
+extern struct clk c6x_mcbsp2_clk;
+extern struct clk c6x_mdio_clk;
+
+#endif
+
+#endif /* _ASM_C6X_CLOCK_H */
diff --git a/arch/c6x/include/asm/delay.h b/arch/c6x/include/asm/delay.h
new file mode 100644 (file)
index 0000000..f314c2e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_DELAY_H
+#define _ASM_C6X_DELAY_H
+
+#include <linux/kernel.h>
+
+extern unsigned int ticks_per_ns_scaled;
+
+static inline void __delay(unsigned long loops)
+{
+       uint32_t tmp;
+
+       /* 6 cycles per loop */
+       asm volatile ("        mv    .s1  %0,%1\n"
+                     "0: [%1] b     .s1  0b\n"
+                     "        add   .l1  -6,%0,%0\n"
+                     "        cmplt .l1  1,%0,%1\n"
+                     "        nop   3\n"
+                     : "+a"(loops), "=A"(tmp));
+}
+
+static inline void _c6x_tickdelay(unsigned int x)
+{
+       uint32_t cnt, endcnt;
+
+       asm volatile ("        mvc   .s2   TSCL,%0\n"
+                     "        add   .s2x  %0,%1,%2\n"
+                     " ||     mvk   .l2   1,B0\n"
+                     "0: [B0] b     .s2   0b\n"
+                     "        mvc   .s2   TSCL,%0\n"
+                     "        sub   .s2   %0,%2,%0\n"
+                     "        cmpgt .l2   0,%0,B0\n"
+                     "        nop   2\n"
+                     : "=b"(cnt), "+a"(x), "=b"(endcnt) : : "B0");
+}
+
+/* use scaled math to avoid slow division */
+#define C6X_NDELAY_SCALE 10
+
+static inline void _ndelay(unsigned int n)
+{
+       _c6x_tickdelay((ticks_per_ns_scaled * n) >> C6X_NDELAY_SCALE);
+}
+
+static inline void _udelay(unsigned int n)
+{
+       while (n >= 10) {
+               _ndelay(10000);
+               n -= 10;
+       }
+       while (n-- > 0)
+               _ndelay(1000);
+}
+
+#define udelay(x) _udelay((unsigned int)(x))
+#define ndelay(x) _ndelay((unsigned int)(x))
+
+#endif /* _ASM_C6X_DELAY_H */
diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h
new file mode 100644 (file)
index 0000000..03579fd
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot <aurelien.jacquiot@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.
+ *
+ */
+#ifndef _ASM_C6X_DMA_MAPPING_H
+#define _ASM_C6X_DMA_MAPPING_H
+
+#include <linux/dma-debug.h>
+#include <asm-generic/dma-coherent.h>
+
+#define dma_supported(d, m)    1
+
+static inline int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+               return -EIO;
+
+       *dev->dma_mask = dma_mask;
+
+       return 0;
+}
+
+/*
+ * DMA errors are defined by all-bits-set in the DMA address.
+ */
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return dma_addr == ~0;
+}
+
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                                size_t size, enum dma_data_direction dir);
+
+extern void dma_unmap_single(struct device *dev, dma_addr_t handle,
+                            size_t size, enum dma_data_direction dir);
+
+extern int dma_map_sg(struct device *dev, struct scatterlist *sglist,
+                     int nents, enum dma_data_direction direction);
+
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                        int nents, enum dma_data_direction direction);
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction dir)
+{
+       dma_addr_t handle;
+
+       handle = dma_map_single(dev, page_address(page) + offset, size, dir);
+
+       debug_dma_map_page(dev, page, offset, size, dir, handle, false);
+
+       return handle;
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
+               size_t size, enum dma_data_direction dir)
+{
+       dma_unmap_single(dev, handle, size, dir);
+
+       debug_dma_unmap_page(dev, handle, size, dir, false);
+}
+
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+                                   size_t size, enum dma_data_direction dir);
+
+extern void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+                                      size_t size,
+                                      enum dma_data_direction dir);
+
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                               int nents, enum dma_data_direction dir);
+
+extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+                                  int nents, enum dma_data_direction dir);
+
+extern void coherent_mem_init(u32 start, u32 size);
+extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
+extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
+#define dma_free_noncoherent(d, s, v, h)  dma_free_coherent((d), (s), (v), (h))
+
+#endif /* _ASM_C6X_DMA_MAPPING_H */
diff --git a/arch/c6x/include/asm/dscr.h b/arch/c6x/include/asm/dscr.h
new file mode 100644 (file)
index 0000000..561ba83
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+#ifndef _ASM_C6X_DSCR_H
+#define _ASM_C6X_DSCR_H
+
+enum dscr_devstate_t {
+       DSCR_DEVSTATE_ENABLED,
+       DSCR_DEVSTATE_DISABLED,
+};
+
+/*
+ * Set the device state of the device with the given ID.
+ *
+ * Individual drivers should use this to enable or disable the
+ * hardware device. The devid used to identify the device being
+ * controlled should be a property in the device's tree node.
+ */
+extern void dscr_set_devstate(int devid, enum dscr_devstate_t state);
+
+/*
+ * Assert or de-assert an RMII reset.
+ */
+extern void dscr_rmii_reset(int id, int assert);
+
+extern void dscr_probe(void);
+
+#endif /* _ASM_C6X_DSCR_H */
diff --git a/arch/c6x/include/asm/elf.h b/arch/c6x/include/asm/elf.h
new file mode 100644 (file)
index 0000000..d57865b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_ELF_H
+#define _ASM_C6X_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+#include <asm/ptrace.h>
+
+typedef unsigned long elf_greg_t;
+typedef unsigned long elf_fpreg_t;
+
+#define ELF_NGREG  58
+#define ELF_NFPREG 1
+
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_TI_C6000)
+
+#define elf_check_const_displacement(x) (1)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#ifdef __LITTLE_ENDIAN__
+#define ELF_DATA       ELFDATA2LSB
+#else
+#define ELF_DATA       ELFDATA2MSB
+#endif
+
+#define ELF_CLASS      ELFCLASS32
+#define ELF_ARCH       EM_TI_C6000
+
+/* Nothing for now. Need to setup DP... */
+#define ELF_PLAT_INIT(_r)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE      4096
+
+#define ELF_CORE_COPY_REGS(_dest, _regs)               \
+       memcpy((char *) &_dest, (char *) _regs,         \
+       sizeof(struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  */
+
+#define ELF_HWCAP      (0)
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo.  */
+
+#define ELF_PLATFORM  (NULL)
+
+#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
+
+/* C6X specific section types */
+#define SHT_C6000_UNWIND       0x70000001
+#define SHT_C6000_PREEMPTMAP   0x70000002
+#define SHT_C6000_ATTRIBUTES   0x70000003
+
+/* C6X specific DT_ tags */
+#define DT_C6000_DSBT_BASE     0x70000000
+#define DT_C6000_DSBT_SIZE     0x70000001
+#define DT_C6000_PREEMPTMAP    0x70000002
+#define DT_C6000_DSBT_INDEX    0x70000003
+
+/* C6X specific relocs */
+#define R_C6000_NONE           0
+#define R_C6000_ABS32          1
+#define R_C6000_ABS16          2
+#define R_C6000_ABS8           3
+#define R_C6000_PCR_S21                4
+#define R_C6000_PCR_S12                5
+#define R_C6000_PCR_S10                6
+#define R_C6000_PCR_S7         7
+#define R_C6000_ABS_S16                8
+#define R_C6000_ABS_L16                9
+#define R_C6000_ABS_H16                10
+#define R_C6000_SBR_U15_B      11
+#define R_C6000_SBR_U15_H      12
+#define R_C6000_SBR_U15_W      13
+#define R_C6000_SBR_S16                14
+#define R_C6000_SBR_L16_B      15
+#define R_C6000_SBR_L16_H      16
+#define R_C6000_SBR_L16_W      17
+#define R_C6000_SBR_H16_B      18
+#define R_C6000_SBR_H16_H      19
+#define R_C6000_SBR_H16_W      20
+#define R_C6000_SBR_GOT_U15_W  21
+#define R_C6000_SBR_GOT_L16_W  22
+#define R_C6000_SBR_GOT_H16_W  23
+#define R_C6000_DSBT_INDEX     24
+#define R_C6000_PREL31         25
+#define R_C6000_COPY           26
+#define R_C6000_ALIGN          253
+#define R_C6000_FPHEAD         254
+#define R_C6000_NOCMP          255
+
+#endif /*_ASM_C6X_ELF_H */
diff --git a/arch/c6x/include/asm/ftrace.h b/arch/c6x/include/asm/ftrace.h
new file mode 100644 (file)
index 0000000..3701958
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_C6X_FTRACE_H
+#define _ASM_C6X_FTRACE_H
+
+/* empty */
+
+#endif /* _ASM_C6X_FTRACE_H */
diff --git a/arch/c6x/include/asm/hardirq.h b/arch/c6x/include/asm/hardirq.h
new file mode 100644 (file)
index 0000000..9621954
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_C6X_HARDIRQ_H
+#define _ASM_C6X_HARDIRQ_H
+
+extern void ack_bad_irq(int irq);
+#define ack_bad_irq ack_bad_irq
+
+#include <asm-generic/hardirq.h>
+
+#endif /* _ASM_C6X_HARDIRQ_H */
diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h
new file mode 100644 (file)
index 0000000..a6ae3c9
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Large parts taken directly from powerpc.
+ *
+ *  This program is free software; you can 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_C6X_IRQ_H
+#define _ASM_C6X_IRQ_H
+
+#include <linux/threads.h>
+#include <linux/list.h>
+#include <linux/radix-tree.h>
+#include <asm/percpu.h>
+
+#define irq_canonicalize(irq)  (irq)
+
+/*
+ * The C64X+ core has 16 IRQ vectors. One each is used by Reset and NMI. Two
+ * are reserved. The remaining 12 vectors are used to route SoC interrupts.
+ * These interrupt vectors are prioritized with IRQ 4 having the highest
+ * priority and IRQ 15 having the lowest.
+ *
+ * The C64x+ megamodule provides a PIC which combines SoC IRQ sources into a
+ * single core IRQ vector. There are four combined sources, each of which
+ * feed into one of the 12 general interrupt vectors. The remaining 8 vectors
+ * can each route a single SoC interrupt directly.
+ */
+#define NR_PRIORITY_IRQS 16
+
+#define NR_IRQS_LEGACY NR_PRIORITY_IRQS
+
+/* Total number of virq in the platform */
+#define NR_IRQS                256
+
+/* This number is used when no interrupt has been assigned */
+#define NO_IRQ         0
+
+/* This type is the placeholder for a hardware interrupt number. It has to
+ * be big enough to enclose whatever representation is used by a given
+ * platform.
+ */
+typedef unsigned long irq_hw_number_t;
+
+/* Interrupt controller "host" data structure. This could be defined as a
+ * irq domain controller. That is, it handles the mapping between hardware
+ * and virtual interrupt numbers for a given interrupt domain. The host
+ * structure is generally created by the PIC code for a given PIC instance
+ * (though a host can cover more than one PIC if they have a flat number
+ * model). It's the host callbacks that are responsible for setting the
+ * irq_chip on a given irq_desc after it's been mapped.
+ *
+ * The host code and data structures are fairly agnostic to the fact that
+ * we use an open firmware device-tree. We do have references to struct
+ * device_node in two places: in irq_find_host() to find the host matching
+ * a given interrupt controller node, and of course as an argument to its
+ * counterpart host->ops->match() callback. However, those are treated as
+ * generic pointers by the core and the fact that it's actually a device-node
+ * pointer is purely a convention between callers and implementation. This
+ * code could thus be used on other architectures by replacing those two
+ * by some sort of arch-specific void * "token" used to identify interrupt
+ * controllers.
+ */
+struct irq_host;
+struct radix_tree_root;
+struct device_node;
+
+/* Functions below are provided by the host and called whenever a new mapping
+ * is created or an old mapping is disposed. The host can then proceed to
+ * whatever internal data structures management is required. It also needs
+ * to setup the irq_desc when returning from map().
+ */
+struct irq_host_ops {
+       /* Match an interrupt controller device node to a host, returns
+        * 1 on a match
+        */
+       int (*match)(struct irq_host *h, struct device_node *node);
+
+       /* Create or update a mapping between a virtual irq number and a hw
+        * irq number. This is called only once for a given mapping.
+        */
+       int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
+
+       /* Dispose of such a mapping */
+       void (*unmap)(struct irq_host *h, unsigned int virq);
+
+       /* Translate device-tree interrupt specifier from raw format coming
+        * from the firmware to a irq_hw_number_t (interrupt line number) and
+        * type (sense) that can be passed to set_irq_type(). In the absence
+        * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
+        * will return the hw number in the first cell and IRQ_TYPE_NONE for
+        * the type (which amount to keeping whatever default value the
+        * interrupt controller has for that line)
+        */
+       int (*xlate)(struct irq_host *h, struct device_node *ctrler,
+                    const u32 *intspec, unsigned int intsize,
+                    irq_hw_number_t *out_hwirq, unsigned int *out_type);
+};
+
+struct irq_host {
+       struct list_head        link;
+
+       /* type of reverse mapping technique */
+       unsigned int            revmap_type;
+#define IRQ_HOST_MAP_PRIORITY   0 /* core priority irqs, get irqs 1..15 */
+#define IRQ_HOST_MAP_NOMAP     1 /* no fast reverse mapping */
+#define IRQ_HOST_MAP_LINEAR    2 /* linear map of interrupts */
+#define IRQ_HOST_MAP_TREE      3 /* radix tree */
+       union {
+               struct {
+                       unsigned int size;
+                       unsigned int *revmap;
+               } linear;
+               struct radix_tree_root tree;
+       } revmap_data;
+       struct irq_host_ops     *ops;
+       void                    *host_data;
+       irq_hw_number_t         inval_irq;
+
+       /* Optional device node pointer */
+       struct device_node      *of_node;
+};
+
+struct irq_data;
+extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
+extern irq_hw_number_t virq_to_hw(unsigned int virq);
+extern bool virq_is_host(unsigned int virq, struct irq_host *host);
+
+/**
+ * irq_alloc_host - Allocate a new irq_host data structure
+ * @of_node: optional device-tree node of the interrupt controller
+ * @revmap_type: type of reverse mapping to use
+ * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
+ * @ops: map/unmap host callbacks
+ * @inval_irq: provide a hw number in that host space that is always invalid
+ *
+ * Allocates and initialize and irq_host structure. Note that in the case of
+ * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
+ * for all legacy interrupts except 0 (which is always the invalid irq for
+ * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
+ * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
+ * later during boot automatically (the reverse mapping will use the slow path
+ * until that happens).
+ */
+extern struct irq_host *irq_alloc_host(struct device_node *of_node,
+                                      unsigned int revmap_type,
+                                      unsigned int revmap_arg,
+                                      struct irq_host_ops *ops,
+                                      irq_hw_number_t inval_irq);
+
+
+/**
+ * irq_find_host - Locates a host for a given device node
+ * @node: device-tree node of the interrupt controller
+ */
+extern struct irq_host *irq_find_host(struct device_node *node);
+
+
+/**
+ * irq_set_default_host - Set a "default" host
+ * @host: default host pointer
+ *
+ * For convenience, it's possible to set a "default" host that will be used
+ * whenever NULL is passed to irq_create_mapping(). It makes life easier for
+ * platforms that want to manipulate a few hard coded interrupt numbers that
+ * aren't properly represented in the device-tree.
+ */
+extern void irq_set_default_host(struct irq_host *host);
+
+
+/**
+ * irq_set_virq_count - Set the maximum number of virt irqs
+ * @count: number of linux virtual irqs, capped with NR_IRQS
+ *
+ * This is mainly for use by platforms like iSeries who want to program
+ * the virtual irq number in the controller to avoid the reverse mapping
+ */
+extern void irq_set_virq_count(unsigned int count);
+
+
+/**
+ * irq_create_mapping - Map a hardware interrupt into linux virq space
+ * @host: host owning this hardware interrupt or NULL for default host
+ * @hwirq: hardware irq number in that host space
+ *
+ * Only one mapping per hardware interrupt is permitted. Returns a linux
+ * virq number.
+ * If the sense/trigger is to be specified, set_irq_type() should be called
+ * on the number returned from that call.
+ */
+extern unsigned int irq_create_mapping(struct irq_host *host,
+                                      irq_hw_number_t hwirq);
+
+
+/**
+ * irq_dispose_mapping - Unmap an interrupt
+ * @virq: linux virq number of the interrupt to unmap
+ */
+extern void irq_dispose_mapping(unsigned int virq);
+
+/**
+ * irq_find_mapping - Find a linux virq from an hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is a slow path, for use by generic code. It's expected that an
+ * irq controller implementation directly calls the appropriate low level
+ * mapping function.
+ */
+extern unsigned int irq_find_mapping(struct irq_host *host,
+                                    irq_hw_number_t hwirq);
+
+/**
+ * irq_create_direct_mapping - Allocate a virq for direct mapping
+ * @host: host to allocate the virq for or NULL for default host
+ *
+ * This routine is used for irq controllers which can choose the hardware
+ * interrupt numbers they generate. In such a case it's simplest to use
+ * the linux virq as the hardware interrupt number.
+ */
+extern unsigned int irq_create_direct_mapping(struct irq_host *host);
+
+/**
+ * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
+ * @host: host owning this hardware interrupt
+ * @virq: linux irq number
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is for use by irq controllers that use a radix tree reverse
+ * mapping for fast lookup.
+ */
+extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+                                   irq_hw_number_t hwirq);
+
+/**
+ * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is a fast path, for use by irq controller code that uses radix tree
+ * revmaps
+ */
+extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+                                           irq_hw_number_t hwirq);
+
+/**
+ * irq_linear_revmap - Find a linux virq from a hw irq number.
+ * @host: host owning this hardware interrupt
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is a fast path, for use by irq controller code that uses linear
+ * revmaps. It does fallback to the slow path if the revmap doesn't exist
+ * yet and will create the revmap entry with appropriate locking
+ */
+
+extern unsigned int irq_linear_revmap(struct irq_host *host,
+                                     irq_hw_number_t hwirq);
+
+
+
+/**
+ * irq_alloc_virt - Allocate virtual irq numbers
+ * @host: host owning these new virtual irqs
+ * @count: number of consecutive numbers to allocate
+ * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
+ *
+ * This is a low level function that is used internally by irq_create_mapping()
+ * and that can be used by some irq controllers implementations for things
+ * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
+ */
+extern unsigned int irq_alloc_virt(struct irq_host *host,
+                                  unsigned int count,
+                                  unsigned int hint);
+
+/**
+ * irq_free_virt - Free virtual irq numbers
+ * @virq: virtual irq number of the first interrupt to free
+ * @count: number of interrupts to free
+ *
+ * This function is the opposite of irq_alloc_virt. It will not clear reverse
+ * maps, this should be done previously by unmap'ing the interrupt. In fact,
+ * all interrupts covered by the range being freed should have been unmapped
+ * prior to calling this.
+ */
+extern void irq_free_virt(unsigned int virq, unsigned int count);
+
+extern void __init init_pic_c64xplus(void);
+
+extern void init_IRQ(void);
+
+struct pt_regs;
+
+extern asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs);
+
+extern unsigned long irq_err_count;
+
+#endif /* _ASM_C6X_IRQ_H */
diff --git a/arch/c6x/include/asm/irqflags.h b/arch/c6x/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..cf78e09
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  C6X IRQ flag handling
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#ifndef __ASSEMBLY__
+
+/* read interrupt enabled status */
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+
+       asm volatile (" mvc .s2 CSR,%0\n" : "=b"(flags));
+       return flags;
+}
+
+/* set interrupt enabled status */
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags));
+}
+
+/* unconditionally enable interrupts */
+static inline void arch_local_irq_enable(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       flags |= 1;
+       arch_local_irq_restore(flags);
+}
+
+/* unconditionally disable interrupts */
+static inline void arch_local_irq_disable(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       flags &= ~1;
+       arch_local_irq_restore(flags);
+}
+
+/* get status and disable interrupts */
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+
+       flags = arch_local_save_flags();
+       arch_local_irq_restore(flags & ~1);
+       return flags;
+}
+
+/* test flags */
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & 1) == 0;
+}
+
+/* test hardware interrupt enable bit */
+static inline int arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_IRQFLAGS_H */
diff --git a/arch/c6x/include/asm/linkage.h b/arch/c6x/include/asm/linkage.h
new file mode 100644 (file)
index 0000000..376925c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _ASM_C6X_LINKAGE_H
+#define _ASM_C6X_LINKAGE_H
+
+#ifdef __ASSEMBLER__
+
+#define __ALIGN                .align 2
+#define __ALIGN_STR    ".align 2"
+
+#ifndef __DSBT__
+#define ENTRY(name)            \
+       .global name @          \
+       __ALIGN @               \
+name:
+#else
+#define ENTRY(name)            \
+       .global name @          \
+       .hidden name @          \
+       __ALIGN @               \
+name:
+#endif
+
+#define ENDPROC(name)          \
+       .type name, @function @ \
+       .size name, . - name
+
+#endif
+
+#include <asm-generic/linkage.h>
+
+#endif /* _ASM_C6X_LINKAGE_H */
diff --git a/arch/c6x/include/asm/megamod-pic.h b/arch/c6x/include/asm/megamod-pic.h
new file mode 100644 (file)
index 0000000..eca0a86
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _C6X_MEGAMOD_PIC_H
+#define _C6X_MEGAMOD_PIC_H
+
+#ifdef __KERNEL__
+
+extern void __init megamod_pic_init(void);
+
+#endif /* __KERNEL__ */
+#endif /* _C6X_MEGAMOD_PIC_H */
diff --git a/arch/c6x/include/asm/mmu.h b/arch/c6x/include/asm/mmu.h
new file mode 100644 (file)
index 0000000..41592bf
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_MMU_H
+#define _ASM_C6X_MMU_H
+
+typedef struct {
+       unsigned long           end_brk;
+} mm_context_t;
+
+#endif /* _ASM_C6X_MMU_H */
diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h
new file mode 100644 (file)
index 0000000..a453f97
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.34 by: Mark Salter (msalter@redhat.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_MODULE_H
+#define _ASM_C6X_MODULE_H
+
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Sym                Elf32_Sym
+#define Elf_Ehdr       Elf32_Ehdr
+#define Elf_Addr       Elf32_Addr
+#define Elf_Word       Elf32_Word
+
+/*
+ * This file contains the C6x architecture specific module code.
+ */
+struct mod_arch_specific {
+};
+
+struct loaded_sections {
+       unsigned int new_vaddr;
+       unsigned int loaded;
+};
+
+#endif /* _ASM_C6X_MODULE_H */
diff --git a/arch/c6x/include/asm/mutex.h b/arch/c6x/include/asm/mutex.h
new file mode 100644 (file)
index 0000000..7a7248e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_C6X_MUTEX_H
+#define _ASM_C6X_MUTEX_H
+
+#include <asm-generic/mutex-null.h>
+
+#endif /* _ASM_C6X_MUTEX_H */
diff --git a/arch/c6x/include/asm/page.h b/arch/c6x/include/asm/page.h
new file mode 100644 (file)
index 0000000..d18e2b0
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_C6X_PAGE_H
+#define _ASM_C6X_PAGE_H
+
+#define VM_DATA_DEFAULT_FLAGS \
+       (VM_READ | VM_WRITE | \
+       ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#include <asm-generic/page.h>
+
+#endif /* _ASM_C6X_PAGE_H */
diff --git a/arch/c6x/include/asm/pgtable.h b/arch/c6x/include/asm/pgtable.h
new file mode 100644 (file)
index 0000000..68c8af4
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_PGTABLE_H
+#define _ASM_C6X_PGTABLE_H
+
+#include <asm-generic/4level-fixup.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define        VMALLOC_START   0
+#define        VMALLOC_END     0xffffffff
+
+#define pgd_present(pgd)       (1)
+#define pgd_none(pgd)          (0)
+#define pgd_bad(pgd)           (0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr) (1)
+
+#define pmd_offset(a, b)       ((void *)0)
+#define pmd_none(x)            (!pmd_val(x))
+#define pmd_present(x)         (pmd_val(x))
+#define pmd_clear(xp)          do { set_pmd(xp, __pmd(0)); } while (0)
+#define pmd_bad(x)             (pmd_val(x) & ~PAGE_MASK)
+
+#define PAGE_NONE              __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_SHARED            __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_COPY              __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_READONLY          __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_KERNEL            __pgprot(0)    /* these mean nothing to NO_MM */
+#define pgprot_noncached(prot) (prot)
+
+extern void paging_init(void);
+
+#define __swp_type(x)          (0)
+#define __swp_offset(x)                (0)
+#define __swp_entry(typ, off)  ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
+
+static inline int pte_file(pte_t pte)
+{
+       return 0;
+}
+
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr)       virt_to_page(empty_zero_page)
+extern unsigned long empty_zero_page;
+
+#define swapper_pg_dir ((pgd_t *) 0)
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()   do { } while (0)
+#define io_remap_pfn_range      remap_pfn_range
+
+#define io_remap_page_range(vma, vaddr, paddr, size, prot)             \
+               remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
+
+#include <asm-generic/pgtable.h>
+
+#endif /* _ASM_C6X_PGTABLE_H */
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
new file mode 100644 (file)
index 0000000..8154c4e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.34: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_PROCESSOR_H
+#define _ASM_C6X_PROCESSOR_H
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/current.h>
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr()                    \
+({                                             \
+       void *__pc;                             \
+       asm("mvc .S2 pce1,%0\n" : "=b"(__pc));  \
+       __pc;                                   \
+})
+
+/*
+ * User space process size. This is mostly meaningless for NOMMU
+ * but some C6X processors may have RAM addresses up to 0xFFFFFFFF.
+ * Since calls like mmap() can return an address or an error, we
+ * have to allow room for error returns when code does something
+ * like:
+ *
+ *       addr = do_mmap(...)
+ *       if ((unsigned long)addr >= TASK_SIZE)
+ *            ... its an error code, not an address ...
+ *
+ * Here, we allow for 4096 error codes which means we really can't
+ * use the last 4K page on systems with RAM extending all the way
+ * to the end of the 32-bit address space.
+ */
+#define TASK_SIZE      0xFFFFF000
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's. We won't be using it
+ */
+#define TASK_UNMAPPED_BASE     0
+
+struct thread_struct {
+       unsigned long long b15_14;
+       unsigned long long a15_14;
+       unsigned long long b13_12;
+       unsigned long long a13_12;
+       unsigned long long b11_10;
+       unsigned long long a11_10;
+       unsigned long long ricl_icl;
+       unsigned long  usp;             /* user stack pointer */
+       unsigned long  pc;              /* kernel pc */
+       unsigned long  wchan;
+};
+
+#define INIT_THREAD                                    \
+{                                                      \
+       .usp = 0,                                       \
+       .wchan = 0,                                     \
+}
+
+#define INIT_MMAP { \
+       &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, \
+       NULL, NULL }
+
+#define task_pt_regs(task) \
+       ((struct pt_regs *)(THREAD_START_SP + task_stack_page(task)) - 1)
+
+#define alloc_kernel_stack()   __get_free_page(GFP_KERNEL)
+#define free_kernel_stack(page) free_page((page))
+
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+extern void start_thread(struct pt_regs *regs, unsigned int pc,
+                        unsigned long usp);
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk)   do { } while (0)
+
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+#define copy_segments(tsk, mm)         do { } while (0)
+#define release_segments(mm)           do { } while (0)
+
+/*
+ * saved PC of a blocked thread.
+ */
+#define thread_saved_pc(tsk) (task_pt_regs(tsk)->pc)
+
+/*
+ * saved kernel SP and DP of a blocked thread.
+ */
+#ifdef _BIG_ENDIAN
+#define thread_saved_ksp(tsk) \
+       (*(unsigned long *)&(tsk)->thread.b15_14)
+#define thread_saved_dp(tsk) \
+       (*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
+#else
+#define thread_saved_ksp(tsk) \
+       (*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
+#define thread_saved_dp(tsk) \
+       (*(unsigned long *)&(tsk)->thread.b15_14)
+#endif
+
+extern unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk)  (task_pt_regs(task)->pc)
+#define        KSTK_ESP(tsk)   (task_pt_regs(task)->sp)
+
+#define cpu_relax()            do { } while (0)
+
+extern const struct seq_operations cpuinfo_op;
+
+#endif /* ASM_C6X_PROCESSOR_H */
diff --git a/arch/c6x/include/asm/procinfo.h b/arch/c6x/include/asm/procinfo.h
new file mode 100644 (file)
index 0000000..c139d1e
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2010 Texas Instruments Incorporated
+ *  Author: Mark Salter (msalter@redhat.com)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_PROCINFO_H
+#define _ASM_C6X_PROCINFO_H
+
+#ifdef __KERNEL__
+
+struct proc_info_list {
+       unsigned int            cpu_val;
+       unsigned int            cpu_mask;
+       const char              *arch_name;
+       const char              *elf_name;
+       unsigned int            elf_hwcap;
+};
+
+#else  /* __KERNEL__ */
+#include <asm/elf.h>
+#warning "Please include asm/elf.h instead"
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_C6X_PROCINFO_H */
diff --git a/arch/c6x/include/asm/prom.h b/arch/c6x/include/asm/prom.h
new file mode 100644 (file)
index 0000000..b4ec95f
--- /dev/null
@@ -0,0 +1 @@
+/* dummy prom.h; here to make linux/of.h's #includes happy */
diff --git a/arch/c6x/include/asm/ptrace.h b/arch/c6x/include/asm/ptrace.h
new file mode 100644 (file)
index 0000000..21e8d79
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  Copyright (C) 2004, 2006, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.34: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_PTRACE_H
+#define _ASM_C6X_PTRACE_H
+
+#define BKPT_OPCODE    0x56454314      /* illegal opcode */
+
+#ifdef _BIG_ENDIAN
+#define PT_LO(odd, even)  odd
+#define PT_HI(odd, even)  even
+#else
+#define PT_LO(odd, even)  even
+#define PT_HI(odd, even)  odd
+#endif
+
+#define PT_A4_ORG  PT_LO(1, 0)
+#define PT_TSR    PT_HI(1, 0)
+#define PT_ILC    PT_LO(3, 2)
+#define PT_RILC    PT_HI(3, 2)
+#define PT_CSR    PT_LO(5, 4)
+#define PT_PC     PT_HI(5, 4)
+#define PT_B16    PT_LO(7, 6)
+#define PT_B17    PT_HI(7, 6)
+#define PT_B18    PT_LO(9, 8)
+#define PT_B19    PT_HI(9, 8)
+#define PT_B20    PT_LO(11, 10)
+#define PT_B21    PT_HI(11, 10)
+#define PT_B22    PT_LO(13, 12)
+#define PT_B23    PT_HI(13, 12)
+#define PT_B24    PT_LO(15, 14)
+#define PT_B25    PT_HI(15, 14)
+#define PT_B26    PT_LO(17, 16)
+#define PT_B27    PT_HI(17, 16)
+#define PT_B28    PT_LO(19, 18)
+#define PT_B29    PT_HI(19, 18)
+#define PT_B30    PT_LO(21, 20)
+#define PT_B31    PT_HI(21, 20)
+#define PT_B0     PT_LO(23, 22)
+#define PT_B1     PT_HI(23, 22)
+#define PT_B2     PT_LO(25, 24)
+#define PT_B3     PT_HI(25, 24)
+#define PT_B4     PT_LO(27, 26)
+#define PT_B5     PT_HI(27, 26)
+#define PT_B6     PT_LO(29, 28)
+#define PT_B7     PT_HI(29, 28)
+#define PT_B8     PT_LO(31, 30)
+#define PT_B9     PT_HI(31, 30)
+#define PT_B10    PT_LO(33, 32)
+#define PT_B11    PT_HI(33, 32)
+#define PT_B12    PT_LO(35, 34)
+#define PT_B13    PT_HI(35, 34)
+#define PT_A16    PT_LO(37, 36)
+#define PT_A17    PT_HI(37, 36)
+#define PT_A18    PT_LO(39, 38)
+#define PT_A19    PT_HI(39, 38)
+#define PT_A20    PT_LO(41, 40)
+#define PT_A21    PT_HI(41, 40)
+#define PT_A22    PT_LO(43, 42)
+#define PT_A23    PT_HI(43, 42)
+#define PT_A24    PT_LO(45, 44)
+#define PT_A25    PT_HI(45, 44)
+#define PT_A26    PT_LO(47, 46)
+#define PT_A27    PT_HI(47, 46)
+#define PT_A28    PT_LO(49, 48)
+#define PT_A29    PT_HI(49, 48)
+#define PT_A30    PT_LO(51, 50)
+#define PT_A31    PT_HI(51, 50)
+#define PT_A0     PT_LO(53, 52)
+#define PT_A1     PT_HI(53, 52)
+#define PT_A2     PT_LO(55, 54)
+#define PT_A3     PT_HI(55, 54)
+#define PT_A4     PT_LO(57, 56)
+#define PT_A5     PT_HI(57, 56)
+#define PT_A6     PT_LO(59, 58)
+#define PT_A7     PT_HI(59, 58)
+#define PT_A8     PT_LO(61, 60)
+#define PT_A9     PT_HI(61, 60)
+#define PT_A10    PT_LO(63, 62)
+#define PT_A11    PT_HI(63, 62)
+#define PT_A12    PT_LO(65, 64)
+#define PT_A13    PT_HI(65, 64)
+#define PT_A14    PT_LO(67, 66)
+#define PT_A15    PT_HI(67, 66)
+#define PT_B14    PT_LO(69, 68)
+#define PT_B15    PT_HI(69, 68)
+
+#define NR_PTREGS  70
+
+#define PT_DP     PT_B14  /* Data Segment Pointer (B14) */
+#define PT_SP     PT_B15  /* Stack Pointer (B15)  */
+
+#ifndef __ASSEMBLY__
+
+#ifdef _BIG_ENDIAN
+#define REG_PAIR(odd, even) unsigned long odd; unsigned long even
+#else
+#define REG_PAIR(odd, even) unsigned long even; unsigned long odd
+#endif
+
+/*
+ * this struct defines the way the registers are stored on the
+ * stack during a system call. fields defined with REG_PAIR
+ * are saved and restored using double-word memory operations
+ * which means the word ordering of the pair depends on endianess.
+ */
+struct pt_regs {
+       REG_PAIR(tsr, orig_a4);
+       REG_PAIR(rilc, ilc);
+       REG_PAIR(pc, csr);
+
+       REG_PAIR(b17, b16);
+       REG_PAIR(b19, b18);
+       REG_PAIR(b21, b20);
+       REG_PAIR(b23, b22);
+       REG_PAIR(b25, b24);
+       REG_PAIR(b27, b26);
+       REG_PAIR(b29, b28);
+       REG_PAIR(b31, b30);
+
+       REG_PAIR(b1, b0);
+       REG_PAIR(b3, b2);
+       REG_PAIR(b5, b4);
+       REG_PAIR(b7, b6);
+       REG_PAIR(b9, b8);
+       REG_PAIR(b11, b10);
+       REG_PAIR(b13, b12);
+
+       REG_PAIR(a17, a16);
+       REG_PAIR(a19, a18);
+       REG_PAIR(a21, a20);
+       REG_PAIR(a23, a22);
+       REG_PAIR(a25, a24);
+       REG_PAIR(a27, a26);
+       REG_PAIR(a29, a28);
+       REG_PAIR(a31, a30);
+
+       REG_PAIR(a1, a0);
+       REG_PAIR(a3, a2);
+       REG_PAIR(a5, a4);
+       REG_PAIR(a7, a6);
+       REG_PAIR(a9, a8);
+       REG_PAIR(a11, a10);
+       REG_PAIR(a13, a12);
+
+       REG_PAIR(a15, a14);
+       REG_PAIR(sp, dp);
+};
+
+#ifdef __KERNEL__
+
+#include <linux/linkage.h>
+
+#define user_mode(regs)        ((((regs)->tsr) & 0x40) != 0)
+
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->sp)
+
+extern void show_regs(struct pt_regs *);
+
+extern asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_exit(struct pt_regs *regs);
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_C6X_PTRACE_H */
diff --git a/arch/c6x/include/asm/sections.h b/arch/c6x/include/asm/sections.h
new file mode 100644 (file)
index 0000000..f703989
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _ASM_C6X_SECTIONS_H
+#define _ASM_C6X_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+extern char _vectors_start[];
+extern char _vectors_end[];
+
+extern char _data_lma[];
+extern char _fdt_start[], _fdt_end[];
+
+#endif /* _ASM_C6X_SECTIONS_H */
diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h
new file mode 100644 (file)
index 0000000..1808f27
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_SETUP_H
+#define _ASM_C6X_SETUP_H
+
+#define COMMAND_LINE_SIZE   1024
+
+#ifndef __ASSEMBLY__
+extern char c6x_command_line[COMMAND_LINE_SIZE];
+
+extern int c6x_add_memory(phys_addr_t start, unsigned long size);
+
+extern unsigned long ram_start;
+extern unsigned long ram_end;
+
+extern int c6x_num_cores;
+extern unsigned int c6x_silicon_rev;
+extern unsigned int c6x_devstat;
+extern unsigned char c6x_fuse_mac[6];
+
+extern void machine_init(unsigned long dt_ptr);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASM_C6X_SETUP_H */
diff --git a/arch/c6x/include/asm/sigcontext.h b/arch/c6x/include/asm/sigcontext.h
new file mode 100644 (file)
index 0000000..eb702f3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_SIGCONTEXT_H
+#define _ASM_C6X_SIGCONTEXT_H
+
+
+struct sigcontext {
+       unsigned long  sc_mask;         /* old sigmask */
+       unsigned long  sc_sp;           /* old user stack pointer */
+
+       unsigned long  sc_a4;
+       unsigned long  sc_b4;
+       unsigned long  sc_a6;
+       unsigned long  sc_b6;
+       unsigned long  sc_a8;
+       unsigned long  sc_b8;
+
+       unsigned long  sc_a0;
+       unsigned long  sc_a1;
+       unsigned long  sc_a2;
+       unsigned long  sc_a3;
+       unsigned long  sc_a5;
+       unsigned long  sc_a7;
+       unsigned long  sc_a9;
+
+       unsigned long  sc_b0;
+       unsigned long  sc_b1;
+       unsigned long  sc_b2;
+       unsigned long  sc_b3;
+       unsigned long  sc_b5;
+       unsigned long  sc_b7;
+       unsigned long  sc_b9;
+
+       unsigned long  sc_a16;
+       unsigned long  sc_a17;
+       unsigned long  sc_a18;
+       unsigned long  sc_a19;
+       unsigned long  sc_a20;
+       unsigned long  sc_a21;
+       unsigned long  sc_a22;
+       unsigned long  sc_a23;
+       unsigned long  sc_a24;
+       unsigned long  sc_a25;
+       unsigned long  sc_a26;
+       unsigned long  sc_a27;
+       unsigned long  sc_a28;
+       unsigned long  sc_a29;
+       unsigned long  sc_a30;
+       unsigned long  sc_a31;
+
+       unsigned long  sc_b16;
+       unsigned long  sc_b17;
+       unsigned long  sc_b18;
+       unsigned long  sc_b19;
+       unsigned long  sc_b20;
+       unsigned long  sc_b21;
+       unsigned long  sc_b22;
+       unsigned long  sc_b23;
+       unsigned long  sc_b24;
+       unsigned long  sc_b25;
+       unsigned long  sc_b26;
+       unsigned long  sc_b27;
+       unsigned long  sc_b28;
+       unsigned long  sc_b29;
+       unsigned long  sc_b30;
+       unsigned long  sc_b31;
+
+       unsigned long  sc_csr;
+       unsigned long  sc_pc;
+};
+
+#endif /* _ASM_C6X_SIGCONTEXT_H */
diff --git a/arch/c6x/include/asm/signal.h b/arch/c6x/include/asm/signal.h
new file mode 100644 (file)
index 0000000..f1cd870
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _ASM_C6X_SIGNAL_H
+#define _ASM_C6X_SIGNAL_H
+
+#include <asm-generic/signal.h>
+
+#ifndef __ASSEMBLY__
+#include <linux/linkage.h>
+
+struct pt_regs;
+
+extern asmlinkage int do_rt_sigreturn(struct pt_regs *regs);
+extern asmlinkage void do_notify_resume(struct pt_regs *regs,
+                                       u32 thread_info_flags,
+                                       int syscall);
+#endif
+
+#endif /* _ASM_C6X_SIGNAL_H */
diff --git a/arch/c6x/include/asm/soc.h b/arch/c6x/include/asm/soc.h
new file mode 100644 (file)
index 0000000..43f5015
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Miscellaneous SoC-specific hooks.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Author: Mark Salter <msalter@redhat.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 _ASM_C6X_SOC_H
+#define _ASM_C6X_SOC_H
+
+struct soc_ops {
+       /* Return active exception event or -1 if none */
+       int             (*get_exception)(void);
+
+       /* Assert an event */
+       void            (*assert_event)(unsigned int evt);
+};
+
+extern struct soc_ops soc_ops;
+
+extern int soc_get_exception(void);
+extern void soc_assert_event(unsigned int event);
+extern int soc_mac_addr(unsigned int index, u8 *addr);
+
+/*
+ * for mmio on SoC devices. regs are always same byte order as cpu.
+ */
+#define soc_readl(addr)    __raw_readl(addr)
+#define soc_writel(b, addr) __raw_writel((b), (addr))
+
+#endif /* _ASM_C6X_SOC_H */
diff --git a/arch/c6x/include/asm/string.h b/arch/c6x/include/asm/string.h
new file mode 100644 (file)
index 0000000..b21517c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_STRING_H
+#define _ASM_C6X_STRING_H
+
+#include <asm/page.h>
+#include <linux/linkage.h>
+
+asmlinkage extern void *memcpy(void *to, const void *from, size_t n);
+
+#define __HAVE_ARCH_MEMCPY
+
+#endif /* _ASM_C6X_STRING_H */
diff --git a/arch/c6x/include/asm/swab.h b/arch/c6x/include/asm/swab.h
new file mode 100644 (file)
index 0000000..fd4bb05
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_SWAB_H
+#define _ASM_C6X_SWAB_H
+
+static inline __attribute_const__ __u16 __c6x_swab16(__u16 val)
+{
+       asm("swap4 .l1 %0,%0\n" : "+a"(val));
+       return val;
+}
+
+static inline __attribute_const__ __u32 __c6x_swab32(__u32 val)
+{
+       asm("swap4 .l1 %0,%0\n"
+           "swap2 .l1 %0,%0\n"
+           : "+a"(val));
+       return val;
+}
+
+static inline __attribute_const__ __u64 __c6x_swab64(__u64 val)
+{
+       asm("   swap2 .s1 %p0,%P0\n"
+           "|| swap2 .l1 %P0,%p0\n"
+           "   swap4 .l1 %p0,%p0\n"
+           "   swap4 .l1 %P0,%P0\n"
+           : "+a"(val));
+       return val;
+}
+
+static inline __attribute_const__ __u32 __c6x_swahw32(__u32 val)
+{
+       asm("swap2 .l1 %0,%0\n" : "+a"(val));
+       return val;
+}
+
+static inline __attribute_const__ __u32 __c6x_swahb32(__u32 val)
+{
+       asm("swap4 .l1 %0,%0\n" : "+a"(val));
+       return val;
+}
+
+#define __arch_swab16 __c6x_swab16
+#define __arch_swab32 __c6x_swab32
+#define __arch_swab64 __c6x_swab64
+#define __arch_swahw32 __c6x_swahw32
+#define __arch_swahb32 __c6x_swahb32
+
+#endif /* _ASM_C6X_SWAB_H */
diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h
new file mode 100644 (file)
index 0000000..ae2be31
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ * Author: Mark Salter <msalter@redhat.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_C6X_SYSCALL_H
+#define __ASM_C6X_SYSCALL_H
+
+#include <linux/err.h>
+#include <linux/sched.h>
+
+static inline int syscall_get_nr(struct task_struct *task,
+                                struct pt_regs *regs)
+{
+       return regs->b0;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+                                   struct pt_regs *regs)
+{
+       /* do nothing */
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+                                    struct pt_regs *regs)
+{
+       return IS_ERR_VALUE(regs->a4) ? regs->a4 : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->a4;
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+                                           struct pt_regs *regs,
+                                           int error, long val)
+{
+       regs->a4 = error ?: val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+                                        struct pt_regs *regs, unsigned int i,
+                                        unsigned int n, unsigned long *args)
+{
+       switch (i) {
+       case 0:
+               if (!n--)
+                       break;
+               *args++ = regs->a4;
+       case 1:
+               if (!n--)
+                       break;
+               *args++ = regs->b4;
+       case 2:
+               if (!n--)
+                       break;
+               *args++ = regs->a6;
+       case 3:
+               if (!n--)
+                       break;
+               *args++ = regs->b6;
+       case 4:
+               if (!n--)
+                       break;
+               *args++ = regs->a8;
+       case 5:
+               if (!n--)
+                       break;
+               *args++ = regs->b8;
+       case 6:
+               if (!n--)
+                       break;
+       default:
+               BUG();
+       }
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+                                        struct pt_regs *regs,
+                                        unsigned int i, unsigned int n,
+                                        const unsigned long *args)
+{
+       switch (i) {
+       case 0:
+               if (!n--)
+                       break;
+               regs->a4 = *args++;
+       case 1:
+               if (!n--)
+                       break;
+               regs->b4 = *args++;
+       case 2:
+               if (!n--)
+                       break;
+               regs->a6 = *args++;
+       case 3:
+               if (!n--)
+                       break;
+               regs->b6 = *args++;
+       case 4:
+               if (!n--)
+                       break;
+               regs->a8 = *args++;
+       case 5:
+               if (!n--)
+                       break;
+               regs->a9 = *args++;
+       case 6:
+               if (!n)
+                       break;
+       default:
+               BUG();
+       }
+}
+
+#endif /* __ASM_C6X_SYSCALLS_H */
diff --git a/arch/c6x/include/asm/syscalls.h b/arch/c6x/include/asm/syscalls.h
new file mode 100644 (file)
index 0000000..aed53da
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ * Author: Mark Salter <msalter@redhat.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 in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __ASM_C6X_SYSCALLS_H
+#define __ASM_C6X_SYSCALLS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+/* The array of function pointers for syscalls. */
+extern void *sys_call_table[];
+
+/* The following are trampolines in entry.S to handle 64-bit arguments */
+extern long sys_pread_c6x(unsigned int fd, char __user *buf,
+                         size_t count, off_t pos_low, off_t pos_high);
+extern long sys_pwrite_c6x(unsigned int fd, const char __user *buf,
+                          size_t count, off_t pos_low, off_t pos_high);
+extern long sys_truncate64_c6x(const char __user *path,
+                              off_t length_low, off_t length_high);
+extern long sys_ftruncate64_c6x(unsigned int fd,
+                              off_t length_low, off_t length_high);
+extern long sys_fadvise64_c6x(int fd, u32 offset_lo, u32 offset_hi,
+                             u32 len, int advice);
+extern long sys_fadvise64_64_c6x(int fd, u32 offset_lo, u32 offset_hi,
+                               u32 len_lo, u32 len_hi, int advice);
+extern long sys_fallocate_c6x(int fd, int mode,
+                             u32 offset_lo, u32 offset_hi,
+                             u32 len_lo, u32 len_hi);
+extern int sys_cache_sync(unsigned long s, unsigned long e);
+
+struct pt_regs;
+
+extern asmlinkage long sys_c6x_clone(struct pt_regs *regs);
+extern asmlinkage long sys_c6x_execve(const char __user *name,
+                                     const char __user *const __user *argv,
+                                     const char __user *const __user *envp,
+                                     struct pt_regs *regs);
+
+
+#include <asm-generic/syscalls.h>
+
+#endif /* __ASM_C6X_SYSCALLS_H */
diff --git a/arch/c6x/include/asm/system.h b/arch/c6x/include/asm/system.h
new file mode 100644 (file)
index 0000000..e076dc0
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_SYSTEM_H
+#define _ASM_C6X_SYSTEM_H
+
+#include <linux/linkage.h>
+#include <linux/irqflags.h>
+
+#define prepare_to_switch()    do { } while (0)
+
+struct task_struct;
+struct thread_struct;
+asmlinkage void *__switch_to(struct thread_struct *prev,
+                            struct thread_struct *next,
+                            struct task_struct *tsk);
+
+#define switch_to(prev, next, last)                            \
+       do {                                                    \
+               current->thread.wchan = (u_long) __builtin_return_address(0); \
+               (last) = __switch_to(&(prev)->thread,           \
+                                    &(next)->thread, (prev));  \
+               mb();                                           \
+               current->thread.wchan = 0;                      \
+       } while (0)
+
+/* Reset the board */
+#define HARD_RESET_NOW()
+
+#define get_creg(reg) \
+       ({ unsigned int __x; \
+          asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; })
+
+#define set_creg(reg, v) \
+       do { unsigned int __x = (unsigned int)(v); \
+               asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \
+       } while (0)
+
+#define or_creg(reg, n) \
+       do { unsigned __x, __n = (unsigned)(n);           \
+               asm volatile ("mvc .s2 " #reg ",%0\n"     \
+                             "or  .l2 %1,%0,%0\n"        \
+                             "mvc .s2 %0," #reg "\n"     \
+                             "nop\n"                     \
+                             : "=&b"(__x) : "b"(__n));   \
+       } while (0)
+
+#define and_creg(reg, n) \
+       do { unsigned __x, __n = (unsigned)(n);           \
+               asm volatile ("mvc .s2 " #reg ",%0\n"     \
+                             "and .l2 %1,%0,%0\n"        \
+                             "mvc .s2 %0," #reg "\n"     \
+                             "nop\n"    \
+                             : "=&b"(__x) : "b"(__n));   \
+       } while (0)
+
+#define get_coreid() (get_creg(DNUM) & 0xff)
+
+/* Set/get IST */
+#define set_ist(x)     set_creg(ISTP, x)
+#define get_ist()       get_creg(ISTP)
+
+/*
+ * Exception management
+ */
+asmlinkage void enable_exception(void);
+#define disable_exception()
+#define get_except_type()        get_creg(EFR)
+#define ack_exception(type)      set_creg(ECR, 1 << (type))
+#define get_iexcept()            get_creg(IERR)
+#define set_iexcept(mask)        set_creg(IERR, (mask))
+
+/*
+ * Misc. functions
+ */
+#define nop()                    asm("NOP\n");
+#define mb()                     barrier()
+#define rmb()                    barrier()
+#define wmb()                    barrier()
+#define set_mb(var, value)       do { var = value;  mb(); } while (0)
+#define set_wmb(var, value)      do { var = value; wmb(); } while (0)
+
+#define smp_mb()                barrier()
+#define smp_rmb()               barrier()
+#define smp_wmb()               barrier()
+#define smp_read_barrier_depends()     do { } while (0)
+
+#define xchg(ptr, x) \
+       ((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
+                                   sizeof(*(ptr))))
+#define tas(ptr)    xchg((ptr), 1)
+
+unsigned int _lmbd(unsigned int, unsigned int);
+unsigned int _bitr(unsigned int);
+
+struct __xchg_dummy { unsigned int a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
+{
+       unsigned int tmp;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       switch (size) {
+       case 1:
+               tmp = 0;
+               tmp = *((unsigned char *) ptr);
+               *((unsigned char *) ptr) = (unsigned char) x;
+               break;
+       case 2:
+               tmp = 0;
+               tmp = *((unsigned short *) ptr);
+               *((unsigned short *) ptr) = x;
+               break;
+       case 4:
+               tmp = 0;
+               tmp = *((unsigned int *) ptr);
+               *((unsigned int *) ptr) = x;
+               break;
+       }
+       local_irq_restore(flags);
+       return tmp;
+}
+
+#include <asm-generic/cmpxchg-local.h>
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n)                                       \
+       ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr),             \
+                                                    (unsigned long)(o), \
+                                                    (unsigned long)(n), \
+                                                    sizeof(*(ptr))))
+#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
+
+#include <asm-generic/cmpxchg.h>
+
+#define _extu(x, s, e)                                                 \
+       ({      unsigned int __x;                                       \
+               asm volatile ("extu .S2 %3,%1,%2,%0\n" :                \
+                             "=b"(__x) : "n"(s), "n"(e), "b"(x));      \
+              __x; })
+
+
+extern unsigned int c6x_core_freq;
+
+struct pt_regs;
+
+extern void die(char *str, struct pt_regs *fp, int nr);
+extern asmlinkage int process_exception(struct pt_regs *regs);
+extern void time_init(void);
+extern void free_initmem(void);
+
+extern void (*c6x_restart)(void);
+extern void (*c6x_halt)(void);
+
+#endif /* _ASM_C6X_SYSTEM_H */
diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h
new file mode 100644 (file)
index 0000000..fd99148
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.3x: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_THREAD_INFO_H
+#define _ASM_C6X_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#include <asm/page.h>
+
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE            4096
+#define THREAD_SHIFT           12
+#define THREAD_ORDER           0
+#else
+#define THREAD_SIZE            8192
+#define THREAD_SHIFT           13
+#define THREAD_ORDER           1
+#endif
+
+#define THREAD_START_SP                (THREAD_SIZE - 8)
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
+/*
+ * low level task data.
+ */
+struct thread_info {
+       struct task_struct      *task;          /* main task structure */
+       struct exec_domain      *exec_domain;   /* execution domain */
+       unsigned long           flags;          /* low level flags */
+       int                     cpu;            /* cpu we're on */
+       int                     preempt_count;  /* 0 = preemptable, <0 = BUG */
+       mm_segment_t            addr_limit;     /* thread address space */
+       struct restart_block    restart_block;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+#define INIT_THREAD_INFO(tsk)                  \
+{                                              \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+       .flags          = 0,                    \
+       .cpu            = 0,                    \
+       .preempt_count  = INIT_PREEMPT_COUNT,   \
+       .addr_limit     = KERNEL_DS,            \
+       .restart_block  = {                     \
+               .fn = do_no_restart_syscall,    \
+       },                                      \
+}
+
+#define init_thread_info       (init_thread_union.thread_info)
+#define init_stack             (init_thread_union.stack)
+
+/* get the thread information struct of current task */
+static inline __attribute__((const))
+struct thread_info *current_thread_info(void)
+{
+       struct thread_info *ti;
+       asm volatile (" clr   .s2 B15,0,%1,%0\n"
+                     : "=b" (ti)
+                     : "Iu5" (THREAD_SHIFT - 1));
+       return ti;
+}
+
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
+
+/* thread information allocation */
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
+#else
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK)
+#endif
+
+#define alloc_thread_info_node(tsk, node)      \
+       ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
+
+#define free_thread_info(ti)   free_pages((unsigned long) (ti), THREAD_ORDER)
+#define get_thread_info(ti)    get_task_struct((ti)->task)
+#define put_thread_info(ti)    put_task_struct((ti)->task)
+#endif /* __ASSEMBLY__ */
+
+#define        PREEMPT_ACTIVE  0x10000000
+
+/*
+ * thread information flag bit numbers
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
+#define TIF_NOTIFY_RESUME      1       /* resumption notification requested */
+#define TIF_SIGPENDING         2       /* signal pending */
+#define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_RESTORE_SIGMASK    4       /* restore signal mask in do_signal() */
+
+#define TIF_POLLING_NRFLAG     16      /* true if polling TIF_NEED_RESCHED */
+#define TIF_MEMDIE             17      /* OOM killer killed process */
+
+#define TIF_WORK_MASK          0x00007FFE /* work on irq/exception return */
+#define TIF_ALLWORK_MASK       0x00007FFF /* work on any return to u-space */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_C6X_THREAD_INFO_H */
diff --git a/arch/c6x/include/asm/timer64.h b/arch/c6x/include/asm/timer64.h
new file mode 100644 (file)
index 0000000..bbe27bb
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _C6X_TIMER64_H
+#define _C6X_TIMER64_H
+
+extern void __init timer64_init(void);
+
+#endif /* _C6X_TIMER64_H */
diff --git a/arch/c6x/include/asm/timex.h b/arch/c6x/include/asm/timex.h
new file mode 100644 (file)
index 0000000..508c3ec
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Modified for 2.6.34: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_TIMEX_H
+#define _ASM_C6X_TIMEX_H
+
+#define CLOCK_TICK_RATE ((1000 * 1000000UL) / 6)
+
+/* 64-bit timestamp */
+typedef unsigned long long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+       unsigned l, h;
+
+       asm volatile (" dint\n"
+                     " mvc .s2 TSCL,%0\n"
+                     " mvc .s2 TSCH,%1\n"
+                     " rint\n"
+                     : "=b"(l), "=b"(h));
+       return ((cycles_t)h << 32) | l;
+}
+
+#endif /* _ASM_C6X_TIMEX_H */
diff --git a/arch/c6x/include/asm/tlb.h b/arch/c6x/include/asm/tlb.h
new file mode 100644 (file)
index 0000000..8709e5e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_C6X_TLB_H
+#define _ASM_C6X_TLB_H
+
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#endif /* _ASM_C6X_TLB_H */
diff --git a/arch/c6x/include/asm/traps.h b/arch/c6x/include/asm/traps.h
new file mode 100644 (file)
index 0000000..62124d7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_TRAPS_H
+#define _ASM_C6X_TRAPS_H
+
+#define EXCEPT_TYPE_NXF   31      /* NMI */
+#define EXCEPT_TYPE_EXC   30      /* external exception */
+#define EXCEPT_TYPE_IXF   1       /* internal exception */
+#define EXCEPT_TYPE_SXF   0       /* software exception */
+
+#define EXCEPT_CAUSE_LBX  (1 << 7) /* loop buffer exception */
+#define EXCEPT_CAUSE_PRX  (1 << 6) /* privilege exception */
+#define EXCEPT_CAUSE_RAX  (1 << 5) /* resource access exception */
+#define EXCEPT_CAUSE_RCX  (1 << 4) /* resource conflict exception */
+#define EXCEPT_CAUSE_OPX  (1 << 3) /* opcode exception */
+#define EXCEPT_CAUSE_EPX  (1 << 2) /* execute packet exception */
+#define EXCEPT_CAUSE_FPX  (1 << 1) /* fetch packet exception */
+#define EXCEPT_CAUSE_IFX  (1 << 0) /* instruction fetch exception */
+
+struct exception_info {
+       char *kernel_str;
+       int  signo;
+       int  code;
+};
+
+extern int (*c6x_nmi_handler)(struct pt_regs *regs);
+
+#endif /* _ASM_C6X_TRAPS_H */
diff --git a/arch/c6x/include/asm/uaccess.h b/arch/c6x/include/asm/uaccess.h
new file mode 100644 (file)
index 0000000..453dd26
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_UACCESS_H
+#define _ASM_C6X_UACCESS_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/string.h>
+
+#ifdef CONFIG_ACCESS_CHECK
+#define __access_ok _access_ok
+#endif
+
+/*
+ * __copy_from_user/copy_to_user are based on ones in asm-generic/uaccess.h
+ *
+ * C6X supports unaligned 32 and 64 bit loads and stores.
+ */
+static inline __must_check long __copy_from_user(void *to,
+               const void __user *from, unsigned long n)
+{
+       u32 tmp32;
+       u64 tmp64;
+
+       if (__builtin_constant_p(n)) {
+               switch (n) {
+               case 1:
+                       *(u8 *)to = *(u8 __force *)from;
+                       return 0;
+               case 4:
+                       asm volatile ("ldnw .d1t1 *%2,%0\n"
+                                     "nop  4\n"
+                                     "stnw .d1t1 %0,*%1\n"
+                                     : "=&a"(tmp32)
+                                     : "A"(to), "a"(from)
+                                     : "memory");
+                       return 0;
+               case 8:
+                       asm volatile ("ldndw .d1t1 *%2,%0\n"
+                                     "nop   4\n"
+                                     "stndw .d1t1 %0,*%1\n"
+                                     : "=&a"(tmp64)
+                                     : "a"(to), "a"(from)
+                                     : "memory");
+                       return 0;
+               default:
+                       break;
+               }
+       }
+
+       memcpy(to, (const void __force *)from, n);
+       return 0;
+}
+
+static inline __must_check long __copy_to_user(void __user *to,
+               const void *from, unsigned long n)
+{
+       u32 tmp32;
+       u64 tmp64;
+
+       if (__builtin_constant_p(n)) {
+               switch (n) {
+               case 1:
+                       *(u8 __force *)to = *(u8 *)from;
+                       return 0;
+               case 4:
+                       asm volatile ("ldnw .d1t1 *%2,%0\n"
+                                     "nop  4\n"
+                                     "stnw .d1t1 %0,*%1\n"
+                                     : "=&a"(tmp32)
+                                     : "a"(to), "a"(from)
+                                     : "memory");
+                       return 0;
+               case 8:
+                       asm volatile ("ldndw .d1t1 *%2,%0\n"
+                                     "nop   4\n"
+                                     "stndw .d1t1 %0,*%1\n"
+                                     : "=&a"(tmp64)
+                                     : "a"(to), "a"(from)
+                                     : "memory");
+                       return 0;
+               default:
+                       break;
+               }
+       }
+
+       memcpy((void __force *)to, from, n);
+       return 0;
+}
+
+#define __copy_to_user   __copy_to_user
+#define __copy_from_user __copy_from_user
+
+extern int _access_ok(unsigned long addr, unsigned long size);
+#ifdef CONFIG_ACCESS_CHECK
+#define __access_ok _access_ok
+#endif
+
+#include <asm-generic/uaccess.h>
+
+#endif /* _ASM_C6X_UACCESS_H */
diff --git a/arch/c6x/include/asm/unaligned.h b/arch/c6x/include/asm/unaligned.h
new file mode 100644 (file)
index 0000000..b976cb7
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *  Rewritten for 2.6.3x: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_UNALIGNED_H
+#define _ASM_C6X_UNALIGNED_H
+
+#include <linux/swab.h>
+
+/*
+ * The C64x+ can do unaligned word and dword accesses in hardware
+ * using special load/store instructions.
+ */
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+       const u8 *_p = p;
+       return _p[0] | _p[1] << 8;
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+       const u8 *_p = p;
+       return _p[0] << 8 | _p[1];
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+       u8 *_p = p;
+       _p[0] = val;
+       _p[1] = val >> 8;
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+       u8 *_p = p;
+       _p[0] = val >> 8;
+       _p[1] = val;
+}
+
+static inline u32 get_unaligned32(const void *p)
+{
+       u32 val = (u32) p;
+       asm (" ldnw     .d1t1   *%0,%0\n"
+            " nop     4\n"
+            : "+a"(val));
+       return val;
+}
+
+static inline void put_unaligned32(u32 val, void *p)
+{
+       asm volatile (" stnw    .d2t1   %0,*%1\n"
+                     : : "a"(val), "b"(p) : "memory");
+}
+
+static inline u64 get_unaligned64(const void *p)
+{
+       u64 val;
+       asm volatile (" ldndw   .d1t1   *%1,%0\n"
+                     " nop     4\n"
+                     : "=a"(val) : "a"(p));
+       return val;
+}
+
+static inline void put_unaligned64(u64 val, const void *p)
+{
+       asm volatile (" stndw   .d2t1   %0,*%1\n"
+                     : : "a"(val), "b"(p) : "memory");
+}
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+
+#define get_unaligned_le32(p)   __swab32(get_unaligned32(p))
+#define get_unaligned_le64(p)   __swab64(get_unaligned64(p))
+#define get_unaligned_be32(p)   get_unaligned32(p)
+#define get_unaligned_be64(p)   get_unaligned64(p)
+#define put_unaligned_le32(v, p) put_unaligned32(__swab32(v), (p))
+#define put_unaligned_le64(v, p) put_unaligned64(__swab64(v), (p))
+#define put_unaligned_be32(v, p) put_unaligned32((v), (p))
+#define put_unaligned_be64(v, p) put_unaligned64((v), (p))
+#define get_unaligned  __get_unaligned_be
+#define put_unaligned  __put_unaligned_be
+
+#else
+
+#define get_unaligned_le32(p)   get_unaligned32(p)
+#define get_unaligned_le64(p)   get_unaligned64(p)
+#define get_unaligned_be32(p)   __swab32(get_unaligned32(p))
+#define get_unaligned_be64(p)   __swab64(get_unaligned64(p))
+#define put_unaligned_le32(v, p) put_unaligned32((v), (p))
+#define put_unaligned_le64(v, p) put_unaligned64((v), (p))
+#define put_unaligned_be32(v, p) put_unaligned32(__swab32(v), (p))
+#define put_unaligned_be64(v, p) put_unaligned64(__swab64(v), (p))
+#define get_unaligned  __get_unaligned_le
+#define put_unaligned  __put_unaligned_le
+
+#endif
+
+/*
+ * Cause a link-time error if we try an unaligned access other than
+ * 1,2,4 or 8 bytes long
+ */
+extern int __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) (typeof(*(ptr)))({                     \
+       sizeof(*(ptr)) == 1 ? *(ptr) :                                  \
+         (sizeof(*(ptr)) == 2 ? get_unaligned_le16((ptr)) :            \
+            (sizeof(*(ptr)) == 4 ? get_unaligned_le32((ptr)) :         \
+               (sizeof(*(ptr)) == 8 ? get_unaligned_le64((ptr)) :      \
+                  __bad_unaligned_access_size())));                    \
+       })
+
+#define __get_unaligned_be(ptr) (__force typeof(*(ptr)))({     \
+       sizeof(*(ptr)) == 1 ? *(ptr) :                                  \
+         (sizeof(*(ptr)) == 2 ? get_unaligned_be16((ptr)) :            \
+            (sizeof(*(ptr)) == 4 ? get_unaligned_be32((ptr)) :         \
+               (sizeof(*(ptr)) == 8 ? get_unaligned_be64((ptr)) :      \
+                  __bad_unaligned_access_size())));                    \
+       })
+
+#define __put_unaligned_le(val, ptr) ({                                        \
+       void *__gu_p = (ptr);                                           \
+       switch (sizeof(*(ptr))) {                                       \
+       case 1:                                                         \
+               *(u8 *)__gu_p = (__force u8)(val);                      \
+               break;                                                  \
+       case 2:                                                         \
+               put_unaligned_le16((__force u16)(val), __gu_p);         \
+               break;                                                  \
+       case 4:                                                         \
+               put_unaligned_le32((__force u32)(val), __gu_p);         \
+               break;                                                  \
+       case 8:                                                         \
+               put_unaligned_le64((__force u64)(val), __gu_p);         \
+               break;                                                  \
+       default:                                                        \
+               __bad_unaligned_access_size();                          \
+               break;                                                  \
+       }                                                               \
+       (void)0; })
+
+#define __put_unaligned_be(val, ptr) ({                                        \
+       void *__gu_p = (ptr);                                           \
+       switch (sizeof(*(ptr))) {                                       \
+       case 1:                                                         \
+               *(u8 *)__gu_p = (__force u8)(val);                      \
+               break;                                                  \
+       case 2:                                                         \
+               put_unaligned_be16((__force u16)(val), __gu_p);         \
+               break;                                                  \
+       case 4:                                                         \
+               put_unaligned_be32((__force u32)(val), __gu_p);         \
+               break;                                                  \
+       case 8:                                                         \
+               put_unaligned_be64((__force u64)(val), __gu_p);         \
+               break;                                                  \
+       default:                                                        \
+               __bad_unaligned_access_size();                          \
+               break;                                                  \
+       }                                                               \
+       (void)0; })
+
+#endif /* _ASM_C6X_UNALIGNED_H */
diff --git a/arch/c6x/include/asm/unistd.h b/arch/c6x/include/asm/unistd.h
new file mode 100644 (file)
index 0000000..6d54ea4
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ * Based on arch/tile version.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT. See the GNU General Public License for
+ *   more details.
+ */
+#if !defined(_ASM_C6X_UNISTD_H) || defined(__SYSCALL)
+#define _ASM_C6X_UNISTD_H
+
+/* Use the standard ABI for syscalls. */
+#include <asm-generic/unistd.h>
+
+/* C6X-specific syscalls. */
+#define __NR_cache_sync        (__NR_arch_specific_syscall + 0)
+__SYSCALL(__NR_cache_sync, sys_cache_sync)
+
+#endif /* _ASM_C6X_UNISTD_H */
diff --git a/arch/c6x/kernel/Makefile b/arch/c6x/kernel/Makefile
new file mode 100644 (file)
index 0000000..580a515
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for arch/c6x/kernel/
+#
+
+extra-y := head.o vmlinux.lds
+
+obj-y := process.o traps.o irq.o signal.o ptrace.o
+obj-y += setup.o sys_c6x.o time.o devicetree.o
+obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o
+obj-y += soc.o dma.o
+
+obj-$(CONFIG_MODULES)           += module.o
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..759ad6d
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+#include <asm/procinfo.h>
+#include <linux/kbuild.h>
+#include <linux/unistd.h>
+
+void foo(void)
+{
+       OFFSET(REGS_A16,        pt_regs, a16);
+       OFFSET(REGS_A17,        pt_regs, a17);
+       OFFSET(REGS_A18,        pt_regs, a18);
+       OFFSET(REGS_A19,        pt_regs, a19);
+       OFFSET(REGS_A20,        pt_regs, a20);
+       OFFSET(REGS_A21,        pt_regs, a21);
+       OFFSET(REGS_A22,        pt_regs, a22);
+       OFFSET(REGS_A23,        pt_regs, a23);
+       OFFSET(REGS_A24,        pt_regs, a24);
+       OFFSET(REGS_A25,        pt_regs, a25);
+       OFFSET(REGS_A26,        pt_regs, a26);
+       OFFSET(REGS_A27,        pt_regs, a27);
+       OFFSET(REGS_A28,        pt_regs, a28);
+       OFFSET(REGS_A29,        pt_regs, a29);
+       OFFSET(REGS_A30,        pt_regs, a30);
+       OFFSET(REGS_A31,        pt_regs, a31);
+
+       OFFSET(REGS_B16,        pt_regs, b16);
+       OFFSET(REGS_B17,        pt_regs, b17);
+       OFFSET(REGS_B18,        pt_regs, b18);
+       OFFSET(REGS_B19,        pt_regs, b19);
+       OFFSET(REGS_B20,        pt_regs, b20);
+       OFFSET(REGS_B21,        pt_regs, b21);
+       OFFSET(REGS_B22,        pt_regs, b22);
+       OFFSET(REGS_B23,        pt_regs, b23);
+       OFFSET(REGS_B24,        pt_regs, b24);
+       OFFSET(REGS_B25,        pt_regs, b25);
+       OFFSET(REGS_B26,        pt_regs, b26);
+       OFFSET(REGS_B27,        pt_regs, b27);
+       OFFSET(REGS_B28,        pt_regs, b28);
+       OFFSET(REGS_B29,        pt_regs, b29);
+       OFFSET(REGS_B30,        pt_regs, b30);
+       OFFSET(REGS_B31,        pt_regs, b31);
+
+       OFFSET(REGS_A0,         pt_regs, a0);
+       OFFSET(REGS_A1,         pt_regs, a1);
+       OFFSET(REGS_A2,         pt_regs, a2);
+       OFFSET(REGS_A3,         pt_regs, a3);
+       OFFSET(REGS_A4,         pt_regs, a4);
+       OFFSET(REGS_A5,         pt_regs, a5);
+       OFFSET(REGS_A6,         pt_regs, a6);
+       OFFSET(REGS_A7,         pt_regs, a7);
+       OFFSET(REGS_A8,         pt_regs, a8);
+       OFFSET(REGS_A9,         pt_regs, a9);
+       OFFSET(REGS_A10,        pt_regs, a10);
+       OFFSET(REGS_A11,        pt_regs, a11);
+       OFFSET(REGS_A12,        pt_regs, a12);
+       OFFSET(REGS_A13,        pt_regs, a13);
+       OFFSET(REGS_A14,        pt_regs, a14);
+       OFFSET(REGS_A15,        pt_regs, a15);
+
+       OFFSET(REGS_B0,         pt_regs, b0);
+       OFFSET(REGS_B1,         pt_regs, b1);
+       OFFSET(REGS_B2,         pt_regs, b2);
+       OFFSET(REGS_B3,         pt_regs, b3);
+       OFFSET(REGS_B4,         pt_regs, b4);
+       OFFSET(REGS_B5,         pt_regs, b5);
+       OFFSET(REGS_B6,         pt_regs, b6);
+       OFFSET(REGS_B7,         pt_regs, b7);
+       OFFSET(REGS_B8,         pt_regs, b8);
+       OFFSET(REGS_B9,         pt_regs, b9);
+       OFFSET(REGS_B10,        pt_regs, b10);
+       OFFSET(REGS_B11,        pt_regs, b11);
+       OFFSET(REGS_B12,        pt_regs, b12);
+       OFFSET(REGS_B13,        pt_regs, b13);
+       OFFSET(REGS_DP,         pt_regs, dp);
+       OFFSET(REGS_SP,         pt_regs, sp);
+
+       OFFSET(REGS_TSR,        pt_regs, tsr);
+       OFFSET(REGS_ORIG_A4,    pt_regs, orig_a4);
+
+       DEFINE(REGS__END,       sizeof(struct pt_regs));
+       BLANK();
+
+       OFFSET(THREAD_PC,       thread_struct, pc);
+       OFFSET(THREAD_B15_14,   thread_struct, b15_14);
+       OFFSET(THREAD_A15_14,   thread_struct, a15_14);
+       OFFSET(THREAD_B13_12,   thread_struct, b13_12);
+       OFFSET(THREAD_A13_12,   thread_struct, a13_12);
+       OFFSET(THREAD_B11_10,   thread_struct, b11_10);
+       OFFSET(THREAD_A11_10,   thread_struct, a11_10);
+       OFFSET(THREAD_RICL_ICL, thread_struct, ricl_icl);
+       BLANK();
+
+       OFFSET(TASK_STATE,      task_struct, state);
+       BLANK();
+
+       OFFSET(THREAD_INFO_FLAGS,       thread_info, flags);
+       OFFSET(THREAD_INFO_PREEMPT_COUNT, thread_info, preempt_count);
+       BLANK();
+
+       /* These would be unneccessary if we ran asm files
+        * through the preprocessor.
+        */
+       DEFINE(KTHREAD_SIZE, THREAD_SIZE);
+       DEFINE(KTHREAD_SHIFT, THREAD_SHIFT);
+       DEFINE(KTHREAD_START_SP, THREAD_START_SP);
+       DEFINE(ENOSYS_, ENOSYS);
+       DEFINE(NR_SYSCALLS_, __NR_syscalls);
+
+       DEFINE(_TIF_SYSCALL_TRACE, (1<<TIF_SYSCALL_TRACE));
+       DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
+       DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
+       DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
+       DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
+
+       DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
+       DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
+}
diff --git a/arch/c6x/kernel/c6x_ksyms.c b/arch/c6x/kernel/c6x_ksyms.c
new file mode 100644 (file)
index 0000000..0ba3e0b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 <asm/checksum.h>
+#include <linux/io.h>
+
+/*
+ * libgcc functions - used internally by the compiler...
+ */
+extern int __c6xabi_divi(int dividend, int divisor);
+EXPORT_SYMBOL(__c6xabi_divi);
+
+extern unsigned __c6xabi_divu(unsigned dividend, unsigned divisor);
+EXPORT_SYMBOL(__c6xabi_divu);
+
+extern int __c6xabi_remi(int dividend, int divisor);
+EXPORT_SYMBOL(__c6xabi_remi);
+
+extern unsigned __c6xabi_remu(unsigned dividend, unsigned divisor);
+EXPORT_SYMBOL(__c6xabi_remu);
+
+extern int __c6xabi_divremi(int dividend, int divisor);
+EXPORT_SYMBOL(__c6xabi_divremi);
+
+extern unsigned __c6xabi_divremu(unsigned  dividend, unsigned divisor);
+EXPORT_SYMBOL(__c6xabi_divremu);
+
+extern unsigned long long __c6xabi_mpyll(unsigned long long src1,
+                                        unsigned long long src2);
+EXPORT_SYMBOL(__c6xabi_mpyll);
+
+extern long long __c6xabi_negll(long long src);
+EXPORT_SYMBOL(__c6xabi_negll);
+
+extern unsigned long long __c6xabi_llshl(unsigned long long src1, uint src2);
+EXPORT_SYMBOL(__c6xabi_llshl);
+
+extern long long __c6xabi_llshr(long long src1, uint src2);
+EXPORT_SYMBOL(__c6xabi_llshr);
+
+extern unsigned long long __c6xabi_llshru(unsigned long long src1, uint src2);
+EXPORT_SYMBOL(__c6xabi_llshru);
+
+extern void __c6xabi_strasgi(int *dst, const int *src, unsigned cnt);
+EXPORT_SYMBOL(__c6xabi_strasgi);
+
+extern void __c6xabi_push_rts(void);
+EXPORT_SYMBOL(__c6xabi_push_rts);
+
+extern void __c6xabi_pop_rts(void);
+EXPORT_SYMBOL(__c6xabi_pop_rts);
+
+extern void __c6xabi_strasgi_64plus(int *dst, const int *src, unsigned cnt);
+EXPORT_SYMBOL(__c6xabi_strasgi_64plus);
+
+/* lib functions */
+EXPORT_SYMBOL(memcpy);
diff --git a/arch/c6x/kernel/devicetree.c b/arch/c6x/kernel/devicetree.c
new file mode 100644 (file)
index 0000000..bdb56f0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Architecture specific OF callbacks.
+ *
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/initrd.h>
+#include <linux/memblock.h>
+
+void __init early_init_devtree(void *params)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* Retrieve various informations from the /chosen node of the
+        * device-tree, including the platform type, initrd location and
+        * size and more ...
+        */
+       of_scan_flat_dt(early_init_dt_scan_chosen, c6x_command_line);
+
+       /* Scan memory nodes and rebuild MEMBLOCKs */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+}
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+               unsigned long end)
+{
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
+}
+#endif
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       c6x_add_memory(base, size);
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __va(memblock_alloc(size, align));
+}
diff --git a/arch/c6x/kernel/dma.c b/arch/c6x/kernel/dma.c
new file mode 100644 (file)
index 0000000..ab7b12d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+
+#include <asm/cacheflush.h>
+
+static void c6x_dma_sync(dma_addr_t handle, size_t size,
+                        enum dma_data_direction dir)
+{
+       unsigned long paddr = handle;
+
+       BUG_ON(!valid_dma_direction(dir));
+
+       switch (dir) {
+       case DMA_FROM_DEVICE:
+               L2_cache_block_invalidate(paddr, paddr + size);
+               break;
+       case DMA_TO_DEVICE:
+               L2_cache_block_writeback(paddr, paddr + size);
+               break;
+       case DMA_BIDIRECTIONAL:
+               L2_cache_block_writeback_invalidate(paddr, paddr + size);
+               break;
+       default:
+               break;
+       }
+}
+
+dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+                         enum dma_data_direction dir)
+{
+       dma_addr_t addr = virt_to_phys(ptr);
+
+       c6x_dma_sync(addr, size, dir);
+
+       debug_dma_map_page(dev, virt_to_page(ptr),
+                          (unsigned long)ptr & ~PAGE_MASK, size,
+                          dir, addr, true);
+       return addr;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+
+void dma_unmap_single(struct device *dev, dma_addr_t handle,
+                     size_t size, enum dma_data_direction dir)
+{
+       c6x_dma_sync(handle, size, dir);
+
+       debug_dma_unmap_page(dev, handle, size, dir, true);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+
+int dma_map_sg(struct device *dev, struct scatterlist *sglist,
+              int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nents, i)
+               sg->dma_address = dma_map_single(dev, sg_virt(sg), sg->length,
+                                                dir);
+
+       debug_dma_map_sg(dev, sglist, nents, nents, dir);
+
+       return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
+                 int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nents, i)
+               dma_unmap_single(dev, sg_dma_address(sg), sg->length, dir);
+
+       debug_dma_unmap_sg(dev, sglist, nents, dir);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
+                            size_t size, enum dma_data_direction dir)
+{
+       c6x_dma_sync(handle, size, dir);
+
+       debug_dma_sync_single_for_cpu(dev, handle, size, dir);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
+                               size_t size, enum dma_data_direction dir)
+{
+       c6x_dma_sync(handle, size, dir);
+
+       debug_dma_sync_single_for_device(dev, handle, size, dir);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist,
+                        int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nents, i)
+               dma_sync_single_for_cpu(dev, sg_dma_address(sg),
+                                       sg->length, dir);
+
+       debug_dma_sync_sg_for_cpu(dev, sglist, nents, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+                           int nents, enum dma_data_direction dir)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sglist, sg, nents, i)
+               dma_sync_single_for_device(dev, sg_dma_address(sg),
+                                          sg->length, dir);
+
+       debug_dma_sync_sg_for_device(dev, sglist, nents, dir);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+
+/* Number of entries preallocated for DMA-API debugging */
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+       return 0;
+}
+fs_initcall(dma_init);
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
new file mode 100644 (file)
index 0000000..3e977cc
--- /dev/null
@@ -0,0 +1,803 @@
+;
+;  Port on Texas Instruments TMS320C6x architecture
+;
+;  Copyright (C) 2004-2011 Texas Instruments Incorporated
+;  Author: Aurelien Jacquiot (aurelien.jacquiot@virtuallogix.com)
+;  Updated for 2.6.34: Mark Salter <msalter@redhat.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/sys.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+
+; Registers naming
+#define DP     B14
+#define SP     B15
+
+#ifndef CONFIG_PREEMPT
+#define resume_kernel restore_all
+#endif
+
+       .altmacro
+
+       .macro MASK_INT reg
+       MVC     .S2     CSR,reg
+       CLR     .S2     reg,0,0,reg
+       MVC     .S2     reg,CSR
+       .endm
+
+       .macro UNMASK_INT reg
+       MVC     .S2     CSR,reg
+       SET     .S2     reg,0,0,reg
+       MVC     .S2     reg,CSR
+       .endm
+
+       .macro GET_THREAD_INFO reg
+       SHR     .S1X    SP,THREAD_SHIFT,reg
+       SHL     .S1     reg,THREAD_SHIFT,reg
+       .endm
+
+       ;;
+       ;;  This defines the normal kernel pt_regs layout.
+       ;;
+       .macro SAVE_ALL __rp __tsr
+       STW     .D2T2   B0,*SP--[2]             ; save original B0
+       MVKL    .S2     current_ksp,B0
+       MVKH    .S2     current_ksp,B0
+       LDW     .D2T2   *B0,B1                  ; KSP
+
+       NOP     3
+       STW     .D2T2   B1,*+SP[1]              ; save original B1
+       XOR     .D2     SP,B1,B0                ; (SP ^ KSP)
+       LDW     .D2T2   *+SP[1],B1              ; restore B0/B1
+       LDW     .D2T2   *++SP[2],B0
+       SHR     .S2     B0,THREAD_SHIFT,B0      ; 0 if already using kstack
+  [B0] STDW    .D2T2   SP:DP,*--B1[1]          ; user: save user sp/dp kstack
+  [B0] MV      .S2     B1,SP                   ;    and switch to kstack
+||[!B0] STDW   .D2T2   SP:DP,*--SP[1]          ; kernel: save on current stack
+
+       SUBAW   .D2     SP,2,SP
+
+       ADD     .D1X    SP,-8,A15
+ ||    STDW    .D2T1   A15:A14,*SP--[16]       ; save A15:A14
+
+       STDW    .D2T2   B13:B12,*SP--[1]
+ ||    STDW    .D1T1   A13:A12,*A15--[1]
+ ||    MVC     .S2     __rp,B13
+
+       STDW    .D2T2   B11:B10,*SP--[1]
+ ||    STDW    .D1T1   A11:A10,*A15--[1]
+ ||    MVC     .S2     CSR,B12
+
+       STDW    .D2T2   B9:B8,*SP--[1]
+ ||    STDW    .D1T1   A9:A8,*A15--[1]
+ ||    MVC     .S2     RILC,B11
+       STDW    .D2T2   B7:B6,*SP--[1]
+ ||    STDW    .D1T1   A7:A6,*A15--[1]
+ ||    MVC     .S2     ILC,B10
+
+       STDW    .D2T2   B5:B4,*SP--[1]
+ ||    STDW    .D1T1   A5:A4,*A15--[1]
+
+       STDW    .D2T2   B3:B2,*SP--[1]
+ ||    STDW    .D1T1   A3:A2,*A15--[1]
+ ||    MVC     .S2     __tsr,B5
+
+       STDW    .D2T2   B1:B0,*SP--[1]
+ ||    STDW    .D1T1   A1:A0,*A15--[1]
+ ||    MV      .S1X    B5,A5
+
+       STDW    .D2T2   B31:B30,*SP--[1]
+ ||    STDW    .D1T1   A31:A30,*A15--[1]
+       STDW    .D2T2   B29:B28,*SP--[1]
+ ||    STDW    .D1T1   A29:A28,*A15--[1]
+       STDW    .D2T2   B27:B26,*SP--[1]
+ ||    STDW    .D1T1   A27:A26,*A15--[1]
+       STDW    .D2T2   B25:B24,*SP--[1]
+ ||    STDW    .D1T1   A25:A24,*A15--[1]
+       STDW    .D2T2   B23:B22,*SP--[1]
+ ||    STDW    .D1T1   A23:A22,*A15--[1]
+       STDW    .D2T2   B21:B20,*SP--[1]
+ ||    STDW    .D1T1   A21:A20,*A15--[1]
+       STDW    .D2T2   B19:B18,*SP--[1]
+ ||    STDW    .D1T1   A19:A18,*A15--[1]
+       STDW    .D2T2   B17:B16,*SP--[1]
+ ||    STDW    .D1T1   A17:A16,*A15--[1]
+
+       STDW    .D2T2   B13:B12,*SP--[1]        ; save PC and CSR
+
+       STDW    .D2T2   B11:B10,*SP--[1]        ; save RILC and ILC
+       STDW    .D2T1   A5:A4,*SP--[1]          ; save TSR and orig A4
+
+       ;; We left an unused word on the stack just above pt_regs.
+       ;; It is used to save whether or not this frame is due to
+       ;; a syscall. It is cleared here, but the syscall handler
+       ;; sets it to a non-zero value.
+       MVK     .L2     0,B1
+       STW     .D2T2   B1,*+SP(REGS__END+8)    ; clear syscall flag
+       .endm
+
+       .macro RESTORE_ALL __rp __tsr
+       LDDW    .D2T2   *++SP[1],B9:B8          ; get TSR (B9)
+       LDDW    .D2T2   *++SP[1],B11:B10        ; get RILC (B11) and ILC (B10)
+       LDDW    .D2T2   *++SP[1],B13:B12        ; get PC (B13) and CSR (B12)
+
+       ADDAW   .D1X    SP,30,A15
+
+       LDDW    .D1T1   *++A15[1],A17:A16
+ ||    LDDW    .D2T2   *++SP[1],B17:B16
+       LDDW    .D1T1   *++A15[1],A19:A18
+ ||    LDDW    .D2T2   *++SP[1],B19:B18
+       LDDW    .D1T1   *++A15[1],A21:A20
+ ||    LDDW    .D2T2   *++SP[1],B21:B20
+       LDDW    .D1T1   *++A15[1],A23:A22
+ ||    LDDW    .D2T2   *++SP[1],B23:B22
+       LDDW    .D1T1   *++A15[1],A25:A24
+ ||    LDDW    .D2T2   *++SP[1],B25:B24
+       LDDW    .D1T1   *++A15[1],A27:A26
+ ||    LDDW    .D2T2   *++SP[1],B27:B26
+       LDDW    .D1T1   *++A15[1],A29:A28
+ ||    LDDW    .D2T2   *++SP[1],B29:B28
+       LDDW    .D1T1   *++A15[1],A31:A30
+ ||    LDDW    .D2T2   *++SP[1],B31:B30
+
+       LDDW    .D1T1   *++A15[1],A1:A0
+ ||    LDDW    .D2T2   *++SP[1],B1:B0
+
+       LDDW    .D1T1   *++A15[1],A3:A2
+ ||    LDDW    .D2T2   *++SP[1],B3:B2
+ ||    MVC     .S2     B9,__tsr
+       LDDW    .D1T1   *++A15[1],A5:A4
+ ||    LDDW    .D2T2   *++SP[1],B5:B4
+ ||    MVC     .S2     B11,RILC
+       LDDW    .D1T1   *++A15[1],A7:A6
+ ||    LDDW    .D2T2   *++SP[1],B7:B6
+ ||    MVC     .S2     B10,ILC
+
+       LDDW    .D1T1   *++A15[1],A9:A8
+ ||    LDDW    .D2T2   *++SP[1],B9:B8
+ ||    MVC     .S2     B13,__rp
+
+       LDDW    .D1T1   *++A15[1],A11:A10
+ ||    LDDW    .D2T2   *++SP[1],B11:B10
+ ||    MVC     .S2     B12,CSR
+
+       LDDW    .D1T1   *++A15[1],A13:A12
+ ||    LDDW    .D2T2   *++SP[1],B13:B12
+
+       MV      .D2X    A15,SP
+ ||    MVKL    .S1     current_ksp,A15
+       MVKH    .S1     current_ksp,A15
+ ||    ADDAW   .D1X    SP,6,A14
+       STW     .D1T1   A14,*A15        ; save kernel stack pointer
+
+       LDDW    .D2T1   *++SP[1],A15:A14
+
+       B       .S2     __rp            ; return from interruption
+       LDDW    .D2T2   *+SP[1],SP:DP
+       NOP     4
+       .endm
+
+       .section .text
+
+       ;;
+       ;; Jump to schedule() then return to ret_from_exception
+       ;;
+_reschedule:
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     schedule,A0
+       MVKH    .S1     schedule,A0
+       B       .S2X    A0
+#else
+       B       .S1     schedule
+#endif
+       ADDKPC  .S2     ret_from_exception,B3,4
+
+       ;;
+       ;; Called before syscall handler when process is being debugged
+       ;;
+tracesys_on:
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     syscall_trace_entry,A0
+       MVKH    .S1     syscall_trace_entry,A0
+       B       .S2X    A0
+#else
+       B       .S1     syscall_trace_entry
+#endif
+       ADDKPC  .S2     ret_from_syscall_trace,B3,3
+       ADD     .S1X    8,SP,A4
+
+ret_from_syscall_trace:
+       ;; tracing returns (possibly new) syscall number
+       MV      .D2X    A4,B0
+ ||    MVK     .S2     __NR_syscalls,B1
+       CMPLTU  .L2     B0,B1,B1
+
+ [!B1] BNOP    .S2     ret_from_syscall_function,5
+ ||    MVK     .S1     -ENOSYS,A4
+
+       ;; reload syscall args from (possibly modified) stack frame
+       ;; and get syscall handler addr from sys_call_table:
+       LDW     .D2T2   *+SP(REGS_B4+8),B4
+ ||    MVKL    .S2     sys_call_table,B1
+       LDW     .D2T1   *+SP(REGS_A6+8),A6
+ ||    MVKH    .S2     sys_call_table,B1
+       LDW     .D2T2   *+B1[B0],B0
+ ||    MVKL    .S2     ret_from_syscall_function,B3
+       LDW     .D2T2   *+SP(REGS_B6+8),B6
+ ||    MVKH    .S2     ret_from_syscall_function,B3
+       LDW     .D2T1   *+SP(REGS_A8+8),A8
+       LDW     .D2T2   *+SP(REGS_B8+8),B8
+       NOP
+       ; B0 = sys_call_table[__NR_*]
+       BNOP    .S2     B0,5                    ; branch to syscall handler
+ ||    LDW     .D2T1   *+SP(REGS_ORIG_A4+8),A4
+
+syscall_exit_work:
+       AND     .D1     _TIF_SYSCALL_TRACE,A2,A0
+ [!A0] BNOP    .S1     work_pending,5
+ [A0]  B       .S2     syscall_trace_exit
+       ADDKPC  .S2     resume_userspace,B3,1
+       MVC     .S2     CSR,B1
+       SET     .S2     B1,0,0,B1
+       MVC     .S2     B1,CSR          ; enable ints
+
+work_pending:
+       AND     .D1     _TIF_NEED_RESCHED,A2,A0
+ [!A0] BNOP    .S1     work_notifysig,5
+
+work_resched:
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     schedule,A1
+       MVKH    .S1     schedule,A1
+       B       .S2X    A1
+#else
+       B       .S2     schedule
+#endif
+       ADDKPC  .S2     work_rescheduled,B3,4
+work_rescheduled:
+       ;; make sure we don't miss an interrupt setting need_resched or
+       ;; sigpending between sampling and the rti
+       MASK_INT B2
+       GET_THREAD_INFO A12
+       LDW     .D1T1   *+A12(THREAD_INFO_FLAGS),A2
+       MVK     .S1     _TIF_WORK_MASK,A1
+       MVK     .S1     _TIF_NEED_RESCHED,A3
+       NOP     2
+       AND     .D1     A1,A2,A0
+ ||    AND     .S1     A3,A2,A1
+ [!A0] BNOP    .S1     restore_all,5
+ [A1]  BNOP    .S1     work_resched,5
+
+work_notifysig:
+       B       .S2     do_notify_resume
+       LDW     .D2T1   *+SP(REGS__END+8),A6 ; syscall flag
+       ADDKPC  .S2     resume_userspace,B3,1
+       ADD     .S1X    8,SP,A4         ; pt_regs pointer is first arg
+       MV      .D2X    A2,B4           ; thread_info flags is second arg
+
+       ;;
+       ;; On C64x+, the return way from exception and interrupt
+       ;; is a little bit different
+       ;;
+ENTRY(ret_from_exception)
+#ifdef CONFIG_PREEMPT
+       MASK_INT B2
+#endif
+
+ENTRY(ret_from_interrupt)
+       ;;
+       ;; Check if we are comming from user mode.
+       ;;
+       LDW     .D2T2   *+SP(REGS_TSR+8),B0
+       MVK     .S2     0x40,B1
+       NOP     3
+       AND     .D2     B0,B1,B0
+ [!B0] BNOP    .S2     resume_kernel,5
+
+resume_userspace:
+       ;; make sure we don't miss an interrupt setting need_resched or
+       ;; sigpending between sampling and the rti
+       MASK_INT B2
+       GET_THREAD_INFO A12
+       LDW     .D1T1   *+A12(THREAD_INFO_FLAGS),A2
+       MVK     .S1     _TIF_WORK_MASK,A1
+       MVK     .S1     _TIF_NEED_RESCHED,A3
+       NOP     2
+       AND     .D1     A1,A2,A0
+ [A0]  BNOP    .S1     work_pending,5
+       BNOP    .S1     restore_all,5
+
+       ;;
+       ;; System call handling
+       ;; B0 = syscall number (in sys_call_table)
+       ;; A4,B4,A6,B6,A8,B8 = arguments of the syscall function
+       ;; A4 is the return value register
+       ;;
+system_call_saved:
+       MVK     .L2     1,B2
+       STW     .D2T2   B2,*+SP(REGS__END+8)    ; set syscall flag
+       MVC     .S2     B2,ECR                  ; ack the software exception
+
+       UNMASK_INT B2                   ; re-enable global IT
+
+system_call_saved_noack:
+       ;; Check system call number
+       MVK     .S2     __NR_syscalls,B1
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_ni_syscall,A0
+#endif
+       CMPLTU  .L2     B0,B1,B1
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKH    .S1     sys_ni_syscall,A0
+#endif
+
+       ;; Check for ptrace
+       GET_THREAD_INFO A12
+
+#ifdef CONFIG_C6X_BIG_KERNEL
+ [!B1] B       .S2X    A0
+#else
+ [!B1] B       .S2     sys_ni_syscall
+#endif
+ [!B1] ADDKPC  .S2     ret_from_syscall_function,B3,4
+
+       ;; Get syscall handler addr from sys_call_table
+       ;; call tracesys_on or call syscall handler
+       LDW     .D1T1   *+A12(THREAD_INFO_FLAGS),A2
+ ||    MVKL    .S2     sys_call_table,B1
+       MVKH    .S2     sys_call_table,B1
+       LDW     .D2T2   *+B1[B0],B0
+       NOP     2
+       ; A2 = thread_info flags
+       AND     .D1     _TIF_SYSCALL_TRACE,A2,A2
+ [A2]  BNOP    .S1     tracesys_on,5
+       ;; B0 = _sys_call_table[__NR_*]
+       B       .S2     B0
+       ADDKPC  .S2     ret_from_syscall_function,B3,4
+
+ret_from_syscall_function:
+       STW     .D2T1   A4,*+SP(REGS_A4+8)      ; save return value in A4
+                                               ; original A4 is in orig_A4
+syscall_exit:
+       ;; make sure we don't miss an interrupt setting need_resched or
+       ;; sigpending between sampling and the rti
+       MASK_INT B2
+       LDW     .D1T1   *+A12(THREAD_INFO_FLAGS),A2
+       MVK     .S1     _TIF_ALLWORK_MASK,A1
+       NOP     3
+       AND     .D1     A1,A2,A2 ; check for work to do
+ [A2]  BNOP    .S1     syscall_exit_work,5
+
+restore_all:
+       RESTORE_ALL NRP,NTSR
+
+       ;;
+       ;; After a fork we jump here directly from resume,
+       ;; so that A4 contains the previous task structure.
+       ;;
+ENTRY(ret_from_fork)
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     schedule_tail,A0
+       MVKH    .S1     schedule_tail,A0
+       B       .S2X    A0
+#else
+       B       .S2     schedule_tail
+#endif
+       ADDKPC  .S2     ret_from_fork_2,B3,4
+ret_from_fork_2:
+       ;; return 0 in A4 for child process
+       GET_THREAD_INFO A12
+       BNOP    .S2     syscall_exit,3
+       MVK     .L2     0,B0
+       STW     .D2T2   B0,*+SP(REGS_A4+8)
+ENDPROC(ret_from_fork)
+
+       ;;
+       ;; These are the interrupt handlers, responsible for calling __do_IRQ()
+       ;; int6 is used for syscalls (see _system_call entry)
+       ;;
+       .macro SAVE_ALL_INT
+       SAVE_ALL IRP,ITSR
+       .endm
+
+       .macro CALL_INT int
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     c6x_do_IRQ,A0
+       MVKH    .S1     c6x_do_IRQ,A0
+       BNOP    .S2X    A0,1
+       MVK     .S1     int,A4
+       ADDAW   .D2     SP,2,B4
+       MVKL    .S2     ret_from_interrupt,B3
+       MVKH    .S2     ret_from_interrupt,B3
+#else
+       CALLP   .S2     c6x_do_IRQ,B3
+ ||    MVK     .S1     int,A4
+ ||    ADDAW   .D2     SP,2,B4
+       B       .S1     ret_from_interrupt
+       NOP     5
+#endif
+       .endm
+
+ENTRY(_int4_handler)
+       SAVE_ALL_INT
+       CALL_INT 4
+ENDPROC(_int4_handler)
+
+ENTRY(_int5_handler)
+       SAVE_ALL_INT
+       CALL_INT 5
+ENDPROC(_int5_handler)
+
+ENTRY(_int6_handler)
+       SAVE_ALL_INT
+       CALL_INT 6
+ENDPROC(_int6_handler)
+
+ENTRY(_int7_handler)
+       SAVE_ALL_INT
+       CALL_INT 7
+ENDPROC(_int7_handler)
+
+ENTRY(_int8_handler)
+       SAVE_ALL_INT
+       CALL_INT 8
+ENDPROC(_int8_handler)
+
+ENTRY(_int9_handler)
+       SAVE_ALL_INT
+       CALL_INT 9
+ENDPROC(_int9_handler)
+
+ENTRY(_int10_handler)
+       SAVE_ALL_INT
+       CALL_INT 10
+ENDPROC(_int10_handler)
+
+ENTRY(_int11_handler)
+       SAVE_ALL_INT
+       CALL_INT 11
+ENDPROC(_int11_handler)
+
+ENTRY(_int12_handler)
+       SAVE_ALL_INT
+       CALL_INT 12
+ENDPROC(_int12_handler)
+
+ENTRY(_int13_handler)
+       SAVE_ALL_INT
+       CALL_INT 13
+ENDPROC(_int13_handler)
+
+ENTRY(_int14_handler)
+       SAVE_ALL_INT
+       CALL_INT 14
+ENDPROC(_int14_handler)
+
+ENTRY(_int15_handler)
+       SAVE_ALL_INT
+       CALL_INT 15
+ENDPROC(_int15_handler)
+
+       ;;
+       ;; Handler for uninitialized and spurious interrupts
+       ;;
+ENTRY(_bad_interrupt)
+       B       .S2     IRP
+       NOP     5
+ENDPROC(_bad_interrupt)
+
+       ;;
+       ;; Entry for NMI/exceptions/syscall
+       ;;
+ENTRY(_nmi_handler)
+       SAVE_ALL NRP,NTSR
+
+       MVC     .S2     EFR,B2
+       CMPEQ   .L2     1,B2,B2
+ ||    MVC     .S2     TSR,B1
+       CLR     .S2     B1,10,10,B1
+       MVC     .S2     B1,TSR
+#ifdef CONFIG_C6X_BIG_KERNEL
+ [!B2] MVKL    .S1     process_exception,A0
+ [!B2] MVKH    .S1     process_exception,A0
+ [!B2] B       .S2X    A0
+#else
+ [!B2] B       .S2     process_exception
+#endif
+ [B2]  B       .S2     system_call_saved
+ [!B2] ADDAW   .D2     SP,2,B1
+ [!B2] MV      .D1X    B1,A4
+       ADDKPC  .S2     ret_from_trap,B3,2
+
+ret_from_trap:
+       MV      .D2X    A4,B0
+ [!B0] BNOP    .S2     ret_from_exception,5
+
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S2     system_call_saved_noack,B3
+       MVKH    .S2     system_call_saved_noack,B3
+#endif
+       LDW     .D2T2   *+SP(REGS_B0+8),B0
+       LDW     .D2T1   *+SP(REGS_A4+8),A4
+       LDW     .D2T2   *+SP(REGS_B4+8),B4
+       LDW     .D2T1   *+SP(REGS_A6+8),A6
+       LDW     .D2T2   *+SP(REGS_B6+8),B6
+       LDW     .D2T1   *+SP(REGS_A8+8),A8
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    B       .S2     B3
+#else
+ ||    B       .S2     system_call_saved_noack
+#endif
+       LDW     .D2T2   *+SP(REGS_B8+8),B8
+       NOP     4
+ENDPROC(_nmi_handler)
+
+       ;;
+       ;; Jump to schedule() then return to ret_from_isr
+       ;;
+#ifdef CONFIG_PREEMPT
+resume_kernel:
+       GET_THREAD_INFO A12
+       LDW     .D1T1   *+A12(THREAD_INFO_PREEMPT_COUNT),A1
+       NOP     4
+ [A1]  BNOP    .S2     restore_all,5
+
+preempt_schedule:
+       GET_THREAD_INFO A2
+       LDW     .D1T1   *+A2(THREAD_INFO_FLAGS),A1
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S2     preempt_schedule_irq,B0
+       MVKH    .S2     preempt_schedule_irq,B0
+       NOP     2
+#else
+       NOP     4
+#endif
+       AND     .D1     _TIF_NEED_RESCHED,A1,A1
+ [!A1] BNOP    .S2     restore_all,5
+#ifdef CONFIG_C6X_BIG_KERNEL
+       B       .S2     B0
+#else
+       B       .S2     preempt_schedule_irq
+#endif
+       ADDKPC  .S2     preempt_schedule,B3,4
+#endif /* CONFIG_PREEMPT */
+
+ENTRY(enable_exception)
+       DINT
+       MVC     .S2     TSR,B0
+       MVC     .S2     B3,NRP
+       MVK     .L2     0xc,B1
+       OR      .D2     B0,B1,B0
+       MVC     .S2     B0,TSR                  ;  Set GEE and XEN in TSR
+       B       .S2     NRP
+       NOP     5
+ENDPROC(enable_exception)
+
+ENTRY(sys_sigaltstack)
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     do_sigaltstack,A0       ; branch to do_sigaltstack
+       MVKH    .S1     do_sigaltstack,A0
+       B       .S2X    A0
+#else
+       B       .S2     do_sigaltstack
+#endif
+       LDW     .D2T1   *+SP(REGS_SP+8),A6
+       NOP     4
+ENDPROC(sys_sigaltstack)
+
+       ;; kernel_execve
+ENTRY(kernel_execve)
+       MVK     .S2     __NR_execve,B0
+       SWE
+       BNOP    .S2     B3,5
+ENDPROC(kernel_execve)
+
+       ;;
+       ;; Special system calls
+       ;; return address is in B3
+       ;;
+ENTRY(sys_clone)
+       ADD     .D1X    SP,8,A4
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_c6x_clone,A0
+       MVKH    .S1     sys_c6x_clone,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     sys_c6x_clone
+       NOP     5
+#endif
+ENDPROC(sys_clone)
+
+ENTRY(sys_rt_sigreturn)
+       ADD     .D1X    SP,8,A4
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     do_rt_sigreturn,A0
+       MVKH    .S1     do_rt_sigreturn,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     do_rt_sigreturn
+       NOP     5
+#endif
+ENDPROC(sys_rt_sigreturn)
+
+ENTRY(sys_execve)
+       ADDAW   .D2     SP,2,B6         ; put regs addr in 4th parameter
+                                       ; & adjust regs stack addr
+       LDW     .D2T2   *+SP(REGS_B4+8),B4
+
+       ;; c6x_execve(char *name, char **argv,
+       ;;            char **envp, struct pt_regs *regs)
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_c6x_execve,A0
+       MVKH    .S1     sys_c6x_execve,A0
+       B       .S2X    A0
+#else
+ ||    B       .S2     sys_c6x_execve
+#endif
+       STW     .D2T2   B3,*SP--[2]
+       ADDKPC  .S2     ret_from_c6x_execve,B3,3
+
+ret_from_c6x_execve:
+       LDW     .D2T2   *++SP[2],B3
+       NOP     4
+       BNOP    .S2     B3,5
+ENDPROC(sys_execve)
+
+ENTRY(sys_pread_c6x)
+       MV      .D2X    A8,B7
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_pread64,A0
+       MVKH    .S1     sys_pread64,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     sys_pread64
+       NOP     5
+#endif
+ENDPROC(sys_pread_c6x)
+
+ENTRY(sys_pwrite_c6x)
+       MV      .D2X    A8,B7
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_pwrite64,A0
+       MVKH    .S1     sys_pwrite64,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     sys_pwrite64
+       NOP     5
+#endif
+ENDPROC(sys_pwrite_c6x)
+
+;; On Entry
+;;   A4 - path
+;;   B4 - offset_lo (LE), offset_hi (BE)
+;;   A6 - offset_lo (BE), offset_hi (LE)
+ENTRY(sys_truncate64_c6x)
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       MV      .S2     B4,B5
+       MV      .D2X    A6,B4
+#else
+       MV      .D2X    A6,B5
+#endif
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_truncate64,A0
+       MVKH    .S1     sys_truncate64,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     sys_truncate64
+       NOP     5
+#endif
+ENDPROC(sys_truncate64_c6x)
+
+;; On Entry
+;;   A4 - fd
+;;   B4 - offset_lo (LE), offset_hi (BE)
+;;   A6 - offset_lo (BE), offset_hi (LE)
+ENTRY(sys_ftruncate64_c6x)
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       MV      .S2     B4,B5
+       MV      .D2X    A6,B4
+#else
+       MV      .D2X    A6,B5
+#endif
+#ifdef CONFIG_C6X_BIG_KERNEL
+ ||    MVKL    .S1     sys_ftruncate64,A0
+       MVKH    .S1     sys_ftruncate64,A0
+       BNOP    .S2X    A0,5
+#else
+ ||    B       .S2     sys_ftruncate64
+       NOP     5
+#endif
+ENDPROC(sys_ftruncate64_c6x)
+
+#ifdef __ARCH_WANT_SYSCALL_OFF_T
+;; On Entry
+;;   A4 - fd
+;;   B4 - offset_lo (LE), offset_hi (BE)
+;;   A6 - offset_lo (BE), offset_hi (LE)
+;;   B6 - len
+;;   A8 - advice
+ENTRY(sys_fadvise64_c6x)
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     sys_fadvise64,A0
+       MVKH    .S1     sys_fadvise64,A0
+       BNOP    .S2X    A0,2
+#else
+       B       .S2     sys_fadvise64
+       NOP     2
+#endif
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       MV      .L2     B4,B5
+ ||    MV      .D2X    A6,B4
+#else
+       MV      .D2X    A6,B5
+#endif
+       MV      .D1X    B6,A6
+       MV      .D2X    A8,B6
+#endif
+ENDPROC(sys_fadvise64_c6x)
+
+;; On Entry
+;;   A4 - fd
+;;   B4 - offset_lo (LE), offset_hi (BE)
+;;   A6 - offset_lo (BE), offset_hi (LE)
+;;   B6 - len_lo (LE), len_hi (BE)
+;;   A8 - len_lo (BE), len_hi (LE)
+;;   B8 - advice
+ENTRY(sys_fadvise64_64_c6x)
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     sys_fadvise64_64,A0
+       MVKH    .S1     sys_fadvise64_64,A0
+       BNOP    .S2X    A0,2
+#else
+       B       .S2     sys_fadvise64_64
+       NOP     2
+#endif
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       MV      .L2     B4,B5
+ ||    MV      .D2X    A6,B4
+       MV      .L1     A8,A6
+ ||    MV      .D1X    B6,A7
+#else
+       MV      .D2X    A6,B5
+       MV      .L1     A8,A7
+ ||    MV      .D1X    B6,A6
+#endif
+       MV      .L2     B8,B6
+ENDPROC(sys_fadvise64_64_c6x)
+
+;; On Entry
+;;   A4 - fd
+;;   B4 - mode
+;;   A6 - offset_hi
+;;   B6 - offset_lo
+;;   A8 - len_hi
+;;   B8 - len_lo
+ENTRY(sys_fallocate_c6x)
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     sys_fallocate,A0
+       MVKH    .S1     sys_fallocate,A0
+       BNOP    .S2X    A0,1
+#else
+       B       .S2     sys_fallocate
+       NOP
+#endif
+       MV      .D1     A6,A7
+       MV      .D1X    B6,A6
+       MV      .D2X    A8,B7
+       MV      .D2     B8,B6
+ENDPROC(sys_fallocate_c6x)
+
+       ;; put this in .neardata for faster access when using DSBT mode
+       .section .neardata,"aw",@progbits
+       .global current_ksp
+       .hidden current_ksp
+current_ksp:
+       .word   init_thread_union + THREAD_START_SP
diff --git a/arch/c6x/kernel/head.S b/arch/c6x/kernel/head.S
new file mode 100644 (file)
index 0000000..133eab6
--- /dev/null
@@ -0,0 +1,84 @@
+;
+;  Port on Texas Instruments TMS320C6x architecture
+;
+;  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+;  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/linkage.h>
+#include <linux/of_fdt.h>
+#include <asm/asm-offsets.h>
+
+       __HEAD
+ENTRY(_c_int00)
+       ;; Save magic and pointer
+       MV      .S1     A4,A10
+       MV      .S2     B4,B10
+       MVKL    .S2     __bss_start,B5
+       MVKH    .S2     __bss_start,B5
+       MVKL    .S2     __bss_stop,B6
+       MVKH    .S2     __bss_stop,B6
+       SUB     .L2     B6,B5,B6 ; bss size
+
+       ;; Set the stack pointer
+       MVKL    .S2     current_ksp,B0
+       MVKH    .S2     current_ksp,B0
+       LDW     .D2T2   *B0,B15
+
+       ;; clear bss
+       SHR     .S2     B6,3,B0   ; number of dwords to clear
+       ZERO    .L2     B13
+       ZERO    .L2     B12
+bss_loop:
+       BDEC    .S2     bss_loop,B0
+       NOP     3
+       CMPLT   .L2     B0,0,B1
+ [!B1] STDW    .D2T2   B13:B12,*B5++[1]
+
+       NOP     4
+       AND     .D2     ~7,B15,B15
+
+       ;; Clear GIE and PGIE
+       MVC     .S2     CSR,B2
+       CLR     .S2     B2,0,1,B2
+       MVC     .S2     B2,CSR
+       MVC     .S2     TSR,B2
+       CLR     .S2     B2,0,1,B2
+       MVC     .S2     B2,TSR
+       MVC     .S2     ITSR,B2
+       CLR     .S2     B2,0,1,B2
+       MVC     .S2     B2,ITSR
+       MVC     .S2     NTSR,B2
+       CLR     .S2     B2,0,1,B2
+       MVC     .S2     B2,NTSR
+
+       ;; pass DTB pointer to machine_init (or zero if none)
+       MVKL    .S1     OF_DT_HEADER,A0
+       MVKH    .S1     OF_DT_HEADER,A0
+       CMPEQ   .L1     A10,A0,A0
+  [A0] MV      .S1X    B10,A4
+  [!A0] MVK    .S1     0,A4
+
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     machine_init,A0
+       MVKH    .S1     machine_init,A0
+       B       .S2X    A0
+       ADDKPC  .S2     0f,B3,4
+0:
+#else
+       CALLP   .S2     machine_init,B3
+#endif
+
+       ;; Jump to Linux init
+#ifdef CONFIG_C6X_BIG_KERNEL
+       MVKL    .S1     start_kernel,A0
+       MVKH    .S1     start_kernel,A0
+       B       .S2X    A0
+#else
+       B       .S2     start_kernel
+#endif
+       NOP     5
+L1:    BNOP    .S2     L1,5
diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c
new file mode 100644 (file)
index 0000000..0929e4b
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *
+ *  This borrows heavily from powerpc version, which is:
+ *
+ *  Derived from arch/i386/kernel/irq.c
+ *    Copyright (C) 1992 Linus Torvalds
+ *  Adapted from arch/i386 by Gary Thomas
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
+ *    Copyright (C) 1996-2001 Cort Dougan
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/radix-tree.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/megamod-pic.h>
+
+unsigned long irq_err_count;
+
+static DEFINE_RAW_SPINLOCK(core_irq_lock);
+
+static void mask_core_irq(struct irq_data *data)
+{
+       unsigned int prio = data->irq;
+
+       BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
+
+       raw_spin_lock(&core_irq_lock);
+       and_creg(IER, ~(1 << prio));
+       raw_spin_unlock(&core_irq_lock);
+}
+
+static void unmask_core_irq(struct irq_data *data)
+{
+       unsigned int prio = data->irq;
+
+       raw_spin_lock(&core_irq_lock);
+       or_creg(IER, 1 << prio);
+       raw_spin_unlock(&core_irq_lock);
+}
+
+static struct irq_chip core_chip = {
+       .name           = "core",
+       .irq_mask       = mask_core_irq,
+       .irq_unmask     = unmask_core_irq,
+};
+
+asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       irq_enter();
+
+       BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
+
+       generic_handle_irq(prio);
+
+       irq_exit();
+
+       set_irq_regs(old_regs);
+}
+
+static struct irq_host *core_host;
+
+static int core_host_map(struct irq_host *h, unsigned int virq,
+                        irq_hw_number_t hw)
+{
+       if (hw < 4 || hw >= NR_PRIORITY_IRQS)
+               return -EINVAL;
+
+       irq_set_status_flags(virq, IRQ_LEVEL);
+       irq_set_chip_and_handler(virq, &core_chip, handle_level_irq);
+       return 0;
+}
+
+static struct irq_host_ops core_host_ops = {
+       .map = core_host_map,
+};
+
+void __init init_IRQ(void)
+{
+       struct device_node *np;
+
+       /* Mask all priority IRQs */
+       and_creg(IER, ~0xfff0);
+
+       np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
+       if (np != NULL) {
+               /* create the core host */
+               core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0,
+                                          &core_host_ops, 0);
+               if (core_host)
+                       irq_set_default_host(core_host);
+               of_node_put(np);
+       }
+
+       printk(KERN_INFO "Core interrupt controller initialized\n");
+
+       /* now we're ready for other SoC controllers */
+       megamod_pic_init();
+
+       /* Clear all general IRQ flags */
+       set_creg(ICR, 0xfff0);
+}
+
+void ack_bad_irq(int irq)
+{
+       printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
+       irq_err_count++;
+}
+
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+       seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
+       return 0;
+}
+
+/*
+ * IRQ controller and virtual interrupts
+ */
+
+/* The main irq map itself is an array of NR_IRQ entries containing the
+ * associate host and irq number. An entry with a host of NULL is free.
+ * An entry can be allocated if it's free, the allocator always then sets
+ * hwirq first to the host's invalid irq number and then fills ops.
+ */
+struct irq_map_entry {
+       irq_hw_number_t hwirq;
+       struct irq_host *host;
+};
+
+static LIST_HEAD(irq_hosts);
+static DEFINE_RAW_SPINLOCK(irq_big_lock);
+static DEFINE_MUTEX(revmap_trees_mutex);
+static struct irq_map_entry irq_map[NR_IRQS];
+static unsigned int irq_virq_count = NR_IRQS;
+static struct irq_host *irq_default_host;
+
+irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
+{
+       return irq_map[d->irq].hwirq;
+}
+EXPORT_SYMBOL_GPL(irqd_to_hwirq);
+
+irq_hw_number_t virq_to_hw(unsigned int virq)
+{
+       return irq_map[virq].hwirq;
+}
+EXPORT_SYMBOL_GPL(virq_to_hw);
+
+bool virq_is_host(unsigned int virq, struct irq_host *host)
+{
+       return irq_map[virq].host == host;
+}
+EXPORT_SYMBOL_GPL(virq_is_host);
+
+static int default_irq_host_match(struct irq_host *h, struct device_node *np)
+{
+       return h->of_node != NULL && h->of_node == np;
+}
+
+struct irq_host *irq_alloc_host(struct device_node *of_node,
+                               unsigned int revmap_type,
+                               unsigned int revmap_arg,
+                               struct irq_host_ops *ops,
+                               irq_hw_number_t inval_irq)
+{
+       struct irq_host *host;
+       unsigned int size = sizeof(struct irq_host);
+       unsigned int i;
+       unsigned int *rmap;
+       unsigned long flags;
+
+       /* Allocate structure and revmap table if using linear mapping */
+       if (revmap_type == IRQ_HOST_MAP_LINEAR)
+               size += revmap_arg * sizeof(unsigned int);
+       host = kzalloc(size, GFP_KERNEL);
+       if (host == NULL)
+               return NULL;
+
+       /* Fill structure */
+       host->revmap_type = revmap_type;
+       host->inval_irq = inval_irq;
+       host->ops = ops;
+       host->of_node = of_node_get(of_node);
+
+       if (host->ops->match == NULL)
+               host->ops->match = default_irq_host_match;
+
+       raw_spin_lock_irqsave(&irq_big_lock, flags);
+
+       /* Check for the priority controller. */
+       if (revmap_type == IRQ_HOST_MAP_PRIORITY) {
+               if (irq_map[0].host != NULL) {
+                       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+                       of_node_put(host->of_node);
+                       kfree(host);
+                       return NULL;
+               }
+               irq_map[0].host = host;
+       }
+
+       list_add(&host->link, &irq_hosts);
+       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+
+       /* Additional setups per revmap type */
+       switch (revmap_type) {
+       case IRQ_HOST_MAP_PRIORITY:
+               /* 0 is always the invalid number for priority */
+               host->inval_irq = 0;
+               /* setup us as the host for all priority interrupts */
+               for (i = 1; i < NR_PRIORITY_IRQS; i++) {
+                       irq_map[i].hwirq = i;
+                       smp_wmb();
+                       irq_map[i].host = host;
+                       smp_wmb();
+
+                       ops->map(host, i, i);
+               }
+               break;
+       case IRQ_HOST_MAP_LINEAR:
+               rmap = (unsigned int *)(host + 1);
+               for (i = 0; i < revmap_arg; i++)
+                       rmap[i] = NO_IRQ;
+               host->revmap_data.linear.size = revmap_arg;
+               smp_wmb();
+               host->revmap_data.linear.revmap = rmap;
+               break;
+       case IRQ_HOST_MAP_TREE:
+               INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
+               break;
+       default:
+               break;
+       }
+
+       pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
+
+       return host;
+}
+
+struct irq_host *irq_find_host(struct device_node *node)
+{
+       struct irq_host *h, *found = NULL;
+       unsigned long flags;
+
+       /* We might want to match the legacy controller last since
+        * it might potentially be set to match all interrupts in
+        * the absence of a device node. This isn't a problem so far
+        * yet though...
+        */
+       raw_spin_lock_irqsave(&irq_big_lock, flags);
+       list_for_each_entry(h, &irq_hosts, link)
+               if (h->ops->match(h, node)) {
+                       found = h;
+                       break;
+               }
+       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+       return found;
+}
+EXPORT_SYMBOL_GPL(irq_find_host);
+
+void irq_set_default_host(struct irq_host *host)
+{
+       pr_debug("irq: Default host set to @0x%p\n", host);
+
+       irq_default_host = host;
+}
+
+void irq_set_virq_count(unsigned int count)
+{
+       pr_debug("irq: Trying to set virq count to %d\n", count);
+
+       BUG_ON(count < NR_PRIORITY_IRQS);
+       if (count < NR_IRQS)
+               irq_virq_count = count;
+}
+
+static int irq_setup_virq(struct irq_host *host, unsigned int virq,
+                           irq_hw_number_t hwirq)
+{
+       int res;
+
+       res = irq_alloc_desc_at(virq, 0);
+       if (res != virq) {
+               pr_debug("irq: -> allocating desc failed\n");
+               goto error;
+       }
+
+       /* map it */
+       smp_wmb();
+       irq_map[virq].hwirq = hwirq;
+       smp_mb();
+
+       if (host->ops->map(host, virq, hwirq)) {
+               pr_debug("irq: -> mapping failed, freeing\n");
+               goto errdesc;
+       }
+
+       irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
+       return 0;
+
+errdesc:
+       irq_free_descs(virq, 1);
+error:
+       irq_free_virt(virq, 1);
+       return -1;
+}
+
+unsigned int irq_create_direct_mapping(struct irq_host *host)
+{
+       unsigned int virq;
+
+       if (host == NULL)
+               host = irq_default_host;
+
+       BUG_ON(host == NULL);
+       WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
+
+       virq = irq_alloc_virt(host, 1, 0);
+       if (virq == NO_IRQ) {
+               pr_debug("irq: create_direct virq allocation failed\n");
+               return NO_IRQ;
+       }
+
+       pr_debug("irq: create_direct obtained virq %d\n", virq);
+
+       if (irq_setup_virq(host, virq, virq))
+               return NO_IRQ;
+
+       return virq;
+}
+
+unsigned int irq_create_mapping(struct irq_host *host,
+                               irq_hw_number_t hwirq)
+{
+       unsigned int virq, hint;
+
+       pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
+
+       /* Look for default host if nececssary */
+       if (host == NULL)
+               host = irq_default_host;
+       if (host == NULL) {
+               printk(KERN_WARNING "irq_create_mapping called for"
+                      " NULL host, hwirq=%lx\n", hwirq);
+               WARN_ON(1);
+               return NO_IRQ;
+       }
+       pr_debug("irq: -> using host @%p\n", host);
+
+       /* Check if mapping already exists */
+       virq = irq_find_mapping(host, hwirq);
+       if (virq != NO_IRQ) {
+               pr_debug("irq: -> existing mapping on virq %d\n", virq);
+               return virq;
+       }
+
+       /* Allocate a virtual interrupt number */
+       hint = hwirq % irq_virq_count;
+       virq = irq_alloc_virt(host, 1, hint);
+       if (virq == NO_IRQ) {
+               pr_debug("irq: -> virq allocation failed\n");
+               return NO_IRQ;
+       }
+
+       if (irq_setup_virq(host, virq, hwirq))
+               return NO_IRQ;
+
+       pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
+               hwirq, host->of_node ? host->of_node->full_name : "null", virq);
+
+       return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_mapping);
+
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       struct irq_host *host;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       unsigned int virq;
+
+       if (controller == NULL)
+               host = irq_default_host;
+       else
+               host = irq_find_host(controller);
+       if (host == NULL) {
+               printk(KERN_WARNING "irq: no irq host found for %s !\n",
+                      controller->full_name);
+               return NO_IRQ;
+       }
+
+       /* If host has no translation, then we assume interrupt line */
+       if (host->ops->xlate == NULL)
+               hwirq = intspec[0];
+       else {
+               if (host->ops->xlate(host, controller, intspec, intsize,
+                                    &hwirq, &type))
+                       return NO_IRQ;
+       }
+
+       /* Create mapping */
+       virq = irq_create_mapping(host, hwirq);
+       if (virq == NO_IRQ)
+               return virq;
+
+       /* Set type if specified and different than the current one */
+       if (type != IRQ_TYPE_NONE &&
+           type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
+               irq_set_irq_type(virq, type);
+       return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+void irq_dispose_mapping(unsigned int virq)
+{
+       struct irq_host *host;
+       irq_hw_number_t hwirq;
+
+       if (virq == NO_IRQ)
+               return;
+
+       /* Never unmap priority interrupts */
+       if (virq < NR_PRIORITY_IRQS)
+               return;
+
+       host = irq_map[virq].host;
+       if (WARN_ON(host == NULL))
+               return;
+
+       irq_set_status_flags(virq, IRQ_NOREQUEST);
+
+       /* remove chip and handler */
+       irq_set_chip_and_handler(virq, NULL, NULL);
+
+       /* Make sure it's completed */
+       synchronize_irq(virq);
+
+       /* Tell the PIC about it */
+       if (host->ops->unmap)
+               host->ops->unmap(host, virq);
+       smp_mb();
+
+       /* Clear reverse map */
+       hwirq = irq_map[virq].hwirq;
+       switch (host->revmap_type) {
+       case IRQ_HOST_MAP_LINEAR:
+               if (hwirq < host->revmap_data.linear.size)
+                       host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
+               break;
+       case IRQ_HOST_MAP_TREE:
+               mutex_lock(&revmap_trees_mutex);
+               radix_tree_delete(&host->revmap_data.tree, hwirq);
+               mutex_unlock(&revmap_trees_mutex);
+               break;
+       }
+
+       /* Destroy map */
+       smp_mb();
+       irq_map[virq].hwirq = host->inval_irq;
+
+       irq_free_descs(virq, 1);
+       /* Free it */
+       irq_free_virt(virq, 1);
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+
+unsigned int irq_find_mapping(struct irq_host *host,
+                             irq_hw_number_t hwirq)
+{
+       unsigned int i;
+       unsigned int hint = hwirq % irq_virq_count;
+
+       /* Look for default host if nececssary */
+       if (host == NULL)
+               host = irq_default_host;
+       if (host == NULL)
+               return NO_IRQ;
+
+       /* Slow path does a linear search of the map */
+       i = hint;
+       do  {
+               if (irq_map[i].host == host &&
+                   irq_map[i].hwirq == hwirq)
+                       return i;
+               i++;
+               if (i >= irq_virq_count)
+                       i = 4;
+       } while (i != hint);
+       return NO_IRQ;
+}
+EXPORT_SYMBOL_GPL(irq_find_mapping);
+
+unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+                                    irq_hw_number_t hwirq)
+{
+       struct irq_map_entry *ptr;
+       unsigned int virq;
+
+       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
+               return irq_find_mapping(host, hwirq);
+
+       /*
+        * The ptr returned references the static global irq_map.
+        * but freeing an irq can delete nodes along the path to
+        * do the lookup via call_rcu.
+        */
+       rcu_read_lock();
+       ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
+       rcu_read_unlock();
+
+       /*
+        * If found in radix tree, then fine.
+        * Else fallback to linear lookup - this should not happen in practice
+        * as it means that we failed to insert the node in the radix tree.
+        */
+       if (ptr)
+               virq = ptr - irq_map;
+       else
+               virq = irq_find_mapping(host, hwirq);
+
+       return virq;
+}
+
+void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+                            irq_hw_number_t hwirq)
+{
+       if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
+               return;
+
+       if (virq != NO_IRQ) {
+               mutex_lock(&revmap_trees_mutex);
+               radix_tree_insert(&host->revmap_data.tree, hwirq,
+                                 &irq_map[virq]);
+               mutex_unlock(&revmap_trees_mutex);
+       }
+}
+
+unsigned int irq_linear_revmap(struct irq_host *host,
+                              irq_hw_number_t hwirq)
+{
+       unsigned int *revmap;
+
+       if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
+               return irq_find_mapping(host, hwirq);
+
+       /* Check revmap bounds */
+       if (unlikely(hwirq >= host->revmap_data.linear.size))
+               return irq_find_mapping(host, hwirq);
+
+       /* Check if revmap was allocated */
+       revmap = host->revmap_data.linear.revmap;
+       if (unlikely(revmap == NULL))
+               return irq_find_mapping(host, hwirq);
+
+       /* Fill up revmap with slow path if no mapping found */
+       if (unlikely(revmap[hwirq] == NO_IRQ))
+               revmap[hwirq] = irq_find_mapping(host, hwirq);
+
+       return revmap[hwirq];
+}
+
+unsigned int irq_alloc_virt(struct irq_host *host,
+                           unsigned int count,
+                           unsigned int hint)
+{
+       unsigned long flags;
+       unsigned int i, j, found = NO_IRQ;
+
+       if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS))
+               return NO_IRQ;
+
+       raw_spin_lock_irqsave(&irq_big_lock, flags);
+
+       /* Use hint for 1 interrupt if any */
+       if (count == 1 && hint >= NR_PRIORITY_IRQS &&
+           hint < irq_virq_count && irq_map[hint].host == NULL) {
+               found = hint;
+               goto hint_found;
+       }
+
+       /* Look for count consecutive numbers in the allocatable
+        * (non-legacy) space
+        */
+       for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) {
+               if (irq_map[i].host != NULL)
+                       j = 0;
+               else
+                       j++;
+
+               if (j == count) {
+                       found = i - count + 1;
+                       break;
+               }
+       }
+       if (found == NO_IRQ) {
+               raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+               return NO_IRQ;
+       }
+ hint_found:
+       for (i = found; i < (found + count); i++) {
+               irq_map[i].hwirq = host->inval_irq;
+               smp_wmb();
+               irq_map[i].host = host;
+       }
+       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+       return found;
+}
+
+void irq_free_virt(unsigned int virq, unsigned int count)
+{
+       unsigned long flags;
+       unsigned int i;
+
+       WARN_ON(virq < NR_PRIORITY_IRQS);
+       WARN_ON(count == 0 || (virq + count) > irq_virq_count);
+
+       if (virq < NR_PRIORITY_IRQS) {
+               if (virq + count < NR_PRIORITY_IRQS)
+                       return;
+               count  -= NR_PRIORITY_IRQS - virq;
+               virq = NR_PRIORITY_IRQS;
+       }
+
+       if (count > irq_virq_count || virq > irq_virq_count - count) {
+               if (virq > irq_virq_count)
+                       return;
+               count = irq_virq_count - virq;
+       }
+
+       raw_spin_lock_irqsave(&irq_big_lock, flags);
+       for (i = virq; i < (virq + count); i++) {
+               struct irq_host *host;
+
+               host = irq_map[i].host;
+               irq_map[i].hwirq = host->inval_irq;
+               smp_wmb();
+               irq_map[i].host = NULL;
+       }
+       raw_spin_unlock_irqrestore(&irq_big_lock, flags);
+}
+
+#ifdef CONFIG_VIRQ_DEBUG
+static int virq_debug_show(struct seq_file *m, void *private)
+{
+       unsigned long flags;
+       struct irq_desc *desc;
+       const char *p;
+       static const char none[] = "none";
+       void *data;
+       int i;
+
+       seq_printf(m, "%-5s  %-7s  %-15s  %-18s  %s\n", "virq", "hwirq",
+                     "chip name", "chip data", "host name");
+
+       for (i = 1; i < nr_irqs; i++) {
+               desc = irq_to_desc(i);
+               if (!desc)
+                       continue;
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+
+               if (desc->action && desc->action->handler) {
+                       struct irq_chip *chip;
+
+                       seq_printf(m, "%5d  ", i);
+                       seq_printf(m, "0x%05lx  ", irq_map[i].hwirq);
+
+                       chip = irq_desc_get_chip(desc);
+                       if (chip && chip->name)
+                               p = chip->name;
+                       else
+                               p = none;
+                       seq_printf(m, "%-15s  ", p);
+
+                       data = irq_desc_get_chip_data(desc);
+                       seq_printf(m, "0x%16p  ", data);
+
+                       if (irq_map[i].host && irq_map[i].host->of_node)
+                               p = irq_map[i].host->of_node->full_name;
+                       else
+                               p = none;
+                       seq_printf(m, "%s\n", p);
+               }
+
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
+       }
+
+       return 0;
+}
+
+static int virq_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, virq_debug_show, inode->i_private);
+}
+
+static const struct file_operations virq_debug_fops = {
+       .open = virq_debug_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init irq_debugfs_init(void)
+{
+       if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
+                                NULL, &virq_debug_fops) == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+device_initcall(irq_debugfs_init);
+#endif /* CONFIG_VIRQ_DEBUG */
diff --git a/arch/c6x/kernel/module.c b/arch/c6x/kernel/module.c
new file mode 100644 (file)
index 0000000..5fc03f1
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Thomas Charleux (thomas.charleux@jaluna.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/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/kernel.h>
+
+static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift)
+{
+       u32 opcode;
+       long ep = (long)ip & ~31;
+       long delta = ((long)dest - ep) >> 2;
+       long mask = (1 << maskbits) - 1;
+
+       if ((delta >> (maskbits - 1)) == 0 ||
+           (delta >> (maskbits - 1)) == -1) {
+               opcode = *ip;
+               opcode &= ~(mask << shift);
+               opcode |= ((delta & mask) << shift);
+               *ip = opcode;
+
+               pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n",
+                        maskbits, ip, (void *)dest, opcode);
+
+               return 0;
+       }
+       pr_err("PCR_S%d reloc %p -> %p out of range!\n",
+              maskbits, ip, (void *)dest);
+
+       return -1;
+}
+
+/*
+ * apply a RELA relocation
+ */
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr;
+       Elf_Sym *sym;
+       u32 *location, opcode;
+       unsigned int i;
+       Elf32_Addr v;
+       Elf_Addr offset = 0;
+
+       pr_debug("Applying relocate section %u to %u with offset 0x%x\n",
+                relsec, sechdrs[relsec].sh_info, offset);
+
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset - offset;
+
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               /* this is the adjustment to be made */
+               v = sym->st_value + rel[i].r_addend;
+
+               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               case R_C6000_ABS32:
+                       pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v);
+                       *location = v;
+                       break;
+               case R_C6000_ABS16:
+                       pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v);
+                       *(u16 *)location = v;
+                       break;
+               case R_C6000_ABS8:
+                       pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v);
+                       *(u8 *)location = v;
+                       break;
+               case R_C6000_ABS_L16:
+                       opcode = *location;
+                       opcode &= ~0x7fff80;
+                       opcode |= ((v & 0xffff) << 7);
+                       pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n",
+                                location, v, opcode);
+                       *location = opcode;
+                       break;
+               case R_C6000_ABS_H16:
+                       opcode = *location;
+                       opcode &= ~0x7fff80;
+                       opcode |= ((v >> 9) & 0x7fff80);
+                       pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n",
+                                location, v, opcode);
+                       *location = opcode;
+                       break;
+               case R_C6000_PCR_S21:
+                       if (fixup_pcr(location, v, 21, 7))
+                               return -ENOEXEC;
+                       break;
+               case R_C6000_PCR_S12:
+                       if (fixup_pcr(location, v, 12, 16))
+                               return -ENOEXEC;
+                       break;
+               case R_C6000_PCR_S10:
+                       if (fixup_pcr(location, v, 10, 13))
+                               return -ENOEXEC;
+                       break;
+               default:
+                       pr_err("module %s: Unknown RELA relocation: %u\n",
+                              me->name, ELF32_R_TYPE(rel[i].r_info));
+                       return -ENOEXEC;
+               }
+       }
+
+       return 0;
+}
diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c
new file mode 100644 (file)
index 0000000..7ca8c41
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/init_task.h>
+#include <linux/tick.h>
+#include <linux/mqueue.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+
+#include <asm/syscalls.h>
+
+/* hooks for board specific support */
+void   (*c6x_restart)(void);
+void   (*c6x_halt)(void);
+
+extern asmlinkage void ret_from_fork(void);
+
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+
+/*
+ * Initial thread structure.
+ */
+union thread_union init_thread_union __init_task_data =        {
+       INIT_THREAD_INFO(init_task)
+};
+
+/*
+ * Initial task structure.
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+/*
+ * power off function, if any
+ */
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+static void c6x_idle(void)
+{
+       unsigned long tmp;
+
+       /*
+        * Put local_irq_enable and idle in same execute packet
+        * to make them atomic and avoid race to idle with
+        * interrupts enabled.
+        */
+       asm volatile ("   mvc .s2 CSR,%0\n"
+                     "   or  .d2 1,%0,%0\n"
+                     "   mvc .s2 %0,CSR\n"
+                     "|| idle\n"
+                     : "=b"(tmp));
+}
+
+/*
+ * The idle loop for C64x
+ */
+void cpu_idle(void)
+{
+       /* endless idle loop with no priority at all */
+       while (1) {
+               tick_nohz_idle_enter();
+               rcu_idle_enter();
+               while (1) {
+                       local_irq_disable();
+                       if (need_resched()) {
+                               local_irq_enable();
+                               break;
+                       }
+                       c6x_idle(); /* enables local irqs */
+               }
+               rcu_idle_exit();
+               tick_nohz_idle_exit();
+
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+static void halt_loop(void)
+{
+       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       local_irq_disable();
+       while (1)
+               asm volatile("idle\n");
+}
+
+void machine_restart(char *__unused)
+{
+       if (c6x_restart)
+               c6x_restart();
+       halt_loop();
+}
+
+void machine_halt(void)
+{
+       if (c6x_halt)
+               c6x_halt();
+       halt_loop();
+}
+
+void machine_power_off(void)
+{
+       if (pm_power_off)
+               pm_power_off();
+       halt_loop();
+}
+
+static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *))
+{
+       do_exit(fn(arg));
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       struct pt_regs regs;
+
+       /*
+        * copy_thread sets a4 to zero (child return from fork)
+        * so we can't just set things up to directly return to
+        * fn.
+        */
+       memset(&regs, 0, sizeof(regs));
+       regs.b4 = (unsigned long) arg;
+       regs.a6 = (unsigned long) fn;
+       regs.pc = (unsigned long) kernel_thread_helper;
+       local_save_flags(regs.csr);
+       regs.csr |= 1;
+       regs.tsr = 5; /* Set GEE and GIE in TSR */
+
+       /* Ok, create the new process.. */
+       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, &regs,
+                      0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+void flush_thread(void)
+{
+}
+
+void exit_thread(void)
+{
+}
+
+SYSCALL_DEFINE1(c6x_clone, struct pt_regs *, regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+
+       /* syscall puts clone_flags in A4 and usp in B4 */
+       clone_flags = regs->orig_a4;
+       if (regs->b4)
+               newsp = regs->b4;
+       else
+               newsp = regs->sp;
+
+       return do_fork(clone_flags, newsp, regs, 0, (int __user *)regs->a6,
+                      (int __user *)regs->b6);
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
+{
+       /*
+        * The binfmt loader will setup a "full" stack, but the C6X
+        * operates an "empty" stack. So we adjust the usp so that
+        * argc doesn't get destroyed if an interrupt is taken before
+        * it is read from the stack.
+        *
+        * NB: Library startup code needs to match this.
+        */
+       usp -= 8;
+
+       set_fs(USER_DS);
+       regs->pc  = pc;
+       regs->sp  = usp;
+       regs->tsr |= 0x40; /* set user mode */
+       current->thread.usp = usp;
+}
+
+/*
+ * Copy a new thread context in its stack.
+ */
+int copy_thread(unsigned long clone_flags, unsigned long usp,
+               unsigned long ustk_size,
+               struct task_struct *p, struct pt_regs *regs)
+{
+       struct pt_regs *childregs;
+
+       childregs = task_pt_regs(p);
+
+       *childregs = *regs;
+       childregs->a4 = 0;
+
+       if (usp == -1)
+               /* case of  __kernel_thread: we return to supervisor space */
+               childregs->sp = (unsigned long)(childregs + 1);
+       else
+               /* Otherwise use the given stack */
+               childregs->sp = usp;
+
+       /* Set usp/ksp */
+       p->thread.usp = childregs->sp;
+       /* switch_to uses stack to save/restore 14 callee-saved regs */
+       thread_saved_ksp(p) = (unsigned long)childregs - 8;
+       p->thread.pc = (unsigned int) ret_from_fork;
+       p->thread.wchan = (unsigned long) ret_from_fork;
+#ifdef __DSBT__
+       {
+               unsigned long dp;
+
+               asm volatile ("mv .S2 b14,%0\n" : "=b"(dp));
+
+               thread_saved_dp(p) = dp;
+               if (usp == -1)
+                       childregs->dp = dp;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * c6x_execve() executes a new program.
+ */
+SYSCALL_DEFINE4(c6x_execve, const char __user *, name,
+               const char __user *const __user *, argv,
+               const char __user *const __user *, envp,
+               struct pt_regs *, regs)
+{
+       int error;
+       char *filename;
+
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+out:
+       return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       return p->thread.wchan;
+}
diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..3c494e8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.34: Mark Salter <msalter@redhat.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/ptrace.h>
+#include <linux/tracehook.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
+
+#include <asm/cacheflush.h>
+
+#define PT_REG_SIZE      (sizeof(struct pt_regs))
+
+/*
+ * Called by kernel/ptrace.c when detaching.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       /* nothing to do */
+}
+
+/*
+ * Get a register number from live pt_regs for the specified task.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+       long *addr = (long *)task_pt_regs(task);
+
+       if (regno == PT_TSR || regno == PT_CSR)
+               return 0;
+
+       return addr[regno];
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task,
+                         int regno,
+                         unsigned long data)
+{
+       unsigned long *addr = (unsigned long *)task_pt_regs(task);
+
+       if (regno != PT_TSR && regno != PT_CSR)
+               addr[regno] = data;
+
+       return 0;
+}
+
+/* regset get/set implementations */
+
+static int gpr_get(struct task_struct *target,
+                  const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       struct pt_regs *regs = task_pt_regs(target);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  regs,
+                                  0, sizeof(*regs));
+}
+
+static int gpr_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;
+       struct pt_regs *regs = task_pt_regs(target);
+
+       /* Don't copyin TSR or CSR */
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs,
+                                0, PT_TSR * sizeof(long));
+       if (ret)
+               return ret;
+
+       ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       PT_TSR * sizeof(long),
+                                       (PT_TSR + 1) * sizeof(long));
+       if (ret)
+               return ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs,
+                                (PT_TSR + 1) * sizeof(long),
+                                PT_CSR * sizeof(long));
+       if (ret)
+               return ret;
+
+       ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+                                       PT_CSR * sizeof(long),
+                                       (PT_CSR + 1) * sizeof(long));
+       if (ret)
+               return ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &regs,
+                                (PT_CSR + 1) * sizeof(long), -1);
+       return ret;
+}
+
+enum c6x_regset {
+       REGSET_GPR,
+};
+
+static const struct user_regset c6x_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = ELF_NGREG,
+               .size = sizeof(u32),
+               .align = sizeof(u32),
+               .get = gpr_get,
+               .set = gpr_set
+       },
+};
+
+static const struct user_regset_view user_c6x_native_view = {
+       .name           = "tic6x",
+       .e_machine      = EM_TI_C6000,
+       .regsets        = c6x_regsets,
+       .n              = ARRAY_SIZE(c6x_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &user_c6x_native_view;
+}
+
+/*
+ * Perform ptrace request
+ */
+long arch_ptrace(struct task_struct *child, long request,
+                unsigned long addr, unsigned long data)
+{
+       int ret = 0;
+
+       switch (request) {
+               /*
+                * write the word at location addr.
+                */
+       case PTRACE_POKETEXT:
+               ret = generic_ptrace_pokedata(child, addr, data);
+               if (ret == 0 && request == PTRACE_POKETEXT)
+                       flush_icache_range(addr, addr + 4);
+               break;
+       default:
+               ret = ptrace_request(child, request, addr, data);
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * handle tracing of system call entry
+ * - return the revised system call number or ULONG_MAX to cause ENOSYS
+ */
+asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
+{
+       if (tracehook_report_syscall_entry(regs))
+               /* tracing decided this syscall should not happen, so
+                * We'll return a bogus call number to get an ENOSYS
+                * error, but leave the original number in
+                * regs->orig_a4
+                */
+               return ULONG_MAX;
+
+       return regs->b0;
+}
+
+/*
+ * handle tracing of system call exit
+ */
+asmlinkage void syscall_trace_exit(struct pt_regs *regs)
+{
+       tracehook_report_syscall_exit(regs, 0);
+}
diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c
new file mode 100644 (file)
index 0000000..0c07921
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/dma-mapping.h>
+#include <linux/memblock.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/clkdev.h>
+#include <linux/initrd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cache.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/fs.h>
+#include <linux/of.h>
+
+
+#include <asm/sections.h>
+#include <asm/div64.h>
+#include <asm/setup.h>
+#include <asm/dscr.h>
+#include <asm/clock.h>
+#include <asm/soc.h>
+
+static const char *c6x_soc_name;
+
+int c6x_num_cores;
+EXPORT_SYMBOL_GPL(c6x_num_cores);
+
+unsigned int c6x_silicon_rev;
+EXPORT_SYMBOL_GPL(c6x_silicon_rev);
+
+/*
+ * Device status register. This holds information
+ * about device configuration needed by some drivers.
+ */
+unsigned int c6x_devstat;
+EXPORT_SYMBOL_GPL(c6x_devstat);
+
+/*
+ * Some SoCs have fuse registers holding a unique MAC
+ * address. This is parsed out of the device tree with
+ * the resulting MAC being held here.
+ */
+unsigned char c6x_fuse_mac[6];
+
+unsigned long memory_start;
+unsigned long memory_end;
+
+unsigned long ram_start;
+unsigned long ram_end;
+
+/* Uncached memory for DMA consistent use (memdma=) */
+static unsigned long dma_start __initdata;
+static unsigned long dma_size __initdata;
+
+char c6x_command_line[COMMAND_LINE_SIZE];
+
+#if defined(CONFIG_CMDLINE_BOOL)
+static const char default_command_line[COMMAND_LINE_SIZE] __section(.cmdline) =
+       CONFIG_CMDLINE;
+#endif
+
+struct cpuinfo_c6x {
+       const char *cpu_name;
+       const char *cpu_voltage;
+       const char *mmu;
+       const char *fpu;
+       char *cpu_rev;
+       unsigned int core_id;
+       char __cpu_rev[5];
+};
+
+static DEFINE_PER_CPU(struct cpuinfo_c6x, cpu_data);
+
+unsigned int ticks_per_ns_scaled;
+EXPORT_SYMBOL(ticks_per_ns_scaled);
+
+unsigned int c6x_core_freq;
+
+static void __init get_cpuinfo(void)
+{
+       unsigned cpu_id, rev_id, csr;
+       struct clk *coreclk = clk_get_sys(NULL, "core");
+       unsigned long core_khz;
+       u64 tmp;
+       struct cpuinfo_c6x *p;
+       struct device_node *node, *np;
+
+       p = &per_cpu(cpu_data, smp_processor_id());
+
+       if (!IS_ERR(coreclk))
+               c6x_core_freq = clk_get_rate(coreclk);
+       else {
+               printk(KERN_WARNING
+                      "Cannot find core clock frequency. Using 700MHz\n");
+               c6x_core_freq = 700000000;
+       }
+
+       core_khz = c6x_core_freq / 1000;
+
+       tmp = (uint64_t)core_khz << C6X_NDELAY_SCALE;
+       do_div(tmp, 1000000);
+       ticks_per_ns_scaled = tmp;
+
+       csr = get_creg(CSR);
+       cpu_id = csr >> 24;
+       rev_id = (csr >> 16) & 0xff;
+
+       p->mmu = "none";
+       p->fpu = "none";
+       p->cpu_voltage = "unknown";
+
+       switch (cpu_id) {
+       case 0:
+               p->cpu_name = "C67x";
+               p->fpu = "yes";
+               break;
+       case 2:
+               p->cpu_name = "C62x";
+               break;
+       case 8:
+               p->cpu_name = "C64x";
+               break;
+       case 12:
+               p->cpu_name = "C64x";
+               break;
+       case 16:
+               p->cpu_name = "C64x+";
+               p->cpu_voltage = "1.2";
+               break;
+       default:
+               p->cpu_name = "unknown";
+               break;
+       }
+
+       if (cpu_id < 16) {
+               switch (rev_id) {
+               case 0x1:
+                       if (cpu_id > 8) {
+                               p->cpu_rev = "DM640/DM641/DM642/DM643";
+                               p->cpu_voltage = "1.2 - 1.4";
+                       } else {
+                               p->cpu_rev = "C6201";
+                               p->cpu_voltage = "2.5";
+                       }
+                       break;
+               case 0x2:
+                       p->cpu_rev = "C6201B/C6202/C6211";
+                       p->cpu_voltage = "1.8";
+                       break;
+               case 0x3:
+                       p->cpu_rev = "C6202B/C6203/C6204/C6205";
+                       p->cpu_voltage = "1.5";
+                       break;
+               case 0x201:
+                       p->cpu_rev = "C6701 revision 0 (early CPU)";
+                       p->cpu_voltage = "1.8";
+                       break;
+               case 0x202:
+                       p->cpu_rev = "C6701/C6711/C6712";
+                       p->cpu_voltage = "1.8";
+                       break;
+               case 0x801:
+                       p->cpu_rev = "C64x";
+                       p->cpu_voltage = "1.5";
+                       break;
+               default:
+                       p->cpu_rev = "unknown";
+               }
+       } else {
+               p->cpu_rev = p->__cpu_rev;
+               snprintf(p->__cpu_rev, sizeof(p->__cpu_rev), "0x%x", cpu_id);
+       }
+
+       p->core_id = get_coreid();
+
+       node = of_find_node_by_name(NULL, "cpus");
+       if (node) {
+               for_each_child_of_node(node, np)
+                       if (!strcmp("cpu", np->name))
+                               ++c6x_num_cores;
+               of_node_put(node);
+       }
+
+       node = of_find_node_by_name(NULL, "soc");
+       if (node) {
+               if (of_property_read_string(node, "model", &c6x_soc_name))
+                       c6x_soc_name = "unknown";
+               of_node_put(node);
+       } else
+               c6x_soc_name = "unknown";
+
+       printk(KERN_INFO "CPU%d: %s rev %s, %s volts, %uMHz\n",
+              p->core_id, p->cpu_name, p->cpu_rev,
+              p->cpu_voltage, c6x_core_freq / 1000000);
+}
+
+/*
+ * Early parsing of the command line
+ */
+static u32 mem_size __initdata;
+
+/* "mem=" parsing. */
+static int __init early_mem(char *p)
+{
+       if (!p)
+               return -EINVAL;
+
+       mem_size = memparse(p, &p);
+       /* don't remove all of memory when handling "mem={invalid}" */
+       if (mem_size == 0)
+               return -EINVAL;
+
+       return 0;
+}
+early_param("mem", early_mem);
+
+/* "memdma=<size>[@<address>]" parsing. */
+static int __init early_memdma(char *p)
+{
+       if (!p)
+               return -EINVAL;
+
+       dma_size = memparse(p, &p);
+       if (*p == '@')
+               dma_start = memparse(p, &p);
+
+       return 0;
+}
+early_param("memdma", early_memdma);
+
+int __init c6x_add_memory(phys_addr_t start, unsigned long size)
+{
+       static int ram_found __initdata;
+
+       /* We only handle one bank (the one with PAGE_OFFSET) for now */
+       if (ram_found)
+               return -EINVAL;
+
+       if (start > PAGE_OFFSET || PAGE_OFFSET >= (start + size))
+               return 0;
+
+       ram_start = start;
+       ram_end = start + size;
+
+       ram_found = 1;
+       return 0;
+}
+
+/*
+ * Do early machine setup and device tree parsing. This is called very
+ * early on the boot process.
+ */
+notrace void __init machine_init(unsigned long dt_ptr)
+{
+       struct boot_param_header *dtb = __va(dt_ptr);
+       struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start;
+
+       /* interrupts must be masked */
+       set_creg(IER, 2);
+
+       /*
+        * Set the Interrupt Service Table (IST) to the beginning of the
+        * vector table.
+        */
+       set_ist(_vectors_start);
+
+       lockdep_init();
+
+       /*
+        * dtb is passed in from bootloader.
+        * fdt is linked in blob.
+        */
+       if (dtb && dtb != fdt)
+               fdt = dtb;
+
+       /* Do some early initialization based on the flat device tree */
+       early_init_devtree(fdt);
+
+       /* parse_early_param needs a boot_command_line */
+       strlcpy(boot_command_line, c6x_command_line, COMMAND_LINE_SIZE);
+       parse_early_param();
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+       int bootmap_size;
+       struct memblock_region *reg;
+
+       printk(KERN_INFO "Initializing kernel\n");
+
+       /* Initialize command line */
+       *cmdline_p = c6x_command_line;
+
+       memory_end = ram_end;
+       memory_end &= ~(PAGE_SIZE - 1);
+
+       if (mem_size && (PAGE_OFFSET + PAGE_ALIGN(mem_size)) < memory_end)
+               memory_end = PAGE_OFFSET + PAGE_ALIGN(mem_size);
+
+       /* add block that this kernel can use */
+       memblock_add(PAGE_OFFSET, memory_end - PAGE_OFFSET);
+
+       /* reserve kernel text/data/bss */
+       memblock_reserve(PAGE_OFFSET,
+                        PAGE_ALIGN((unsigned long)&_end - PAGE_OFFSET));
+
+       if (dma_size) {
+               /* align to cacheability granularity */
+               dma_size = CACHE_REGION_END(dma_size);
+
+               if (!dma_start)
+                       dma_start = memory_end - dma_size;
+
+               /* align to cacheability granularity */
+               dma_start = CACHE_REGION_START(dma_start);
+
+               /* reserve DMA memory taken from kernel memory */
+               if (memblock_is_region_memory(dma_start, dma_size))
+                       memblock_reserve(dma_start, dma_size);
+       }
+
+       memory_start = PAGE_ALIGN((unsigned int) &_end);
+
+       printk(KERN_INFO "Memory Start=%08lx, Memory End=%08lx\n",
+              memory_start, memory_end);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       /*
+        * Reserve initrd memory if in kernel memory.
+        */
+       if (initrd_start < initrd_end)
+               if (memblock_is_region_memory(initrd_start,
+                                             initrd_end - initrd_start))
+                       memblock_reserve(initrd_start,
+                                        initrd_end - initrd_start);
+#endif
+
+       init_mm.start_code = (unsigned long) &_stext;
+       init_mm.end_code   = (unsigned long) &_etext;
+       init_mm.end_data   = memory_start;
+       init_mm.brk        = memory_start;
+
+       /*
+        * Give all the memory to the bootmap allocator,  tell it to put the
+        * boot mem_map at the start of memory
+        */
+       bootmap_size = init_bootmem_node(NODE_DATA(0),
+                                        memory_start >> PAGE_SHIFT,
+                                        PAGE_OFFSET >> PAGE_SHIFT,
+                                        memory_end >> PAGE_SHIFT);
+       memblock_reserve(memory_start, bootmap_size);
+
+       unflatten_device_tree();
+
+       c6x_cache_init();
+
+       /* Set the whole external memory as non-cacheable */
+       disable_caching(ram_start, ram_end - 1);
+
+       /* Set caching of external RAM used by Linux */
+       for_each_memblock(memory, reg)
+               enable_caching(CACHE_REGION_START(reg->base),
+                              CACHE_REGION_START(reg->base + reg->size - 1));
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       /*
+        * Enable caching for initrd which falls outside kernel memory.
+        */
+       if (initrd_start < initrd_end) {
+               if (!memblock_is_region_memory(initrd_start,
+                                              initrd_end - initrd_start))
+                       enable_caching(CACHE_REGION_START(initrd_start),
+                                      CACHE_REGION_START(initrd_end - 1));
+       }
+#endif
+
+       /*
+        * Disable caching for dma coherent memory taken from kernel memory.
+        */
+       if (dma_size && memblock_is_region_memory(dma_start, dma_size))
+               disable_caching(dma_start,
+                               CACHE_REGION_START(dma_start + dma_size - 1));
+
+       /* Initialize the coherent memory allocator */
+       coherent_mem_init(dma_start, dma_size);
+
+       /*
+        * Free all memory as a starting point.
+        */
+       free_bootmem(PAGE_OFFSET, memory_end - PAGE_OFFSET);
+
+       /*
+        * Then reserve memory which is already being used.
+        */
+       for_each_memblock(reserved, reg) {
+               pr_debug("reserved - 0x%08x-0x%08x\n",
+                        (u32) reg->base, (u32) reg->size);
+               reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+       }
+
+       max_low_pfn = PFN_DOWN(memory_end);
+       min_low_pfn = PFN_UP(memory_start);
+       max_mapnr = max_low_pfn - min_low_pfn;
+
+       /* Get kmalloc into gear */
+       paging_init();
+
+       /*
+        * Probe for Device State Configuration Registers.
+        * We have to do this early in case timer needs to be enabled
+        * through DSCR.
+        */
+       dscr_probe();
+
+       /* We do this early for timer and core clock frequency */
+       c64x_setup_clocks();
+
+       /* Get CPU info */
+       get_cpuinfo();
+
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+}
+
+#define cpu_to_ptr(n) ((void *)((long)(n)+1))
+#define ptr_to_cpu(p) ((long)(p) - 1)
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+       int n = ptr_to_cpu(v);
+       struct cpuinfo_c6x *p = &per_cpu(cpu_data, n);
+
+       if (n == 0) {
+               seq_printf(m,
+                          "soc\t\t: %s\n"
+                          "soc revision\t: 0x%x\n"
+                          "soc cores\t: %d\n",
+                          c6x_soc_name, c6x_silicon_rev, c6x_num_cores);
+       }
+
+       seq_printf(m,
+                  "\n"
+                  "processor\t: %d\n"
+                  "cpu\t\t: %s\n"
+                  "core revision\t: %s\n"
+                  "core voltage\t: %s\n"
+                  "core id\t\t: %d\n"
+                  "mmu\t\t: %s\n"
+                  "fpu\t\t: %s\n"
+                  "cpu MHz\t\t: %u\n"
+                  "bogomips\t: %lu.%02lu\n\n",
+                  n,
+                  p->cpu_name, p->cpu_rev, p->cpu_voltage,
+                  p->core_id, p->mmu, p->fpu,
+                  (c6x_core_freq + 500000) / 1000000,
+                  (loops_per_jiffy/(500000/HZ)),
+                  (loops_per_jiffy/(5000/HZ))%100);
+
+       return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return NULL;
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+       c_start,
+       c_stop,
+       c_next,
+       show_cpuinfo
+};
+
+static struct cpu cpu_devices[NR_CPUS];
+
+static int __init topology_init(void)
+{
+       int i;
+
+       for_each_present_cpu(i)
+               register_cpu(&cpu_devices[i], i);
+
+       return 0;
+}
+
+subsys_initcall(topology_init);
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
new file mode 100644 (file)
index 0000000..304f675
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ *  Updated for 2.6.34: Mark Salter <msalter@redhat.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/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/tracehook.h>
+
+#include <asm/ucontext.h>
+#include <asm/cacheflush.h>
+
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * Do a signal return, undo the signal stack.
+ */
+
+#define RETCODE_SIZE (9 << 2)  /* 9 instructions = 36 bytes */
+
+struct rt_sigframe {
+       struct siginfo __user *pinfo;
+       void __user *puc;
+       struct siginfo info;
+       struct ucontext uc;
+       unsigned long retcode[RETCODE_SIZE >> 2];
+};
+
+static int restore_sigcontext(struct pt_regs *regs,
+                             struct sigcontext __user *sc)
+{
+       int err = 0;
+
+       /* The access_ok check was done by caller, so use __get_user here */
+#define COPY(x)  (err |= __get_user(regs->x, &sc->sc_##x))
+
+       COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
+       COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
+       COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
+
+       COPY(a16); COPY(a17); COPY(a18); COPY(a19);
+       COPY(a20); COPY(a21); COPY(a22); COPY(a23);
+       COPY(a24); COPY(a25); COPY(a26); COPY(a27);
+       COPY(a28); COPY(a29); COPY(a30); COPY(a31);
+       COPY(b16); COPY(b17); COPY(b18); COPY(b19);
+       COPY(b20); COPY(b21); COPY(b22); COPY(b23);
+       COPY(b24); COPY(b25); COPY(b26); COPY(b27);
+       COPY(b28); COPY(b29); COPY(b30); COPY(b31);
+
+       COPY(csr); COPY(pc);
+
+#undef COPY
+
+       return err;
+}
+
+asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
+{
+       struct rt_sigframe __user *frame;
+       sigset_t set;
+
+       /*
+        * Since we stacked the signal on a dword boundary,
+        * 'sp' should be dword aligned here.  If it's
+        * not, then the user is trying to mess with us.
+        */
+       if (regs->sp & 7)
+               goto badframe;
+
+       frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8);
+
+       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(regs, &frame->uc.uc_mcontext))
+               goto badframe;
+
+       return regs->a4;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+                           unsigned long mask)
+{
+       int err = 0;
+
+       err |= __put_user(mask, &sc->sc_mask);
+
+       /* The access_ok check was done by caller, so use __put_user here */
+#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x))
+
+       COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
+       COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
+       COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
+
+       COPY(a16); COPY(a17); COPY(a18); COPY(a19);
+       COPY(a20); COPY(a21); COPY(a22); COPY(a23);
+       COPY(a24); COPY(a25); COPY(a26); COPY(a27);
+       COPY(a28); COPY(a29); COPY(a30); COPY(a31);
+       COPY(b16); COPY(b17); COPY(b18); COPY(b19);
+       COPY(b20); COPY(b21); COPY(b22); COPY(b23);
+       COPY(b24); COPY(b25); COPY(b26); COPY(b27);
+       COPY(b28); COPY(b29); COPY(b30); COPY(b31);
+
+       COPY(csr); COPY(pc);
+
+#undef COPY
+
+       return err;
+}
+
+static inline void __user *get_sigframe(struct k_sigaction *ka,
+                                       struct pt_regs *regs,
+                                       unsigned long framesize)
+{
+       unsigned long sp = regs->sp;
+
+       /*
+        * This is the X/Open sanctioned signal stack switching.
+        */
+       if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp) == 0)
+               sp = current->sas_ss_sp + current->sas_ss_size;
+
+       /*
+        * No matter what happens, 'sp' must be dword
+        * aligned. Otherwise, nasty things will happen
+        */
+       return (void __user *)((sp - framesize) & ~7);
+}
+
+static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+                          sigset_t *set, struct pt_regs *regs)
+{
+       struct rt_sigframe __user *frame;
+       unsigned long __user *retcode;
+       int err = 0;
+
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto segv_and_exit;
+
+       err |= __put_user(&frame->info, &frame->pinfo);
+       err |= __put_user(&frame->uc, &frame->puc);
+       err |= copy_siginfo_to_user(&frame->info, info);
+
+       /* Clear all the bits of the ucontext we don't use.  */
+       err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       /* Set up to return from userspace */
+       retcode = (unsigned long __user *) &frame->retcode;
+
+       /* The access_ok check was done above, so use __put_user here */
+#define COPY(x) (err |= __put_user(x, retcode++))
+
+       COPY(0x0000002AUL | (__NR_rt_sigreturn << 7));
+                               /* MVK __NR_rt_sigreturn,B0 */
+       COPY(0x10000000UL);     /* SWE */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+       COPY(0x00006000UL);     /* NOP 4 */
+
+#undef COPY
+
+       if (err)
+               goto segv_and_exit;
+
+       flush_icache_range((unsigned long) &frame->retcode,
+                          (unsigned long) &frame->retcode + RETCODE_SIZE);
+
+       retcode = (unsigned long __user *) &frame->retcode;
+
+       /* Change user context to branch to signal handler */
+       regs->sp = (unsigned long) frame - 8;
+       regs->b3 = (unsigned long) retcode;
+       regs->pc = (unsigned long) ka->sa.sa_handler;
+
+       /* Give the signal number to the handler */
+       regs->a4 = signr;
+
+       /*
+        * For realtime signals we must also set the second and third
+        * arguments for the signal handler.
+        *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
+        */
+       regs->b4 = (unsigned long)&frame->info;
+       regs->a6 = (unsigned long)&frame->uc;
+
+       return 0;
+
+segv_and_exit:
+       force_sigsegv(signr, current);
+       return -EFAULT;
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+       switch (regs->a4) {
+       case -ERESTARTNOHAND:
+               if (!has_handler)
+                       goto do_restart;
+               regs->a4 = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+                       regs->a4 = -EINTR;
+                       break;
+               }
+       /* fallthrough */
+       case -ERESTARTNOINTR:
+do_restart:
+               regs->a4 = regs->orig_a4;
+               regs->pc -= 4;
+               break;
+       }
+}
+
+/*
+ * handle the actual delivery of a signal to userspace
+ */
+static int handle_signal(int sig,
+                        siginfo_t *info, struct k_sigaction *ka,
+                        sigset_t *oldset, struct pt_regs *regs,
+                        int syscall)
+{
+       int ret;
+
+       /* Are we from a system call? */
+       if (syscall) {
+               /* If so, check system call restarting.. */
+               switch (regs->a4) {
+               case -ERESTART_RESTARTBLOCK:
+               case -ERESTARTNOHAND:
+                       regs->a4 = -EINTR;
+                       break;
+
+               case -ERESTARTSYS:
+                       if (!(ka->sa.sa_flags & SA_RESTART)) {
+                               regs->a4 = -EINTR;
+                               break;
+                       }
+
+                       /* fallthrough */
+               case -ERESTARTNOINTR:
+                       regs->a4 = regs->orig_a4;
+                       regs->pc -= 4;
+               }
+       }
+
+       /* Set up the stack frame */
+       ret = setup_rt_frame(sig, ka, info, oldset, regs);
+       if (ret == 0) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked, &current->blocked,
+                         &ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked, sig);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+
+       return ret;
+}
+
+/*
+ * handle a potential signal
+ */
+static void do_signal(struct pt_regs *regs, int syscall)
+{
+       struct k_sigaction ka;
+       siginfo_t info;
+       sigset_t *oldset;
+       int signr;
+
+       /* we want the common case to go fast, which is why we may in certain
+        * cases get here from kernel mode */
+       if (!user_mode(regs))
+               return;
+
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
+               if (handle_signal(signr, &info, &ka, oldset,
+                                 regs, syscall) == 0) {
+                       /* a signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TIF_RESTORE_SIGMASK flag */
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+                       tracehook_signal_handler(signr, &info, &ka, regs, 0);
+               }
+
+               return;
+       }
+
+       /* did we come from a system call? */
+       if (syscall) {
+               /* restart the system call - no handlers present */
+               switch (regs->a4) {
+               case -ERESTARTNOHAND:
+               case -ERESTARTSYS:
+               case -ERESTARTNOINTR:
+                       regs->a4 = regs->orig_a4;
+                       regs->pc -= 4;
+                       break;
+
+               case -ERESTART_RESTARTBLOCK:
+                       regs->a4 = regs->orig_a4;
+                       regs->b0 = __NR_restart_syscall;
+                       regs->pc -= 4;
+                       break;
+               }
+       }
+
+       /* if there's no signal to deliver, we just put the saved sigmask
+        * back */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+}
+
+/*
+ * notification of userspace execution resumption
+ * - triggered by current->work.notify_resume
+ */
+asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
+                                int syscall)
+{
+       /* deal with pending signal delivery */
+       if (thread_info_flags & ((1 << TIF_SIGPENDING) |
+                                (1 << TIF_RESTORE_SIGMASK)))
+               do_signal(regs, syscall);
+
+       if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
+}
diff --git a/arch/c6x/kernel/soc.c b/arch/c6x/kernel/soc.c
new file mode 100644 (file)
index 0000000..dd45bc3
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  Miscellaneous SoC-specific hooks.
+ *
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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/ctype.h>
+#include <linux/etherdevice.h>
+#include <asm/system.h>
+#include <asm/setup.h>
+#include <asm/soc.h>
+
+struct soc_ops soc_ops;
+
+int soc_get_exception(void)
+{
+       if (!soc_ops.get_exception)
+               return -1;
+       return soc_ops.get_exception();
+}
+
+void soc_assert_event(unsigned int evt)
+{
+       if (soc_ops.assert_event)
+               soc_ops.assert_event(evt);
+}
+
+static u8 cmdline_mac[6];
+
+static int __init get_mac_addr_from_cmdline(char *str)
+{
+       int count, i, val;
+
+       for (count = 0; count < 6 && *str; count++, str += 3) {
+               if (!isxdigit(str[0]) || !isxdigit(str[1]))
+                       return 0;
+               if (str[2] != ((count < 5) ? ':' : '\0'))
+                       return 0;
+
+               for (i = 0, val = 0; i < 2; i++) {
+                       val = val << 4;
+                       val |= isdigit(str[i]) ?
+                               str[i] - '0' : toupper(str[i]) - 'A' + 10;
+               }
+               cmdline_mac[count] = val;
+       }
+       return 1;
+}
+__setup("emac_addr=", get_mac_addr_from_cmdline);
+
+/*
+ * Setup the MAC address for SoC ethernet devices.
+ *
+ * Before calling this function, the ethernet driver will have
+ * initialized the addr with local-mac-address from the device
+ * tree (if found). Allow command line to override, but not
+ * the fused address.
+ */
+int soc_mac_addr(unsigned int index, u8 *addr)
+{
+       int i, have_dt_mac = 0, have_cmdline_mac = 0, have_fuse_mac = 0;
+
+       for (i = 0; i < 6; i++) {
+               if (cmdline_mac[i])
+                       have_cmdline_mac = 1;
+               if (c6x_fuse_mac[i])
+                       have_fuse_mac = 1;
+               if (addr[i])
+                       have_dt_mac = 1;
+       }
+
+       /* cmdline overrides all */
+       if (have_cmdline_mac)
+               memcpy(addr, cmdline_mac, 6);
+       else if (!have_dt_mac) {
+               if (have_fuse_mac)
+                       memcpy(addr, c6x_fuse_mac, 6);
+               else
+                       random_ether_addr(addr);
+       }
+
+       /* adjust for specific EMAC device */
+       addr[5] += index * c6x_num_cores;
+       return 1;
+}
+EXPORT_SYMBOL_GPL(soc_mac_addr);
diff --git a/arch/c6x/kernel/switch_to.S b/arch/c6x/kernel/switch_to.S
new file mode 100644 (file)
index 0000000..09177ed
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter (msalter@redhat.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/linkage.h>
+#include <asm/asm-offsets.h>
+
+#define SP     B15
+
+       /*
+        * void __switch_to(struct thread_info *prev,
+        *                  struct thread_info *next,
+        *                  struct task_struct *tsk) ;
+        */
+ENTRY(__switch_to)
+       LDDW    .D2T2   *+B4(THREAD_B15_14),B7:B6
+ ||    MV      .L2X    A4,B5   ; prev
+ ||    MV      .L1X    B4,A5   ; next
+ ||    MVC     .S2     RILC,B1
+
+       STW     .D2T2   B3,*+B5(THREAD_PC)
+ ||    STDW    .D1T1   A13:A12,*+A4(THREAD_A13_12)
+ ||    MVC     .S2     ILC,B0
+
+       LDW     .D2T2   *+B4(THREAD_PC),B3
+ ||    LDDW    .D1T1   *+A5(THREAD_A13_12),A13:A12
+
+       STDW    .D1T1   A11:A10,*+A4(THREAD_A11_10)
+ ||    STDW    .D2T2   B1:B0,*+B5(THREAD_RICL_ICL)
+#ifndef __DSBT__
+ ||    MVKL    .S2     current_ksp,B1
+#endif
+
+       STDW    .D2T2   B15:B14,*+B5(THREAD_B15_14)
+ ||    STDW    .D1T1   A15:A14,*+A4(THREAD_A15_14)
+#ifndef __DSBT__
+ ||    MVKH    .S2     current_ksp,B1
+#endif
+
+       ;; Switch to next SP
+       MV      .S2     B7,SP
+#ifdef __DSBT__
+ ||    STW     .D2T2   B7,*+B14(current_ksp)
+#else
+ ||    STW     .D2T2   B7,*B1
+ ||    MV      .L2     B6,B14
+#endif
+ ||    LDDW    .D1T1   *+A5(THREAD_RICL_ICL),A1:A0
+
+       STDW    .D2T2   B11:B10,*+B5(THREAD_B11_10)
+ ||    LDDW    .D1T1   *+A5(THREAD_A15_14),A15:A14
+
+       STDW    .D2T2   B13:B12,*+B5(THREAD_B13_12)
+ ||    LDDW    .D1T1   *+A5(THREAD_A11_10),A11:A10
+
+       B       .S2     B3              ; return in next E1
+ ||    LDDW    .D2T2   *+B4(THREAD_B13_12),B13:B12
+
+       LDDW    .D2T2   *+B4(THREAD_B11_10),B11:B10
+       NOP
+
+       MV      .L2X    A0,B0
+ ||    MV      .S1     A6,A4
+
+       MVC     .S2     B0,ILC
+ ||    MV      .L2X    A1,B1
+
+       MVC     .S2     B1,RILC
+ENDPROC(__switch_to)
diff --git a/arch/c6x/kernel/sys_c6x.c b/arch/c6x/kernel/sys_c6x.c
new file mode 100644 (file)
index 0000000..3e9bdfb
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/syscalls.h>
+#include <linux/uaccess.h>
+
+#include <asm/syscalls.h>
+
+#ifdef CONFIG_ACCESS_CHECK
+int _access_ok(unsigned long addr, unsigned long size)
+{
+       if (!size)
+               return 1;
+
+       if (!addr || addr > (0xffffffffUL - (size - 1)))
+               goto _bad_access;
+
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 1;
+
+       if (memory_start <= addr && (addr + size - 1) < memory_end)
+               return 1;
+
+_bad_access:
+       pr_debug("Bad access attempt: pid[%d] addr[%08lx] size[0x%lx]\n",
+                current->pid, addr, size);
+       return 0;
+}
+EXPORT_SYMBOL(_access_ok);
+#endif
+
+/* sys_cache_sync -- sync caches over given range */
+asmlinkage int sys_cache_sync(unsigned long s, unsigned long e)
+{
+       L1D_cache_block_writeback_invalidate(s, e);
+       L1P_cache_block_invalidate(s, e);
+
+       return 0;
+}
+
+/* Provide the actual syscall number to call mapping. */
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+/*
+ * Use trampolines
+ */
+#define sys_pread64            sys_pread_c6x
+#define sys_pwrite64           sys_pwrite_c6x
+#define sys_truncate64         sys_truncate64_c6x
+#define sys_ftruncate64                sys_ftruncate64_c6x
+#define sys_fadvise64          sys_fadvise64_c6x
+#define sys_fadvise64_64       sys_fadvise64_64_c6x
+#define sys_fallocate          sys_fallocate_c6x
+
+/* Use sys_mmap_pgoff directly */
+#define sys_mmap2 sys_mmap_pgoff
+
+/*
+ * Note that we can't include <linux/unistd.h> here since the header
+ * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
+ */
+void *sys_call_table[__NR_syscalls] = {
+       [0 ... __NR_syscalls-1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c
new file mode 100644 (file)
index 0000000..4c9f136
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/clocksource.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+#include <asm/timer64.h>
+
+static u32 sched_clock_multiplier;
+#define SCHED_CLOCK_SHIFT 16
+
+static cycle_t tsc_read(struct clocksource *cs)
+{
+       return get_cycles();
+}
+
+static struct clocksource clocksource_tsc = {
+       .name           = "timestamp",
+       .rating         = 300,
+       .read           = tsc_read,
+       .mask           = CLOCKSOURCE_MASK(64),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * scheduler clock - returns current time in nanoseconds.
+ */
+u64 sched_clock(void)
+{
+       u64 tsc = get_cycles();
+
+       return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
+}
+
+void time_init(void)
+{
+       u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
+
+       do_div(tmp, c6x_core_freq);
+       sched_clock_multiplier = tmp;
+
+       clocksource_register_hz(&clocksource_tsc, c6x_core_freq);
+
+       /* write anything into TSCL to enable counting */
+       set_creg(TSCL, 0);
+
+       /* probe for timer64 event timer */
+       timer64_init();
+}
diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c
new file mode 100644 (file)
index 0000000..f50e3ed
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/ptrace.h>
+#include <linux/kallsyms.h>
+#include <linux/bug.h>
+
+#include <asm/soc.h>
+#include <asm/traps.h>
+
+int (*c6x_nmi_handler)(struct pt_regs *regs);
+
+void __init trap_init(void)
+{
+       ack_exception(EXCEPT_TYPE_NXF);
+       ack_exception(EXCEPT_TYPE_EXC);
+       ack_exception(EXCEPT_TYPE_IXF);
+       ack_exception(EXCEPT_TYPE_SXF);
+       enable_exception();
+}
+
+void show_regs(struct pt_regs *regs)
+{
+       pr_err("\n");
+       pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp);
+       pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4);
+       pr_err("A0: %08lx  B0: %08lx\n", regs->a0, regs->b0);
+       pr_err("A1: %08lx  B1: %08lx\n", regs->a1, regs->b1);
+       pr_err("A2: %08lx  B2: %08lx\n", regs->a2, regs->b2);
+       pr_err("A3: %08lx  B3: %08lx\n", regs->a3, regs->b3);
+       pr_err("A4: %08lx  B4: %08lx\n", regs->a4, regs->b4);
+       pr_err("A5: %08lx  B5: %08lx\n", regs->a5, regs->b5);
+       pr_err("A6: %08lx  B6: %08lx\n", regs->a6, regs->b6);
+       pr_err("A7: %08lx  B7: %08lx\n", regs->a7, regs->b7);
+       pr_err("A8: %08lx  B8: %08lx\n", regs->a8, regs->b8);
+       pr_err("A9: %08lx  B9: %08lx\n", regs->a9, regs->b9);
+       pr_err("A10: %08lx  B10: %08lx\n", regs->a10, regs->b10);
+       pr_err("A11: %08lx  B11: %08lx\n", regs->a11, regs->b11);
+       pr_err("A12: %08lx  B12: %08lx\n", regs->a12, regs->b12);
+       pr_err("A13: %08lx  B13: %08lx\n", regs->a13, regs->b13);
+       pr_err("A14: %08lx  B14: %08lx\n", regs->a14, regs->dp);
+       pr_err("A15: %08lx  B15: %08lx\n", regs->a15, regs->sp);
+       pr_err("A16: %08lx  B16: %08lx\n", regs->a16, regs->b16);
+       pr_err("A17: %08lx  B17: %08lx\n", regs->a17, regs->b17);
+       pr_err("A18: %08lx  B18: %08lx\n", regs->a18, regs->b18);
+       pr_err("A19: %08lx  B19: %08lx\n", regs->a19, regs->b19);
+       pr_err("A20: %08lx  B20: %08lx\n", regs->a20, regs->b20);
+       pr_err("A21: %08lx  B21: %08lx\n", regs->a21, regs->b21);
+       pr_err("A22: %08lx  B22: %08lx\n", regs->a22, regs->b22);
+       pr_err("A23: %08lx  B23: %08lx\n", regs->a23, regs->b23);
+       pr_err("A24: %08lx  B24: %08lx\n", regs->a24, regs->b24);
+       pr_err("A25: %08lx  B25: %08lx\n", regs->a25, regs->b25);
+       pr_err("A26: %08lx  B26: %08lx\n", regs->a26, regs->b26);
+       pr_err("A27: %08lx  B27: %08lx\n", regs->a27, regs->b27);
+       pr_err("A28: %08lx  B28: %08lx\n", regs->a28, regs->b28);
+       pr_err("A29: %08lx  B29: %08lx\n", regs->a29, regs->b29);
+       pr_err("A30: %08lx  B30: %08lx\n", regs->a30, regs->b30);
+       pr_err("A31: %08lx  B31: %08lx\n", regs->a31, regs->b31);
+}
+
+void dump_stack(void)
+{
+       unsigned long stack;
+
+       show_stack(current, &stack);
+}
+EXPORT_SYMBOL(dump_stack);
+
+
+void die(char *str, struct pt_regs *fp, int nr)
+{
+       console_verbose();
+       pr_err("%s: %08x\n", str, nr);
+       show_regs(fp);
+
+       pr_err("Process %s (pid: %d, stackpage=%08lx)\n",
+              current->comm, current->pid, (PAGE_SIZE +
+                                            (unsigned long) current));
+
+       dump_stack();
+       while (1)
+               ;
+}
+
+static void die_if_kernel(char *str, struct pt_regs *fp, int nr)
+{
+       if (user_mode(fp))
+               return;
+
+       die(str, fp, nr);
+}
+
+
+/* Internal exceptions */
+static struct exception_info iexcept_table[10] = {
+       { "Oops - instruction fetch", SIGBUS, BUS_ADRERR },
+       { "Oops - fetch packet", SIGBUS, BUS_ADRERR },
+       { "Oops - execute packet", SIGILL, ILL_ILLOPC },
+       { "Oops - undefined instruction", SIGILL, ILL_ILLOPC },
+       { "Oops - resource conflict", SIGILL, ILL_ILLOPC },
+       { "Oops - resource access", SIGILL, ILL_PRVREG },
+       { "Oops - privilege", SIGILL, ILL_PRVOPC },
+       { "Oops - loops buffer", SIGILL, ILL_ILLOPC },
+       { "Oops - software exception", SIGILL, ILL_ILLTRP },
+       { "Oops - unknown exception", SIGILL, ILL_ILLOPC }
+};
+
+/* External exceptions */
+static struct exception_info eexcept_table[128] = {
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - external exception", SIGBUS, BUS_ADRERR },
+       { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
+       { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
+       { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
+       { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
+       { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
+       { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
+       { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
+       { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
+       { "Oops - EMC bus error", SIGBUS, BUS_ADRERR }
+};
+
+static void do_trap(struct exception_info *except_info, struct pt_regs *regs)
+{
+       unsigned long addr = instruction_pointer(regs);
+       siginfo_t info;
+
+       if (except_info->code != TRAP_BRKPT)
+               pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n",
+                      except_info->kernel_str, regs->pc,
+                      except_info->signo, except_info->code);
+
+       die_if_kernel(except_info->kernel_str, regs, addr);
+
+       info.si_signo = except_info->signo;
+       info.si_errno = 0;
+       info.si_code  = except_info->code;
+       info.si_addr  = (void __user *)addr;
+
+       force_sig_info(except_info->signo, &info, current);
+}
+
+/*
+ * Process an internal exception (non maskable)
+ */
+static int process_iexcept(struct pt_regs *regs)
+{
+       unsigned int iexcept_report = get_iexcept();
+       unsigned int iexcept_num;
+
+       ack_exception(EXCEPT_TYPE_IXF);
+
+       pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc);
+
+       while (iexcept_report) {
+               iexcept_num = __ffs(iexcept_report);
+               iexcept_report &= ~(1 << iexcept_num);
+               set_iexcept(iexcept_report);
+               if (*(unsigned int *)regs->pc == BKPT_OPCODE) {
+                       /* This is a breakpoint */
+                       struct exception_info bkpt_exception = {
+                               "Oops - undefined instruction",
+                                 SIGTRAP, TRAP_BRKPT
+                       };
+                       do_trap(&bkpt_exception, regs);
+                       iexcept_report &= ~(0xFF);
+                       set_iexcept(iexcept_report);
+                       continue;
+               }
+
+               do_trap(&iexcept_table[iexcept_num], regs);
+       }
+       return 0;
+}
+
+/*
+ * Process an external exception (maskable)
+ */
+static void process_eexcept(struct pt_regs *regs)
+{
+       int evt;
+
+       pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc);
+
+       while ((evt = soc_get_exception()) >= 0)
+               do_trap(&eexcept_table[evt], regs);
+
+       ack_exception(EXCEPT_TYPE_EXC);
+}
+
+/*
+ * Main exception processing
+ */
+asmlinkage int process_exception(struct pt_regs *regs)
+{
+       unsigned int type;
+       unsigned int type_num;
+       unsigned int ie_num = 9; /* default is unknown exception */
+
+       while ((type = get_except_type()) != 0) {
+               type_num = fls(type) - 1;
+
+               switch (type_num) {
+               case EXCEPT_TYPE_NXF:
+                       ack_exception(EXCEPT_TYPE_NXF);
+                       if (c6x_nmi_handler)
+                               (c6x_nmi_handler)(regs);
+                       else
+                               pr_alert("NMI interrupt!\n");
+                       break;
+
+               case EXCEPT_TYPE_IXF:
+                       if (process_iexcept(regs))
+                               return 1;
+                       break;
+
+               case EXCEPT_TYPE_EXC:
+                       process_eexcept(regs);
+                       break;
+
+               case EXCEPT_TYPE_SXF:
+                       ie_num = 8;
+               default:
+                       ack_exception(type_num);
+                       do_trap(&iexcept_table[ie_num], regs);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int kstack_depth_to_print = 48;
+
+static void show_trace(unsigned long *stack, unsigned long *endstack)
+{
+       unsigned long addr;
+       int i;
+
+       pr_debug("Call trace:");
+       i = 0;
+       while (stack + 1 <= endstack) {
+               addr = *stack++;
+               /*
+                * If the address is either in the text segment of the
+                * kernel, or in the region which contains vmalloc'ed
+                * memory, it *may* be the address of a calling
+                * routine; if so, print it so that someone tracing
+                * down the cause of the crash will be able to figure
+                * out the call path that was taken.
+                */
+               if (__kernel_text_address(addr)) {
+#ifndef CONFIG_KALLSYMS
+                       if (i % 5 == 0)
+                               pr_debug("\n        ");
+#endif
+                       pr_debug(" [<%08lx>]", addr);
+                       print_symbol(" %s\n", addr);
+                       i++;
+               }
+       }
+       pr_debug("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+       unsigned long *p, *endstack;
+       int i;
+
+       if (!stack) {
+               if (task && task != current)
+                       /* We know this is a kernel stack,
+                          so this is the start/end */
+                       stack = (unsigned long *)thread_saved_ksp(task);
+               else
+                       stack = (unsigned long *)&stack;
+       }
+       endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1)
+                                    & -THREAD_SIZE);
+
+       pr_debug("Stack from %08lx:", (unsigned long)stack);
+       for (i = 0, p = stack; i < kstack_depth_to_print; i++) {
+               if (p + 1 > endstack)
+                       break;
+               if (i % 8 == 0)
+                       pr_cont("\n         ");
+               pr_cont(" %08lx", *p++);
+       }
+       pr_cont("\n");
+       show_trace(stack, endstack);
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+       return __kernel_text_address(addr);
+}
diff --git a/arch/c6x/kernel/vectors.S b/arch/c6x/kernel/vectors.S
new file mode 100644 (file)
index 0000000..c95c66f
--- /dev/null
@@ -0,0 +1,81 @@
+;
+;  Port on Texas Instruments TMS320C6x architecture
+;
+;  Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+;  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 section handles all the interrupt vector routines.
+;  At RESET the processor sets up the DRAM timing parameters and
+;  branches to the label _c_int00 which handles initialization for the C code.
+;
+
+#define ALIGNMENT 5
+
+       .macro IRQVEC name, handler
+       .align ALIGNMENT
+       .hidden \name
+       .global \name
+\name:
+#ifdef CONFIG_C6X_BIG_KERNEL
+       STW     .D2T1   A0,*B15--[2]
+ ||    MVKL    .S1     \handler,A0
+       MVKH    .S1     \handler,A0
+       B       .S2X    A0
+       LDW     .D2T1   *++B15[2],A0
+       NOP     4
+       NOP
+       NOP
+       .endm
+#else /* CONFIG_C6X_BIG_KERNEL */
+       B       .S2     \handler
+       NOP
+       NOP
+       NOP
+       NOP
+       NOP
+       NOP
+       NOP
+       .endm
+#endif /* CONFIG_C6X_BIG_KERNEL */
+
+          .sect ".vectors","ax"
+          .align ALIGNMENT
+          .global RESET
+          .hidden RESET
+RESET:
+#ifdef CONFIG_C6X_BIG_KERNEL
+          MVKL .S1     _c_int00,A0             ; branch to _c_int00
+          MVKH .S1     _c_int00,A0
+          B    .S2X    A0
+#else
+          B    .S2     _c_int00
+          NOP
+          NOP
+#endif
+          NOP
+          NOP
+          NOP
+          NOP
+          NOP
+
+
+          IRQVEC NMI,_nmi_handler              ; NMI interrupt
+          IRQVEC AINT,_bad_interrupt           ; reserved
+          IRQVEC MSGINT,_bad_interrupt         ; reserved
+
+          IRQVEC INT4,_int4_handler
+          IRQVEC INT5,_int5_handler
+          IRQVEC INT6,_int6_handler
+          IRQVEC INT7,_int7_handler
+          IRQVEC INT8,_int8_handler
+          IRQVEC INT9,_int9_handler
+          IRQVEC INT10,_int10_handler
+          IRQVEC INT11,_int11_handler
+          IRQVEC INT12,_int12_handler
+          IRQVEC INT13,_int13_handler
+          IRQVEC INT14,_int14_handler
+          IRQVEC INT15,_int15_handler
diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..1d81c4c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * ld script for the c6x kernel
+ *
+ *  Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ *  Mark Salter <msalter@redhat.com>
+ */
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
+
+ENTRY(_c_int00)
+
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+jiffies = jiffies_64 + 4;
+#else
+jiffies = jiffies_64;
+#endif
+
+#define        READONLY_SEGMENT_START  \
+       . = PAGE_OFFSET;
+#define        READWRITE_SEGMENT_START \
+       . = ALIGN(128);         \
+       _data_lma = .;
+
+SECTIONS
+{
+       /*
+        * Start kernel read only segment
+        */
+       READONLY_SEGMENT_START
+
+       .vectors :
+       {
+               _vectors_start = .;
+               *(.vectors)
+               . = ALIGN(0x400);
+               _vectors_end = .;
+       }
+
+       . = ALIGN(0x1000);
+       .cmdline :
+       {
+               *(.cmdline)
+       }
+
+       /*
+        * This section contains data which may be shared with other
+        * cores. It needs to be a fixed offset from PAGE_OFFSET
+        * regardless of kernel configuration.
+        */
+       .virtio_ipc_dev :
+       {
+               *(.virtio_ipc_dev)
+       }
+
+       . = ALIGN(PAGE_SIZE);
+       .init :
+       {
+               _stext = .;
+               _sinittext = .;
+               HEAD_TEXT
+               INIT_TEXT
+               _einittext = .;
+       }
+
+       __init_begin = _stext;
+       INIT_DATA_SECTION(16)
+
+       PERCPU_SECTION(128)
+
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;
+
+       .text :
+       {
+               _text = .;
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               IRQENTRY_TEXT
+               KPROBES_TEXT
+               *(.fixup)
+               *(.gnu.warning)
+       }
+
+       EXCEPTION_TABLE(16)
+       NOTES
+
+       RO_DATA_SECTION(PAGE_SIZE)
+       .const :
+       {
+               *(.const .const.* .gnu.linkonce.r.*)
+               *(.switch)
+       }
+
+       . = ALIGN (8) ;
+       __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET)
+       {
+               _fdt_start = . ;        /* place for fdt blob */
+               *(__fdt_blob) ;         /* Any link-placed DTB */
+               BYTE(0);                /* section always has contents */
+               . = _fdt_start + 0x4000;        /* Pad up to 16kbyte */
+               _fdt_end = . ;
+       }
+
+       _etext = .;
+
+       /*
+        * Start kernel read-write segment.
+        */
+       READWRITE_SEGMENT_START
+       _sdata = .;
+
+       .fardata : AT(ADDR(.fardata) - LOAD_OFFSET)
+       {
+               INIT_TASK_DATA(THREAD_SIZE)
+               NOSAVE_DATA
+               PAGE_ALIGNED_DATA(PAGE_SIZE)
+               CACHELINE_ALIGNED_DATA(128)
+               READ_MOSTLY_DATA(128)
+               DATA_DATA
+               CONSTRUCTORS
+               *(.data1)
+               *(.fardata .fardata.*)
+               *(.data.debug_bpt)
+       }
+
+       .neardata ALIGN(8) : AT(ADDR(.neardata) - LOAD_OFFSET)
+       {
+               *(.neardata2 .neardata2.* .gnu.linkonce.s2.*)
+               *(.neardata .neardata.* .gnu.linkonce.s.*)
+               . = ALIGN(8);
+       }
+
+       _edata = .;
+
+       __bss_start = .;
+       SBSS(8)
+       BSS(8)
+       .far :
+       {
+               . = ALIGN(8);
+               *(.dynfar)
+               *(.far .far.* .gnu.linkonce.b.*)
+               . = ALIGN(8);
+       }
+       __bss_stop = .;
+
+       _end = .;
+
+       DWARF_DEBUG
+
+       /DISCARD/ :
+       {
+                 EXIT_TEXT
+                 EXIT_DATA
+                 EXIT_CALL
+                 *(.discard)
+                 *(.discard.*)
+                 *(.interp)
+       }
+}
diff --git a/arch/c6x/lib/Makefile b/arch/c6x/lib/Makefile
new file mode 100644 (file)
index 0000000..ffd3c65
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for arch/c6x/lib/
+#
+
+lib-y := divu.o divi.o pop_rts.o push_rts.o remi.o remu.o strasgi.o llshru.o
+lib-y += llshr.o llshl.o negll.o mpyll.o divremi.o divremu.o
+lib-y += checksum.o csum_64plus.o memcpy_64plus.o strasgi_64plus.o
diff --git a/arch/c6x/lib/checksum.c b/arch/c6x/lib/checksum.c
new file mode 100644 (file)
index 0000000..67cc93b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the 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 <net/checksum.h>
+
+#include <asm/byteorder.h>
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst, int len,
+                           __wsum sum, int *csum_err)
+{
+       int missing;
+
+       missing = __copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *csum_err = -EFAULT;
+       } else
+               *csum_err = 0;
+
+       return csum_partial(dst, len, sum);
+}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+/* These are from csum_64plus.S */
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy);
+EXPORT_SYMBOL(ip_compute_csum);
+EXPORT_SYMBOL(ip_fast_csum);
diff --git a/arch/c6x/lib/csum_64plus.S b/arch/c6x/lib/csum_64plus.S
new file mode 100644 (file)
index 0000000..6d25896
--- /dev/null
@@ -0,0 +1,419 @@
+;
+;  linux/arch/c6x/lib/csum_64plus.s
+;
+;  Port on Texas Instruments TMS320C6x architecture
+;
+;  Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated
+;  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/linkage.h>
+
+;
+;unsigned int csum_partial_copy(const char *src, char * dst,
+;                              int len, int sum)
+;
+; A4:  src
+; B4:  dst
+; A6:  len
+; B6:  sum
+; return csum in A4
+;
+
+       .text
+ENTRY(csum_partial_copy)
+       MVC     .S2     ILC,B30
+
+       MV      .D1X    B6,A31          ; given csum
+       ZERO    .D1     A9              ; csum (a side)
+||     ZERO    .D2     B9              ; csum (b side)
+||     SHRU    .S2X    A6,2,B5         ; len / 4
+
+       ;; Check alignment and size
+       AND     .S1     3,A4,A1
+||     AND     .S2     3,B4,B0
+       OR      .L2X    B0,A1,B0        ; non aligned condition
+||     MVC     .S2     B5,ILC
+||     MVK     .D2     1,B2
+||     MV      .D1X    B5,A1           ; words condition
+  [!A1]        B       .S1     L8
+   [B0] BNOP   .S1     L6,5
+
+       SPLOOP          1
+
+       ;; Main loop for aligned words
+       LDW     .D1T1   *A4++,A7
+       NOP     4
+       MV      .S2X    A7,B7
+||     EXTU    .S1     A7,0,16,A16
+       STW     .D2T2   B7,*B4++
+||     MPYU    .M2     B7,B2,B8
+||     ADD     .L1     A16,A9,A9
+       NOP
+       SPKERNEL        8,0
+||     ADD     .L2     B8,B9,B9
+
+       ZERO    .D1     A1
+||     ADD     .L1X    A9,B9,A9        ;  add csum from a and b sides
+
+L6:
+  [!A1]        BNOP    .S1     L8,5
+
+       ;; Main loop for non-aligned words
+       SPLOOP          2
+ ||    MVK     .L1     1,A2
+
+       LDNW    .D1T1   *A4++,A7
+       NOP             3
+
+       NOP
+       MV      .S2X    A7,B7
+ ||    EXTU    .S1     A7,0,16,A16
+ ||    MPYU    .M1     A7,A2,A8
+
+       ADD     .L1     A16,A9,A9
+       SPKERNEL        6,0
+ ||    STNW    .D2T2   B7,*B4++
+ ||    ADD     .L1     A8,A9,A9
+
+L8:    AND     .S2X    2,A6,B5
+       CMPGT   .L2     B5,0,B0
+  [!B0]        BNOP    .S1     L82,4
+
+       ;; Manage half-word
+       ZERO    .L1     A7
+||     ZERO    .D1     A8
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+
+       LDBU    .D1T1   *A4++,A7
+       LDBU    .D1T1   *A4++,A8
+       NOP             3
+       SHL     .S1     A7,8,A0
+       ADD     .S1     A8,A9,A9
+       STB     .D2T1   A7,*B4++
+||     ADD     .S1     A0,A9,A9
+       STB     .D2T1   A8,*B4++
+
+#else
+
+       LDBU    .D1T1   *A4++,A7
+       LDBU    .D1T1   *A4++,A8
+       NOP             3
+       ADD     .S1     A7,A9,A9
+       SHL     .S1     A8,8,A0
+
+       STB     .D2T1   A7,*B4++
+||     ADD     .S1     A0,A9,A9
+       STB     .D2T1   A8,*B4++
+
+#endif
+
+       ;; Manage eventually the last byte
+L82:   AND     .S2X    1,A6,B0
+  [!B0]        BNOP    .S1     L9,5
+
+||     ZERO    .L1     A7
+
+L83:   LDBU    .D1T1   *A4++,A7
+       NOP             4
+
+       MV      .L2X    A7,B7
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+
+       STB     .D2T2   B7,*B4++
+||     SHL     .S1     A7,8,A7
+       ADD     .S1     A7,A9,A9
+
+#else
+
+       STB     .D2T2   B7,*B4++
+||     ADD     .S1     A7,A9,A9
+
+#endif
+
+       ;; Fold the csum
+L9:    SHRU    .S2X    A9,16,B0
+  [!B0]        BNOP    .S1     L10,5
+
+L91:   SHRU    .S2X    A9,16,B4
+||     EXTU    .S1     A9,16,16,A3
+       ADD     .D1X    A3,B4,A9
+
+       SHRU    .S1     A9,16,A0
+   [A0]        BNOP    .S1     L91,5
+
+L10:   ADD     .D1     A31,A9,A9
+       MV      .D1     A9,A4
+
+       BNOP    .S2     B3,4
+       MVC     .S2     B30,ILC
+ENDPROC(csum_partial_copy)
+
+;
+;unsigned short
+;ip_fast_csum(unsigned char *iph, unsigned int ihl)
+;{
+;      unsigned int checksum = 0;
+;      unsigned short *tosum = (unsigned short *) iph;
+;      int len;
+;
+;      len = ihl*4;
+;
+;      if (len <= 0)
+;              return 0;
+;
+;      while(len) {
+;              len -= 2;
+;              checksum += *tosum++;
+;      }
+;      if (len & 1)
+;              checksum += *(unsigned char*) tosum;
+;
+;      while(checksum >> 16)
+;              checksum = (checksum & 0xffff) + (checksum >> 16);
+;
+;      return ~checksum;
+;}
+;
+; A4:  iph
+; B4:  ihl
+; return checksum in A4
+;
+       .text
+
+ENTRY(ip_fast_csum)
+       ZERO    .D1     A5
+ ||    MVC     .S2     ILC,B30
+       SHL     .S2     B4,2,B0
+       CMPGT   .L2     B0,0,B1
+  [!B1] BNOP   .S1     L15,4
+  [!B1]        ZERO    .D1     A3
+
+  [!B0]        B       .S1     L12
+       SHRU    .S2     B0,1,B0
+       MVC     .S2     B0,ILC
+       NOP     3
+
+       SPLOOP  1
+       LDHU    .D1T1   *A4++,A3
+       NOP     3
+       NOP
+       SPKERNEL        5,0
+ ||    ADD     .L1     A3,A5,A5
+
+L12:   SHRU    .S1     A5,16,A0
+  [!A0]        BNOP    .S1     L14,5
+
+L13:   SHRU    .S2X    A5,16,B4
+       EXTU    .S1     A5,16,16,A3
+       ADD     .D1X    A3,B4,A5
+       SHRU    .S1     A5,16,A0
+  [A0] BNOP    .S1     L13,5
+
+L14:   NOT     .D1     A5,A3
+       EXTU    .S1     A3,16,16,A3
+
+L15:   BNOP    .S2     B3,3
+       MVC     .S2     B30,ILC
+       MV      .D1     A3,A4
+ENDPROC(ip_fast_csum)
+
+;
+;unsigned short
+;do_csum(unsigned char *buff, unsigned int len)
+;{
+;      int odd, count;
+;      unsigned int result = 0;
+;
+;      if (len <= 0)
+;              goto out;
+;      odd = 1 & (unsigned long) buff;
+;      if (odd) {
+;#ifdef __LITTLE_ENDIAN
+;              result += (*buff << 8);
+;#else
+;              result = *buff;
+;#endif
+;              len--;
+;              buff++;
+;      }
+;      count = len >> 1;               /* nr of 16-bit words.. */
+;      if (count) {
+;              if (2 & (unsigned long) buff) {
+;                      result += *(unsigned short *) buff;
+;                      count--;
+;                      len -= 2;
+;                      buff += 2;
+;              }
+;              count >>= 1;            /* nr of 32-bit words.. */
+;              if (count) {
+;                      unsigned int carry = 0;
+;                      do {
+;                              unsigned int w = *(unsigned int *) buff;
+;                              count--;
+;                              buff += 4;
+;                              result += carry;
+;                              result += w;
+;                              carry = (w > result);
+;                      } while (count);
+;                      result += carry;
+;                      result = (result & 0xffff) + (result >> 16);
+;              }
+;              if (len & 2) {
+;                      result += *(unsigned short *) buff;
+;                      buff += 2;
+;              }
+;      }
+;      if (len & 1)
+;#ifdef __LITTLE_ENDIAN
+;              result += *buff;
+;#else
+;              result += (*buff << 8);
+;#endif
+;      result = (result & 0xffff) + (result >> 16);
+;      /* add up carry.. */
+;      result = (result & 0xffff) + (result >> 16);
+;      if (odd)
+;              result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+;out:
+;      return result;
+;}
+;
+; A4:  buff
+; B4:  len
+; return checksum in A4
+;
+
+ENTRY(do_csum)
+          CMPGT   .L2     B4,0,B0
+   [!B0]   BNOP    .S1    L26,3
+          EXTU    .S1     A4,31,31,A0
+
+          MV      .L1     A0,A3
+||        MV      .S1X    B3,A5
+||        MV      .L2     B4,B3
+||        ZERO    .D1     A1
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+   [A0]    SUB    .L2     B3,1,B3
+|| [A0]    LDBU    .D1T1   *A4++,A1
+#else
+   [!A0]   BNOP    .S1    L21,5
+|| [A0]    LDBU    .D1T1   *A4++,A0
+          SUB     .L2     B3,1,B3
+||        SHL     .S1     A0,8,A1
+L21:
+#endif
+          SHR     .S2     B3,1,B0
+   [!B0]   BNOP    .S1    L24,3
+          MVK     .L1     2,A0
+          AND     .L1     A4,A0,A0
+
+   [!A0]   BNOP    .S1    L22,5
+|| [A0]    LDHU    .D1T1   *A4++,A0
+          SUB     .L2     B0,1,B0
+||        SUB     .S2     B3,2,B3
+||        ADD     .L1     A0,A1,A1
+L22:
+          SHR     .S2     B0,1,B0
+||        ZERO    .L1     A0
+
+   [!B0]   BNOP    .S1    L23,5
+|| [B0]    MVC    .S2     B0,ILC
+
+          SPLOOP  3
+          SPMASK  L1
+||        MV      .L1     A1,A2
+||        LDW     .D1T1   *A4++,A1
+
+          NOP     4
+          ADD     .L1     A0,A1,A0
+          ADD     .L1     A2,A0,A2
+
+          SPKERNEL 1,2
+||        CMPGTU  .L1     A1,A2,A0
+
+          ADD     .L1     A0,A2,A6
+          EXTU    .S1     A6,16,16,A7
+          SHRU    .S2X    A6,16,B0
+          NOP             1
+          ADD     .L1X    A7,B0,A1
+L23:
+          MVK     .L2     2,B0
+          AND     .L2     B3,B0,B0
+   [B0]    LDHU    .D1T1   *A4++,A0
+          NOP     4
+   [B0]    ADD    .L1     A0,A1,A1
+L24:
+          EXTU    .S2     B3,31,31,B0
+#ifdef CONFIG_CPU_BIG_ENDIAN
+   [!B0]   BNOP    .S1    L25,4
+|| [B0]    LDBU    .D1T1   *A4,A0
+          SHL     .S1     A0,8,A0
+          ADD     .L1     A0,A1,A1
+L25:
+#else
+   [B0]    LDBU    .D1T1   *A4,A0
+          NOP     4
+   [B0]    ADD    .L1     A0,A1,A1
+#endif
+          EXTU    .S1     A1,16,16,A0
+          SHRU    .S2X    A1,16,B0
+          NOP     1
+          ADD     .L1X    A0,B0,A0
+          SHRU    .S1     A0,16,A1
+          ADD     .L1     A0,A1,A0
+          EXTU    .S1     A0,16,16,A1
+          EXTU    .S1     A1,16,24,A2
+
+          EXTU    .S1     A1,24,16,A0
+||        MV      .L2X    A3,B0
+
+   [B0]    OR     .L1     A0,A2,A1
+L26:
+          NOP     1
+          BNOP    .S2X    A5,4
+          MV      .L1     A1,A4
+ENDPROC(do_csum)
+
+;__wsum csum_partial(const void *buff, int len, __wsum wsum)
+;{
+;      unsigned int sum = (__force unsigned int)wsum;
+;      unsigned int result = do_csum(buff, len);
+;
+;      /* add in old sum, and carry.. */
+;      result += sum;
+;      if (sum > result)
+;              result += 1;
+;      return (__force __wsum)result;
+;}
+;
+ENTRY(csum_partial)
+          MV      .L1X    B3,A9
+||        CALLP   .S2     do_csum,B3
+||        MV      .S1     A6,A8
+          BNOP    .S2X    A9,2
+          ADD     .L1     A8,A4,A1
+          CMPGTU  .L1     A8,A1,A0
+          ADD     .L1     A1,A0,A4
+ENDPROC(csum_partial)
+
+;unsigned short
+;ip_compute_csum(unsigned char *buff, unsigned int len)
+;
+; A4:  buff
+; B4:  len
+; return checksum in A4
+
+ENTRY(ip_compute_csum)
+          MV      .L1X    B3,A9
+||        CALLP   .S2     do_csum,B3
+          BNOP    .S2X    A9,3
+          NOT     .S1     A4,A4
+          CLR     .S1     A4,16,31,A4
+ENDPROC(ip_compute_csum)
diff --git a/arch/c6x/lib/divi.S b/arch/c6x/lib/divi.S
new file mode 100644 (file)
index 0000000..4bde924
--- /dev/null
@@ -0,0 +1,53 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       ;; ABI considerations for the divide functions
+       ;; The following registers are call-used:
+       ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
+       ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
+       ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
+       ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
+       ;;
+       ;; In our implementation, divu and remu are leaf functions,
+       ;; while both divi and remi call into divu.
+       ;; A0 is not clobbered by any of the functions.
+       ;; divu does not clobber B2 either, which is taken advantage of
+       ;; in remi.
+       ;; divi uses B5 to hold the original return address during
+       ;; the call to divu.
+       ;; remi uses B2 and A5 to hold the input values during the
+       ;; call to divu.  It stores B3 in on the stack.
+
+       .text
+ENTRY(__c6xabi_divi)
+       call    .s2     __c6xabi_divu
+||     mv      .d2     B3, B5
+||     cmpgt   .l1     0, A4, A1
+||     cmpgt   .l2     0, B4, B1
+
+   [A1]        neg     .l1     A4, A4
+|| [B1]        neg     .l2     B4, B4
+||     xor     .s1x    A1, B1, A1
+   [A1] addkpc .s2     _divu_ret, B3, 4
+_divu_ret:
+       neg     .l1     A4, A4
+||     mv      .l2     B3,B5
+||     ret     .s2     B5
+       nop             5
+ENDPROC(__c6xabi_divi)
diff --git a/arch/c6x/lib/divremi.S b/arch/c6x/lib/divremi.S
new file mode 100644 (file)
index 0000000..64bc5aa
--- /dev/null
@@ -0,0 +1,46 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_divremi)
+       stw     .d2t2   B3, *B15--[2]
+||     cmpgt   .l1     0, A4, A1
+||     cmpgt   .l2     0, B4, B2
+||     mv      .s1     A4, A5
+||     call    .s2     __c6xabi_divu
+
+   [A1]        neg     .l1     A4, A4
+|| [B2]        neg     .l2     B4, B4
+||     xor     .s2x    B2, A1, B0
+||     mv      .d2     B4, B2
+
+   [B0]        addkpc  .s2     _divu_ret_1, B3, 1
+  [!B0] addkpc .s2     _divu_ret_2, B3, 1
+       nop     2
+_divu_ret_1:
+       neg     .l1     A4, A4
+_divu_ret_2:
+       ldw     .d2t2   *++B15[2], B3
+
+       mpy32   .m1x    A4, B2, A6
+       nop             3
+       ret     .s2     B3
+       sub     .l1     A5, A6, A5
+       nop     4
+ENDPROC(__c6xabi_divremi)
diff --git a/arch/c6x/lib/divremu.S b/arch/c6x/lib/divremu.S
new file mode 100644 (file)
index 0000000..caa9f23
--- /dev/null
@@ -0,0 +1,87 @@
+;;  Copyright 2011  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_divremu)
+       ;; We use a series of up to 31 subc instructions.  First, we find
+       ;; out how many leading zero bits there are in the divisor.  This
+       ;; gives us both a shift count for aligning (shifting) the divisor
+       ;; to the, and the number of times we have to execute subc.
+
+       ;; At the end, we have both the remainder and most of the quotient
+       ;; in A4.  The top bit of the quotient is computed first and is
+       ;; placed in A2.
+
+       ;; Return immediately if the dividend is zero.  Setting B4 to 1
+       ;; is a trick to allow us to leave the following insns in the jump
+       ;; delay slot without affecting the result.
+       mv      .s2x    A4, B1
+
+  [b1] lmbd    .l2     1, B4, B1
+||[!b1] b      .s2     B3      ; RETURN A
+||[!b1] mvk    .d2     1, B4
+
+||[!b1] zero   .s1     A5
+       mv      .l1x    B1, A6
+||     shl     .s2     B4, B1, B4
+
+       ;; The loop performs a maximum of 28 steps, so we do the
+       ;; first 3 here.
+       cmpltu  .l1x    A4, B4, A2
+  [!A2]        sub     .l1x    A4, B4, A4
+||     shru    .s2     B4, 1, B4
+||     xor     .s1     1, A2, A2
+
+       shl     .s1     A2, 31, A2
+|| [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+
+       ;; RETURN A may happen here (note: must happen before the next branch)
+__divremu0:
+       cmpgt   .l2     B1, 7, B0
+|| [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+|| [b0] b      .s1     __divremu0
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+   [b1]        subc    .l1x    A4,B4,A4
+|| [b1]        add     .s2     -1, B1, B1
+       ;; loop backwards branch happens here
+
+       ret     .s2     B3
+||     mvk     .s1     32, A1
+       sub     .l1     A1, A6, A6
+||     extu    .s1     A4, A6, A5
+       shl     .s1     A4, A6, A4
+       shru    .s1     A4, 1, A4
+||     sub     .l1     A6, 1, A6
+       or      .l1     A2, A4, A4
+       shru    .s1     A4, A6, A4
+       nop
+ENDPROC(__c6xabi_divremu)
diff --git a/arch/c6x/lib/divu.S b/arch/c6x/lib/divu.S
new file mode 100644 (file)
index 0000000..64af3c0
--- /dev/null
@@ -0,0 +1,98 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       ;; ABI considerations for the divide functions
+       ;; The following registers are call-used:
+       ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
+       ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
+       ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
+       ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
+       ;;
+       ;; In our implementation, divu and remu are leaf functions,
+       ;; while both divi and remi call into divu.
+       ;; A0 is not clobbered by any of the functions.
+       ;; divu does not clobber B2 either, which is taken advantage of
+       ;; in remi.
+       ;; divi uses B5 to hold the original return address during
+       ;; the call to divu.
+       ;; remi uses B2 and A5 to hold the input values during the
+       ;; call to divu.  It stores B3 in on the stack.
+
+       .text
+ENTRY(__c6xabi_divu)
+       ;; We use a series of up to 31 subc instructions.  First, we find
+       ;; out how many leading zero bits there are in the divisor.  This
+       ;; gives us both a shift count for aligning (shifting) the divisor
+       ;; to the, and the number of times we have to execute subc.
+
+       ;; At the end, we have both the remainder and most of the quotient
+       ;; in A4.  The top bit of the quotient is computed first and is
+       ;; placed in A2.
+
+       ;; Return immediately if the dividend is zero.
+        mv     .s2x    A4, B1
+   [B1]         lmbd   .l2     1, B4, B1
+|| [!B1] b     .s2     B3      ; RETURN A
+|| [!B1] mvk   .d2     1, B4
+        mv     .l1x    B1, A6
+||      shl    .s2     B4, B1, B4
+
+       ;; The loop performs a maximum of 28 steps, so we do the
+       ;; first 3 here.
+        cmpltu .l1x    A4, B4, A2
+   [!A2] sub   .l1x    A4, B4, A4
+||      shru   .s2     B4, 1, B4
+||      xor    .s1     1, A2, A2
+
+        shl    .s1     A2, 31, A2
+|| [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+
+       ;; RETURN A may happen here (note: must happen before the next branch)
+_divu_loop:
+        cmpgt  .l2     B1, 7, B0
+|| [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+|| [B0]  b     .s1     _divu_loop
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+       ;; loop backwards branch happens here
+
+        ret    .s2     B3
+||      mvk    .s1     32, A1
+        sub    .l1     A1, A6, A6
+        shl    .s1     A4, A6, A4
+        shru   .s1     A4, 1, A4
+||      sub    .l1     A6, 1, A6
+        or     .l1     A2, A4, A4
+        shru   .s1     A4, A6, A4
+        nop
+ENDPROC(__c6xabi_divu)
diff --git a/arch/c6x/lib/llshl.S b/arch/c6x/lib/llshl.S
new file mode 100644 (file)
index 0000000..7b105e2
--- /dev/null
@@ -0,0 +1,37 @@
+;;  Copyright (C) 2010 Texas Instruments Incorporated
+;;  Contributed by Mark Salter <msalter@redhat.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;;  uint64_t __c6xabi_llshl(uint64_t val, uint shift)
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_llshl)
+        mv     .l1x    B4,A1
+   [!A1] b     .s2     B3              ; just return if zero shift
+        mvk    .s1     32,A0
+        sub    .d1     A0,A1,A0
+        cmplt  .l1     0,A0,A2
+   [A2]         shru   .s1     A4,A0,A0
+   [!A2] neg   .l1     A0,A5
+|| [A2]  shl   .s1     A5,A1,A5
+   [!A2] shl   .s1     A4,A5,A5
+|| [A2]  or    .d1     A5,A0,A5
+|| [!A2] mvk   .l1     0,A4
+   [A2]         shl    .s1     A4,A1,A4
+        bnop   .s2     B3,5
+ENDPROC(__c6xabi_llshl)
diff --git a/arch/c6x/lib/llshr.S b/arch/c6x/lib/llshr.S
new file mode 100644 (file)
index 0000000..fde1bec
--- /dev/null
@@ -0,0 +1,38 @@
+;;  Copyright (C) 2010 Texas Instruments Incorporated
+;;  Contributed by Mark Salter <msalter@redhat.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;;  uint64_t __c6xabi_llshr(uint64_t val, uint shift)
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_llshr)
+        mv     .l1x    B4,A1
+   [!A1] b     .s2     B3              ; return if zero shift count
+        mvk    .s1     32,A0
+        sub    .d1     A0,A1,A0
+        cmplt  .l1     0,A0,A2
+   [A2]  shl   .s1     A5,A0,A0
+        nop
+   [!A2] neg   .l1     A0,A4
+|| [A2]  shru  .s1     A4,A1,A4
+   [!A2] shr   .s1     A5,A4,A4
+|| [A2]  or    .d1     A4,A0,A4
+   [!A2] shr   .s1     A5,0x1f,A5
+   [A2]  shr   .s1     A5,A1,A5
+        bnop   .s2     B3,5
+ENDPROC(__c6xabi_llshr)
diff --git a/arch/c6x/lib/llshru.S b/arch/c6x/lib/llshru.S
new file mode 100644 (file)
index 0000000..596ae3f
--- /dev/null
@@ -0,0 +1,38 @@
+;;  Copyright (C) 2010 Texas Instruments Incorporated
+;;  Contributed by Mark Salter <msalter@redhat.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;;  uint64_t __c6xabi_llshru(uint64_t val, uint shift)
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_llshru)
+        mv     .l1x    B4,A1
+   [!A1] b     .s2     B3              ; return if zero shift count
+        mvk    .s1     32,A0
+        sub    .d1     A0,A1,A0
+        cmplt  .l1     0,A0,A2
+   [A2]  shl   .s1     A5,A0,A0
+        nop
+   [!A2] neg   .l1     A0,A4
+|| [A2]  shru  .s1     A4,A1,A4
+   [!A2] shru  .s1     A5,A4,A4
+|| [A2]  or    .d1     A4,A0,A4
+|| [!A2] mvk   .l1     0,A5
+   [A2]  shru  .s1     A5,A1,A5
+        bnop   .s2     B3,5
+ENDPROC(__c6xabi_llshru)
diff --git a/arch/c6x/lib/memcpy_64plus.S b/arch/c6x/lib/memcpy_64plus.S
new file mode 100644 (file)
index 0000000..0bbc2cb
--- /dev/null
@@ -0,0 +1,46 @@
+;  Port on Texas Instruments TMS320C6x architecture
+;
+;  Copyright (C) 2006, 2009, 2010 Texas Instruments Incorporated
+;  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/linkage.h>
+
+       .text
+
+ENTRY(memcpy)
+       AND     .L1     0x1,A6,A0
+ ||    AND     .S1     0x2,A6,A1
+ ||    AND     .L2X    0x4,A6,B0
+ ||    MV      .D1     A4,A3
+ ||    MVC     .S2     ILC,B2
+
+   [A0] LDB    .D2T1   *B4++,A5
+   [A1] LDB    .D2T1   *B4++,A7
+   [A1] LDB    .D2T1   *B4++,A8
+   [B0] LDNW   .D2T1   *B4++,A9
+ ||    SHRU    .S2X    A6,0x3,B1
+  [!B1] BNOP   .S2     B3,1
+
+   [A0] STB    .D1T1   A5,*A3++
+ ||[B1] MVC    .S2     B1,ILC
+   [A1] STB    .D1T1   A7,*A3++
+   [A1] STB    .D1T1   A8,*A3++
+   [B0] STNW   .D1T1   A9,*A3++        ; return when len < 8
+
+       SPLOOP  2
+
+       LDNDW   .D2T1   *B4++,A9:A8
+       NOP     3
+
+       NOP
+       SPKERNEL        0,0
+ ||    STNDW   .D1T1   A9:A8,*A3++
+
+       BNOP    .S2     B3,4
+       MVC     .S2     B2,ILC
+ENDPROC(memcpy)
diff --git a/arch/c6x/lib/mpyll.S b/arch/c6x/lib/mpyll.S
new file mode 100644 (file)
index 0000000..f103441
--- /dev/null
@@ -0,0 +1,49 @@
+;;  Copyright (C) 2010 Texas Instruments Incorporated
+;;  Contributed by Mark Salter <msalter@redhat.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       ;; uint64_t __c6xabi_mpyll(uint64_t x, uint64_t y)
+       ;;
+       ;; 64x64 multiply
+       ;; First compute partial results using 32-bit parts of x and y:
+       ;;
+       ;;   b63         b32 b31          b0
+       ;;    -----------------------------
+       ;;    |      1      |      0      |
+       ;;    -----------------------------
+       ;;
+       ;;   P0 = X0*Y0
+       ;;   P1 = X0*Y1 + X1*Y0
+       ;;   P2 = X1*Y1
+       ;;
+       ;;   result = (P2 << 64) + (P1 << 32) + P0
+       ;;
+       ;; Since the result is also 64-bit, we can skip the P2 term.
+
+       .text
+ENTRY(__c6xabi_mpyll)
+       mpy32u  .m1x    A4,B4,A1:A0     ; X0*Y0
+       b       .s2     B3
+ ||    mpy32u  .m2x    B5,A4,B1:B0     ; X0*Y1 (don't need upper 32-bits)
+ ||    mpy32u  .m1x    A5,B4,A3:A2     ; X1*Y0 (don't need upper 32-bits)
+       nop
+       nop
+       mv      .s1     A0,A4
+       add     .l1x    A2,B0,A5
+       add     .s1     A1,A5,A5
+ENDPROC(__c6xabi_mpyll)
diff --git a/arch/c6x/lib/negll.S b/arch/c6x/lib/negll.S
new file mode 100644 (file)
index 0000000..82f4bce
--- /dev/null
@@ -0,0 +1,31 @@
+;;  Copyright (C) 2010 Texas Instruments Incorporated
+;;  Contributed by Mark Salter <msalter@redhat.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;;  int64_t __c6xabi_negll(int64_t val)
+
+#include <linux/linkage.h>
+
+       .text
+ENTRY(__c6xabi_negll)
+       b       .s2     B3
+       mvk     .l1     0,A0
+       subu    .l1     A0,A4,A3:A2
+       sub     .l1     A0,A5,A0
+||     ext     .s1     A3,24,24,A5
+       add     .l1     A5,A0,A5
+       mv      .s1     A2,A4
+ENDPROC(__c6xabi_negll)
diff --git a/arch/c6x/lib/pop_rts.S b/arch/c6x/lib/pop_rts.S
new file mode 100644 (file)
index 0000000..d7d96c7
--- /dev/null
@@ -0,0 +1,32 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+
+ENTRY(__c6xabi_pop_rts)
+       lddw    .d2t2   *++B15, B3:B2
+       lddw    .d2t1   *++B15, A11:A10
+       lddw    .d2t2   *++B15, B11:B10
+       lddw    .d2t1   *++B15, A13:A12
+       lddw    .d2t2   *++B15, B13:B12
+       lddw    .d2t1   *++B15, A15:A14
+||     b       .s2     B3
+       ldw     .d2t2   *++B15[2], B14
+       nop     4
+ENDPROC(__c6xabi_pop_rts)
diff --git a/arch/c6x/lib/push_rts.S b/arch/c6x/lib/push_rts.S
new file mode 100644 (file)
index 0000000..f6e3db3
--- /dev/null
@@ -0,0 +1,31 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+
+ENTRY(__c6xabi_push_rts)
+       stw     .d2t2   B14, *B15--[2]
+       stdw    .d2t1   A15:A14, *B15--
+||     b       .s2x    A3
+       stdw    .d2t2   B13:B12, *B15--
+       stdw    .d2t1   A13:A12, *B15--
+       stdw    .d2t2   B11:B10, *B15--
+       stdw    .d2t1   A11:A10, *B15--
+       stdw    .d2t2   B3:B2, *B15--
+ENDPROC(__c6xabi_push_rts)
diff --git a/arch/c6x/lib/remi.S b/arch/c6x/lib/remi.S
new file mode 100644 (file)
index 0000000..6f2ca18
--- /dev/null
@@ -0,0 +1,64 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       ;; ABI considerations for the divide functions
+       ;; The following registers are call-used:
+       ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
+       ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
+       ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
+       ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
+       ;;
+       ;; In our implementation, divu and remu are leaf functions,
+       ;; while both divi and remi call into divu.
+       ;; A0 is not clobbered by any of the functions.
+       ;; divu does not clobber B2 either, which is taken advantage of
+       ;; in remi.
+       ;; divi uses B5 to hold the original return address during
+       ;; the call to divu.
+       ;; remi uses B2 and A5 to hold the input values during the
+       ;; call to divu.  It stores B3 in on the stack.
+
+       .text
+
+ENTRY(__c6xabi_remi)
+       stw     .d2t2   B3, *B15--[2]
+||     cmpgt   .l1     0, A4, A1
+||     cmpgt   .l2     0, B4, B2
+||     mv      .s1     A4, A5
+||     call    .s2     __c6xabi_divu
+
+   [A1]        neg     .l1     A4, A4
+|| [B2]        neg     .l2     B4, B4
+||     xor     .s2x    B2, A1, B0
+||     mv      .d2     B4, B2
+
+   [B0]        addkpc  .s2     _divu_ret_1, B3, 1
+  [!B0] addkpc .s2     _divu_ret_2, B3, 1
+       nop     2
+_divu_ret_1:
+       neg     .l1     A4, A4
+_divu_ret_2:
+       ldw     .d2t2   *++B15[2], B3
+
+       mpy32   .m1x    A4, B2, A6
+       nop             3
+       ret     .s2     B3
+       sub     .l1     A5, A6, A4
+       nop     4
+ENDPROC(__c6xabi_remi)
diff --git a/arch/c6x/lib/remu.S b/arch/c6x/lib/remu.S
new file mode 100644 (file)
index 0000000..3fae719
--- /dev/null
@@ -0,0 +1,82 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       ;; ABI considerations for the divide functions
+       ;; The following registers are call-used:
+       ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
+       ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
+       ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
+       ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
+       ;;
+       ;; In our implementation, divu and remu are leaf functions,
+       ;; while both divi and remi call into divu.
+       ;; A0 is not clobbered by any of the functions.
+       ;; divu does not clobber B2 either, which is taken advantage of
+       ;; in remi.
+       ;; divi uses B5 to hold the original return address during
+       ;; the call to divu.
+       ;; remi uses B2 and A5 to hold the input values during the
+       ;; call to divu.  It stores B3 in on the stack.
+
+
+       .text
+
+ENTRY(__c6xabi_remu)
+       ;; The ABI seems designed to prevent these functions calling each other,
+       ;; so we duplicate most of the divsi3 code here.
+        mv     .s2x    A4, B1
+        lmbd   .l2     1, B4, B1
+|| [!B1] b     .s2     B3      ; RETURN A
+|| [!B1] mvk   .d2     1, B4
+
+        mv     .l1x    B1, A7
+||      shl    .s2     B4, B1, B4
+
+        cmpltu .l1x    A4, B4, A1
+   [!A1] sub   .l1x    A4, B4, A4
+        shru   .s2     B4, 1, B4
+
+_remu_loop:
+        cmpgt  .l2     B1, 7, B0
+|| [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+       ;; RETURN A may happen here (note: must happen before the next branch)
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+|| [B0]         b      .s1     _remu_loop
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+       ;; loop backwards branch happens here
+
+        ret    .s2     B3
+   [B1]         subc   .l1x    A4,B4,A4
+|| [B1]         add    .s2     -1, B1, B1
+   [B1]         subc   .l1x    A4,B4,A4
+
+        extu   .s1     A4, A7, A4
+        nop    2
+ENDPROC(__c6xabi_remu)
diff --git a/arch/c6x/lib/strasgi.S b/arch/c6x/lib/strasgi.S
new file mode 100644 (file)
index 0000000..de27407
--- /dev/null
@@ -0,0 +1,89 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+
+ENTRY(__c6xabi_strasgi)
+       ;; This is essentially memcpy, with alignment known to be at least
+       ;; 4, and the size a multiple of 4 greater than or equal to 28.
+        ldw    .d2t1   *B4++, A0
+||      mvk    .s2     16, B1
+        ldw    .d2t1   *B4++, A1
+||      mvk    .s2     20, B2
+||      sub    .d1     A6, 24, A6
+        ldw    .d2t1   *B4++, A5
+        ldw    .d2t1   *B4++, A7
+||      mv     .l2x    A6, B7
+        ldw    .d2t1   *B4++, A8
+        ldw    .d2t1   *B4++, A9
+||      mv     .s2x    A0, B5
+||      cmpltu .l2     B2, B7, B0
+
+_strasgi_loop:
+        stw    .d1t2   B5, *A4++
+|| [B0]         ldw    .d2t1   *B4++, A0
+||      mv     .s2x    A1, B5
+||      mv     .l2     B7, B6
+
+   [B0]         sub    .d2     B6, 24, B7
+|| [B0]         b      .s2     _strasgi_loop
+||      cmpltu .l2     B1, B6, B0
+
+   [B0]         ldw    .d2t1   *B4++, A1
+||      stw    .d1t2   B5, *A4++
+||      mv     .s2x    A5, B5
+||      cmpltu .l2     12, B6, B0
+
+   [B0]         ldw    .d2t1   *B4++, A5
+||      stw    .d1t2   B5, *A4++
+||      mv     .s2x    A7, B5
+||      cmpltu .l2     8, B6, B0
+
+   [B0]         ldw    .d2t1   *B4++, A7
+||      stw    .d1t2   B5, *A4++
+||      mv     .s2x    A8, B5
+||      cmpltu .l2     4, B6, B0
+
+   [B0]         ldw    .d2t1   *B4++, A8
+||      stw    .d1t2   B5, *A4++
+||      mv     .s2x    A9, B5
+||      cmpltu .l2     0, B6, B0
+
+   [B0]         ldw    .d2t1   *B4++, A9
+||      stw    .d1t2   B5, *A4++
+||      mv     .s2x    A0, B5
+||      cmpltu .l2     B2, B7, B0
+
+       ;; loop back branch happens here
+
+        cmpltu .l2     B1, B6, B0
+||      ret    .s2     b3
+
+   [B0]         stw    .d1t1   A1, *A4++
+||      cmpltu .l2     12, B6, B0
+   [B0]         stw    .d1t1   A5, *A4++
+||      cmpltu .l2     8, B6, B0
+   [B0]         stw    .d1t1   A7, *A4++
+||      cmpltu .l2     4, B6, B0
+   [B0]         stw    .d1t1   A8, *A4++
+||      cmpltu .l2     0, B6, B0
+   [B0]         stw    .d1t1   A9, *A4++
+
+       ;; return happens here
+ENDPROC(__c6xabi_strasgi)
diff --git a/arch/c6x/lib/strasgi_64plus.S b/arch/c6x/lib/strasgi_64plus.S
new file mode 100644 (file)
index 0000000..c9fd159
--- /dev/null
@@ -0,0 +1,39 @@
+;;  Copyright 2010  Free Software Foundation, Inc.
+;;  Contributed by Bernd Schmidt <bernds@codesourcery.com>.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <linux/linkage.h>
+
+       .text
+
+ENTRY(__c6xabi_strasgi_64plus)
+       shru    .s2x    a6, 2, b31
+||     mv      .s1     a4, a30
+||     mv      .d2     b4, b30
+
+       add     .s2     -4, b31, b31
+
+       sploopd         1
+||     mvc     .s2     b31, ilc
+       ldw     .d2t2   *b30++, b31
+       nop     4
+       mv      .s1x    b31,a31
+       spkernel        6, 0
+||     stw     .d1t1   a31, *a30++
+
+       ret     .s2     b3
+       nop 5
+ENDPROC(__c6xabi_strasgi_64plus)
diff --git a/arch/c6x/mm/Makefile b/arch/c6x/mm/Makefile
new file mode 100644 (file)
index 0000000..136a975
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux c6x-specific parts of the memory manager.
+#
+
+obj-y := init.o dma-coherent.o
diff --git a/arch/c6x/mm/dma-coherent.c b/arch/c6x/mm/dma-coherent.c
new file mode 100644 (file)
index 0000000..4187e51
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot <aurelien.jacquiot@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.
+ *
+ *  DMA uncached mapping support.
+ *
+ *  Using code pulled from ARM
+ *  Copyright (C) 2000-2004 Russell King
+ *
+ */
+#include <linux/slab.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/memblock.h>
+
+#include <asm/page.h>
+
+/*
+ * DMA coherent memory management, can be redefined using the memdma=
+ * kernel command line
+ */
+
+/* none by default */
+static phys_addr_t dma_base;
+static u32 dma_size;
+static u32 dma_pages;
+
+static unsigned long *dma_bitmap;
+
+/* bitmap lock */
+static DEFINE_SPINLOCK(dma_lock);
+
+/*
+ * Return a DMA coherent and contiguous memory chunk from the DMA memory
+ */
+static inline u32 __alloc_dma_pages(int order)
+{
+       unsigned long flags;
+       u32 pos;
+
+       spin_lock_irqsave(&dma_lock, flags);
+       pos = bitmap_find_free_region(dma_bitmap, dma_pages, order);
+       spin_unlock_irqrestore(&dma_lock, flags);
+
+       return dma_base + (pos << PAGE_SHIFT);
+}
+
+static void __free_dma_pages(u32 addr, int order)
+{
+       unsigned long flags;
+       u32 pos = (addr - dma_base) >> PAGE_SHIFT;
+
+       if (addr < dma_base || (pos + (1 << order)) >= dma_pages) {
+               printk(KERN_ERR "%s: freeing outside range.\n", __func__);
+               BUG();
+       }
+
+       spin_lock_irqsave(&dma_lock, flags);
+       bitmap_release_region(dma_bitmap, pos, order);
+       spin_unlock_irqrestore(&dma_lock, flags);
+}
+
+/*
+ * Allocate DMA coherent memory space and return both the kernel
+ * virtual and DMA address for that space.
+ */
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                        dma_addr_t *handle, gfp_t gfp)
+{
+       u32 paddr;
+       int order;
+
+       if (!dma_size || !size)
+               return NULL;
+
+       order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
+
+       paddr = __alloc_dma_pages(order);
+
+       if (handle)
+               *handle = paddr;
+
+       if (!paddr)
+               return NULL;
+
+       return phys_to_virt(paddr);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+/*
+ * Free DMA coherent memory as defined by the above mapping.
+ */
+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+                      dma_addr_t dma_handle)
+{
+       int order;
+
+       if (!dma_size || !size)
+               return;
+
+       order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
+
+       __free_dma_pages(virt_to_phys(vaddr), order);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+/*
+ * Initialise the coherent DMA memory allocator using the given uncached region.
+ */
+void __init coherent_mem_init(phys_addr_t start, u32 size)
+{
+       phys_addr_t bitmap_phys;
+
+       if (!size)
+               return;
+
+       printk(KERN_INFO
+              "Coherent memory (DMA) region start=0x%x size=0x%x\n",
+              start, size);
+
+       dma_base = start;
+       dma_size = size;
+
+       /* allocate bitmap */
+       dma_pages = dma_size >> PAGE_SHIFT;
+       if (dma_size & (PAGE_SIZE - 1))
+               ++dma_pages;
+
+       bitmap_phys = memblock_alloc(BITS_TO_LONGS(dma_pages) * sizeof(long),
+                                    sizeof(long));
+
+       dma_bitmap = phys_to_virt(bitmap_phys);
+       memset(dma_bitmap, 0, dma_pages * PAGE_SIZE);
+}
diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c
new file mode 100644 (file)
index 0000000..89395f0
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
+ *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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/mm.h>
+#include <linux/swap.h>
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blkdev.h>
+#endif
+#include <linux/initrd.h>
+
+#include <asm/sections.h>
+
+/*
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+unsigned long empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses  of available kernel virtual memory.
+ */
+void __init paging_init(void)
+{
+       struct pglist_data *pgdat = NODE_DATA(0);
+       unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+       empty_zero_page      = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+       memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+       /*
+        * Set up user data space
+        */
+       set_fs(KERNEL_DS);
+
+       /*
+        * Define zones
+        */
+       zones_size[ZONE_NORMAL] = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT;
+       pgdat->node_zones[ZONE_NORMAL].zone_start_pfn =
+               __pa(PAGE_OFFSET) >> PAGE_SHIFT;
+
+       free_area_init(zones_size);
+}
+
+void __init mem_init(void)
+{
+       int codek, datak;
+       unsigned long tmp;
+       unsigned long len = memory_end - memory_start;
+
+       high_memory = (void *)(memory_end & PAGE_MASK);
+
+       /* this will put all memory onto the freelists */
+       totalram_pages = free_all_bootmem();
+
+       codek = (_etext - _stext) >> 10;
+       datak = (_end - _sdata) >> 10;
+
+       tmp = nr_free_pages() << PAGE_SHIFT;
+       printk(KERN_INFO "Memory: %luk/%luk RAM (%dk kernel code, %dk data)\n",
+              tmp >> 10, len >> 10, codek, datak);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init free_initrd_mem(unsigned long start, unsigned long end)
+{
+       int pages = 0;
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               init_page_count(virt_to_page(start));
+               free_page(start);
+               totalram_pages++;
+               pages++;
+       }
+       printk(KERN_INFO "Freeing initrd memory: %luk freed\n",
+              (pages * PAGE_SIZE) >> 10);
+}
+#endif
+
+void __init free_initmem(void)
+{
+       unsigned long addr;
+
+       /*
+        * The following code should be cool even if these sections
+        * are not page aligned.
+        */
+       addr = PAGE_ALIGN((unsigned long)(__init_begin));
+
+       /* next to check that the page we free is not a partial page */
+       for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
+            addr += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(addr));
+               init_page_count(virt_to_page(addr));
+               free_page(addr);
+               totalram_pages++;
+       }
+       printk(KERN_INFO "Freeing unused kernel memory: %dK freed\n",
+              (int) ((addr - PAGE_ALIGN((long) &__init_begin)) >> 10));
+}
diff --git a/arch/c6x/platforms/Kconfig b/arch/c6x/platforms/Kconfig
new file mode 100644 (file)
index 0000000..401ee67
--- /dev/null
@@ -0,0 +1,16 @@
+
+config SOC_TMS320C6455
+       bool "TMS320C6455"
+       default n
+
+config SOC_TMS320C6457
+       bool "TMS320C6457"
+       default n
+
+config SOC_TMS320C6472
+       bool "TMS320C6472"
+       default n
+
+config SOC_TMS320C6474
+       bool "TMS320C6474"
+       default n
diff --git a/arch/c6x/platforms/Makefile b/arch/c6x/platforms/Makefile
new file mode 100644 (file)
index 0000000..9a95b9b
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for arch/c6x/platforms
+#
+# Copyright 2010, 2011 Texas Instruments Incorporated
+#
+
+obj-y = platform.o cache.o megamod-pic.o pll.o plldata.o timer64.o
+obj-y += dscr.o
+
+# SoC objects
+obj-$(CONFIG_SOC_TMS320C6455)   += emif.o
+obj-$(CONFIG_SOC_TMS320C6457)   += emif.o
diff --git a/arch/c6x/platforms/cache.c b/arch/c6x/platforms/cache.c
new file mode 100644 (file)
index 0000000..86318a1
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+
+#include <asm/cache.h>
+#include <asm/soc.h>
+
+/*
+ * Internal Memory Control Registers for caches
+ */
+#define IMCR_CCFG        0x0000
+#define IMCR_L1PCFG      0x0020
+#define IMCR_L1PCC       0x0024
+#define IMCR_L1DCFG      0x0040
+#define IMCR_L1DCC       0x0044
+#define IMCR_L2ALLOC0    0x2000
+#define IMCR_L2ALLOC1    0x2004
+#define IMCR_L2ALLOC2    0x2008
+#define IMCR_L2ALLOC3    0x200c
+#define IMCR_L2WBAR      0x4000
+#define IMCR_L2WWC       0x4004
+#define IMCR_L2WIBAR     0x4010
+#define IMCR_L2WIWC      0x4014
+#define IMCR_L2IBAR      0x4018
+#define IMCR_L2IWC       0x401c
+#define IMCR_L1PIBAR     0x4020
+#define IMCR_L1PIWC      0x4024
+#define IMCR_L1DWIBAR    0x4030
+#define IMCR_L1DWIWC     0x4034
+#define IMCR_L1DWBAR     0x4040
+#define IMCR_L1DWWC      0x4044
+#define IMCR_L1DIBAR     0x4048
+#define IMCR_L1DIWC      0x404c
+#define IMCR_L2WB        0x5000
+#define IMCR_L2WBINV     0x5004
+#define IMCR_L2INV       0x5008
+#define IMCR_L1PINV      0x5028
+#define IMCR_L1DWB       0x5040
+#define IMCR_L1DWBINV    0x5044
+#define IMCR_L1DINV      0x5048
+#define IMCR_MAR_BASE    0x8000
+#define IMCR_MAR96_111   0x8180
+#define IMCR_MAR128_191   0x8200
+#define IMCR_MAR224_239   0x8380
+#define IMCR_L2MPFAR     0xa000
+#define IMCR_L2MPFSR     0xa004
+#define IMCR_L2MPFCR     0xa008
+#define IMCR_L2MPLK0     0xa100
+#define IMCR_L2MPLK1     0xa104
+#define IMCR_L2MPLK2     0xa108
+#define IMCR_L2MPLK3     0xa10c
+#define IMCR_L2MPLKCMD   0xa110
+#define IMCR_L2MPLKSTAT   0xa114
+#define IMCR_L2MPPA_BASE  0xa200
+#define IMCR_L1PMPFAR    0xa400
+#define IMCR_L1PMPFSR    0xa404
+#define IMCR_L1PMPFCR    0xa408
+#define IMCR_L1PMPLK0    0xa500
+#define IMCR_L1PMPLK1    0xa504
+#define IMCR_L1PMPLK2    0xa508
+#define IMCR_L1PMPLK3    0xa50c
+#define IMCR_L1PMPLKCMD   0xa510
+#define IMCR_L1PMPLKSTAT  0xa514
+#define IMCR_L1PMPPA_BASE 0xa600
+#define IMCR_L1DMPFAR    0xac00
+#define IMCR_L1DMPFSR    0xac04
+#define IMCR_L1DMPFCR    0xac08
+#define IMCR_L1DMPLK0    0xad00
+#define IMCR_L1DMPLK1    0xad04
+#define IMCR_L1DMPLK2    0xad08
+#define IMCR_L1DMPLK3    0xad0c
+#define IMCR_L1DMPLKCMD   0xad10
+#define IMCR_L1DMPLKSTAT  0xad14
+#define IMCR_L1DMPPA_BASE 0xae00
+#define IMCR_L2PDWAKE0   0xc040
+#define IMCR_L2PDWAKE1   0xc044
+#define IMCR_L2PDSLEEP0   0xc050
+#define IMCR_L2PDSLEEP1   0xc054
+#define IMCR_L2PDSTAT0   0xc060
+#define IMCR_L2PDSTAT1   0xc064
+
+/*
+ * CCFG register values and bits
+ */
+#define L2MODE_0K_CACHE   0x0
+#define L2MODE_32K_CACHE  0x1
+#define L2MODE_64K_CACHE  0x2
+#define L2MODE_128K_CACHE 0x3
+#define L2MODE_256K_CACHE 0x7
+
+#define L2PRIO_URGENT     0x0
+#define L2PRIO_HIGH       0x1
+#define L2PRIO_MEDIUM     0x2
+#define L2PRIO_LOW        0x3
+
+#define CCFG_ID           0x100   /* Invalidate L1P bit */
+#define CCFG_IP           0x200   /* Invalidate L1D bit */
+
+static void __iomem *cache_base;
+
+/*
+ * L1 & L2 caches generic functions
+ */
+#define imcr_get(reg) soc_readl(cache_base + (reg))
+#define imcr_set(reg, value) \
+do {                                                           \
+       soc_writel((value), cache_base + (reg));                \
+       soc_readl(cache_base + (reg));                          \
+} while (0)
+
+static void cache_block_operation_wait(unsigned int wc_reg)
+{
+       /* Wait for completion */
+       while (imcr_get(wc_reg))
+               cpu_relax();
+}
+
+static DEFINE_SPINLOCK(cache_lock);
+
+/*
+ * Generic function to perform a block cache operation as
+ * invalidate or writeback/invalidate
+ */
+static void cache_block_operation(unsigned int *start,
+                                 unsigned int *end,
+                                 unsigned int bar_reg,
+                                 unsigned int wc_reg)
+{
+       unsigned long flags;
+       unsigned int wcnt =
+               (L2_CACHE_ALIGN_CNT((unsigned int) end)
+                - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2;
+       unsigned int wc = 0;
+
+       for (; wcnt; wcnt -= wc, start += wc) {
+loop:
+               spin_lock_irqsave(&cache_lock, flags);
+
+               /*
+                * If another cache operation is occuring
+                */
+               if (unlikely(imcr_get(wc_reg))) {
+                       spin_unlock_irqrestore(&cache_lock, flags);
+
+                       /* Wait for previous operation completion */
+                       cache_block_operation_wait(wc_reg);
+
+                       /* Try again */
+                       goto loop;
+               }
+
+               imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start));
+
+               if (wcnt > 0xffff)
+                       wc = 0xffff;
+               else
+                       wc = wcnt;
+
+               /* Set word count value in the WC register */
+               imcr_set(wc_reg, wc & 0xffff);
+
+               spin_unlock_irqrestore(&cache_lock, flags);
+
+               /* Wait for completion */
+               cache_block_operation_wait(wc_reg);
+       }
+}
+
+static void cache_block_operation_nowait(unsigned int *start,
+                                        unsigned int *end,
+                                        unsigned int bar_reg,
+                                        unsigned int wc_reg)
+{
+       unsigned long flags;
+       unsigned int wcnt =
+               (L2_CACHE_ALIGN_CNT((unsigned int) end)
+                - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2;
+       unsigned int wc = 0;
+
+       for (; wcnt; wcnt -= wc, start += wc) {
+
+               spin_lock_irqsave(&cache_lock, flags);
+
+               imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start));
+
+               if (wcnt > 0xffff)
+                       wc = 0xffff;
+               else
+                       wc = wcnt;
+
+               /* Set word count value in the WC register */
+               imcr_set(wc_reg, wc & 0xffff);
+
+               spin_unlock_irqrestore(&cache_lock, flags);
+
+               /* Don't wait for completion on last cache operation */
+               if (wcnt > 0xffff)
+                       cache_block_operation_wait(wc_reg);
+       }
+}
+
+/*
+ * L1 caches management
+ */
+
+/*
+ * Disable L1 caches
+ */
+void L1_cache_off(void)
+{
+       unsigned int dummy;
+
+       imcr_set(IMCR_L1PCFG, 0);
+       dummy = imcr_get(IMCR_L1PCFG);
+
+       imcr_set(IMCR_L1DCFG, 0);
+       dummy = imcr_get(IMCR_L1DCFG);
+}
+
+/*
+ * Enable L1 caches
+ */
+void L1_cache_on(void)
+{
+       unsigned int dummy;
+
+       imcr_set(IMCR_L1PCFG, 7);
+       dummy = imcr_get(IMCR_L1PCFG);
+
+       imcr_set(IMCR_L1DCFG, 7);
+       dummy = imcr_get(IMCR_L1DCFG);
+}
+
+/*
+ *  L1P global-invalidate all
+ */
+void L1P_cache_global_invalidate(void)
+{
+       unsigned int set = 1;
+       imcr_set(IMCR_L1PINV, set);
+       while (imcr_get(IMCR_L1PINV) & 1)
+               cpu_relax();
+}
+
+/*
+ *  L1D global-invalidate all
+ *
+ * Warning: this operation causes all updated data in L1D to
+ * be discarded rather than written back to the lower levels of
+ * memory
+ */
+void L1D_cache_global_invalidate(void)
+{
+       unsigned int set = 1;
+       imcr_set(IMCR_L1DINV, set);
+       while (imcr_get(IMCR_L1DINV) & 1)
+               cpu_relax();
+}
+
+void L1D_cache_global_writeback(void)
+{
+       unsigned int set = 1;
+       imcr_set(IMCR_L1DWB, set);
+       while (imcr_get(IMCR_L1DWB) & 1)
+               cpu_relax();
+}
+
+void L1D_cache_global_writeback_invalidate(void)
+{
+       unsigned int set = 1;
+       imcr_set(IMCR_L1DWBINV, set);
+       while (imcr_get(IMCR_L1DWBINV) & 1)
+               cpu_relax();
+}
+
+/*
+ * L2 caches management
+ */
+
+/*
+ * Set L2 operation mode
+ */
+void L2_cache_set_mode(unsigned int mode)
+{
+       unsigned int ccfg = imcr_get(IMCR_CCFG);
+
+       /* Clear and set the L2MODE bits in CCFG */
+       ccfg &= ~7;
+       ccfg |= (mode & 7);
+       imcr_set(IMCR_CCFG, ccfg);
+       ccfg = imcr_get(IMCR_CCFG);
+}
+
+/*
+ *  L2 global-writeback and global-invalidate all
+ */
+void L2_cache_global_writeback_invalidate(void)
+{
+       imcr_set(IMCR_L2WBINV, 1);
+       while (imcr_get(IMCR_L2WBINV))
+               cpu_relax();
+}
+
+/*
+ *  L2 global-writeback all
+ */
+void L2_cache_global_writeback(void)
+{
+       imcr_set(IMCR_L2WB, 1);
+       while (imcr_get(IMCR_L2WB))
+               cpu_relax();
+}
+
+/*
+ * Cacheability controls
+ */
+void enable_caching(unsigned long start, unsigned long end)
+{
+       unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2);
+       unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2);
+
+       for (; mar <= mar_e; mar += 4)
+               imcr_set(mar, imcr_get(mar) | 1);
+}
+
+void disable_caching(unsigned long start, unsigned long end)
+{
+       unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2);
+       unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2);
+
+       for (; mar <= mar_e; mar += 4)
+               imcr_set(mar, imcr_get(mar) & ~1);
+}
+
+
+/*
+ *  L1 block operations
+ */
+void L1P_cache_block_invalidate(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L1PIBAR, IMCR_L1PIWC);
+}
+
+void L1D_cache_block_invalidate(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L1DIBAR, IMCR_L1DIWC);
+}
+
+void L1D_cache_block_writeback_invalidate(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L1DWIBAR, IMCR_L1DWIWC);
+}
+
+void L1D_cache_block_writeback(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L1DWBAR, IMCR_L1DWWC);
+}
+
+/*
+ *  L2 block operations
+ */
+void L2_cache_block_invalidate(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L2IBAR, IMCR_L2IWC);
+}
+
+void L2_cache_block_writeback(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L2WBAR, IMCR_L2WWC);
+}
+
+void L2_cache_block_writeback_invalidate(unsigned int start, unsigned int end)
+{
+       cache_block_operation((unsigned int *) start,
+                             (unsigned int *) end,
+                             IMCR_L2WIBAR, IMCR_L2WIWC);
+}
+
+void L2_cache_block_invalidate_nowait(unsigned int start, unsigned int end)
+{
+       cache_block_operation_nowait((unsigned int *) start,
+                                    (unsigned int *) end,
+                                    IMCR_L2IBAR, IMCR_L2IWC);
+}
+
+void L2_cache_block_writeback_nowait(unsigned int start, unsigned int end)
+{
+       cache_block_operation_nowait((unsigned int *) start,
+                                    (unsigned int *) end,
+                                    IMCR_L2WBAR, IMCR_L2WWC);
+}
+
+void L2_cache_block_writeback_invalidate_nowait(unsigned int start,
+                                               unsigned int end)
+{
+       cache_block_operation_nowait((unsigned int *) start,
+                                    (unsigned int *) end,
+                                    IMCR_L2WIBAR, IMCR_L2WIWC);
+}
+
+
+/*
+ * L1 and L2 caches configuration
+ */
+void __init c6x_cache_init(void)
+{
+       struct device_node *node;
+
+       node = of_find_compatible_node(NULL, NULL, "ti,c64x+cache");
+       if (!node)
+               return;
+
+       cache_base = of_iomap(node, 0);
+
+       of_node_put(node);
+
+       if (!cache_base)
+               return;
+
+       /* Set L2 caches on the the whole L2 SRAM memory */
+       L2_cache_set_mode(L2MODE_SIZE);
+
+       /* Enable L1 */
+       L1_cache_on();
+}
diff --git a/arch/c6x/platforms/dscr.c b/arch/c6x/platforms/dscr.c
new file mode 100644 (file)
index 0000000..f848a65
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ *  Device State Control Registers driver
+ *
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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 Device State Control Registers (DSCR) provide SoC level control over
+ * a number of peripherals. Details vary considerably among the various SoC
+ * parts. In general, the DSCR block will provide one or more configuration
+ * registers often protected by a lock register. One or more key values must
+ * be written to a lock register in order to unlock the configuration register.
+ * The configuration register may be used to enable (and disable in some
+ * cases) SoC pin drivers, peripheral clock sources (internal or pin), etc.
+ * In some cases, a configuration register is write once or the individual
+ * bits are write once. That is, you may be able to enable a device, but
+ * will not be able to disable it.
+ *
+ * In addition to device configuration, the DSCR block may provide registers
+ * which are used to reset SoC peripherals, provide device ID information,
+ * provide MAC addresses, and other miscellaneous functions.
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <asm/soc.h>
+#include <asm/dscr.h>
+
+#define MAX_DEVSTATE_IDS   32
+#define MAX_DEVCTL_REGS     8
+#define MAX_DEVSTAT_REGS    8
+#define MAX_LOCKED_REGS     4
+#define MAX_SOC_EMACS       2
+
+struct rmii_reset_reg {
+       u32 reg;
+       u32 mask;
+};
+
+/*
+ * Some registerd may be locked. In order to write to these
+ * registers, the key value must first be written to the lockreg.
+ */
+struct locked_reg {
+       u32 reg;        /* offset from base */
+       u32 lockreg;    /* offset from base */
+       u32 key;        /* unlock key */
+};
+
+/*
+ * This describes a contiguous area of like control bits used to enable/disable
+ * SoC devices. Each controllable device is given an ID which is used by the
+ * individual device drivers to control the device state. These IDs start at
+ * zero and are assigned sequentially to the control bitfield ranges described
+ * by this structure.
+ */
+struct devstate_ctl_reg {
+       u32 reg;                /* register holding the control bits */
+       u8  start_id;           /* start id of this range */
+       u8  num_ids;            /* number of devices in this range */
+       u8  enable_only;        /* bits are write-once to enable only */
+       u8  enable;             /* value used to enable device */
+       u8  disable;            /* value used to disable device */
+       u8  shift;              /* starting (rightmost) bit in range */
+       u8  nbits;              /* number of bits per device */
+};
+
+
+/*
+ * This describes a region of status bits indicating the state of
+ * various devices. This is used internally to wait for status
+ * change completion when enabling/disabling a device. Status is
+ * optional and not all device controls will have a corresponding
+ * status.
+ */
+struct devstate_stat_reg {
+       u32 reg;                /* register holding the status bits */
+       u8  start_id;           /* start id of this range */
+       u8  num_ids;            /* number of devices in this range */
+       u8  enable;             /* value indicating enabled state */
+       u8  disable;            /* value indicating disabled state */
+       u8  shift;              /* starting (rightmost) bit in range */
+       u8  nbits;              /* number of bits per device */
+};
+
+struct devstate_info {
+       struct devstate_ctl_reg *ctl;
+       struct devstate_stat_reg *stat;
+};
+
+/* These are callbacks to SOC-specific code. */
+struct dscr_ops {
+       void (*init)(struct device_node *node);
+};
+
+struct dscr_regs {
+       spinlock_t              lock;
+       void __iomem            *base;
+       u32                     kick_reg[2];
+       u32                     kick_key[2];
+       struct locked_reg       locked[MAX_LOCKED_REGS];
+       struct devstate_info    devstate_info[MAX_DEVSTATE_IDS];
+       struct rmii_reset_reg   rmii_resets[MAX_SOC_EMACS];
+       struct devstate_ctl_reg devctl[MAX_DEVCTL_REGS];
+       struct devstate_stat_reg devstat[MAX_DEVSTAT_REGS];
+};
+
+static struct dscr_regs        dscr;
+
+static struct locked_reg *find_locked_reg(u32 reg)
+{
+       int i;
+
+       for (i = 0; i < MAX_LOCKED_REGS; i++)
+               if (dscr.locked[i].key && reg == dscr.locked[i].reg)
+                       return &dscr.locked[i];
+       return NULL;
+}
+
+/*
+ * Write to a register with one lock
+ */
+static void dscr_write_locked1(u32 reg, u32 val,
+                              u32 lock, u32 key)
+{
+       void __iomem *reg_addr = dscr.base + reg;
+       void __iomem *lock_addr = dscr.base + lock;
+
+       /*
+        * For some registers, the lock is relocked after a short number
+        * of cycles. We have to put the lock write and register write in
+        * the same fetch packet to meet this timing. The .align ensures
+        * the two stw instructions are in the same fetch packet.
+        */
+       asm volatile ("b        .s2     0f\n"
+                     "nop      5\n"
+                     "    .align 5\n"
+                     "0:\n"
+                     "stw      .D1T2   %3,*%2\n"
+                     "stw      .D1T2   %1,*%0\n"
+                     :
+                     : "a"(reg_addr), "b"(val), "a"(lock_addr), "b"(key)
+               );
+
+       /* in case the hw doesn't reset the lock */
+       soc_writel(0, lock_addr);
+}
+
+/*
+ * Write to a register protected by two lock registers
+ */
+static void dscr_write_locked2(u32 reg, u32 val,
+                              u32 lock0, u32 key0,
+                              u32 lock1, u32 key1)
+{
+       soc_writel(key0, dscr.base + lock0);
+       soc_writel(key1, dscr.base + lock1);
+       soc_writel(val, dscr.base + reg);
+       soc_writel(0, dscr.base + lock0);
+       soc_writel(0, dscr.base + lock1);
+}
+
+static void dscr_write(u32 reg, u32 val)
+{
+       struct locked_reg *lock;
+
+       lock = find_locked_reg(reg);
+       if (lock)
+               dscr_write_locked1(reg, val, lock->lockreg, lock->key);
+       else if (dscr.kick_key[0])
+               dscr_write_locked2(reg, val, dscr.kick_reg[0], dscr.kick_key[0],
+                                  dscr.kick_reg[1], dscr.kick_key[1]);
+       else
+               soc_writel(val, dscr.base + reg);
+}
+
+
+/*
+ * Drivers can use this interface to enable/disable SoC IP blocks.
+ */
+void dscr_set_devstate(int id, enum dscr_devstate_t state)
+{
+       struct devstate_ctl_reg *ctl;
+       struct devstate_stat_reg *stat;
+       struct devstate_info *info;
+       u32 ctl_val, val;
+       int ctl_shift, ctl_mask;
+       unsigned long flags;
+
+       if (!dscr.base)
+               return;
+
+       if (id < 0 || id >= MAX_DEVSTATE_IDS)
+               return;
+
+       info = &dscr.devstate_info[id];
+       ctl = info->ctl;
+       stat = info->stat;
+
+       if (ctl == NULL)
+               return;
+
+       ctl_shift = ctl->shift + ctl->nbits * (id - ctl->start_id);
+       ctl_mask = ((1 << ctl->nbits) - 1) << ctl_shift;
+
+       switch (state) {
+       case DSCR_DEVSTATE_ENABLED:
+               ctl_val = ctl->enable << ctl_shift;
+               break;
+       case DSCR_DEVSTATE_DISABLED:
+               if (ctl->enable_only)
+                       return;
+               ctl_val = ctl->disable << ctl_shift;
+               break;
+       default:
+               return;
+       }
+
+       spin_lock_irqsave(&dscr.lock, flags);
+
+       val = soc_readl(dscr.base + ctl->reg);
+       val &= ~ctl_mask;
+       val |= ctl_val;
+
+       dscr_write(ctl->reg, val);
+
+       spin_unlock_irqrestore(&dscr.lock, flags);
+
+       if (!stat)
+               return;
+
+       ctl_shift = stat->shift + stat->nbits * (id - stat->start_id);
+
+       if (state == DSCR_DEVSTATE_ENABLED)
+               ctl_val = stat->enable;
+       else
+               ctl_val = stat->disable;
+
+       do {
+               val = soc_readl(dscr.base + stat->reg);
+               val >>= ctl_shift;
+               val &= ((1 << stat->nbits) - 1);
+       } while (val != ctl_val);
+}
+EXPORT_SYMBOL(dscr_set_devstate);
+
+/*
+ * Drivers can use this to reset RMII module.
+ */
+void dscr_rmii_reset(int id, int assert)
+{
+       struct rmii_reset_reg *r;
+       unsigned long flags;
+       u32 val;
+
+       if (id < 0 || id >= MAX_SOC_EMACS)
+               return;
+
+       r = &dscr.rmii_resets[id];
+       if (r->mask == 0)
+               return;
+
+       spin_lock_irqsave(&dscr.lock, flags);
+
+       val = soc_readl(dscr.base + r->reg);
+       if (assert)
+               dscr_write(r->reg, val | r->mask);
+       else
+               dscr_write(r->reg, val & ~(r->mask));
+
+       spin_unlock_irqrestore(&dscr.lock, flags);
+}
+EXPORT_SYMBOL(dscr_rmii_reset);
+
+static void __init dscr_parse_devstat(struct device_node *node,
+                                     void __iomem *base)
+{
+       u32 val;
+       int err;
+
+       err = of_property_read_u32_array(node, "ti,dscr-devstat", &val, 1);
+       if (!err)
+               c6x_devstat = soc_readl(base + val);
+       printk(KERN_INFO "DEVSTAT: %08x\n", c6x_devstat);
+}
+
+static void __init dscr_parse_silicon_rev(struct device_node *node,
+                                        void __iomem *base)
+{
+       u32 vals[3];
+       int err;
+
+       err = of_property_read_u32_array(node, "ti,dscr-silicon-rev", vals, 3);
+       if (!err) {
+               c6x_silicon_rev = soc_readl(base + vals[0]);
+               c6x_silicon_rev >>= vals[1];
+               c6x_silicon_rev &= vals[2];
+       }
+}
+
+/*
+ * Some SoCs will have a pair of fuse registers which hold
+ * an ethernet MAC address. The "ti,dscr-mac-fuse-regs"
+ * property is a mapping from fuse register bytes to MAC
+ * address bytes. The expected format is:
+ *
+ *     ti,dscr-mac-fuse-regs = <reg0 b3 b2 b1 b0
+ *                              reg1 b3 b2 b1 b0>
+ *
+ * reg0 and reg1 are the offsets of the two fuse registers.
+ * b3-b0 positionally represent bytes within the fuse register.
+ * b3 is the most significant byte and b0 is the least.
+ * Allowable values for b3-b0 are:
+ *
+ *       0 = fuse register byte not used in MAC address
+ *      1-6 = index+1 into c6x_fuse_mac[]
+ */
+static void __init dscr_parse_mac_fuse(struct device_node *node,
+                                      void __iomem *base)
+{
+       u32 vals[10], fuse;
+       int f, i, j, err;
+
+       err = of_property_read_u32_array(node, "ti,dscr-mac-fuse-regs",
+                                        vals, 10);
+       if (err)
+               return;
+
+       for (f = 0; f < 2; f++) {
+               fuse = soc_readl(base + vals[f * 5]);
+               for (j = (f * 5) + 1, i = 24; i >= 0; i -= 8, j++)
+                       if (vals[j] && vals[j] <= 6)
+                               c6x_fuse_mac[vals[j] - 1] = fuse >> i;
+       }
+}
+
+static void __init dscr_parse_rmii_resets(struct device_node *node,
+                                         void __iomem *base)
+{
+       const __be32 *p;
+       int i, size;
+
+       /* look for RMII reset registers */
+       p = of_get_property(node, "ti,dscr-rmii-resets", &size);
+       if (p) {
+               /* parse all the reg/mask pairs we can handle */
+               size /= (sizeof(*p) * 2);
+               if (size > MAX_SOC_EMACS)
+                       size = MAX_SOC_EMACS;
+
+               for (i = 0; i < size; i++) {
+                       dscr.rmii_resets[i].reg = be32_to_cpup(p++);
+                       dscr.rmii_resets[i].mask = be32_to_cpup(p++);
+               }
+       }
+}
+
+
+static void __init dscr_parse_privperm(struct device_node *node,
+                                      void __iomem *base)
+{
+       u32 vals[2];
+       int err;
+
+       err = of_property_read_u32_array(node, "ti,dscr-privperm", vals, 2);
+       if (err)
+               return;
+       dscr_write(vals[0], vals[1]);
+}
+
+/*
+ * SoCs may have "locked" DSCR registers which can only be written
+ * to only after writing a key value to a lock registers. These
+ * regisers can be described with the "ti,dscr-locked-regs" property.
+ * This property provides a list of register descriptions with each
+ * description consisting of three values.
+ *
+ *     ti,dscr-locked-regs = <reg0 lockreg0 key0
+ *                               ...
+ *                             regN lockregN keyN>;
+ *
+ * reg is the offset of the locked register
+ * lockreg is the offset of the lock register
+ * key is the unlock key written to lockreg
+ *
+ */
+static void __init dscr_parse_locked_regs(struct device_node *node,
+                                         void __iomem *base)
+{
+       struct locked_reg *r;
+       const __be32 *p;
+       int i, size;
+
+       p = of_get_property(node, "ti,dscr-locked-regs", &size);
+       if (p) {
+               /* parse all the register descriptions we can handle */
+               size /= (sizeof(*p) * 3);
+               if (size > MAX_LOCKED_REGS)
+                       size = MAX_LOCKED_REGS;
+
+               for (i = 0; i < size; i++) {
+                       r = &dscr.locked[i];
+
+                       r->reg = be32_to_cpup(p++);
+                       r->lockreg = be32_to_cpup(p++);
+                       r->key = be32_to_cpup(p++);
+               }
+       }
+}
+
+/*
+ * SoCs may have DSCR registers which are only write enabled after
+ * writing specific key values to two registers. The two key registers
+ * and the key values can be parsed from a "ti,dscr-kick-regs"
+ * propety with the following layout:
+ *
+ *     ti,dscr-kick-regs = <kickreg0 key0 kickreg1 key1>
+ *
+ * kickreg is the offset of the "kick" register
+ * key is the value which unlocks writing for protected regs
+ */
+static void __init dscr_parse_kick_regs(struct device_node *node,
+                                       void __iomem *base)
+{
+       u32 vals[4];
+       int err;
+
+       err = of_property_read_u32_array(node, "ti,dscr-kick-regs", vals, 4);
+       if (!err) {
+               dscr.kick_reg[0] = vals[0];
+               dscr.kick_key[0] = vals[1];
+               dscr.kick_reg[1] = vals[2];
+               dscr.kick_key[1] = vals[3];
+       }
+}
+
+
+/*
+ * SoCs may provide controls to enable/disable individual IP blocks. These
+ * controls in the DSCR usually control pin drivers but also may control
+ * clocking and or resets. The device tree is used to describe the bitfields
+ * in registers used to control device state. The number of bits and their
+ * values may vary even within the same register.
+ *
+ * The layout of these bitfields is described by the ti,dscr-devstate-ctl-regs
+ * property. This property is a list where each element describes a contiguous
+ * range of control fields with like properties. Each element of the list
+ * consists of 7 cells with the following values:
+ *
+ *   start_id num_ids reg enable disable start_bit nbits
+ *
+ * start_id is device id for the first device control in the range
+ * num_ids is the number of device controls in the range
+ * reg is the offset of the register holding the control bits
+ * enable is the value to enable a device
+ * disable is the value to disable a device (0xffffffff if cannot disable)
+ * start_bit is the bit number of the first bit in the range
+ * nbits is the number of bits per device control
+ */
+static void __init dscr_parse_devstate_ctl_regs(struct device_node *node,
+                                               void __iomem *base)
+{
+       struct devstate_ctl_reg *r;
+       const __be32 *p;
+       int i, j, size;
+
+       p = of_get_property(node, "ti,dscr-devstate-ctl-regs", &size);
+       if (p) {
+               /* parse all the ranges we can handle */
+               size /= (sizeof(*p) * 7);
+               if (size > MAX_DEVCTL_REGS)
+                       size = MAX_DEVCTL_REGS;
+
+               for (i = 0; i < size; i++) {
+                       r = &dscr.devctl[i];
+
+                       r->start_id = be32_to_cpup(p++);
+                       r->num_ids = be32_to_cpup(p++);
+                       r->reg = be32_to_cpup(p++);
+                       r->enable = be32_to_cpup(p++);
+                       r->disable = be32_to_cpup(p++);
+                       if (r->disable == 0xffffffff)
+                               r->enable_only = 1;
+                       r->shift = be32_to_cpup(p++);
+                       r->nbits = be32_to_cpup(p++);
+
+                       for (j = r->start_id;
+                            j < (r->start_id + r->num_ids);
+                            j++)
+                               dscr.devstate_info[j].ctl = r;
+               }
+       }
+}
+
+/*
+ * SoCs may provide status registers indicating the state (enabled/disabled) of
+ * devices on the SoC. The device tree is used to describe the bitfields in
+ * registers used to provide device status. The number of bits and their
+ * values used to provide status may vary even within the same register.
+ *
+ * The layout of these bitfields is described by the ti,dscr-devstate-stat-regs
+ * property. This property is a list where each element describes a contiguous
+ * range of status fields with like properties. Each element of the list
+ * consists of 7 cells with the following values:
+ *
+ *   start_id num_ids reg enable disable start_bit nbits
+ *
+ * start_id is device id for the first device status in the range
+ * num_ids is the number of devices covered by the range
+ * reg is the offset of the register holding the status bits
+ * enable is the value indicating device is enabled
+ * disable is the value indicating device is disabled
+ * start_bit is the bit number of the first bit in the range
+ * nbits is the number of bits per device status
+ */
+static void __init dscr_parse_devstate_stat_regs(struct device_node *node,
+                                                void __iomem *base)
+{
+       struct devstate_stat_reg *r;
+       const __be32 *p;
+       int i, j, size;
+
+       p = of_get_property(node, "ti,dscr-devstate-stat-regs", &size);
+       if (p) {
+               /* parse all the ranges we can handle */
+               size /= (sizeof(*p) * 7);
+               if (size > MAX_DEVSTAT_REGS)
+                       size = MAX_DEVSTAT_REGS;
+
+               for (i = 0; i < size; i++) {
+                       r = &dscr.devstat[i];
+
+                       r->start_id = be32_to_cpup(p++);
+                       r->num_ids = be32_to_cpup(p++);
+                       r->reg = be32_to_cpup(p++);
+                       r->enable = be32_to_cpup(p++);
+                       r->disable = be32_to_cpup(p++);
+                       r->shift = be32_to_cpup(p++);
+                       r->nbits = be32_to_cpup(p++);
+
+                       for (j = r->start_id;
+                            j < (r->start_id + r->num_ids);
+                            j++)
+                               dscr.devstate_info[j].stat = r;
+               }
+       }
+}
+
+static struct of_device_id dscr_ids[] __initdata = {
+       { .compatible = "ti,c64x+dscr" },
+       {}
+};
+
+/*
+ * Probe for DSCR area.
+ *
+ * This has to be done early on in case timer or interrupt controller
+ * needs something. e.g. On C6455 SoC, timer must be enabled through
+ * DSCR before it is functional.
+ */
+void __init dscr_probe(void)
+{
+       struct device_node *node;
+       void __iomem *base;
+
+       spin_lock_init(&dscr.lock);
+
+       node = of_find_matching_node(NULL, dscr_ids);
+       if (!node)
+               return;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               of_node_put(node);
+               return;
+       }
+
+       dscr.base = base;
+
+       dscr_parse_devstat(node, base);
+       dscr_parse_silicon_rev(node, base);
+       dscr_parse_mac_fuse(node, base);
+       dscr_parse_rmii_resets(node, base);
+       dscr_parse_locked_regs(node, base);
+       dscr_parse_kick_regs(node, base);
+       dscr_parse_devstate_ctl_regs(node, base);
+       dscr_parse_devstate_stat_regs(node, base);
+       dscr_parse_privperm(node, base);
+}
diff --git a/arch/c6x/platforms/emif.c b/arch/c6x/platforms/emif.c
new file mode 100644 (file)
index 0000000..8b564de
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  External Memory Interface
+ *
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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/of.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <asm/soc.h>
+#include <asm/dscr.h>
+
+#define NUM_EMIFA_CHIP_ENABLES 4
+
+struct emifa_regs {
+       u32     midr;
+       u32     stat;
+       u32     reserved1[6];
+       u32     bprio;
+       u32     reserved2[23];
+       u32     cecfg[NUM_EMIFA_CHIP_ENABLES];
+       u32     reserved3[4];
+       u32     awcc;
+       u32     reserved4[7];
+       u32     intraw;
+       u32     intmsk;
+       u32     intmskset;
+       u32     intmskclr;
+};
+
+static struct of_device_id emifa_match[] __initdata = {
+       { .compatible = "ti,c64x+emifa" },
+       {}
+};
+
+/*
+ * Parse device tree for existence of an EMIF (External Memory Interface)
+ * and initialize it if found.
+ */
+static int __init c6x_emifa_init(void)
+{
+       struct emifa_regs __iomem *regs;
+       struct device_node *node;
+       const __be32 *p;
+       u32 val;
+       int i, len, err;
+
+       node = of_find_matching_node(NULL, emifa_match);
+       if (!node)
+               return 0;
+
+       regs = of_iomap(node, 0);
+       if (!regs)
+               return 0;
+
+       /* look for a dscr-based enable for emifa pin buffers */
+       err = of_property_read_u32_array(node, "ti,dscr-dev-enable", &val, 1);
+       if (!err)
+               dscr_set_devstate(val, DSCR_DEVSTATE_ENABLED);
+
+       /* set up the chip enables */
+       p = of_get_property(node, "ti,emifa-ce-config", &len);
+       if (p) {
+               len /= sizeof(u32);
+               if (len > NUM_EMIFA_CHIP_ENABLES)
+                       len = NUM_EMIFA_CHIP_ENABLES;
+               for (i = 0; i <= len; i++)
+                       soc_writel(be32_to_cpup(&p[i]), &regs->cecfg[i]);
+       }
+
+       err = of_property_read_u32_array(node, "ti,emifa-burst-priority", &val, 1);
+       if (!err)
+               soc_writel(val, &regs->bprio);
+
+       err = of_property_read_u32_array(node, "ti,emifa-async-wait-control", &val, 1);
+       if (!err)
+               soc_writel(val, &regs->awcc);
+
+       iounmap(regs);
+       of_node_put(node);
+       return 0;
+}
+pure_initcall(c6x_emifa_init);
diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c
new file mode 100644 (file)
index 0000000..7c37a94
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ *  Support for C64x+ Megamodule Interrupt Controller
+ *
+ *  Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ *  Contributed by: Mark Salter <msalter@redhat.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/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/soc.h>
+#include <asm/megamod-pic.h>
+
+#define NR_COMBINERS   4
+#define NR_MUX_OUTPUTS  12
+
+#define IRQ_UNMAPPED 0xffff
+
+/*
+ * Megamodule Interrupt Controller register layout
+ */
+struct megamod_regs {
+       u32     evtflag[8];
+       u32     evtset[8];
+       u32     evtclr[8];
+       u32     reserved0[8];
+       u32     evtmask[8];
+       u32     mevtflag[8];
+       u32     expmask[8];
+       u32     mexpflag[8];
+       u32     intmux_unused;
+       u32     intmux[7];
+       u32     reserved1[8];
+       u32     aegmux[2];
+       u32     reserved2[14];
+       u32     intxstat;
+       u32     intxclr;
+       u32     intdmask;
+       u32     reserved3[13];
+       u32     evtasrt;
+};
+
+struct megamod_pic {
+       struct irq_host *irqhost;
+       struct megamod_regs __iomem *regs;
+       raw_spinlock_t lock;
+
+       /* hw mux mapping */
+       unsigned int output_to_irq[NR_MUX_OUTPUTS];
+};
+
+static struct megamod_pic *mm_pic;
+
+struct megamod_cascade_data {
+       struct megamod_pic *pic;
+       int index;
+};
+
+static struct megamod_cascade_data cascade_data[NR_COMBINERS];
+
+static void mask_megamod(struct irq_data *data)
+{
+       struct megamod_pic *pic = irq_data_get_irq_chip_data(data);
+       irq_hw_number_t src = irqd_to_hwirq(data);
+       u32 __iomem *evtmask = &pic->regs->evtmask[src / 32];
+
+       raw_spin_lock(&pic->lock);
+       soc_writel(soc_readl(evtmask) | (1 << (src & 31)), evtmask);
+       raw_spin_unlock(&pic->lock);
+}
+
+static void unmask_megamod(struct irq_data *data)
+{
+       struct megamod_pic *pic = irq_data_get_irq_chip_data(data);
+       irq_hw_number_t src = irqd_to_hwirq(data);
+       u32 __iomem *evtmask = &pic->regs->evtmask[src / 32];
+
+       raw_spin_lock(&pic->lock);
+       soc_writel(soc_readl(evtmask) & ~(1 << (src & 31)), evtmask);
+       raw_spin_unlock(&pic->lock);
+}
+
+static struct irq_chip megamod_chip = {
+       .name           = "megamod",
+       .irq_mask       = mask_megamod,
+       .irq_unmask     = unmask_megamod,
+};
+
+static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct megamod_cascade_data *cascade;
+       struct megamod_pic *pic;
+       u32 events;
+       int n, idx;
+
+       cascade = irq_desc_get_handler_data(desc);
+
+       pic = cascade->pic;
+       idx = cascade->index;
+
+       while ((events = soc_readl(&pic->regs->mevtflag[idx])) != 0) {
+               n = __ffs(events);
+
+               irq = irq_linear_revmap(pic->irqhost, idx * 32 + n);
+
+               soc_writel(1 << n, &pic->regs->evtclr[idx]);
+
+               generic_handle_irq(irq);
+       }
+}
+
+static int megamod_map(struct irq_host *h, unsigned int virq,
+                      irq_hw_number_t hw)
+{
+       struct megamod_pic *pic = h->host_data;
+       int i;
+
+       /* We shouldn't see a hwirq which is muxed to core controller */
+       for (i = 0; i < NR_MUX_OUTPUTS; i++)
+               if (pic->output_to_irq[i] == hw)
+                       return -1;
+
+       irq_set_chip_data(virq, pic);
+       irq_set_chip_and_handler(virq, &megamod_chip, handle_level_irq);
+
+       /* Set default irq type */
+       irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static int megamod_xlate(struct irq_host *h, struct device_node *ct,
+                        const u32 *intspec, unsigned int intsize,
+                        irq_hw_number_t *out_hwirq, unsigned int *out_type)
+
+{
+       /* megamod intspecs must have 1 cell */
+       BUG_ON(intsize != 1);
+       *out_hwirq = intspec[0];
+       *out_type = IRQ_TYPE_NONE;
+       return 0;
+}
+
+static struct irq_host_ops megamod_host_ops = {
+       .map    = megamod_map,
+       .xlate  = megamod_xlate,
+};
+
+static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output)
+{
+       int index, offset;
+       u32 val;
+
+       if (src < 0 || src >= (NR_COMBINERS * 32)) {
+               pic->output_to_irq[output] = IRQ_UNMAPPED;
+               return;
+       }
+
+       /* four mappings per mux register */
+       index = output / 4;
+       offset = (output & 3) * 8;
+
+       val = soc_readl(&pic->regs->intmux[index]);
+       val &= ~(0xff << offset);
+       val |= src << offset;
+       soc_writel(val, &pic->regs->intmux[index]);
+}
+
+/*
+ * Parse the MUX mapping, if one exists.
+ *
+ * The MUX map is an array of up to 12 cells; one for each usable core priority
+ * interrupt. The value of a given cell is the megamodule interrupt source
+ * which is to me MUXed to the output corresponding to the cell position
+ * withing the array. The first cell in the array corresponds to priority
+ * 4 and the last (12th) cell corresponds to priority 15. The allowed
+ * values are 4 - ((NR_COMBINERS * 32) - 1). Note that the combined interrupt
+ * sources (0 - 3) are not allowed to be mapped through this property. They
+ * are handled through the "interrupts" property. This allows us to use a
+ * value of zero as a "do not map" placeholder.
+ */
+static void __init parse_priority_map(struct megamod_pic *pic,
+                                     int *mapping, int size)
+{
+       struct device_node *np = pic->irqhost->of_node;
+       const __be32 *map;
+       int i, maplen;
+       u32 val;
+
+       map = of_get_property(np, "ti,c64x+megamod-pic-mux", &maplen);
+       if (map) {
+               maplen /= 4;
+               if (maplen > size)
+                       maplen = size;
+
+               for (i = 0; i < maplen; i++) {
+                       val = be32_to_cpup(map);
+                       if (val && val >= 4)
+                               mapping[i] = val;
+                       ++map;
+               }
+       }
+}
+
+static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
+{
+       struct megamod_pic *pic;
+       int i, irq;
+       int mapping[NR_MUX_OUTPUTS];
+
+       pr_info("Initializing C64x+ Megamodule PIC\n");
+
+       pic = kzalloc(sizeof(struct megamod_pic), GFP_KERNEL);
+       if (!pic) {
+               pr_err("%s: Could not alloc PIC structure.\n", np->full_name);
+               return NULL;
+       }
+
+       pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
+                                     NR_COMBINERS * 32, &megamod_host_ops,
+                                     IRQ_UNMAPPED);
+       if (!pic->irqhost) {
+               pr_err("%s: Could not alloc host.\n", np->full_name);
+               goto error_free;
+       }
+
+       pic->irqhost->host_data = pic;
+
+       raw_spin_lock_init(&pic->lock);
+
+       pic->regs = of_iomap(np, 0);
+       if (!pic->regs) {
+               pr_err("%s: Could not map registers.\n", np->full_name);
+               goto error_free;
+       }
+
+       /* Initialize MUX map */
+       for (i = 0; i < ARRAY_SIZE(mapping); i++)
+               mapping[i] = IRQ_UNMAPPED;
+
+       parse_priority_map(pic, mapping, ARRAY_SIZE(mapping));
+
+       /*
+        * We can have up to 12 interrupts cascading to the core controller.
+        * These cascades can be from the combined interrupt sources or for
+        * individual interrupt sources. The "interrupts" property only
+        * deals with the cascaded combined interrupts. The individual
+        * interrupts muxed to the core controller use the core controller
+        * as their interrupt parent.
+        */
+       for (i = 0; i < NR_COMBINERS; i++) {
+
+               irq = irq_of_parse_and_map(np, i);
+               if (irq == NO_IRQ)
+                       continue;
+
+               /*
+                * We count on the core priority interrupts (4 - 15) being
+                * direct mapped. Check that device tree provided something
+                * in that range.
+                */
+               if (irq < 4 || irq >= NR_PRIORITY_IRQS) {
+                       pr_err("%s: combiner-%d virq %d out of range!\n",
+                                np->full_name, i, irq);
+                       continue;
+               }
+
+               /* record the mapping */
+               mapping[irq - 4] = i;
+
+               pr_debug("%s: combiner-%d cascading to virq %d\n",
+                        np->full_name, i, irq);
+
+               cascade_data[i].pic = pic;
+               cascade_data[i].index = i;
+
+               /* mask and clear all events in combiner */
+               soc_writel(~0, &pic->regs->evtmask[i]);
+               soc_writel(~0, &pic->regs->evtclr[i]);
+
+               irq_set_handler_data(irq, &cascade_data[i]);
+               irq_set_chained_handler(irq, megamod_irq_cascade);
+       }
+
+       /* Finally, set up the MUX registers */
+       for (i = 0; i < NR_MUX_OUTPUTS; i++) {
+               if (mapping[i] != IRQ_UNMAPPED) {
+                       pr_debug("%s: setting mux %d to priority %d\n",
+                                np->full_name, mapping[i], i + 4);
+                       set_megamod_mux(pic, mapping[i], i);
+               }
+       }
+
+       return pic;
+
+error_free:
+       kfree(pic);
+
+       return NULL;
+}
+
+/*
+ * Return next active event after ACK'ing it.
+ * Return -1 if no events active.
+ */
+static int get_exception(void)
+{
+       int i, bit;
+       u32 mask;
+
+       for (i = 0; i < NR_COMBINERS; i++) {
+               mask = soc_readl(&mm_pic->regs->mexpflag[i]);
+               if (mask) {
+                       bit = __ffs(mask);
+                       soc_writel(1 << bit, &mm_pic->regs->evtclr[i]);
+                       return (i * 32) + bit;
+               }
+       }
+       return -1;
+}
+
+static void assert_event(unsigned int val)
+{
+       soc_writel(val, &mm_pic->regs->evtasrt);
+}
+
+void __init megamod_pic_init(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "ti,c64x+megamod-pic");
+       if (!np)
+               return;
+
+       mm_pic = init_megamod_pic(np);
+       of_node_put(np);
+
+       soc_ops.get_exception = get_exception;
+       soc_ops.assert_event = assert_event;
+
+       return;
+}
diff --git a/arch/c6x/platforms/platform.c b/arch/c6x/platforms/platform.c
new file mode 100644 (file)
index 0000000..26c1a35
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2011 Texas Instruments Incorporated
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+
+static int __init c6x_device_probe(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+       return 0;
+}
+core_initcall(c6x_device_probe);
diff --git a/arch/c6x/platforms/pll.c b/arch/c6x/platforms/pll.c
new file mode 100644 (file)
index 0000000..3aa898f
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Clock and PLL control for C64x+ devices
+ *
+ * Copyright (C) 2010, 2011 Texas Instruments.
+ * Contributed by: Mark Salter <msalter@redhat.com>
+ *
+ * Copied heavily from arm/mach-davinci/clock.c, so:
+ *
+ * Copyright (C) 2006-2007 Texas Instruments.
+ * Copyright (C) 2008-2009 Deep Root Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/clkdev.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <asm/clock.h>
+#include <asm/soc.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+
+static void __clk_enable(struct clk *clk)
+{
+       if (clk->parent)
+               __clk_enable(clk->parent);
+       clk->usecount++;
+}
+
+static void __clk_disable(struct clk *clk)
+{
+       if (WARN_ON(clk->usecount == 0))
+               return;
+       --clk->usecount;
+
+       if (clk->parent)
+               __clk_disable(clk->parent);
+}
+
+int clk_enable(struct clk *clk)
+{
+       unsigned long flags;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       __clk_enable(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+       unsigned long flags;
+
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       __clk_disable(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       if (clk->round_rate)
+               return clk->round_rate(clk, rate);
+
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/* Propagate rate to children */
+static void propagate_rate(struct clk *root)
+{
+       struct clk *clk;
+
+       list_for_each_entry(clk, &root->children, childnode) {
+               if (clk->recalc)
+                       clk->rate = clk->recalc(clk);
+               propagate_rate(clk);
+       }
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       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);
+               propagate_rate(clk);
+       }
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       unsigned long flags;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       /* Cannot change parent on enabled clock */
+       if (WARN_ON(clk->usecount))
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+       clk->parent = parent;
+       list_del_init(&clk->childnode);
+       list_add(&clk->childnode, &clk->parent->children);
+       mutex_unlock(&clocks_mutex);
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       if (clk->recalc)
+               clk->rate = clk->recalc(clk);
+       propagate_rate(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+int clk_register(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       if (WARN(clk->parent && !clk->parent->rate,
+                "CLK: %s parent %s has no rate!\n",
+                clk->name, clk->parent->name))
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+       list_add_tail(&clk->node, &clocks);
+       if (clk->parent)
+               list_add_tail(&clk->childnode, &clk->parent->children);
+       mutex_unlock(&clocks_mutex);
+
+       /* If rate is already set, use it */
+       if (clk->rate)
+               return 0;
+
+       /* Else, see if there is a way to calculate it */
+       if (clk->recalc)
+               clk->rate = clk->recalc(clk);
+
+       /* Otherwise, default to parent rate */
+       else if (clk->parent)
+               clk->rate = clk->parent->rate;
+
+       return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       mutex_lock(&clocks_mutex);
+       list_del(&clk->node);
+       list_del(&clk->childnode);
+       mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+
+static u32 pll_read(struct pll_data *pll, int reg)
+{
+       return soc_readl(pll->base + reg);
+}
+
+static unsigned long clk_sysclk_recalc(struct clk *clk)
+{
+       u32 v, plldiv = 0;
+       struct pll_data *pll;
+       unsigned long rate = clk->rate;
+
+       if (WARN_ON(!clk->parent))
+               return rate;
+
+       rate = clk->parent->rate;
+
+       /* the parent must be a PLL */
+       if (WARN_ON(!clk->parent->pll_data))
+               return rate;
+
+       pll = clk->parent->pll_data;
+
+       /* If pre-PLL, source clock is before the multiplier and divider(s) */
+       if (clk->flags & PRE_PLL)
+               rate = pll->input_rate;
+
+       if (!clk->div) {
+               pr_debug("%s: (no divider) rate = %lu KHz\n",
+                        clk->name, rate / 1000);
+               return rate;
+       }
+
+       if (clk->flags & FIXED_DIV_PLL) {
+               rate /= clk->div;
+               pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n",
+                        clk->name, clk->div, rate / 1000);
+               return rate;
+       }
+
+       v = pll_read(pll, clk->div);
+       if (v & PLLDIV_EN)
+               plldiv = (v & PLLDIV_RATIO_MASK) + 1;
+
+       if (plldiv == 0)
+               plldiv = 1;
+
+       rate /= plldiv;
+
+       pr_debug("%s: (divide by %d) rate = %lu KHz\n",
+                clk->name, plldiv, rate / 1000);
+
+       return rate;
+}
+
+static unsigned long clk_leafclk_recalc(struct clk *clk)
+{
+       if (WARN_ON(!clk->parent))
+               return clk->rate;
+
+       pr_debug("%s: (parent %s) rate = %lu KHz\n",
+                clk->name, clk->parent->name,  clk->parent->rate / 1000);
+
+       return clk->parent->rate;
+}
+
+static unsigned long clk_pllclk_recalc(struct clk *clk)
+{
+       u32 ctrl, mult = 0, prediv = 0, postdiv = 0;
+       u8 bypass;
+       struct pll_data *pll = clk->pll_data;
+       unsigned long rate = clk->rate;
+
+       if (clk->flags & FIXED_RATE_PLL)
+               return rate;
+
+       ctrl = pll_read(pll, PLLCTL);
+       rate = pll->input_rate = clk->parent->rate;
+
+       if (ctrl & PLLCTL_PLLEN)
+               bypass = 0;
+       else
+               bypass = 1;
+
+       if (pll->flags & PLL_HAS_MUL) {
+               mult = pll_read(pll, PLLM);
+               mult = (mult & PLLM_PLLM_MASK) + 1;
+       }
+       if (pll->flags & PLL_HAS_PRE) {
+               prediv = pll_read(pll, PLLPRE);
+               if (prediv & PLLDIV_EN)
+                       prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
+               else
+                       prediv = 0;
+       }
+       if (pll->flags & PLL_HAS_POST) {
+               postdiv = pll_read(pll, PLLPOST);
+               if (postdiv & PLLDIV_EN)
+                       postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1;
+               else
+                       postdiv = 1;
+       }
+
+       if (!bypass) {
+               if (prediv)
+                       rate /= prediv;
+               if (mult)
+                       rate *= mult;
+               if (postdiv)
+                       rate /= postdiv;
+
+               pr_debug("PLL%d: input = %luMHz, pre[%d] mul[%d] post[%d] "
+                        "--> %luMHz output.\n",
+                        pll->num, clk->parent->rate / 1000000,
+                        prediv, mult, postdiv, rate / 1000000);
+       } else
+               pr_debug("PLL%d: input = %luMHz, bypass mode.\n",
+                        pll->num, clk->parent->rate / 1000000);
+
+       return rate;
+}
+
+
+static void __init __init_clk(struct clk *clk)
+{
+       INIT_LIST_HEAD(&clk->node);
+       INIT_LIST_HEAD(&clk->children);
+       INIT_LIST_HEAD(&clk->childnode);
+
+       if (!clk->recalc) {
+
+               /* Check if clock is a PLL */
+               if (clk->pll_data)
+                       clk->recalc = clk_pllclk_recalc;
+
+               /* Else, if it is a PLL-derived clock */
+               else if (clk->flags & CLK_PLL)
+                       clk->recalc = clk_sysclk_recalc;
+
+               /* Otherwise, it is a leaf clock (PSC clock) */
+               else if (clk->parent)
+                       clk->recalc = clk_leafclk_recalc;
+       }
+}
+
+void __init c6x_clks_init(struct clk_lookup *clocks)
+{
+       struct clk_lookup *c;
+       struct clk *clk;
+       size_t num_clocks = 0;
+
+       for (c = clocks; c->clk; c++) {
+               clk = c->clk;
+
+               __init_clk(clk);
+               clk_register(clk);
+               num_clocks++;
+
+               /* Turn on clocks that Linux doesn't otherwise manage */
+               if (clk->flags & ALWAYS_ENABLED)
+                       clk_enable(clk);
+       }
+
+       clkdev_add_table(clocks, num_clocks);
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define CLKNAME_MAX    10              /* longest clock name */
+#define NEST_DELTA     2
+#define NEST_MAX       4
+
+static void
+dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
+{
+       char            *state;
+       char            buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX];
+       struct clk      *clk;
+       unsigned        i;
+
+       if (parent->flags & CLK_PLL)
+               state = "pll";
+       else
+               state = "";
+
+       /* <nest spaces> name <pad to end> */
+       memset(buf, ' ', sizeof(buf) - 1);
+       buf[sizeof(buf) - 1] = 0;
+       i = strlen(parent->name);
+       memcpy(buf + nest, parent->name,
+              min(i, (unsigned)(sizeof(buf) - 1 - nest)));
+
+       seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
+                  buf, parent->usecount, state, clk_get_rate(parent));
+       /* REVISIT show device associations too */
+
+       /* cost is now small, but not linear... */
+       list_for_each_entry(clk, &parent->children, childnode) {
+               dump_clock(s, nest + NEST_DELTA, clk);
+       }
+}
+
+static int c6x_ck_show(struct seq_file *m, void *v)
+{
+       struct clk *clk;
+
+       /*
+        * Show clock tree; We trust nonzero usecounts equate to PSC enables...
+        */
+       mutex_lock(&clocks_mutex);
+       list_for_each_entry(clk, &clocks, node)
+               if (!clk->parent)
+                       dump_clock(m, 0, clk);
+       mutex_unlock(&clocks_mutex);
+
+       return 0;
+}
+
+static int c6x_ck_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, c6x_ck_show, NULL);
+}
+
+static const struct file_operations c6x_ck_operations = {
+       .open           = c6x_ck_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init c6x_clk_debugfs_init(void)
+{
+       debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL,
+                           &c6x_ck_operations);
+
+       return 0;
+}
+device_initcall(c6x_clk_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/c6x/platforms/plldata.c b/arch/c6x/platforms/plldata.c
new file mode 100644 (file)
index 0000000..2cfd6f4
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  Port on Texas Instruments TMS320C6x architecture
+ *
+ *  Copyright (C) 2011 Texas Instruments Incorporated
+ *  Author: Mark Salter <msalter@redhat.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/delay.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/clock.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+/*
+ * Common SoC clock support.
+ */
+
+/* Default input for PLL1 */
+struct clk clkin1 = {
+       .name = "clkin1",
+       .node = LIST_HEAD_INIT(clkin1.node),
+       .children = LIST_HEAD_INIT(clkin1.children),
+       .childnode = LIST_HEAD_INIT(clkin1.childnode),
+};
+
+struct pll_data c6x_soc_pll1 = {
+       .num       = 1,
+       .sysclks   = {
+               {
+                       .name = "pll1",
+                       .parent = &clkin1,
+                       .pll_data = &c6x_soc_pll1,
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk1",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk2",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk3",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk4",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk5",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk6",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk7",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk8",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk9",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk10",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk11",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk12",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk13",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk14",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk15",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+               {
+                       .name = "pll1_sysclk16",
+                       .parent = &c6x_soc_pll1.sysclks[0],
+                       .flags = CLK_PLL,
+               },
+       },
+};
+
+/* CPU core clock */
+struct clk c6x_core_clk = {
+       .name = "core",
+};
+
+/* miscellaneous IO clocks */
+struct clk c6x_i2c_clk = {
+       .name = "i2c",
+};
+
+struct clk c6x_watchdog_clk = {
+       .name = "watchdog",
+};
+
+struct clk c6x_mcbsp1_clk = {
+       .name = "mcbsp1",
+};
+
+struct clk c6x_mcbsp2_clk = {
+       .name = "mcbsp2",
+};
+
+struct clk c6x_mdio_clk = {
+       .name = "mdio",
+};
+
+
+#ifdef CONFIG_SOC_TMS320C6455
+static struct clk_lookup c6455_clks[] = {
+       CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
+       CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
+       CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
+       CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
+       CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
+       CLK(NULL, "core", &c6x_core_clk),
+       CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
+       CLK("watchdog", NULL, &c6x_watchdog_clk),
+       CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
+       CLK("", NULL, NULL)
+};
+
+
+static void __init c6455_setup_clocks(struct device_node *node)
+{
+       struct pll_data *pll = &c6x_soc_pll1;
+       struct clk *sysclks = pll->sysclks;
+
+       pll->flags = PLL_HAS_PRE | PLL_HAS_MUL;
+
+       sysclks[2].flags |= FIXED_DIV_PLL;
+       sysclks[2].div = 3;
+       sysclks[3].flags |= FIXED_DIV_PLL;
+       sysclks[3].div = 6;
+       sysclks[4].div = PLLDIV4;
+       sysclks[5].div = PLLDIV5;
+
+       c6x_core_clk.parent = &sysclks[0];
+       c6x_i2c_clk.parent = &sysclks[3];
+       c6x_watchdog_clk.parent = &sysclks[3];
+       c6x_mdio_clk.parent = &sysclks[3];
+
+       c6x_clks_init(c6455_clks);
+}
+#endif /* CONFIG_SOC_TMS320C6455 */
+
+#ifdef CONFIG_SOC_TMS320C6457
+static struct clk_lookup c6457_clks[] = {
+       CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
+       CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]),
+       CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
+       CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
+       CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
+       CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
+       CLK(NULL, "core", &c6x_core_clk),
+       CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
+       CLK("watchdog", NULL, &c6x_watchdog_clk),
+       CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
+       CLK("", NULL, NULL)
+};
+
+static void __init c6457_setup_clocks(struct device_node *node)
+{
+       struct pll_data *pll = &c6x_soc_pll1;
+       struct clk *sysclks = pll->sysclks;
+
+       pll->flags = PLL_HAS_MUL | PLL_HAS_POST;
+
+       sysclks[1].flags |= FIXED_DIV_PLL;
+       sysclks[1].div = 1;
+       sysclks[2].flags |= FIXED_DIV_PLL;
+       sysclks[2].div = 3;
+       sysclks[3].flags |= FIXED_DIV_PLL;
+       sysclks[3].div = 6;
+       sysclks[4].div = PLLDIV4;
+       sysclks[5].div = PLLDIV5;
+
+       c6x_core_clk.parent = &sysclks[1];
+       c6x_i2c_clk.parent = &sysclks[3];
+       c6x_watchdog_clk.parent = &sysclks[5];
+       c6x_mdio_clk.parent = &sysclks[5];
+
+       c6x_clks_init(c6457_clks);
+}
+#endif /* CONFIG_SOC_TMS320C6455 */
+
+#ifdef CONFIG_SOC_TMS320C6472
+static struct clk_lookup c6472_clks[] = {
+       CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
+       CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]),
+       CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
+       CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
+       CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
+       CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
+       CLK(NULL, "pll1_sysclk6", &c6x_soc_pll1.sysclks[6]),
+       CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]),
+       CLK(NULL, "pll1_sysclk8", &c6x_soc_pll1.sysclks[8]),
+       CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]),
+       CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]),
+       CLK(NULL, "core", &c6x_core_clk),
+       CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
+       CLK("watchdog", NULL, &c6x_watchdog_clk),
+       CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
+       CLK("", NULL, NULL)
+};
+
+/* assumptions used for delay loop calculations */
+#define MIN_CLKIN1_KHz 15625
+#define MAX_CORE_KHz   700000
+#define MIN_PLLOUT_KHz MIN_CLKIN1_KHz
+
+static void __init c6472_setup_clocks(struct device_node *node)
+{
+       struct pll_data *pll = &c6x_soc_pll1;
+       struct clk *sysclks = pll->sysclks;
+       int i;
+
+       pll->flags = PLL_HAS_MUL;
+
+       for (i = 1; i <= 6; i++) {
+               sysclks[i].flags |= FIXED_DIV_PLL;
+               sysclks[i].div = 1;
+       }
+
+       sysclks[7].flags |= FIXED_DIV_PLL;
+       sysclks[7].div = 3;
+       sysclks[8].flags |= FIXED_DIV_PLL;
+       sysclks[8].div = 6;
+       sysclks[9].flags |= FIXED_DIV_PLL;
+       sysclks[9].div = 2;
+       sysclks[10].div = PLLDIV10;
+
+       c6x_core_clk.parent = &sysclks[get_coreid() + 1];
+       c6x_i2c_clk.parent = &sysclks[8];
+       c6x_watchdog_clk.parent = &sysclks[8];
+       c6x_mdio_clk.parent = &sysclks[5];
+
+       c6x_clks_init(c6472_clks);
+}
+#endif /* CONFIG_SOC_TMS320C6472 */
+
+
+#ifdef CONFIG_SOC_TMS320C6474
+static struct clk_lookup c6474_clks[] = {
+       CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
+       CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]),
+       CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]),
+       CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]),
+       CLK(NULL, "pll1_sysclk11", &c6x_soc_pll1.sysclks[11]),
+       CLK(NULL, "pll1_sysclk12", &c6x_soc_pll1.sysclks[12]),
+       CLK(NULL, "pll1_sysclk13", &c6x_soc_pll1.sysclks[13]),
+       CLK(NULL, "core", &c6x_core_clk),
+       CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
+       CLK("mcbsp.1", NULL, &c6x_mcbsp1_clk),
+       CLK("mcbsp.2", NULL, &c6x_mcbsp2_clk),
+       CLK("watchdog", NULL, &c6x_watchdog_clk),
+       CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
+       CLK("", NULL, NULL)
+};
+
+static void __init c6474_setup_clocks(struct device_node *node)
+{
+       struct pll_data *pll = &c6x_soc_pll1;
+       struct clk *sysclks = pll->sysclks;
+
+       pll->flags = PLL_HAS_MUL;
+
+       sysclks[7].flags |= FIXED_DIV_PLL;
+       sysclks[7].div = 1;
+       sysclks[9].flags |= FIXED_DIV_PLL;
+       sysclks[9].div = 3;
+       sysclks[10].flags |= FIXED_DIV_PLL;
+       sysclks[10].div = 6;
+
+       sysclks[11].div = PLLDIV11;
+
+       sysclks[12].flags |= FIXED_DIV_PLL;
+       sysclks[12].div = 2;
+
+       sysclks[13].div = PLLDIV13;
+
+       c6x_core_clk.parent = &sysclks[7];
+       c6x_i2c_clk.parent = &sysclks[10];
+       c6x_watchdog_clk.parent = &sysclks[10];
+       c6x_mcbsp1_clk.parent = &sysclks[10];
+       c6x_mcbsp2_clk.parent = &sysclks[10];
+
+       c6x_clks_init(c6474_clks);
+}
+#endif /* CONFIG_SOC_TMS320C6474 */
+
+static struct of_device_id c6x_clkc_match[] __initdata = {
+#ifdef CONFIG_SOC_TMS320C6455
+       { .compatible = "ti,c6455-pll", .data = c6455_setup_clocks },
+#endif
+#ifdef CONFIG_SOC_TMS320C6457
+       { .compatible = "ti,c6457-pll", .data = c6457_setup_clocks },
+#endif
+#ifdef CONFIG_SOC_TMS320C6472
+       { .compatible = "ti,c6472-pll", .data = c6472_setup_clocks },
+#endif
+#ifdef CONFIG_SOC_TMS320C6474
+       { .compatible = "ti,c6474-pll", .data = c6474_setup_clocks },
+#endif
+       { .compatible = "ti,c64x+pll" },
+       {}
+};
+
+void __init c64x_setup_clocks(void)
+{
+       void (*__setup_clocks)(struct device_node *np);
+       struct pll_data *pll = &c6x_soc_pll1;
+       struct device_node *node;
+       const struct of_device_id *id;
+       int err;
+       u32 val;
+
+       node = of_find_matching_node(NULL, c6x_clkc_match);
+       if (!node)
+               return;
+
+       pll->base = of_iomap(node, 0);
+       if (!pll->base)
+               goto out;
+
+       err = of_property_read_u32(node, "clock-frequency", &val);
+       if (err || val == 0) {
+               pr_err("%s: no clock-frequency found! Using %dMHz\n",
+                      node->full_name, (int)val / 1000000);
+               val = 25000000;
+       }
+       clkin1.rate = val;
+
+       err = of_property_read_u32(node, "ti,c64x+pll-bypass-delay", &val);
+       if (err)
+               val = 5000;
+       pll->bypass_delay = val;
+
+       err = of_property_read_u32(node, "ti,c64x+pll-reset-delay", &val);
+       if (err)
+               val = 30000;
+       pll->reset_delay = val;
+
+       err = of_property_read_u32(node, "ti,c64x+pll-lock-delay", &val);
+       if (err)
+               val = 30000;
+       pll->lock_delay = val;
+
+       /* id->data is a pointer to SoC-specific setup */
+       id = of_match_node(c6x_clkc_match, node);
+       if (id && id->data) {
+               __setup_clocks = id->data;
+               __setup_clocks(node);
+       }
+
+out:
+       of_node_put(node);
+}
diff --git a/arch/c6x/platforms/timer64.c b/arch/c6x/platforms/timer64.c
new file mode 100644 (file)
index 0000000..03c03c2
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  Copyright (C) 2010, 2011 Texas Instruments Incorporated
+ *  Contributed by: Mark Salter (msalter@redhat.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/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <asm/soc.h>
+#include <asm/dscr.h>
+#include <asm/timer64.h>
+
+struct timer_regs {
+       u32     reserved0;
+       u32     emumgt;
+       u32     reserved1;
+       u32     reserved2;
+       u32     cntlo;
+       u32     cnthi;
+       u32     prdlo;
+       u32     prdhi;
+       u32     tcr;
+       u32     tgcr;
+       u32     wdtcr;
+};
+
+static struct timer_regs __iomem *timer;
+
+#define TCR_TSTATLO         0x001
+#define TCR_INVOUTPLO       0x002
+#define TCR_INVINPLO        0x004
+#define TCR_CPLO            0x008
+#define TCR_ENAMODELO_ONCE   0x040
+#define TCR_ENAMODELO_CONT   0x080
+#define TCR_ENAMODELO_MASK   0x0c0
+#define TCR_PWIDLO_MASK      0x030
+#define TCR_CLKSRCLO        0x100
+#define TCR_TIENLO          0x200
+#define TCR_TSTATHI         (0x001 << 16)
+#define TCR_INVOUTPHI       (0x002 << 16)
+#define TCR_CPHI            (0x008 << 16)
+#define TCR_PWIDHI_MASK      (0x030 << 16)
+#define TCR_ENAMODEHI_ONCE   (0x040 << 16)
+#define TCR_ENAMODEHI_CONT   (0x080 << 16)
+#define TCR_ENAMODEHI_MASK   (0x0c0 << 16)
+
+#define TGCR_TIMLORS        0x001
+#define TGCR_TIMHIRS        0x002
+#define TGCR_TIMMODE_UD32    0x004
+#define TGCR_TIMMODE_WDT64   0x008
+#define TGCR_TIMMODE_CD32    0x00c
+#define TGCR_TIMMODE_MASK    0x00c
+#define TGCR_PSCHI_MASK      (0x00f << 8)
+#define TGCR_TDDRHI_MASK     (0x00f << 12)
+
+/*
+ * Timer clocks are divided down from the CPU clock
+ * The divisor is in the EMUMGTCLKSPD register
+ */
+#define TIMER_DIVISOR \
+       ((soc_readl(&timer->emumgt) & (0xf << 16)) >> 16)
+
+#define TIMER64_RATE (c6x_core_freq / TIMER_DIVISOR)
+
+#define TIMER64_MODE_DISABLED 0
+#define TIMER64_MODE_ONE_SHOT TCR_ENAMODELO_ONCE
+#define TIMER64_MODE_PERIODIC TCR_ENAMODELO_CONT
+
+static int timer64_mode;
+static int timer64_devstate_id = -1;
+
+static void timer64_config(unsigned long period)
+{
+       u32 tcr = soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK;
+
+       soc_writel(tcr, &timer->tcr);
+       soc_writel(period - 1, &timer->prdlo);
+       soc_writel(0, &timer->cntlo);
+       tcr |= timer64_mode;
+       soc_writel(tcr, &timer->tcr);
+}
+
+static void timer64_enable(void)
+{
+       u32 val;
+
+       if (timer64_devstate_id >= 0)
+               dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED);
+
+       /* disable timer, reset count */
+       soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
+       soc_writel(0, &timer->prdlo);
+
+       /* use internal clock and 1 cycle pulse width */
+       val = soc_readl(&timer->tcr);
+       soc_writel(val & ~(TCR_CLKSRCLO | TCR_PWIDLO_MASK), &timer->tcr);
+
+       /* dual 32-bit unchained mode */
+       val = soc_readl(&timer->tgcr) & ~TGCR_TIMMODE_MASK;
+       soc_writel(val, &timer->tgcr);
+       soc_writel(val | (TGCR_TIMLORS | TGCR_TIMMODE_UD32), &timer->tgcr);
+}
+
+static void timer64_disable(void)
+{
+       /* disable timer, reset count */
+       soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
+       soc_writel(0, &timer->prdlo);
+
+       if (timer64_devstate_id >= 0)
+               dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_DISABLED);
+}
+
+static int next_event(unsigned long delta,
+                     struct clock_event_device *evt)
+{
+       timer64_config(delta);
+       return 0;
+}
+
+static void set_clock_mode(enum clock_event_mode mode,
+                          struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               timer64_enable();
+               timer64_mode = TIMER64_MODE_PERIODIC;
+               timer64_config(TIMER64_RATE / HZ);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               timer64_enable();
+               timer64_mode = TIMER64_MODE_ONE_SHOT;
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               timer64_mode = TIMER64_MODE_DISABLED;
+               timer64_disable();
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static struct clock_event_device t64_clockevent_device = {
+       .name           = "TIMER64_EVT32_TIMER",
+       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+       .rating         = 200,
+       .set_mode       = set_clock_mode,
+       .set_next_event = next_event,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *cd = &t64_clockevent_device;
+
+       cd->event_handler(cd);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction timer_iact = {
+       .name           = "timer",
+       .flags          = IRQF_TIMER,
+       .handler        = timer_interrupt,
+       .dev_id         = &t64_clockevent_device,
+};
+
+void __init timer64_init(void)
+{
+       struct clock_event_device *cd = &t64_clockevent_device;
+       struct device_node *np, *first = NULL;
+       u32 val;
+       int err, found = 0;
+
+       for_each_compatible_node(np, NULL, "ti,c64x+timer64") {
+               err = of_property_read_u32(np, "ti,core-mask", &val);
+               if (!err) {
+                       if (val & (1 << get_coreid())) {
+                               found = 1;
+                               break;
+                       }
+               } else if (!first)
+                       first = np;
+       }
+       if (!found) {
+               /* try first one with no core-mask */
+               if (first)
+                       np = of_node_get(first);
+               else {
+                       pr_debug("Cannot find ti,c64x+timer64 timer.\n");
+                       return;
+               }
+       }
+
+       timer = of_iomap(np, 0);
+       if (!timer) {
+               pr_debug("%s: Cannot map timer registers.\n", np->full_name);
+               goto out;
+       }
+       pr_debug("%s: Timer registers=%p.\n", np->full_name, timer);
+
+       cd->irq = irq_of_parse_and_map(np, 0);
+       if (cd->irq == NO_IRQ) {
+               pr_debug("%s: Cannot find interrupt.\n", np->full_name);
+               iounmap(timer);
+               goto out;
+       }
+
+       /* If there is a device state control, save the ID. */
+       err = of_property_read_u32(np, "ti,dscr-dev-enable", &val);
+       if (!err) {
+               timer64_devstate_id = val;
+
+               /*
+                * It is necessary to enable the timer block here because
+                * the TIMER_DIVISOR macro needs to read a timer register
+                * to get the divisor.
+                */
+               dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED);
+       }
+
+       pr_debug("%s: Timer irq=%d.\n", np->full_name, cd->irq);
+
+       clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5);
+
+       cd->max_delta_ns        = clockevent_delta2ns(0x7fffffff, cd);
+       cd->min_delta_ns        = clockevent_delta2ns(250, cd);
+
+       cd->cpumask             = cpumask_of(smp_processor_id());
+
+       clockevents_register_device(cd);
+       setup_irq(cd->irq, &timer_iact);
+
+out:
+       of_node_put(np);
+       return;
+}
index 408b055c585f489e9f3a76c66f32da6680be8d91..b3abfb08aa5c3d32face736f2403fc753a0596c1 100644 (file)
@@ -19,10 +19,6 @@ config GENERIC_CMOS_UPDATE
 config ARCH_USES_GETTIMEOFFSET
        def_bool n
 
-config GENERIC_IOMAP
-       bool
-       default y
-
 config ARCH_HAS_ILOG2_U32
        bool
        default n
@@ -52,6 +48,7 @@ config CRIS
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_IOMAP
 
 config HZ
        int
index c5e69abb4889f8956f1e4cd13466f3aaf34e94b4..a685910d2d5ce562f36f8f4ae02811390600682c 100644 (file)
@@ -8,6 +8,7 @@ config FRV
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select GENERIC_CPU_DEVICES
 
 config ZONE_DMA
        bool
@@ -317,6 +318,7 @@ config PCI
        bool "Use PCI"
        depends on MB93090_MB00
        default y
+       select GENERIC_PCI_IOMAP
        help
          Some FR-V systems (such as the MB93090-MB00 VDK) have PCI
          onboard. If you have one of these boards and you wish to use the PCI
index ca7475e73b5ee7f2673334011f86e5cb77ac62b1..8cb50a2fbcb2d9b34b6bad36323cb49513f64ceb 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/virtconvert.h>
 #include <asm/string.h>
 #include <asm/mb-regs.h>
+#include <asm-generic/pci_iomap.h>
 #include <linux/delay.h>
 
 /*
@@ -370,7 +371,6 @@ static inline void iowrite32_rep(void __iomem *p, const void *src, unsigned long
 
 /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
 {
 }
index b73b542f8f48c32d9a771c5aa0be92a78d4cea00..21f1df1b378af0647664113f18734dd45ebb24c5 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 ifeq "$(CONFIG_PCI)" "y"
-obj-y := pci-frv.o pci-irq.o pci-vdk.o pci-iomap.o
+obj-y := pci-frv.o pci-irq.o pci-vdk.o
 
 ifeq "$(CONFIG_MMU)" "y"
 obj-y += pci-dma.o
index 6b4fb28e9f997d1a9bf64f19cd26fba08ac8b9df..c281217654487cb059e1e790c951c3a7dabdef22 100644 (file)
@@ -194,23 +194,3 @@ void __init pcibios_resource_survey(void)
        pcibios_allocate_resources(1);
        pcibios_assign_resources();
 }
-
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-       printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
index f3fe5591479388ba6c2b3d7b6320740dfd392701..089eeba4f3bc4f92b5a28c32e071289723cb8bc3 100644 (file)
@@ -26,8 +26,6 @@ extern unsigned int __nongpreldata pci_probe;
 
 /* pci-frv.c */
 
-extern unsigned int pcibios_max_latency;
-
 void pcibios_resource_survey(void);
 
 /* pci-vdk.c */
diff --git a/arch/frv/mb93090-mb00/pci-iomap.c b/arch/frv/mb93090-mb00/pci-iomap.c
deleted file mode 100644 (file)
index 35f6df2..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* pci-iomap.c: description
- *
- * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.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/pci.h>
-#include <linux/module.h>
-
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-
-       if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM))
-               return (void __iomem *) start;
-
-       return NULL;
-}
-
-EXPORT_SYMBOL(pci_iomap);
index f8dd37e495353f978ca3c4725e330909384d7a58..6b0b82ff4419e70e806fa835b9d7327b9642ac52 100644 (file)
@@ -327,11 +327,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
        printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number);
 #endif
 
-       if (bus->number == 0) {
-               bus->resource[0] = &pci_ioport_resource;
-               bus->resource[1] = &pci_iomem_resource;
-       }
-
        pci_read_bridge_bases(bus);
 
        if (bus->number == 0) {
@@ -357,6 +352,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
 int __init pcibios_init(void)
 {
        struct pci_ops *dir = NULL;
+       LIST_HEAD(resources);
 
        if (!mb93090_mb00_detected)
                return -ENXIO;
@@ -420,7 +416,10 @@ int __init pcibios_init(void)
        }
 
        printk("PCI: Probing PCI hardware\n");
-       pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+       pci_add_resource(&resources, &pci_ioport_resource);
+       pci_add_resource(&resources, &pci_iomem_resource);
+       pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL,
+                                        &resources);
 
        pcibios_irq_init();
        pcibios_fixup_peer_bridges();
index d1f377f5d3b61b6f2cbeb575cb9aa02a8992d821..56e890df5053605a8eb7a66514eb096d0e110b2d 100644 (file)
@@ -4,6 +4,7 @@ config H8300
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_CPU_DEVICES
 
 config SYMBOL_PREFIX
        string
index cc9762091c0a3a47e3f66005c40df51712534228..0b2acaa3dd84c266000880ee604218fd4547a78b 100644 (file)
@@ -9,11 +9,6 @@
 
 #define pcibios_assign_all_busses()    0
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index 02513c2dd5ec99a9e6d0b4c0e4613465c8110a32..9059e3905887196a48750cf3e531abf0aa6d96df 100644 (file)
@@ -26,6 +26,7 @@ config HEXAGON
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
        select NO_IOPORT
+       select GENERIC_IOMAP
        # mostly generic routines, with some accelerated ones
        ---help---
          Qualcomm Hexagon is a processor architecture designed for high
@@ -73,9 +74,6 @@ config GENERIC_CSUM
 config GENERIC_IRQ_PROBE
        def_bool y
 
-config GENERIC_IOMAP
-       def_bool y
-
 #config ZONE_DMA
 #      bool
 #      default y
index 3b7a7c483785929f0f126953756aa5f40c694dd0..bd7266903bf8f497b4ddfd416df6091335d17039 100644 (file)
@@ -32,6 +32,7 @@ config IA64
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select GENERIC_IOMAP
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -105,10 +106,6 @@ config EFI
        bool
        default y
 
-config GENERIC_IOMAP
-       bool
-       default y
-
 config ARCH_CLOCKSOURCE_DATA
        def_bool y
 
index 127dd7be346ac2b3f4b497c9a1a69eb9f7784235..279b38ae74aab41bf0e5ed73fcdd2eb1b7a295c1 100644 (file)
@@ -42,12 +42,6 @@ struct pci_dev;
 extern unsigned long ia64_max_iommu_merge_mask;
 #define PCI_DMA_BUS_IS_PHYS    (ia64_max_iommu_merge_mask == ~0UL)
 
-static inline void
-pcibios_set_master (struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void
 pcibios_penalize_isa_irq (int irq, int active)
 {
index d9f397fae03eb7e89712aa7cedef3b8d11082b4e..691be0b95c1e0fb280721cde45e9d1f88d08af77 100644 (file)
@@ -309,7 +309,6 @@ struct thread_struct {
 }
 
 #define start_thread(regs,new_ip,new_sp) do {                                                  \
-       set_fs(USER_DS);                                                                        \
        regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL))                \
                         & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));              \
        regs->cr_iip = new_ip;                                                                  \
index 7617248f0d11e9d906d82d88d582ed3c2626c558..7a3bd252494468dcc5f4da779a62fc4500d65805 100644 (file)
 #define __NR_sendmmsg                  1331
 #define __NR_process_vm_readv          1332
 #define __NR_process_vm_writev         1333
+#define __NR_accept4                   1334
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    310 /* length of syscall table */
+#define NR_syscalls                    311 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 5b31d46aff67b10e31c35bb6ea273549247613b5..1ccbe12a4d84fe6585455a45b367647b1fa2c240 100644 (file)
@@ -1779,6 +1779,7 @@ sys_call_table:
        data8 sys_sendmmsg
        data8 sys_process_vm_readv
        data8 sys_process_vm_writev
+       data8 sys_accept4
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 3d3aeef469476a85ed4d149608ebd891e72c5f6c..4eed35814994ebfed9c6e5d5dcca527cc327daba 100644 (file)
 #include <asm/sal.h>
 #include <asm/mca.h>
 
-typedef NORET_TYPE void (*relocate_new_kernel_t)(
+typedef void (*relocate_new_kernel_t)(
                                        unsigned long indirection_page,
                                        unsigned long start_address,
                                        struct ia64_boot_param *boot_param,
-                                       unsigned long pal_addr) ATTRIB_NORET;
+                                       unsigned long pal_addr) __noreturn;
 
 struct kimage *ia64_kimage;
 
index 2c27714d7b78302842bee1f6931c9f023e25c64a..f82f5d4b65fdace5e6ebdbff09a85ea02857a57a 100644 (file)
@@ -134,6 +134,7 @@ alloc_pci_controller (int seg)
 struct pci_root_info {
        struct acpi_device *bridge;
        struct pci_controller *controller;
+       struct list_head resources;
        char *name;
 };
 
@@ -315,24 +316,13 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
                                 &window->resource);
        }
 
-       return AE_OK;
-}
-
-static void __devinit
-pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
-{
-       int i;
+       /* HP's firmware has a hack to work around a Windows bug.
+        * Ignore these tiny memory ranges */
+       if (!((window->resource.flags & IORESOURCE_MEM) &&
+             (window->resource.end - window->resource.start < 16)))
+               pci_add_resource(&info->resources, &window->resource);
 
-       pci_bus_remove_resources(bus);
-       for (i = 0; i < ctrl->windows; i++) {
-               struct resource *res = &ctrl->window[i].resource;
-               /* HP's firmware has a hack to work around a Windows bug.
-                * Ignore these tiny memory ranges */
-               if ((res->flags & IORESOURCE_MEM) &&
-                   (res->end - res->start < 16))
-                       continue;
-               pci_bus_add_resource(bus, res, 0);
-       }
+       return AE_OK;
 }
 
 struct pci_bus * __devinit
@@ -343,6 +333,7 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
        int bus = root->secondary.start;
        struct pci_controller *controller;
        unsigned int windows = 0;
+       struct pci_root_info info;
        struct pci_bus *pbus;
        char *name;
        int pxm;
@@ -359,11 +350,10 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
                controller->node = pxm_to_node(pxm);
 #endif
 
+       INIT_LIST_HEAD(&info.resources);
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
                        &windows);
        if (windows) {
-               struct pci_root_info info;
-
                controller->window =
                        kmalloc_node(sizeof(*controller->window) * windows,
                                     GFP_KERNEL, controller->node);
@@ -387,8 +377,14 @@ pci_acpi_scan_root(struct acpi_pci_root *root)
         * should handle the case here, but it appears that IA64 hasn't
         * such quirk. So we just ignore the case now.
         */
-       pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
+       pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
+                                  &info.resources);
+       if (!pbus) {
+               pci_free_resource_list(&info.resources);
+               return NULL;
+       }
 
+       pbus->subordinate = pci_scan_child_bus(pbus);
        return pbus;
 
 out3:
@@ -504,14 +500,15 @@ pcibios_fixup_bus (struct pci_bus *b)
        if (b->self) {
                pci_read_bridge_bases(b);
                pcibios_fixup_bridge_resources(b->self);
-       } else {
-               pcibios_setup_root_windows(b, b->sysdata);
        }
        list_for_each_entry(dev, &b->devices, bus_list)
                pcibios_fixup_device_resources(dev);
        platform_pci_fixup_bus(b);
+}
 
-       return;
+void pcibios_set_master (struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
 }
 
 void __devinit
index 81fdaa72c540e4315c2d9872d75ff0f4e17afba5..ae413d4a8bb770783661104ba6d8d77ae0c3a103 100644 (file)
@@ -6,6 +6,7 @@ config M68K
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
+       select GENERIC_CPU_DEVICES
 
 config RWSEM_GENERIC_SPINLOCK
        bool
@@ -37,9 +38,6 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config GENERIC_IOMAP
-       def_bool MMU
-
 config GENERIC_CSUM
        bool
 
@@ -81,6 +79,7 @@ source "kernel/Kconfig.freezer"
 config MMU
        bool "MMU-based Paged Memory Management Support"
        default y
+       select GENERIC_IOMAP
        help
          Select if you want MMU-based virtualised addressing space
          support by paged memory management. If unsure, say 'Y'.
index 82a4bb51d5d85b4f6271b7f4a830f1150bea5b59..b95a451b1c3ae6292092efcf4ea24fc103e69eda 100644 (file)
@@ -511,8 +511,7 @@ static unsigned long amiga_gettimeoffset(void)
        return ticks + offset;
 }
 
-static NORET_TYPE void amiga_reset(void)
-    ATTRIB_NORET;
+static void amiga_reset(void)  __noreturn;
 
 static void amiga_reset(void)
 {
index e446bab2427bc7c69982190f3e89c0f442752780..74f23a460ba2f4415a1657fd7288b318c469683d 100644 (file)
@@ -17,6 +17,8 @@ config MICROBLAZE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
+       select GENERIC_PCI_IOMAP
+       select GENERIC_CPU_DEVICES
 
 config SWAP
        def_bool n
index cc54187f3d383993e633306092061195469b1d88..a175132e44960a752f2aaf29953fb11b556e3499 100644 (file)
@@ -9,7 +9,14 @@
 #ifndef _ASM_MICROBLAZE_IRQ_H
 #define _ASM_MICROBLAZE_IRQ_H
 
-#define NR_IRQS 32
+
+/*
+ * Linux IRQ# is currently offset by one to map to the hardware
+ * irq number. So hardware IRQ0 maps to Linux irq 1.
+ */
+#define NO_IRQ_OFFSET  1
+#define IRQ_OFFSET     NO_IRQ_OFFSET
+#define NR_IRQS                (32 + IRQ_OFFSET)
 #include <asm-generic/irq.h>
 
 /* This type is the placeholder for a hardware interrupt number. It has to
@@ -20,8 +27,6 @@ typedef unsigned long irq_hw_number_t;
 
 extern unsigned int nr_irq;
 
-#define NO_IRQ (-1)
-
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
index ed9d0f6e2cdb2be99cda93a20eb8987faf393a9c..a25e6b5e2ad454ec08020b3307ed02fbd89991b6 100644 (file)
@@ -174,15 +174,8 @@ extern int page_is_ram(unsigned long pfn);
 
 #define        virt_addr_valid(vaddr)  (pfn_valid(virt_to_pfn(vaddr)))
 
-
-#  ifndef CONFIG_MMU
-#  define __pa(vaddr)  ((unsigned long) (vaddr))
-#  define __va(paddr)  ((void *) (paddr))
-#  else /* CONFIG_MMU */
-#  define __pa(x)      __virt_to_phys((unsigned long)(x))
-#  define __va(x)      ((void *)__phys_to_virt((unsigned long)(x)))
-#  endif /* CONFIG_MMU */
-
+# define __pa(x)       __virt_to_phys((unsigned long)(x))
+# define __va(x)       ((void *)__phys_to_virt((unsigned long)(x)))
 
 /* Convert between virtual and physical address for MMU. */
 /* Handle MicroBlaze processor with virtual memory. */
index 32764cd077c6452136a2aa98d830907741a1ba8f..e9834b2991d07fbca13aa127cacdd59bd89a1ee4 100644 (file)
@@ -140,7 +140,6 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
-extern void pcibios_setup_phb_resources(struct pci_controller *hose);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */
index 1dd9d6b1e275bb2e0ef3246087cb59c1aaa66fda..033137628e8a0aea3681e5ce7cc204b0ce9f2d66 100644 (file)
@@ -42,11 +42,6 @@ struct pci_dev;
  */
 #define pcibios_assign_all_busses()    0
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index 904e5ef6a11b2e958f0b33c29b4f7d3794cecb38..6c72ed7eba9854c5b003555214d0c1376a544684 100644 (file)
@@ -26,12 +26,6 @@ int setup_early_printk(char *opt);
 void remap_early_printk(void);
 void disable_early_printk(void);
 
-#if defined(CONFIG_EARLY_PRINTK)
-#define eprintk early_printk
-#else
-#define eprintk printk
-#endif
-
 void heartbeat(void);
 void setup_heartbeat(void);
 
index 7d7092b917ac5ddb61664075aca7879ca95d6717..d20ffbc86bebcc4b319ce1ff52117ae5c029463a 100644 (file)
 #define __NR_clock_adjtime     373
 #define __NR_syncfs            374
 #define __NR_setns             375
+#define __NR_sendmmsg          376
+#define __NR_process_vm_readv  377
+#define __NR_process_vm_writev 378
 
-#define __NR_syscalls          376
+#define __NR_syscalls          379
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
index d26d92d47754a067481fa40eb78ef2eadba04317..8356e47631c4313199bb4487068ccd8ccf6635ac 100644 (file)
@@ -50,9 +50,9 @@ static void early_printk_uartlite_write(struct console *unused,
                                        const char *s, unsigned n)
 {
        while (*s && n-- > 0) {
-               early_printk_uartlite_putc(*s);
                if (*s == '\n')
                        early_printk_uartlite_putc('\r');
+               early_printk_uartlite_putc(*s);
                s++;
        }
 }
@@ -94,9 +94,9 @@ static void early_printk_uart16550_write(struct console *unused,
                                        const char *s, unsigned n)
 {
        while (*s && n-- > 0) {
-               early_printk_uart16550_putc(*s);
                if (*s == '\n')
                        early_printk_uart16550_putc('\r');
+               early_printk_uart16550_putc(*s);
                s++;
        }
 }
index ca15bc5c7449f9ba79ed9e024f88c1b13d49e60b..66e34a3bfe1b41fe9e333b996ab4e366692a480c 100644 (file)
@@ -468,7 +468,7 @@ C_ENTRY(sys_fork_wrapper):
        addi    r5, r0, SIGCHLD                 /* Arg 0: flags */
        lwi     r6, r1, PT_R1   /* Arg 1: child SP (use parent's) */
        addik   r7, r1, 0                       /* Arg 2: parent context */
-       add     r8. r0, r0                      /* Arg 3: (unused) */
+       add     r8, r0, r0                      /* Arg 3: (unused) */
        add     r9, r0, r0;                     /* Arg 4: (unused) */
        brid    do_fork         /* Do real work (tail-call) */
        add     r10, r0, r0;                    /* Arg 5: (unused) */
index eb41441c7fd0288a84e8f7e38c3dfddfae5b55bd..44b177e2ab124c7338c04eeafb81814bf63177c0 100644 (file)
@@ -42,8 +42,9 @@ unsigned int nr_irq;
 
 static void intc_enable_or_unmask(struct irq_data *d)
 {
-       unsigned long mask = 1 << d->irq;
-       pr_debug("enable_or_unmask: %d\n", d->irq);
+       unsigned long mask = 1 << d->hwirq;
+
+       pr_debug("enable_or_unmask: %ld\n", d->hwirq);
        out_be32(INTC_BASE + SIE, mask);
 
        /* ack level irqs because they can't be acked during
@@ -56,20 +57,21 @@ static void intc_enable_or_unmask(struct irq_data *d)
 
 static void intc_disable_or_mask(struct irq_data *d)
 {
-       pr_debug("disable: %d\n", d->irq);
-       out_be32(INTC_BASE + CIE, 1 << d->irq);
+       pr_debug("disable: %ld\n", d->hwirq);
+       out_be32(INTC_BASE + CIE, 1 << d->hwirq);
 }
 
 static void intc_ack(struct irq_data *d)
 {
-       pr_debug("ack: %d\n", d->irq);
-       out_be32(INTC_BASE + IAR, 1 << d->irq);
+       pr_debug("ack: %ld\n", d->hwirq);
+       out_be32(INTC_BASE + IAR, 1 << d->hwirq);
 }
 
 static void intc_mask_ack(struct irq_data *d)
 {
-       unsigned long mask = 1 << d->irq;
-       pr_debug("disable_and_ack: %d\n", d->irq);
+       unsigned long mask = 1 << d->hwirq;
+
+       pr_debug("disable_and_ack: %ld\n", d->hwirq);
        out_be32(INTC_BASE + CIE, mask);
        out_be32(INTC_BASE + IAR, mask);
 }
@@ -91,7 +93,7 @@ unsigned int get_irq(struct pt_regs *regs)
         * order to handle multiple interrupt controllers. It currently
         * is hardcoded to check for interrupts only on the first INTC.
         */
-       irq = in_be32(INTC_BASE + IVR);
+       irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
        pr_debug("get_irq: %d\n", irq);
 
        return irq;
@@ -99,7 +101,7 @@ unsigned int get_irq(struct pt_regs *regs)
 
 void __init init_IRQ(void)
 {
-       u32 i, j, intr_type;
+       u32 i, intr_mask;
        struct device_node *intc = NULL;
 #ifdef CONFIG_SELFMOD_INTC
        unsigned int intc_baseaddr = 0;
@@ -113,35 +115,24 @@ void __init init_IRQ(void)
                                0
                        };
 #endif
-       const char * const intc_list[] = {
-                               "xlnx,xps-intc-1.00.a",
-                               NULL
-                       };
-
-       for (j = 0; intc_list[j] != NULL; j++) {
-               intc = of_find_compatible_node(NULL, NULL, intc_list[j]);
-               if (intc)
-                       break;
-       }
+       intc = of_find_compatible_node(NULL, NULL, "xlnx,xps-intc-1.00.a");
        BUG_ON(!intc);
 
-       intc_baseaddr = be32_to_cpup(of_get_property(intc,
-                                                               "reg", NULL));
+       intc_baseaddr = be32_to_cpup(of_get_property(intc, "reg", NULL));
        intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
        nr_irq = be32_to_cpup(of_get_property(intc,
                                                "xlnx,num-intr-inputs", NULL));
 
-       intr_type =
-               be32_to_cpup(of_get_property(intc,
-                                               "xlnx,kind-of-intr", NULL));
-       if (intr_type > (u32)((1ULL << nr_irq) - 1))
+       intr_mask =
+               be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL));
+       if (intr_mask > (u32)((1ULL << nr_irq) - 1))
                printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
 
 #ifdef CONFIG_SELFMOD_INTC
        selfmod_function((int *) arr_func, intc_baseaddr);
 #endif
-       printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
-               intc_list[j], intc_baseaddr, nr_irq, intr_type);
+       printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
+               intc_baseaddr, nr_irq, intr_mask);
 
        /*
         * Disable all external interrupts until they are
@@ -155,8 +146,8 @@ void __init init_IRQ(void)
        /* Turn on the Master Enable. */
        out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
 
-       for (i = 0; i < nr_irq; ++i) {
-               if (intr_type & (0x00000001 << i)) {
+       for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
+               if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
                        irq_set_chip_and_handler_name(i, &intc_dev,
                                handle_edge_irq, "edge");
                        irq_clear_status_flags(i, IRQ_LEVEL);
@@ -165,5 +156,6 @@ void __init init_IRQ(void)
                                handle_level_irq, "level");
                        irq_set_status_flags(i, IRQ_LEVEL);
                }
+               irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
        }
 }
index e5d63a89b9b20085e9e81042326c0e68bee362a6..bbebcae72c02f0d5b04598c3a57b1ea48c175aba 100644 (file)
@@ -33,11 +33,12 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        irq_enter();
        irq = get_irq(regs);
 next_irq:
-       BUG_ON(irq == -1U);
-       generic_handle_irq(irq);
+       BUG_ON(!irq);
+       /* Substract 1 because of get_irq */
+       generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
 
        irq = get_irq(regs);
-       if (irq != -1U) {
+       if (irq) {
                pr_debug("next irq: %d\n", irq);
                ++concurrent_irq;
                goto next_irq;
@@ -52,13 +53,13 @@ next_irq:
   intc without any cascades or any connection that's why mapping is 1:1 */
 unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
 {
-       return hwirq;
+       return hwirq + IRQ_OFFSET;
 }
 EXPORT_SYMBOL_GPL(irq_create_mapping);
 
 unsigned int irq_create_of_mapping(struct device_node *controller,
                                   const u32 *intspec, unsigned int intsize)
 {
-       return intspec[0];
+       return intspec[0] + IRQ_OFFSET;
 }
 EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index 142426f631bb7e34ded5faa048144fafcafb8e12..f39257a5abcf2652c9e853661773a49d7a0c49b9 100644 (file)
@@ -100,7 +100,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
                        break;
 
                case R_MICROBLAZE_64_NONE:
-                       pr_debug("R_MICROBLAZE_NONE\n");
+                       pr_debug("R_MICROBLAZE_64_NONE\n");
                        break;
 
                case R_MICROBLAZE_NONE:
index 0e654a12d37e18136caa965bfbbe729f87349d60..604cd9dd133362712e5220510be83be134d96ec1 100644 (file)
@@ -145,32 +145,32 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        setup_early_printk(NULL);
 #endif
 
-       eprintk("Ramdisk addr 0x%08x, ", ram);
+       printk("Ramdisk addr 0x%08x, ", ram);
        if (fdt)
-               eprintk("FDT at 0x%08x\n", fdt);
+               printk("FDT at 0x%08x\n", fdt);
        else
-               eprintk("Compiled-in FDT at 0x%08x\n",
+               printk("Compiled-in FDT at 0x%08x\n",
                                        (unsigned int)_fdt_start);
 
 #ifdef CONFIG_MTD_UCLINUX
-       eprintk("Found romfs @ 0x%08x (0x%08x)\n",
+       printk("Found romfs @ 0x%08x (0x%08x)\n",
                        romfs_base, romfs_size);
-       eprintk("#### klimit %p ####\n", old_klimit);
+       printk("#### klimit %p ####\n", old_klimit);
        BUG_ON(romfs_size < 0); /* What else can we do? */
 
-       eprintk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
+       printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
                        romfs_size, romfs_base, (unsigned)&_ebss);
 
-       eprintk("New klimit: 0x%08x\n", (unsigned)klimit);
+       printk("New klimit: 0x%08x\n", (unsigned)klimit);
 #endif
 
 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
        if (msr)
-               eprintk("!!!Your kernel has setup MSR instruction but "
+               printk("!!!Your kernel has setup MSR instruction but "
                                "CPU don't have it %x\n", msr);
 #else
        if (!msr)
-               eprintk("!!!Your kernel not setup MSR instruction but "
+               printk("!!!Your kernel not setup MSR instruction but "
                                "CPU have it %x\n", msr);
 #endif
 
index 8789daa2a346683d43e7b42efe7935494b332e14..6a2b294ef6dc29525c75735bd7c82f001e5900a8 100644 (file)
@@ -380,3 +380,6 @@ ENTRY(sys_call_table)
        .long sys_clock_adjtime
        .long sys_syncfs
        .long sys_setns                 /* 375 */
+       .long sys_sendmmsg
+       .long sys_process_vm_readv
+       .long sys_process_vm_writev
index af74b1113aabb32fb3849a952109ffba07eacdcf..3cb0bf640135c5ced740bc2af6e0b6e819963792 100644 (file)
@@ -243,7 +243,7 @@ static int timer_initialized;
 
 void __init time_init(void)
 {
-       u32 irq, i = 0;
+       u32 irq;
        u32 timer_num = 1;
        struct device_node *timer = NULL;
        const void *prop;
@@ -258,33 +258,24 @@ void __init time_init(void)
                                0
                        };
 #endif
-       const char * const timer_list[] = {
-               "xlnx,xps-timer-1.00.a",
-               NULL
-       };
-
-       for (i = 0; timer_list[i] != NULL; i++) {
-               timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
-               if (timer)
-                       break;
-       }
+       timer = of_find_compatible_node(NULL, NULL, "xlnx,xps-timer-1.00.a");
        BUG_ON(!timer);
 
        timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
        timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
-       irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL));
+       irq = irq_of_parse_and_map(timer, 0);
        timer_num = be32_to_cpup(of_get_property(timer,
                                                "xlnx,one-timer-only", NULL));
        if (timer_num) {
-               eprintk(KERN_EMERG "Please enable two timers in HW\n");
+               printk(KERN_EMERG "Please enable two timers in HW\n");
                BUG();
        }
 
 #ifdef CONFIG_SELFMOD_TIMER
        selfmod_function((int *) arr_func, timer_baseaddr);
 #endif
-       printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
-               timer_list[i], timer_baseaddr, irq);
+       printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n",
+               timer_baseaddr, irq);
 
        /* If there is clock-frequency property than use it */
        prop = of_get_property(timer, "clock-frequency", NULL);
index c13067b243c3925e486bef404a1ac80aba5ebc6a..844960e8ae189767f96eb5d2e6e79ed2ac3cab2e 100644 (file)
@@ -20,6 +20,7 @@ lib-y += uaccess_old.o
 
 lib-y += ashldi3.o
 lib-y += ashrdi3.o
+lib-y += cmpdi2.o
 lib-y += divsi3.o
 lib-y += lshrdi3.o
 lib-y += modsi3.o
diff --git a/arch/microblaze/lib/cmpdi2.c b/arch/microblaze/lib/cmpdi2.c
new file mode 100644 (file)
index 0000000..a708400
--- /dev/null
@@ -0,0 +1,26 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+word_type __cmpdi2(long long a, long long b)
+{
+       const DWunion au = {
+               .ll = a
+       };
+       const DWunion bu = {
+               .ll = b
+       };
+
+       if (au.s.high < bu.s.high)
+               return 0;
+       else if (au.s.high > bu.s.high)
+               return 2;
+
+       if ((unsigned int) au.s.low < (unsigned int) bu.s.low)
+               return 0;
+       else if ((unsigned int) au.s.low > (unsigned int) bu.s.low)
+               return 2;
+
+       return 1;
+}
+EXPORT_SYMBOL(__cmpdi2);
index 57acda852f5a4723c7a294520b8fb6d51494cb54..b07abbac03197963c43011ceea69d2ec4c834b1f 100644 (file)
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len)
-               return NULL;
-       if (max && len > max)
-               len = max;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM)
-               return ioremap(start, len);
-       /* What? */
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        if (isa_vaddr_is_ioport(addr))
index db841c7b9d5bad1dcbf4c55cb54301ceb76dd460..85f2ac1230a8f5e89d78955f67819999f69367c3 100644 (file)
@@ -190,6 +190,11 @@ int pcibios_add_platform_entries(struct pci_dev *pdev)
        return device_create_file(&pdev->dev, &dev_attr_devspec);
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
 char __devinit *pcibios_setup(char *str)
 {
        return str;
@@ -242,7 +247,7 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
                         line, pin);
 
                virq = irq_create_mapping(NULL, line);
-               if (virq != NO_IRQ)
+               if (virq)
                        irq_set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
        } else {
                pr_debug(" Got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
@@ -253,7 +258,7 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
                virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
                                             oirq.size);
        }
-       if (virq == NO_IRQ) {
+       if (!virq) {
                pr_debug(" Failed to map !\n");
                return -1;
        }
@@ -1019,7 +1024,6 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
        struct pci_dev *dev = bus->self;
 
        pci_bus_for_each_resource(bus, res, i) {
-               res = bus->resource[i];
                if (!res)
                        continue;
                if (!res->flags)
@@ -1219,7 +1223,6 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
                 pci_domain_nr(bus), bus->number);
 
        pci_bus_for_each_resource(bus, res, i) {
-               res = bus->resource[i];
                if (!res || !res->flags
                    || res->start > res->end || res->parent)
                        continue;
@@ -1510,14 +1513,18 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pci_enable_resources(dev, mask);
 }
 
-void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
+static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
 {
-       struct pci_bus *bus = hose->bus;
        struct resource *res;
        int i;
 
        /* Hookup PHB IO resource */
-       bus->resource[0] = res = &hose->io_resource;
+       res = &hose->io_resource;
+
+       /* Fixup IO space offset */
+       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       res->start = (res->start + io_offset) & 0xffffffffu;
+       res->end = (res->end + io_offset) & 0xffffffffu;
 
        if (!res->flags) {
                printk(KERN_WARNING "PCI: I/O resource not set for host"
@@ -1528,6 +1535,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
                res->end = res->start + IO_SPACE_LIMIT;
                res->flags = IORESOURCE_IO;
        }
+       pci_add_resource(resources, res);
 
        pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
                 (unsigned long long)res->start,
@@ -1550,7 +1558,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
                        res->flags = IORESOURCE_MEM;
 
                }
-               bus->resource[i+1] = res;
+               pci_add_resource(resources, res);
 
                pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
                        i, (unsigned long long)res->start,
@@ -1573,34 +1581,27 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
 
 static void __devinit pcibios_scan_phb(struct pci_controller *hose)
 {
+       LIST_HEAD(resources);
        struct pci_bus *bus;
        struct device_node *node = hose->dn;
-       unsigned long io_offset;
-       struct resource *res = &hose->io_resource;
 
        pr_debug("PCI: Scanning PHB %s\n",
                 node ? node->full_name : "<NO NAME>");
 
-       /* Create an empty bus for the toplevel */
-       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
+       pcibios_setup_phb_resources(hose, &resources);
+
+       bus = pci_scan_root_bus(hose->parent, hose->first_busno,
+                               hose->ops, hose, &resources);
        if (bus == NULL) {
                printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
                       hose->global_number);
+               pci_free_resource_list(&resources);
                return;
        }
        bus->secondary = hose->first_busno;
        hose->bus = bus;
 
-       /* Fixup IO space offset */
-       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-       res->start = (res->start + io_offset) & 0xffffffffu;
-       res->end = (res->end + io_offset) & 0xffffffffu;
-
-       /* Wire up PHB bus resources */
-       pcibios_setup_phb_resources(hose);
-
-       /* Scan children */
-       hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+       hose->last_busno = bus->subordinate;
 }
 
 static int __init pcibios_init(void)
@@ -1614,8 +1615,6 @@ static int __init pcibios_init(void)
        list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
                hose->last_busno = 0xff;
                pcibios_scan_phb(hose);
-               printk(KERN_INFO "calling pci_bus_add_devices()\n");
-               pci_bus_add_devices(hose->bus);
                if (next_busno <= hose->last_busno)
                        next_busno = hose->last_busno + 1;
        }
index a7636d3ddc6a373f1d4e2329e3b40d31057ab296..29d92187ff3019914c5fea55f317108dc5745958 100644 (file)
@@ -16,6 +16,7 @@ config MIPS
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_KPROBES
        select HAVE_KRETPROBES
+       select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select RTC_LIB if !MACH_LOONGSON
        select GENERIC_ATOMIC64 if !64BIT
        select HAVE_DMA_ATTRS
@@ -2316,6 +2317,7 @@ config PCI
        bool "Support for PCI controller"
        depends on HW_HAS_PCI
        select PCI_DOMAINS
+       select GENERIC_PCI_IOMAP
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
          bus system, i.e. the way the CPU talks to the other stuff inside
index de39b1f343ea2537b459eed56f53ea9b35732554..7b99c670e478ed9ab79998762c839489cefb66a1 100644 (file)
@@ -144,7 +144,7 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
 extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
 extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
-extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET;
+extern void die(const char *, struct pt_regs *) __noreturn;
 
 static inline void die_if_kernel(const char *str, struct pt_regs *regs)
 {
index 5c8a49d55054dffce696066bad88d1863c5e7f35..bbddb86c1fa159bc50dc9275b38a1754353ede43 100644 (file)
@@ -1340,7 +1340,7 @@ void ejtag_exception_handler(struct pt_regs *regs)
 /*
  * NMI exception handler.
  */
-NORET_TYPE void ATTRIB_NORET nmi_exception_handler(struct pt_regs *regs)
+void __noreturn nmi_exception_handler(struct pt_regs *regs)
 {
        bust_spinlocks(1);
        printk("NMI taken!!!!\n");
index 2ab899c4b4ce1ac38a7b235f5c340af49dcc923c..2635b1a9633385568677b9a121f50adb6f96d8b7 100644 (file)
@@ -40,32 +40,6 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev,
        return (void __iomem *) (ctrl->io_map_base + port);
 }
 
-/*
- * Create a virtual mapping cookie for a PCI BAR (memory or IO)
- */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map_pci(dev, start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       /* What? */
-       return NULL;
-}
-
-EXPORT_SYMBOL(pci_iomap);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
        iounmap(addr);
index 41af7fa2887b7c6266800a1c000bff0d8da06099..fa8e378413b1640ed1e2efaf17894efde23925da 100644 (file)
@@ -81,6 +81,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
 {
        static int next_busno;
        static int need_domain_info;
+       LIST_HEAD(resources);
        struct pci_bus *bus;
 
        if (!hose->iommu)
@@ -89,7 +90,13 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
        if (hose->get_busno && pci_probe_only)
                next_busno = (*hose->get_busno)();
 
-       bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+       pci_add_resource(&resources, hose->mem_resource);
+       pci_add_resource(&resources, hose->io_resource);
+       bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
+                               &resources);
+       if (!bus)
+               pci_free_resource_list(&resources);
+
        hose->bus = bus;
 
        need_domain_info = need_domain_info || hose->index;
@@ -205,27 +212,6 @@ static int pcibios_enable_resources(struct pci_dev *dev, int mask)
        return 0;
 }
 
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-static unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-       printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n",
-              pci_name(dev), lat);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
 unsigned int pcibios_assign_all_busses(void)
 {
        return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
@@ -266,15 +252,11 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* Propagate hose info into the subordinate devices.  */
 
-       struct pci_controller *hose = bus->sysdata;
        struct list_head *ln;
        struct pci_dev *dev = bus->self;
 
-       if (!dev) {
-               bus->resource[0] = hose->io_resource;
-               bus->resource[1] = hose->mem_resource;
-       } else if (pci_probe_only &&
-                  (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+       if (pci_probe_only && dev &&
+           (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
                pci_read_bridge_bases(bus);
                pcibios_fixup_device_resources(dev, bus);
        }
index 438db84a1f7c71bee4bcd1ec17ecbfbaa295b637..8f1c40d5817ebb80e9bc818deed5c0b0d80f3ac7 100644 (file)
@@ -252,6 +252,7 @@ config PCI
        bool "Use PCI"
        depends on MN10300_UNIT_ASB2305
        default y
+       select GENERIC_PCI_IOMAP
        help
          Some systems (such as the ASB2305) have PCI onboard. If you have one
          of these boards and you wish to use the PCI facilities, say Y here.
index ca3e20508c77556a77492b85da8697d8eba4ced6..95a4d42c3a06e6f23a814d333ab6ce111d2b86a5 100644 (file)
@@ -110,7 +110,7 @@ extern asmlinkage void nmi_handler(void);
 extern asmlinkage void misalignment(struct pt_regs *, enum exception_code);
 
 extern void die(const char *, struct pt_regs *, enum exception_code)
-       ATTRIB_NORET;
+       __noreturn;
 
 extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code);
 
index 787255da744e2647a592b1aea12e20f3e76f83f9..139df8c53de83374a86189a8278d91a184d3e26c 100644 (file)
@@ -229,7 +229,6 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
 
 /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
 {
 }
@@ -251,15 +250,15 @@ static inline void *phys_to_virt(unsigned long address)
 /*
  * Change "struct page" to physical address.
  */
-static inline void *__ioremap(unsigned long offset, unsigned long size,
-                             unsigned long flags)
+static inline void __iomem *__ioremap(unsigned long offset, unsigned long size,
+                                     unsigned long flags)
 {
-       return (void *) offset;
+       return (void __iomem *) offset;
 }
 
-static inline void *ioremap(unsigned long offset, unsigned long size)
+static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
 {
-       return (void *) offset;
+       return (void __iomem *) offset;
 }
 
 /*
@@ -267,14 +266,14 @@ static inline void *ioremap(unsigned long offset, unsigned long size)
  * area.  it's useful if some control registers are in such an area and write
  * combining or read caching is not desirable:
  */
-static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+static inline void __iomem *ioremap_nocache(unsigned long offset, unsigned long size)
 {
-       return (void *) (offset | 0x20000000);
+       return (void __iomem *) (offset | 0x20000000);
 }
 
 #define ioremap_wc ioremap_nocache
 
-static inline void iounmap(void *addr)
+static inline void iounmap(void __iomem *addr)
 {
 }
 
index 0551022225b39905a7b5055541ec2afe8c7b0f91..cbc5abaa939a0f2e711c178cfede5d68cd9a312c 100644 (file)
@@ -5,4 +5,4 @@
 ###############################################################################
 obj-y   := unit-init.o leds.o
 
-obj-$(CONFIG_PCI) += pci.o pci-asb2305.o pci-irq.o pci-iomap.o
+obj-$(CONFIG_PCI) += pci.o pci-asb2305.o pci-irq.o
index 8e6763e6f25011f9d4eb68509c12ccb0dcb5014a..c4e2e79281e8de6fa3bf370032578a77fa337f9b 100644 (file)
@@ -213,28 +213,6 @@ void __init pcibios_resource_survey(void)
        pcibios_allocate_resources(1);
 }
 
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
 int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
                        enum pci_mmap_state mmap_state, int write_combine)
 {
index c3fa294b6e2840ecb39556c6064cfde2ae68797e..1194fe486b01e6334c5ec12ec4f43261723e9538 100644 (file)
@@ -31,8 +31,6 @@ extern unsigned int pci_probe;
 
 /* pci-asb2305.c */
 
-extern unsigned int pcibios_max_latency;
-
 extern void pcibios_resource_survey(void);
 
 /* pci.c */
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c
deleted file mode 100644 (file)
index c1a8d8f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* ASB2305 PCI I/O mapping handler
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#include <linux/pci.h>
-#include <linux/module.h>
-
-/*
- * Create a virtual mapping cookie for a PCI BAR (memory or IO)
- */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-
-       if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM))
-               return (void __iomem *) start;
-
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
index a4954fe82094be9404d8bdab02ea2bd1fc38ea3c..a7c5f08ca9f5ecfb1aee4930552e89b317e9e8e5 100644 (file)
@@ -380,11 +380,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
-       if (bus->number == 0) {
-               bus->resource[0] = &pci_ioport_resource;
-               bus->resource[1] = &pci_iomem_resource;
-       }
-
        if (bus->self) {
                pci_read_bridge_bases(bus);
                pcibios_fixup_device_resources(bus->self);
@@ -402,6 +397,8 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
  */
 static int __init pcibios_init(void)
 {
+       LIST_HEAD(resources);
+
        ioport_resource.start   = 0xA0000000;
        ioport_resource.end     = 0xDFFFFFFF;
        iomem_resource.start    = 0xA0000000;
@@ -423,7 +420,10 @@ static int __init pcibios_init(void)
        printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
               MEM_PAGING_REG);
 
-       pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL);
+       pci_add_resource(&resources, &pci_ioport_resource);
+       pci_add_resource(&resources, &pci_iomem_resource);
+       pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL,
+                                        &resources);
 
        pcibios_irq_init();
        pcibios_fixup_irqs();
index e518a5a4cf4c19abf6f3fa537c478957602a86ad..bc428b5f126c18b48d5b52e502d39eaf6241ac84 100644 (file)
@@ -15,6 +15,7 @@ config OPENRISC
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
+       select GENERIC_CPU_DEVICES
 
 config MMU
        def_bool y
@@ -38,9 +39,6 @@ config RWSEM_XCHGADD_ALGORITHM
 config GENERIC_HWEIGHT
        def_bool y
 
-config GENERIC_IOMAP
-       def_bool y
-
 config NO_IOPORT
        def_bool y
 
index fdfd8be29e951021140390d1ba37f1006d8f353d..242a1b7ac759448ba6ab06be9f28d4c9e9bfb69a 100644 (file)
@@ -14,6 +14,7 @@ config PARISC
        select GENERIC_ATOMIC64 if !64BIT
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
+       select GENERIC_PCI_IOMAP
        select IRQ_PER_CPU
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
 
index 9ce66e9d1c2b845275c41aaaf290a5fb5e123ba1..7213ec9e594cd4de25b912c17693dca742f46192 100644 (file)
@@ -196,7 +196,6 @@ typedef unsigned int elf_caddr_t;
        /* offset pc for priv. level */                 \
        pc |= 3;                                        \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
@@ -299,7 +298,6 @@ on downward growing arches, it looks like this:
        elf_addr_t pc = (elf_addr_t)new_pc | 3;         \
        elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;      \
                                                        \
-       set_fs(USER_DS);                                \
        regs->iasq[0] = spaceid;                        \
        regs->iasq[1] = spaceid;                        \
        regs->iaoq[0] = pc;                             \
index 4b4b9181a1a0aef8df25667f4a0229bb275e8d7f..62c60b87d0395d66b02a929095fe37bbb33b849b 100644 (file)
@@ -192,7 +192,6 @@ void flush_thread(void)
        /* Only needs to handle fpu stuff or perf monitors.
        ** REVISIT: several arches implement a "lazy fpu state".
        */
-       set_fs(USER_DS);
 }
 
 void release_thread(struct task_struct *dead_task)
index 8f470c93b16d10a94706f3f5375f2152db22e582..fb8e10a4fb39d5184b127a934308df1a7aac7900 100644 (file)
@@ -436,28 +436,6 @@ void ioport_unmap(void __iomem *addr)
        }
 }
 
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       /* What? */
-       return NULL;
-}
-
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
        if (!INDIRECT_ADDR(addr)) {
@@ -483,5 +461,4 @@ EXPORT_SYMBOL(iowrite16_rep);
 EXPORT_SYMBOL(iowrite32_rep);
 EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
index 692ac7588e20d45afa608a7ae6d5f3a7638a315e..1919634a9b32c261c6f989f7c87b7403a5c6c57e 100644 (file)
@@ -718,6 +718,7 @@ config PCI
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
        default PCI_QSPAN if !4xx && !CPM2 && 8xx
        select ARCH_SUPPORTS_MSI
+       select GENERIC_PCI_IOMAP
        help
          Find out whether your system includes a PCI bus. PCI is the name of
          a bus system, i.e. the way the CPU talks to the other stuff inside
index 882b6aa6c85765f9bdd5df1f55c1cfad13d07ac1..5d487657322e11d38ccfd47591a264dd2e73145e 100644 (file)
@@ -226,7 +226,6 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
 /* Allocate & free a PCI host bridge structure */
 extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev);
 extern void pcibios_free_controller(struct pci_controller *phb);
-extern void pcibios_setup_phb_resources(struct pci_controller *hose);
 
 #ifdef CONFIG_PCI
 extern int pcibios_vaddr_is_ioport(void __iomem *address);
index 1c92013466e3c68d3bd1792864b62548df037846..f54b3d26ce9d80e1f361d33d451253b048c0521b 100644 (file)
@@ -46,11 +46,6 @@ struct pci_dev;
 #define pcibios_assign_all_busses() \
        (pci_has_flag(PCI_REASSIGN_ALL_BUS))
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index 262791807397375612e29860ae64e5d86ee6cc6a..97a3715ac8bd83dadfb23555a398260de144ab9e 100644 (file)
@@ -119,24 +119,6 @@ EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
 
 #ifdef CONFIG_PCI
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len)
-               return NULL;
-       if (max && len > max)
-               len = max;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM)
-               return ioremap(start, len);
-       /* What? */
-       return NULL;
-}
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        if (isa_vaddr_is_ioport(addr))
@@ -146,6 +128,5 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
        iounmap(addr);
 }
 
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
 #endif /* CONFIG_PCI */
index e63f2e7d2efb029fca417c344ecee0d9e96daf88..affe5dcce7f465bcfcae706e3c3a1ebb24b44dbe 100644 (file)
 #include <asm/hw_irq.h>
 #include <asm/io.h>
 
-typedef NORET_TYPE void (*relocate_new_kernel_t)(
+typedef void (*relocate_new_kernel_t)(
                                unsigned long indirection_page,
                                unsigned long reboot_code_buffer,
-                               unsigned long start_address) ATTRIB_NORET;
+                               unsigned long start_address) __noreturn;
 
 /*
  * This is a generic machine_kexec function suitable at least for
index 26ccbf77dd4124958f83808b002e3a0176b3f6d4..d7f609086a99925dc9b2a47b479079fbf5b466d4 100644 (file)
@@ -307,9 +307,9 @@ static union thread_union kexec_stack __init_task_data =
 struct paca_struct kexec_paca;
 
 /* Our assembly helper, in kexec_stub.S */
-extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
-                                       void *image, void *control,
-                                       void (*clear_all)(void)) ATTRIB_NORET;
+extern void kexec_sequence(void *newstack, unsigned long start,
+                          void *image, void *control,
+                          void (*clear_all)(void)) __noreturn;
 
 /* too late to fail here */
 void default_machine_kexec(struct kimage *image)
index fa4a573d6716aa3bfe1a10eba2286224adff2388..cce98d76e905ad2188ce0d27e985308abaa2a433 100644 (file)
@@ -1131,6 +1131,11 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
        }
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* When called from the generic PCI probe, read PCI<->PCI bridge
@@ -1560,14 +1565,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pci_enable_resources(dev, mask);
 }
 
-void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
+static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
 {
-       struct pci_bus *bus = hose->bus;
        struct resource *res;
        int i;
 
        /* Hookup PHB IO resource */
-       bus->resource[0] = res = &hose->io_resource;
+       res = &hose->io_resource;
 
        if (!res->flags) {
                printk(KERN_WARNING "PCI: I/O resource not set for host"
@@ -1585,6 +1589,7 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
                 (unsigned long long)res->start,
                 (unsigned long long)res->end,
                 (unsigned long)res->flags);
+       pci_add_resource(resources, res);
 
        /* Hookup PHB Memory resources */
        for (i = 0; i < 3; ++i) {
@@ -1602,12 +1607,12 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
                        res->flags = IORESOURCE_MEM;
 #endif /* CONFIG_PPC32 */
                }
-               bus->resource[i+1] = res;
 
                pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
                         (unsigned long long)res->start,
                         (unsigned long long)res->end,
                         (unsigned long)res->flags);
+               pci_add_resource(resources, res);
        }
 
        pr_debug("PCI: PHB MEM offset     = %016llx\n",
@@ -1701,6 +1706,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
  */
 void __devinit pcibios_scan_phb(struct pci_controller *hose)
 {
+       LIST_HEAD(resources);
        struct pci_bus *bus;
        struct device_node *node = hose->dn;
        int mode;
@@ -1708,22 +1714,24 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose)
        pr_debug("PCI: Scanning PHB %s\n",
                 node ? node->full_name : "<NO NAME>");
 
+       /* Get some IO space for the new PHB */
+       pcibios_setup_phb_io_space(hose);
+
+       /* Wire up PHB bus resources */
+       pcibios_setup_phb_resources(hose, &resources);
+
        /* Create an empty bus for the toplevel */
-       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
+       bus = pci_create_root_bus(hose->parent, hose->first_busno,
+                                 hose->ops, hose, &resources);
        if (bus == NULL) {
                pr_err("Failed to create bus for PCI domain %04x\n",
                        hose->global_number);
+               pci_free_resource_list(&resources);
                return;
        }
        bus->secondary = hose->first_busno;
        hose->bus = bus;
 
-       /* Get some IO space for the new PHB */
-       pcibios_setup_phb_io_space(hose);
-
-       /* Wire up PHB bus resources */
-       pcibios_setup_phb_resources(hose);
-
        /* Get probe mode and perform scan */
        mode = PCI_PROBE_NORMAL;
        if (node && ppc_md.pci_probe_mode)
index bcf4bf9e72d9d658d8ed3dbb0f9d10677d0c8277..3318d39b7d4c34b8c8fe3815eed7aa1fb5a0e09c 100644 (file)
@@ -131,30 +131,13 @@ EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
 
 #endif /* CONFIG_HOTPLUG */
 
-int __devinit pcibios_map_io_space(struct pci_bus *bus)
+static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
 {
        struct vm_struct *area;
        unsigned long phys_page;
        unsigned long size_page;
        unsigned long io_virt_offset;
-       struct pci_controller *hose;
-
-       WARN_ON(bus == NULL);
-
-       /* If this not a PHB, nothing to do, page tables still exist and
-        * thus HPTEs will be faulted in when needed
-        */
-       if (bus->self) {
-               pr_debug("IO mapping for PCI-PCI bridge %s\n",
-                        pci_name(bus->self));
-               pr_debug("  virt=0x%016llx...0x%016llx\n",
-                        bus->resource[0]->start + _IO_BASE,
-                        bus->resource[0]->end + _IO_BASE);
-               return 0;
-       }
 
-       /* Get the host bridge */
-       hose = pci_bus_to_host(bus);
        phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
        size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
 
@@ -198,11 +181,30 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
 
        return 0;
 }
+
+int __devinit pcibios_map_io_space(struct pci_bus *bus)
+{
+       WARN_ON(bus == NULL);
+
+       /* If this not a PHB, nothing to do, page tables still exist and
+        * thus HPTEs will be faulted in when needed
+        */
+       if (bus->self) {
+               pr_debug("IO mapping for PCI-PCI bridge %s\n",
+                        pci_name(bus->self));
+               pr_debug("  virt=0x%016llx...0x%016llx\n",
+                        bus->resource[0]->start + _IO_BASE,
+                        bus->resource[0]->end + _IO_BASE);
+               return 0;
+       }
+
+       return pcibios_map_phb_io_space(pci_bus_to_host(bus));
+}
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
 void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
 {
-       pcibios_map_io_space(hose->bus);
+       pcibios_map_phb_io_space(hose);
 }
 
 #define IOBASE_BRIDGE_NUMBER   0
index 4ff3d8e411a76ce6ee53258bd63d42ea4f472863..3feefc3842a85471ae33c03307d4ad2907894856 100644 (file)
@@ -58,7 +58,7 @@ static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];
  * Allocate node_to_cpumask_map based on number of available nodes
  * Requires node_possible_map to be valid.
  *
- * Note: node_to_cpumask() is not valid until after this is done.
+ * Note: cpumask_of_node() is not valid until after this is done.
  */
 static void __init setup_node_to_cpumask_map(void)
 {
index 31e1adeaa92a371b334d1c3329f6550d5f3edaec..0cfb46d54b8c922db3b4136b1f7eb021213c48e7 100644 (file)
@@ -175,9 +175,6 @@ config PPC_INDIRECT_MMIO
 config PPC_IO_WORKAROUNDS
        bool
 
-config GENERIC_IOMAP
-       bool
-
 source "drivers/cpufreq/Kconfig"
 
 menu "CPU Frequency drivers"
index 330a57b7c17ca48ee997fa2508c9ec29716efd5d..36f957f31842f60688a7485f297ed6181dc926c9 100644 (file)
@@ -638,7 +638,6 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
                /* These are almost always orderly shutdowns. */
                return;
        case KMSG_DUMP_OOPS:
-       case KMSG_DUMP_KEXEC:
                break;
        case KMSG_DUMP_PANIC:
                panicking = true;
index 27272f6a14c2fbecf4f9a6f1a29cba7986f3bb92..d25843a6a91512409aca2d56458d06cd9f90922f 100644 (file)
@@ -236,7 +236,7 @@ static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc)
 /*
  * Function to drop a processor into disabled wait state
  */
-static inline void ATTRIB_NORET disabled_wait(unsigned long code)
+static inline void __noreturn disabled_wait(unsigned long code)
 {
         unsigned long ctl_buf;
         psw_t dw_psw;
index fab88431a06fcb70a92b4fdfe0f475d269be67a6..0fd2e863e114e161ced171368521a3512ea2571d 100644 (file)
@@ -30,7 +30,7 @@ struct mcck_struct {
 
 static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
 
-static NORET_TYPE void s390_handle_damage(char *msg)
+static void s390_handle_damage(char *msg)
 {
        smp_send_stop();
        disabled_wait((unsigned long) __builtin_return_address(0));
index 8b0c9464aa9d10ece5562bad884969665ee6f348..4b285779ac05e34559134072e6de57845abbe2ad 100644 (file)
@@ -4,9 +4,11 @@ config SCORE
        def_bool y
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_IOMAP
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select ARCH_DISCARD_MEMBLOCK
+       select GENERIC_CPU_DEVICES
 
 choice
        prompt "System type"
@@ -36,9 +38,6 @@ endmenu
 config CPU_SCORE7
        bool
 
-config GENERIC_IOMAP
-       def_bool y
-
 config NO_DMA
        bool
        default y
index 47a2f1c2cb0d4d63bf914d1e3f644111fe628276..3c8db65c89e5583ef16907f9d44eb0a9a74461ff 100644 (file)
@@ -85,9 +85,6 @@ config GENERIC_GPIO
 config GENERIC_CALIBRATE_DELAY
        bool
 
-config GENERIC_IOMAP
-       bool
-
 config GENERIC_CLOCKEVENTS
        def_bool y
 
@@ -861,6 +858,7 @@ config PCI
        bool "PCI support"
        depends on SYS_SUPPORTS_PCI
        select PCI_DOMAINS
+       select GENERIC_PCI_IOMAP
        help
          Find out whether you have a PCI motherboard. PCI is the name of a
          bus system, i.e. the way the CPU talks to the other stuff inside
index 93f5039099b708d4ac86e7fcda1f007185d91772..b2ca1d9948fbe0e614477bf091356a2527604f13 100644 (file)
@@ -25,9 +25,6 @@
 
 #define LAN9115_READY  (__raw_readl(0xA8000084UL) & 0x00000001UL)
 
-/* Prefer cmdline over RedBoot */
-static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
-
 /* Wait until reset finished. Timeout is 100ms. */
 static int __init ethernet_reset_finished(void)
 {
@@ -293,8 +290,6 @@ static struct platform_device heartbeat_device = {
        .resource       = heartbeat_resources,
 };
 
-static struct mtd_partition *parsed_partitions;
-
 static struct mtd_partition mpr2_partitions[] = {
        /* Reserved for bootloader, read-only */
        {
@@ -318,6 +313,8 @@ static struct mtd_partition mpr2_partitions[] = {
 };
 
 static struct physmap_flash_data flash_data = {
+       .parts          = mpr2_partitions,
+       .nr_parts       = ARRAY_SIZE(mpr2_partitions),
        .width          = 2,
 };
 
@@ -337,32 +334,6 @@ static struct platform_device flash_device = {
        },
 };
 
-static struct mtd_info *flash_mtd;
-
-static struct map_info mpr2_flash_map = {
-       .name = "Magic Panel R2 Flash",
-       .size = 0x2000000UL,
-       .bankwidth = 2,
-};
-
-static void __init set_mtd_partitions(void)
-{
-       int nr_parts = 0;
-
-       simple_map_init(&mpr2_flash_map);
-       flash_mtd = do_map_probe("cfi_probe", &mpr2_flash_map);
-       nr_parts = parse_mtd_partitions(flash_mtd, probes,
-                                       &parsed_partitions, 0);
-       /* If there is no partition table, used the hard coded table */
-       if (nr_parts <= 0) {
-               flash_data.parts = mpr2_partitions;
-               flash_data.nr_parts = ARRAY_SIZE(mpr2_partitions);
-       } else {
-               flash_data.nr_parts = nr_parts;
-               flash_data.parts = parsed_partitions;
-       }
-}
-
 /*
  * Add all resources to the platform_device
  */
@@ -376,7 +347,6 @@ static struct platform_device *mpr2_devices[] __initdata = {
 
 static int __init mpr2_devices_setup(void)
 {
-       set_mtd_partitions();
        return platform_add_devices(mpr2_devices, ARRAY_SIZE(mpr2_devices));
 }
 device_initcall(mpr2_devices_setup);
index 895e337c79b60ed7477f754f968ca80a9a52d754..0838154dd2168bdd2d51b0fe3ebb33e590eca70f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/sh_eth.h>
+#include <linux/usb/renesas_usbhs.h>
 #include <cpu/sh7757.h>
 #include <asm/heartbeat.h>
 
@@ -264,6 +265,43 @@ static struct platform_device sdhi_device = {
        },
 };
 
+static int usbhs0_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static struct renesas_usbhs_platform_info usb0_data = {
+       .platform_callback = {
+               .get_id = usbhs0_get_id,
+       },
+       .driver_param = {
+               .buswait_bwait = 5,
+       }
+};
+
+static struct resource usb0_resources[] = {
+       [0] = {
+               .start  = 0xfe450000,
+               .end    = 0xfe4501ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 50,
+               .end    = 50,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usb0_device = {
+       .name           = "renesas_usbhs",
+       .id             = 0,
+       .dev = {
+               .platform_data          = &usb0_data,
+       },
+       .num_resources  = ARRAY_SIZE(usb0_resources),
+       .resource       = usb0_resources,
+};
+
 static struct platform_device *sh7757lcr_devices[] __initdata = {
        &heartbeat_device,
        &sh7757_eth0_device,
@@ -272,6 +310,7 @@ static struct platform_device *sh7757lcr_devices[] __initdata = {
        &sh7757_eth_giga1_device,
        &sh_mmcif_device,
        &sdhi_device,
+       &usb0_device,
 };
 
 static struct flash_platform_data spi_flash_data = {
index 7030f4c8cf118ec734c086126fea72a794df6258..74d49c01783b26912f7e611b8d7f483020d27009 100644 (file)
@@ -249,9 +249,6 @@ static struct platform_device lcdc_device = {
        .dev            = {
                .platform_data  = &lcdc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_LCDC,
-       },
 };
 
 static void camera_power(int val)
@@ -424,9 +421,6 @@ static struct platform_device ceu_device = {
        .dev            = {
                .platform_data  = &sh_mobile_ceu_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU,
-       },
 };
 
 static struct resource sdhi0_cn3_resources[] = {
@@ -454,9 +448,6 @@ static struct platform_device sdhi0_cn3_device = {
        .dev = {
                .platform_data = &sdhi0_cn3_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI0,
-       },
 };
 
 static struct resource sdhi1_cn7_resources[] = {
@@ -484,9 +475,6 @@ static struct platform_device sdhi1_cn7_device = {
        .dev = {
                .platform_data = &sdhi1_cn7_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI1,
-       },
 };
 
 static struct i2c_board_info __initdata ap325rxa_i2c_devices[] = {
index 92ddce4b34563faab3c53ac7629140dd05f089f9..9a19fb07276cba9304c3a34fed5febd8414fd378 100644 (file)
@@ -156,9 +156,6 @@ static struct platform_device sh_eth_device = {
        },
        .num_resources = ARRAY_SIZE(sh_eth_resources),
        .resource = sh_eth_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_ETHER,
-       },
 };
 
 /* USB0 host */
@@ -278,9 +275,6 @@ static struct platform_device usbhs_device = {
        },
        .num_resources  = ARRAY_SIZE(usbhs_resources),
        .resource       = usbhs_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_USB1,
-       },
 };
 
 /* LCDC */
@@ -366,9 +360,6 @@ static struct platform_device lcdc_device = {
        .dev            = {
                .platform_data  = &lcdc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_LCDC,
-       },
 };
 
 /* CEU0 */
@@ -400,9 +391,6 @@ static struct platform_device ceu0_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu0_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU0,
-       },
 };
 
 /* CEU1 */
@@ -434,9 +422,6 @@ static struct platform_device ceu1_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu1_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU1,
-       },
 };
 
 /* I2C device */
@@ -491,9 +476,6 @@ static struct platform_device keysc_device = {
        .dev    = {
                .platform_data  = &keysc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_KEYSC,
-       },
 };
 
 /* TouchScreen */
@@ -568,9 +550,6 @@ static struct platform_device sdhi0_device = {
        .dev    = {
                .platform_data  = &sdhi0_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI0,
-       },
 };
 
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
@@ -608,9 +587,6 @@ static struct platform_device sdhi1_device = {
        .dev    = {
                .platform_data  = &sdhi1_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI1,
-       },
 };
 #endif /* CONFIG_MMC_SH_MMCIF */
 
@@ -676,9 +652,6 @@ static struct platform_device msiof0_device = {
        },
        .num_resources  = ARRAY_SIZE(msiof0_resources),
        .resource       = msiof0_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_MSIOF0,
-       },
 };
 
 #endif
@@ -818,9 +791,6 @@ static struct platform_device fsi_device = {
        .dev    = {
                .platform_data  = &fsi_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SPU, /* FSI needs SPU hwblk */
-       },
 };
 
 /* IrDA */
@@ -882,9 +852,6 @@ static struct platform_device vou_device = {
        .dev            = {
                .platform_data  = &sh_vou_pdata,
        },
-       .archdata       = {
-               .hwblk_id       = HWBLK_VOU,
-       },
 };
 
 #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
@@ -936,9 +903,6 @@ static struct platform_device sh_mmcif_device = {
        },
        .num_resources  = ARRAY_SIZE(sh_mmcif_resources),
        .resource       = sh_mmcif_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_MMC,
-       },
 };
 #endif
 
index f65271a8d0754af996d0e8f2519d5d46c21edb7b..5c3c713668480815b63cc24bc4896fc2689bf22f 100644 (file)
@@ -122,9 +122,6 @@ static struct platform_device kfr2r09_sh_keysc_device = {
        .dev    = {
                .platform_data  = &kfr2r09_sh_keysc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_KEYSC,
-       },
 };
 
 static const struct fb_videomode kfr2r09_lcdc_modes[] = {
@@ -191,9 +188,6 @@ static struct platform_device kfr2r09_sh_lcdc_device = {
        .dev    = {
                .platform_data  = &kfr2r09_sh_lcdc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_LCDC,
-       },
 };
 
 static struct r8a66597_platdata kfr2r09_usb0_gadget_data = {
@@ -254,9 +248,6 @@ static struct platform_device kfr2r09_ceu_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU0,
-       },
 };
 
 static struct i2c_board_info kfr2r09_i2c_camera = {
@@ -377,9 +368,6 @@ static struct platform_device kfr2r09_sh_sdhi0_device = {
        .dev = {
                .platform_data  = &sh7724_sdhi0_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI0,
-       },
 };
 
 static struct platform_device *kfr2r09_devices[] __initdata = {
index e4c81195929c3f8b485d5d3eb9995cb03968affc..f8f9377d5684ecfb9a817a35eab371d78400bb7e 100644 (file)
@@ -99,9 +99,6 @@ static struct platform_device sh_keysc_device = {
        .dev    = {
                .platform_data  = &sh_keysc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_KEYSC,
-       },
 };
 
 static struct mtd_partition migor_nor_flash_partitions[] =
@@ -300,9 +297,6 @@ static struct platform_device migor_lcdc_device = {
        .dev    = {
                .platform_data  = &sh_mobile_lcdc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_LCDC,
-       },
 };
 
 static struct clk *camera_clk;
@@ -390,9 +384,6 @@ static struct platform_device migor_ceu_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU,
-       },
 };
 
 static struct resource sdhi_cn9_resources[] = {
@@ -421,9 +412,6 @@ static struct platform_device sdhi_cn9_device = {
        .dev = {
                .platform_data  = &sh7724_sdhi_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI,
-       },
 };
 
 static struct i2c_board_info migor_i2c_devices[] = {
index a5c0df785bfec6bb7c3355a667560dff0b011c21..895f030070d37f95e7d2efde19047862763671d8 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-#ifdef CONFIG_MTD
 #include <linux/mtd/map.h>
-#endif
 #include <asm/machvec.h>
 #include <asm/io.h>
 
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
 static struct mtd_partition rsk_partitions[] = {
        {
                .name           = "Bootloader",
@@ -39,9 +39,10 @@ static struct mtd_partition rsk_partitions[] = {
 };
 
 static struct physmap_flash_data flash_data = {
-       .parts          = rsk_partitions,
-       .nr_parts       = ARRAY_SIZE(rsk_partitions),
-       .width          = 2,
+       .parts                  = rsk_partitions,
+       .nr_parts               = ARRAY_SIZE(rsk_partitions),
+       .width                  = 2,
+       .part_probe_types       = part_probes,
 };
 
 static struct resource flash_resource = {
@@ -60,44 +61,12 @@ static struct platform_device flash_device = {
        },
 };
 
-#ifdef CONFIG_MTD
-static const char *probes[] = { "cmdlinepart", NULL };
-
-static struct map_info rsk_flash_map = {
-       .name           = "RSK+ Flash",
-       .size           = 0x400000,
-       .bankwidth      = 2,
-};
-
-static struct mtd_info *flash_mtd;
-
-static struct mtd_partition *parsed_partitions;
-
-static void __init set_mtd_partitions(void)
-{
-       int nr_parts = 0;
-
-       simple_map_init(&rsk_flash_map);
-       flash_mtd = do_map_probe("cfi_probe", &rsk_flash_map);
-       nr_parts = parse_mtd_partitions(flash_mtd, probes,
-                                       &parsed_partitions, 0);
-       /* If there is no partition table, used the hard coded table */
-       if (nr_parts > 0) {
-               flash_data.nr_parts = nr_parts;
-               flash_data.parts = parsed_partitions;
-       }
-}
-#else
-static inline void set_mtd_partitions(void) {}
-#endif
-
 static struct platform_device *rsk_devices[] __initdata = {
        &flash_device,
 };
 
 static int __init rsk_devices_setup(void)
 {
-       set_mtd_partitions();
        return platform_add_devices(rsk_devices,
                                    ARRAY_SIZE(rsk_devices));
 }
index 80a4e571b310f99e79c04f991236ef92c1d232be..e1963fecd761ace85df196720c2c68c4f4d7a738 100644 (file)
@@ -127,9 +127,6 @@ static struct platform_device sh_keysc_device = {
        .dev    = {
                .platform_data  = &sh_keysc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_KEYSC,
-       },
 };
 
 static struct platform_device *se7722_devices[] __initdata = {
index b747c0ab9264ac3ed5d1894b8c67f471c7bc852d..2585733e9bce205a4f1a20638af38c88921e4e4a 100644 (file)
@@ -210,9 +210,6 @@ static struct platform_device lcdc_device = {
        .dev            = {
                .platform_data  = &lcdc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_LCDC,
-       },
 };
 
 /* CEU0 */
@@ -244,9 +241,6 @@ static struct platform_device ceu0_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu0_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU0,
-       },
 };
 
 /* CEU1 */
@@ -278,9 +272,6 @@ static struct platform_device ceu1_device = {
        .dev    = {
                .platform_data  = &sh_mobile_ceu1_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_CEU1,
-       },
 };
 
 /* FSI */
@@ -310,13 +301,22 @@ static struct platform_device fsi_device = {
        .dev    = {
                .platform_data  = &fsi_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SPU, /* FSI needs SPU hwblk */
-       },
+};
+
+static struct fsi_ak4642_info fsi_ak4642_info = {
+       .name           = "AK4642",
+       .card           = "FSIA-AK4642",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi.0",
+       .id             = FSI_PORT_A,
 };
 
 static struct platform_device fsi_ak4642_device = {
-       .name           = "sh_fsi_a_ak4642",
+       .name   = "fsi-ak4642-audio",
+       .dev    = {
+               .platform_data  = &fsi_ak4642_info,
+       },
 };
 
 /* KEYSC in SoC (Needs SW33-2 set to ON) */
@@ -355,9 +355,6 @@ static struct platform_device keysc_device = {
        .dev    = {
                .platform_data  = &keysc_info,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_KEYSC,
-       },
 };
 
 /* SH Eth */
@@ -386,9 +383,6 @@ static struct platform_device sh_eth_device = {
        },
        .num_resources = ARRAY_SIZE(sh_eth_resources),
        .resource = sh_eth_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_ETHER,
-       },
 };
 
 static struct r8a66597_platdata sh7724_usb0_host_data = {
@@ -418,9 +412,6 @@ static struct platform_device sh7724_usb0_host_device = {
        },
        .num_resources  = ARRAY_SIZE(sh7724_usb0_host_resources),
        .resource       = sh7724_usb0_host_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_USB0,
-       },
 };
 
 static struct r8a66597_platdata sh7724_usb1_gadget_data = {
@@ -479,9 +470,6 @@ static struct platform_device sdhi0_cn7_device = {
        .dev = {
                .platform_data  = &sh7724_sdhi0_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI0,
-       },
 };
 
 static struct resource sdhi1_cn8_resources[] = {
@@ -511,9 +499,6 @@ static struct platform_device sdhi1_cn8_device = {
        .dev = {
                .platform_data  = &sh7724_sdhi1_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_SDHI1,
-       },
 };
 
 /* IrDA */
@@ -576,9 +561,6 @@ static struct platform_device vou_device = {
        .dev            = {
                .platform_data  = &sh_vou_pdata,
        },
-       .archdata       = {
-               .hwblk_id       = HWBLK_VOU,
-       },
 };
 
 static struct platform_device *ms7724se_devices[] __initdata = {
index c2691afe8f79c9e08e402dae2f31a5231e34c6f5..8f18dd090a66021b2a17051a0ade4f03f8ae71b4 100644 (file)
@@ -36,9 +36,15 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
 {
        static int next_busno;
        static int need_domain_info;
+       LIST_HEAD(resources);
+       int i;
        struct pci_bus *bus;
 
-       bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+       for (i = 0; i < hose->nr_resources; i++)
+               pci_add_resource(&resources, hose->resources + i);
+
+       bus = pci_scan_root_bus(NULL, next_busno, hose->pci_ops, hose,
+                               &resources);
        hose->bus = bus;
 
        need_domain_info = need_domain_info || hose->index;
@@ -55,6 +61,8 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
                pci_enable_bridges(bus);
+       } else {
+               pci_free_resource_list(&resources);
        }
 }
 
@@ -162,16 +170,8 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev,
  */
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
-       struct pci_dev *dev = bus->self;
+       struct pci_dev *dev;
        struct list_head *ln;
-       struct pci_channel *hose = bus->sysdata;
-
-       if (!dev) {
-               int i;
-
-               for (i = 0; i < hose->nr_resources; i++)
-                       bus->resource[i] = hose->resources + i;
-       }
 
        for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
                dev = pci_dev_b(ln);
@@ -243,27 +243,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pci_enable_resources(dev, mask);
 }
 
-/*
- *  If we set up a device for bus mastering, we need to check and set
- *  the latency timer as it may not be properly set.
- */
-static unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-       printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n",
-              pci_name(dev), lat);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
 void __init pcibios_update_irq(struct pci_dev *dev, int irq)
 {
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -393,29 +372,6 @@ static void __iomem *ioport_map_pci(struct pci_dev *dev,
        return (void __iomem *)(chan->io_map_base + port);
 }
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (unlikely(!len || !start))
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-
-       if (flags & IORESOURCE_IO)
-               return ioport_map_pci(dev, start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL(pci_iomap);
-
 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 {
        iounmap(addr);
index b16debfe8c1eefe4e529db82850b6b66e4986297..a1c9c0daec109c694184d03da5d0701d049b8c40 100644 (file)
@@ -14,15 +14,5 @@ int platform_resource_setup_memory(struct platform_device *pdev,
 
 void plat_early_device_setup(void);
 
-#define PDEV_ARCHDATA_FLAG_INIT 0
-#define PDEV_ARCHDATA_FLAG_IDLE 1
-#define PDEV_ARCHDATA_FLAG_SUSP 2
-
 struct pdev_archdata {
-       int hwblk_id;
-#ifdef CONFIG_PM_RUNTIME
-       unsigned long flags;
-       struct list_head entry;
-       struct mutex mutex;
-#endif
 };
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
deleted file mode 100644 (file)
index 855e945..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef __ASM_SH_HWBLK_H
-#define __ASM_SH_HWBLK_H
-
-#include <asm/clock.h>
-#include <asm/io.h>
-
-#define HWBLK_CNT_USAGE 0
-#define HWBLK_CNT_IDLE 1
-#define HWBLK_CNT_DEVICES 2
-#define HWBLK_CNT_NR 3
-
-#define HWBLK_AREA_FLAG_PARENT (1 << 0) /* valid parent */
-
-#define HWBLK_AREA(_flags, _parent)            \
-{                                              \
-       .flags = _flags,                        \
-       .parent = _parent,                      \
-}
-
-struct hwblk_area {
-       int cnt[HWBLK_CNT_NR];
-       unsigned char parent;
-       unsigned char flags;
-};
-
-#define HWBLK(_mstp, _bit, _area)              \
-{                                              \
-       .mstp = (void __iomem *)_mstp,          \
-       .bit = _bit,                            \
-       .area = _area,                          \
-}
-
-struct hwblk {
-       void __iomem *mstp;
-       unsigned char bit;
-       unsigned char area;
-       int cnt[HWBLK_CNT_NR];
-};
-
-struct hwblk_info {
-       struct hwblk_area *areas;
-       int nr_areas;
-       struct hwblk *hwblks;
-       int nr_hwblks;
-};
-
-/* Should be defined by processor-specific code */
-int arch_hwblk_init(void);
-int arch_hwblk_sleep_mode(void);
-
-int hwblk_register(struct hwblk_info *info);
-int hwblk_init(void);
-
-void hwblk_enable(struct hwblk_info *info, int hwblk);
-void hwblk_disable(struct hwblk_info *info, int hwblk);
-
-void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
-void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
-
-/* allow clocks to enable and disable hardware blocks */
-#define SH_HWBLK_CLK(_hwblk, _parent, _flags)  \
-[_hwblk] = {                                   \
-       .parent         = _parent,              \
-       .arch_flags     = _hwblk,               \
-       .flags          = _flags,               \
-}
-
-int sh_hwblk_clk_register(struct clk *clks, int nr);
-
-#endif /* __ASM_SH_HWBLK_H */
index bd0622788d64a83ccb7f57799cb16c3143360cc9..3bb74e534d0f8ca44208827d762e9dec03b2525a 100644 (file)
@@ -222,14 +222,11 @@ enum {
 };
 
 enum {
-       HWBLK_UNKNOWN = 0,
-       HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_URAM, HWBLK_XYMEM,
-       HWBLK_INTC, HWBLK_DMAC, HWBLK_SHYWAY, HWBLK_HUDI,
-       HWBLK_UBC, HWBLK_TMU, HWBLK_CMT, HWBLK_RWDT, HWBLK_FLCTL,
-       HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_SIO,
-       HWBLK_SIOF0, HWBLK_SIOF1, HWBLK_IIC, HWBLK_RTC,
-       HWBLK_TPU, HWBLK_IRDA, HWBLK_SDHI, HWBLK_SIM, HWBLK_KEYSC,
-       HWBLK_TSIF, HWBLK_USBF, HWBLK_2DG, HWBLK_SIU, HWBLK_VOU,
+       HWBLK_URAM, HWBLK_XYMEM,
+       HWBLK_TMU, HWBLK_CMT, HWBLK_RWDT, HWBLK_FLCTL,
+       HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_IIC, HWBLK_RTC,
+       HWBLK_SDHI, HWBLK_KEYSC,
+       HWBLK_USBF, HWBLK_2DG, HWBLK_SIU, HWBLK_VOU,
        HWBLK_JPU, HWBLK_BEU, HWBLK_CEU, HWBLK_VEU, HWBLK_VPU,
        HWBLK_LCDC,
        HWBLK_NR,
index 9b36fae72324026ebac9ddaeb0df7936a48568a3..6fae50cb1e9488efadb3f78ba53149a557ef23a2 100644 (file)
@@ -266,10 +266,9 @@ enum {
 };
 
 enum {
-       HWBLK_UNKNOWN = 0,
        HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_L2C, HWBLK_ILMEM, HWBLK_FPU,
        HWBLK_INTC, HWBLK_DMAC0, HWBLK_SHYWAY,
-       HWBLK_HUDI, HWBLK_DBG, HWBLK_UBC, HWBLK_SUBC,
+       HWBLK_HUDI, HWBLK_UBC,
        HWBLK_TMU0, HWBLK_CMT, HWBLK_RWDT, HWBLK_DMAC1, HWBLK_TMU1,
        HWBLK_FLCTL,
        HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2,
index cbc47e6bcab5474b4c675af5600da0c66da1883e..38859f96d4e5e99782ae73980fb679a4fc1b9e02 100644 (file)
@@ -268,10 +268,9 @@ enum {
 };
 
 enum {
-       HWBLK_UNKNOWN = 0,
        HWBLK_TLB, HWBLK_IC, HWBLK_OC, HWBLK_RSMEM, HWBLK_ILMEM, HWBLK_L2C,
        HWBLK_FPU, HWBLK_INTC, HWBLK_DMAC0, HWBLK_SHYWAY,
-       HWBLK_HUDI, HWBLK_DBG, HWBLK_UBC,
+       HWBLK_HUDI, HWBLK_UBC,
        HWBLK_TMU0, HWBLK_CMT, HWBLK_RWDT, HWBLK_DMAC1, HWBLK_TMU1,
        HWBLK_SCIF0, HWBLK_SCIF1, HWBLK_SCIF2, HWBLK_SCIF3,
        HWBLK_SCIF4, HWBLK_SCIF5, HWBLK_MSIOF0, HWBLK_MSIOF1,
@@ -314,5 +313,6 @@ enum {
 
 extern struct clk sh7724_fsimcka_clk;
 extern struct clk sh7724_fsimckb_clk;
+extern struct clk sh7724_dv_clki;
 
 #endif /* __ASM_SH7724_H__ */
index ae95935d93cde7ace0d97584a34a0a95c87e8b85..fa58bfd30d829d5917b022e945b9bb512dfdc212 100644 (file)
@@ -18,4 +18,4 @@ obj-$(CONFIG_ARCH_SHMOBILE)   += shmobile/
 obj-$(CONFIG_SH_ADC)           += adc.o
 obj-$(CONFIG_SH_CLK_CPG_LEGACY)        += clock-cpg.o
 
-obj-y  += irq/ init.o clock.o fpu.o hwblk.o proc.o
+obj-y  += irq/ init.o clock.o fpu.o proc.o
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c
deleted file mode 100644 (file)
index 3e985aa..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <linux/clk.h>
-#include <linux/compiler.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <asm/clock.h>
-
-static DEFINE_SPINLOCK(hwblk_lock);
-
-static void hwblk_area_mod_cnt(struct hwblk_info *info,
-                              int area, int counter, int value, int goal)
-{
-       struct hwblk_area *hap = info->areas + area;
-
-       hap->cnt[counter] += value;
-
-       if (hap->cnt[counter] != goal)
-               return;
-
-       if (hap->flags & HWBLK_AREA_FLAG_PARENT)
-               hwblk_area_mod_cnt(info, hap->parent, counter, value, goal);
-}
-
-
-static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
-                         int counter, int value, int goal)
-{
-       struct hwblk *hp = info->hwblks + hwblk;
-
-       hp->cnt[counter] += value;
-       if (hp->cnt[counter] == goal)
-               hwblk_area_mod_cnt(info, hp->area, counter, value, goal);
-
-       return hp->cnt[counter];
-}
-
-static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk,
-                         int counter, int value, int goal)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hwblk_lock, flags);
-       __hwblk_mod_cnt(info, hwblk, counter, value, goal);
-       spin_unlock_irqrestore(&hwblk_lock, flags);
-}
-
-void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter)
-{
-       hwblk_mod_cnt(info, hwblk, counter, 1, 1);
-}
-
-void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
-{
-       hwblk_mod_cnt(info, hwblk, counter, -1, 0);
-}
-
-void hwblk_enable(struct hwblk_info *info, int hwblk)
-{
-       struct hwblk *hp = info->hwblks + hwblk;
-       unsigned long tmp;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&hwblk_lock, flags);
-
-       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1);
-       if (ret == 1) {
-               tmp = __raw_readl(hp->mstp);
-               tmp &= ~(1 << hp->bit);
-               __raw_writel(tmp, hp->mstp);
-       }
-
-       spin_unlock_irqrestore(&hwblk_lock, flags);
-}
-
-void hwblk_disable(struct hwblk_info *info, int hwblk)
-{
-       struct hwblk *hp = info->hwblks + hwblk;
-       unsigned long tmp;
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&hwblk_lock, flags);
-
-       ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0);
-       if (ret == 0) {
-               tmp = __raw_readl(hp->mstp);
-               tmp |= 1 << hp->bit;
-               __raw_writel(tmp, hp->mstp);
-       }
-
-       spin_unlock_irqrestore(&hwblk_lock, flags);
-}
-
-struct hwblk_info *hwblk_info;
-
-int __init hwblk_register(struct hwblk_info *info)
-{
-       hwblk_info = info;
-       return 0;
-}
-
-int __init __weak arch_hwblk_init(void)
-{
-       return 0;
-}
-
-int __weak arch_hwblk_sleep_mode(void)
-{
-       return SUSP_SH_SLEEP;
-}
-
-int __init hwblk_init(void)
-{
-       return arch_hwblk_init();
-}
-
-/* allow clocks to enable and disable hardware blocks */
-static int sh_hwblk_clk_enable(struct clk *clk)
-{
-       if (!hwblk_info)
-               return -ENOENT;
-
-       hwblk_enable(hwblk_info, clk->arch_flags);
-       return 0;
-}
-
-static void sh_hwblk_clk_disable(struct clk *clk)
-{
-       if (hwblk_info)
-               hwblk_disable(hwblk_info, clk->arch_flags);
-}
-
-static struct clk_ops sh_hwblk_clk_ops = {
-       .enable         = sh_hwblk_clk_enable,
-       .disable        = sh_hwblk_clk_disable,
-       .recalc         = followparent_recalc,
-};
-
-int __init sh_hwblk_clk_register(struct clk *clks, int nr)
-{
-       struct clk *clkp;
-       int ret = 0;
-       int k;
-
-       for (k = 0; !ret && (k < nr); k++) {
-               clkp = clks + k;
-
-               /* skip over clocks using hwblk 0 (HWBLK_UNKNOWN) */
-               if (!clkp->arch_flags)
-                       continue;
-
-               clkp->ops = &sh_hwblk_clk_ops;
-               ret |= clk_register(clkp);
-       }
-
-       return ret;
-}
index a8140f0bbf6cd32d83d6f3ad37949190b05c755f..0a47bd3e7bee1b20e94fa64a323319ae4dc26a54 100644 (file)
@@ -337,7 +337,7 @@ static struct kobj_type ktype_percpu_entry = {
        .default_attrs  = sq_sysfs_attrs,
 };
 
-static int __devinit sq_dev_add(struct device *dev)
+static int sq_dev_add(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
        struct kobject *kobj;
@@ -355,7 +355,7 @@ static int __devinit sq_dev_add(struct device *dev)
        return error;
 }
 
-static int __devexit sq_dev_remove(struct device *dev)
+static int sq_dev_remove(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
        struct kobject *kobj = sq_kobject[cpu];
@@ -365,10 +365,10 @@ static int __devexit sq_dev_remove(struct device *dev)
 }
 
 static struct subsys_interface sq_interface = {
-       .name           = "sq"
+       .name           = "sq",
        .subsys         = &cpu_subsys,
        .add_dev        = sq_dev_add,
-       .remove_dev     = __devexit_p(sq_dev_remove),
+       .remove_dev     = sq_dev_remove,
 };
 
 static int __init sq_api_init(void)
index c57fb287011e0a87278eecb5c0226a53fd70bc3b..0b22d108f4c5fccc16620b65ebf24202650f3572 100644 (file)
@@ -27,9 +27,9 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780)    := clock-sh7780.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7785)     := clock-sh7785.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7786)     := clock-sh7786.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7343)     := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o hwblk-sh7722.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o hwblk-sh7723.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7724)     := clock-sh7724.o hwblk-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722)     := clock-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7723)     := clock-sh7723.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7724)     := clock-sh7724.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7366)     := clock-sh7366.o
 clock-$(CONFIG_CPU_SUBTYPE_SHX3)       := clock-shx3.o
 
index c9a48088ad47f05eecf08a59f6725bd3f45876c1..212c72ef959c5bdc50c358247194072358a60b81 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/clkdev.h>
+#include <linux/sh_clk.h>
 #include <asm/clock.h>
-#include <asm/hwblk.h>
 #include <cpu/sh7722.h>
 
 /* SH7722 registers */
@@ -33,6 +33,9 @@
 #define SCLKBCR                0xa415000c
 #define IRDACLKCR      0xa4150018
 #define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
 #define DLLFRQ         0xa4150050
 
 /* Fixed 32 KHz root clock for RTC and Power Management purposes */
@@ -148,31 +151,31 @@ struct clk div6_clks[DIV6_NR] = {
 };
 
 static struct clk mstp_clks[HWBLK_NR] = {
-       SH_HWBLK_CLK(HWBLK_URAM, &div4_clks[DIV4_U], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_XYMEM, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_TMU, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_FLCTL, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
-
-       SH_HWBLK_CLK(HWBLK_IIC, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
-
-       SH_HWBLK_CLK(HWBLK_SDHI, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_USBF, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SIU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_JPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_BEU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_CEU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VEU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_P], 0),
+       [HWBLK_URAM]  = SH_CLK_MSTP32(&div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       [HWBLK_XYMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+       [HWBLK_TMU]   = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+       [HWBLK_CMT]   = SH_CLK_MSTP32(&r_clk,             MSTPCR0, 14, 0),
+       [HWBLK_RWDT]  = SH_CLK_MSTP32(&r_clk,             MSTPCR0, 13, 0),
+       [HWBLK_FLCTL] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+       [HWBLK_SCIF0] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+       [HWBLK_SCIF1] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 6, 0),
+       [HWBLK_SCIF2] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 5, 0),
+
+       [HWBLK_IIC]   = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+       [HWBLK_RTC]   = SH_CLK_MSTP32(&r_clk,             MSTPCR1, 8, 0),
+
+       [HWBLK_SDHI]  = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 18, 0),
+       [HWBLK_KEYSC] = SH_CLK_MSTP32(&r_clk,             MSTPCR2, 14, 0),
+       [HWBLK_USBF]  = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 11, 0),
+       [HWBLK_2DG]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 9, 0),
+       [HWBLK_SIU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 8, 0),
+       [HWBLK_JPU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 6, 0),
+       [HWBLK_VOU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 5, 0),
+       [HWBLK_BEU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 4, 0),
+       [HWBLK_CEU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 3, 0),
+       [HWBLK_VEU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 2, 0),
+       [HWBLK_VPU]   = SH_CLK_MSTP32(&div4_clks[DIV4_B], MSTPCR2, 1, 0),
+       [HWBLK_LCDC]  = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 0, 0),
 };
 
 static struct clk_lookup lookups[] = {
@@ -205,27 +208,27 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU]),
 
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
-       CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
+       CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
 
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
 
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
-       CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI]),
-       CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+       CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI]),
+       CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
        CLKDEV_CON_ID("usbf0", &mstp_clks[HWBLK_USBF]),
        CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
-       CLKDEV_CON_ID("siu0", &mstp_clks[HWBLK_SIU]),
-       CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+       CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
+       CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
        CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
        CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
-       CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
        CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU]),
        CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
-       CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
 };
 
 int __init arch_clk_init(void)
@@ -258,7 +261,7 @@ int __init arch_clk_init(void)
                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+               ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
 
        return ret;
 }
index 3cc3827380e3251c1d053c1a8ea8431d49a831b3..2f8c9179da47daaf267daac0324aad65b93a948d 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/sh_clk.h>
 #include <asm/clock.h>
-#include <asm/hwblk.h>
 #include <cpu/sh7723.h>
 
 /* SH7723 registers */
@@ -34,6 +34,9 @@
 #define SCLKBCR                0xa415000c
 #define IRDACLKCR      0xa4150018
 #define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
 #define DLLFRQ         0xa4150050
 
 /* Fixed 32 KHz root clock for RTC and Power Management purposes */
@@ -149,55 +152,55 @@ struct clk div6_clks[DIV6_NR] = {
 
 static struct clk mstp_clks[] = {
        /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
-       SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_OC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_L2C, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_ILMEM, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_FPU, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_INTC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_DMAC0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SHYWAY, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_HUDI, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_UBC, &div4_clks[DIV4_I], 0),
-       SH_HWBLK_CLK(HWBLK_TMU0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_DMAC1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_TMU1, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_FLCTL, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF3, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF4, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF5, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_MSIOF0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_MSIOF1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_MERAM, &div4_clks[DIV4_SH], 0),
-
-       SH_HWBLK_CLK(HWBLK_IIC, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
-
-       SH_HWBLK_CLK(HWBLK_ATAPI, &div4_clks[DIV4_SH], 0),
-       SH_HWBLK_CLK(HWBLK_ADC, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_TPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_IRDA, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_TSIF, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_ICB, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_SDHI0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SDHI1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_USB, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SIU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VEU2H1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_BEU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_CEU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VEU2H0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
+       [HWBLK_TLB]    = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+       [HWBLK_IC]     = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+       [HWBLK_OC]     = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+       [HWBLK_L2C]    = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       [HWBLK_ILMEM]  = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 27, CLK_ENABLE_ON_INIT),
+       [HWBLK_FPU]    = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 24, CLK_ENABLE_ON_INIT),
+       [HWBLK_INTC]   = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 22, CLK_ENABLE_ON_INIT),
+       [HWBLK_DMAC0]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 21, 0),
+       [HWBLK_SHYWAY] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
+       [HWBLK_HUDI]   = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 19, 0),
+       [HWBLK_UBC]    = SH_CLK_MSTP32(&div4_clks[DIV4_I],  MSTPCR0, 17, 0),
+       [HWBLK_TMU0]   = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 15, 0),
+       [HWBLK_CMT]    = SH_CLK_MSTP32(&r_clk,              MSTPCR0, 14, 0),
+       [HWBLK_RWDT]   = SH_CLK_MSTP32(&r_clk,              MSTPCR0, 13, 0),
+       [HWBLK_DMAC1]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 12, 0),
+       [HWBLK_TMU1]   = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 11, 0),
+       [HWBLK_FLCTL]  = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 10, 0),
+       [HWBLK_SCIF0]  = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 9, 0),
+       [HWBLK_SCIF1]  = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 8, 0),
+       [HWBLK_SCIF2]  = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR0, 7, 0),
+       [HWBLK_SCIF3]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 6, 0),
+       [HWBLK_SCIF4]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 5, 0),
+       [HWBLK_SCIF5]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 4, 0),
+       [HWBLK_MSIOF0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 2, 0),
+       [HWBLK_MSIOF1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 1, 0),
+       [HWBLK_MERAM]  = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 0, 0),
+
+       [HWBLK_IIC]    = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR1, 9, 0),
+       [HWBLK_RTC]    = SH_CLK_MSTP32(&r_clk,              MSTPCR1, 8, 0),
+
+       [HWBLK_ATAPI]  = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR2, 28, 0),
+       [HWBLK_ADC]    = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR2, 27, 0),
+       [HWBLK_TPU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 25, 0),
+       [HWBLK_IRDA]   = SH_CLK_MSTP32(&div4_clks[DIV4_P],  MSTPCR2, 24, 0),
+       [HWBLK_TSIF]   = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 22, 0),
+       [HWBLK_ICB]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 21, CLK_ENABLE_ON_INIT),
+       [HWBLK_SDHI0]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 18, 0),
+       [HWBLK_SDHI1]  = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 17, 0),
+       [HWBLK_KEYSC]  = SH_CLK_MSTP32(&r_clk,              MSTPCR2, 14, 0),
+       [HWBLK_USB]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 11, 0),
+       [HWBLK_2DG]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 10, 0),
+       [HWBLK_SIU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 8, 0),
+       [HWBLK_VEU2H1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 6, 0),
+       [HWBLK_VOU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 5, 0),
+       [HWBLK_BEU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 4, 0),
+       [HWBLK_CEU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 3, 0),
+       [HWBLK_VEU2H0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 2, 0),
+       [HWBLK_VPU]    = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 1, 0),
+       [HWBLK_LCDC]   = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR2, 0, 0),
 };
 
 static struct clk_lookup lookups[] = {
@@ -229,80 +232,17 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("ilmem0", &mstp_clks[HWBLK_ILMEM]),
        CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
        CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
-       CLKDEV_CON_ID("dmac0", &mstp_clks[HWBLK_DMAC0]),
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
        CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
        CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
        CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       },
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
-       CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
-       CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
-       {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       },
+       CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
+       CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF0],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF1],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF2],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF3],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF4],
-       }, {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF5],
-       },
-       CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
-       CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
-       CLKDEV_CON_ID("meram0", &mstp_clks[HWBLK_MERAM]),
+       CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
+       CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
+       CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[HWBLK_MERAM]),
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
@@ -311,19 +251,34 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
        CLKDEV_CON_ID("tsif0", &mstp_clks[HWBLK_TSIF]),
        CLKDEV_CON_ID("icb0", &mstp_clks[HWBLK_ICB]),
-       CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI0]),
-       CLKDEV_CON_ID("sdhi1", &mstp_clks[HWBLK_SDHI1]),
-       CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+       CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
+       CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
+       CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
        CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB]),
        CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
-       CLKDEV_CON_ID("siu0", &mstp_clks[HWBLK_SIU]),
+       CLKDEV_DEV_ID("siu-pcm-audio", &mstp_clks[HWBLK_SIU]),
        CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU2H1]),
-       CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+       CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
        CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU]),
-       CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU]),
        CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU2H0]),
        CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
-       CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
 };
 
 int __init arch_clk_init(void)
@@ -356,7 +311,7 @@ int __init arch_clk_init(void)
                ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+               ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
 
        return ret;
 }
index 8668f557e0aca654d72a049eeb3b0016202be3bf..b3c039a5064a43756c5a0704f3073e223a091fba 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/sh_clk.h>
 #include <asm/clock.h>
-#include <asm/hwblk.h>
 #include <cpu/sh7724.h>
 
 /* SH7724 registers */
@@ -35,6 +35,9 @@
 #define FCLKBCR                0xa415000c
 #define IRDACLKCR      0xa4150018
 #define PLLCR          0xa4150024
+#define MSTPCR0                0xa4150030
+#define MSTPCR1                0xa4150034
+#define MSTPCR2                0xa4150038
 #define SPUCLKCR       0xa415003c
 #define FLLFRQ         0xa4150050
 #define LSTATS         0xa4150060
@@ -111,13 +114,16 @@ static struct clk div3_clk = {
        .parent         = &pll_clk,
 };
 
-/* External input clock (pin name: FSIMCKA/FSIMCKB ) */
+/* External input clock (pin name: FSIMCKA/FSIMCKB/DV_CLKI ) */
 struct clk sh7724_fsimcka_clk = {
 };
 
 struct clk sh7724_fsimckb_clk = {
 };
 
+struct clk sh7724_dv_clki = {
+};
+
 static struct clk *main_clks[] = {
        &r_clk,
        &extal_clk,
@@ -126,6 +132,7 @@ static struct clk *main_clks[] = {
        &div3_clk,
        &sh7724_fsimcka_clk,
        &sh7724_fsimckb_clk,
+       &sh7724_dv_clki,
 };
 
 static void div4_kick(struct clk *clk)
@@ -163,17 +170,20 @@ struct clk div4_clks[DIV4_NR] = {
        [DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),
 };
 
-enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR };
+enum { DIV6_V, DIV6_I, DIV6_S, DIV6_FA, DIV6_FB, DIV6_NR };
 
-static struct clk div6_clks[DIV6_NR] = {
-       [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
-       [DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0),
-       [DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
+/* Indices are important - they are the actual src selecting values */
+static struct clk *common_parent[] = {
+       [0] = &div3_clk,
+       [1] = NULL,
 };
 
-enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR };
+static struct clk *vclkcr_parent[8] = {
+       [0] = &div3_clk,
+       [2] = &sh7724_dv_clki,
+       [4] = &extal_clk,
+};
 
-/* Indices are important - they are the actual src selecting values */
 static struct clk *fclkacr_parent[] = {
        [0] = &div3_clk,
        [1] = NULL,
@@ -188,68 +198,74 @@ static struct clk *fclkbcr_parent[] = {
        [3] = NULL,
 };
 
-static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
-       [DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0,
+static struct clk div6_clks[DIV6_NR] = {
+       [DIV6_V] = SH_CLK_DIV6_EXT(VCLKCR, 0,
+                       vclkcr_parent, ARRAY_SIZE(vclkcr_parent), 12, 3),
+       [DIV6_I] = SH_CLK_DIV6_EXT(IRDACLKCR, 0,
+                       common_parent, ARRAY_SIZE(common_parent), 6, 1),
+       [DIV6_S] = SH_CLK_DIV6_EXT(SPUCLKCR, CLK_ENABLE_ON_INIT,
+                       common_parent, ARRAY_SIZE(common_parent), 6, 1),
+       [DIV6_FA] = SH_CLK_DIV6_EXT(FCLKACR, 0,
                                      fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),
-       [DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0,
+       [DIV6_FB] = SH_CLK_DIV6_EXT(FCLKBCR, 0,
                                      fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
 };
 
 static struct clk mstp_clks[HWBLK_NR] = {
-       SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_OC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_RSMEM, &div4_clks[DIV4_B], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_ILMEM, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_L2C, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_FPU, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_INTC, &div4_clks[DIV4_P], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_DMAC0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SHYWAY, &div4_clks[DIV4_SH], CLK_ENABLE_ON_INIT),
-       SH_HWBLK_CLK(HWBLK_HUDI, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_UBC, &div4_clks[DIV4_I], 0),
-       SH_HWBLK_CLK(HWBLK_TMU0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_CMT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_RWDT, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_DMAC1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_TMU1, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF1, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF2, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF3, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF4, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SCIF5, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_MSIOF0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_MSIOF1, &div4_clks[DIV4_B], 0),
-
-       SH_HWBLK_CLK(HWBLK_KEYSC, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_RTC, &r_clk, 0),
-       SH_HWBLK_CLK(HWBLK_IIC0, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_IIC1, &div4_clks[DIV4_P], 0),
-
-       SH_HWBLK_CLK(HWBLK_MMC, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_ETHER, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_ATAPI, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_TPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_IRDA, &div4_clks[DIV4_P], 0),
-       SH_HWBLK_CLK(HWBLK_TSIF, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_USB1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_USB0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_2DG, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SDHI0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_SDHI1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VEU1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_CEU1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_BEU1, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_2DDMAC, &div4_clks[DIV4_SH], 0),
-       SH_HWBLK_CLK(HWBLK_SPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_JPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VOU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_BEU0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_CEU0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VEU0, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_VPU, &div4_clks[DIV4_B], 0),
-       SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
+       [HWBLK_TLB] = SH_CLK_MSTP32(&div4_clks[DIV4_I],     MSTPCR0, 31, CLK_ENABLE_ON_INIT),
+       [HWBLK_IC] = SH_CLK_MSTP32(&div4_clks[DIV4_I],      MSTPCR0, 30, CLK_ENABLE_ON_INIT),
+       [HWBLK_OC] = SH_CLK_MSTP32(&div4_clks[DIV4_I],      MSTPCR0, 29, CLK_ENABLE_ON_INIT),
+       [HWBLK_RSMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 28, CLK_ENABLE_ON_INIT),
+       [HWBLK_ILMEM] = SH_CLK_MSTP32(&div4_clks[DIV4_I],   MSTPCR0, 27, CLK_ENABLE_ON_INIT),
+       [HWBLK_L2C] = SH_CLK_MSTP32(&div4_clks[DIV4_SH],    MSTPCR0, 26, CLK_ENABLE_ON_INIT),
+       [HWBLK_FPU] = SH_CLK_MSTP32(&div4_clks[DIV4_I],     MSTPCR0, 24, CLK_ENABLE_ON_INIT),
+       [HWBLK_INTC] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR0, 22, CLK_ENABLE_ON_INIT),
+       [HWBLK_DMAC0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 21, 0),
+       [HWBLK_SHYWAY] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR0, 20, CLK_ENABLE_ON_INIT),
+       [HWBLK_HUDI] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR0, 19, 0),
+       [HWBLK_UBC] = SH_CLK_MSTP32(&div4_clks[DIV4_I],     MSTPCR0, 17, 0),
+       [HWBLK_TMU0] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR0, 15, 0),
+       [HWBLK_CMT] = SH_CLK_MSTP32(&r_clk,                 MSTPCR0, 14, 0),
+       [HWBLK_RWDT] = SH_CLK_MSTP32(&r_clk,                MSTPCR0, 13, 0),
+       [HWBLK_DMAC1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 12, 0),
+       [HWBLK_TMU1] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR0, 10, 0),
+       [HWBLK_SCIF0] = SH_CLK_MSTP32(&div4_clks[DIV4_P],   MSTPCR0, 9, 0),
+       [HWBLK_SCIF1] = SH_CLK_MSTP32(&div4_clks[DIV4_P],   MSTPCR0, 8, 0),
+       [HWBLK_SCIF2] = SH_CLK_MSTP32(&div4_clks[DIV4_P],   MSTPCR0, 7, 0),
+       [HWBLK_SCIF3] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 6, 0),
+       [HWBLK_SCIF4] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 5, 0),
+       [HWBLK_SCIF5] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR0, 4, 0),
+       [HWBLK_MSIOF0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 2, 0),
+       [HWBLK_MSIOF1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],  MSTPCR0, 1, 0),
+
+       [HWBLK_KEYSC] = SH_CLK_MSTP32(&r_clk,               MSTPCR1, 12, 0),
+       [HWBLK_RTC] = SH_CLK_MSTP32(&r_clk,                 MSTPCR1, 11, 0),
+       [HWBLK_IIC0] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR1, 9, 0),
+       [HWBLK_IIC1] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR1, 8, 0),
+
+       [HWBLK_MMC] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 29, 0),
+       [HWBLK_ETHER] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR2, 28, 0),
+       [HWBLK_ATAPI] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR2, 26, 0),
+       [HWBLK_TPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 25, 0),
+       [HWBLK_IRDA] = SH_CLK_MSTP32(&div4_clks[DIV4_P],    MSTPCR2, 24, 0),
+       [HWBLK_TSIF] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 22, 0),
+       [HWBLK_USB1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 21, 0),
+       [HWBLK_USB0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 20, 0),
+       [HWBLK_2DG] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 19, 0),
+       [HWBLK_SDHI0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR2, 18, 0),
+       [HWBLK_SDHI1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],   MSTPCR2, 17, 0),
+       [HWBLK_VEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 15, 0),
+       [HWBLK_CEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 13, 0),
+       [HWBLK_BEU1] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 12, 0),
+       [HWBLK_2DDMAC] = SH_CLK_MSTP32(&div4_clks[DIV4_SH], MSTPCR2, 10, 0),
+       [HWBLK_SPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 9, 0),
+       [HWBLK_JPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 6, 0),
+       [HWBLK_VOU] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 5, 0),
+       [HWBLK_BEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 4, 0),
+       [HWBLK_CEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 3, 0),
+       [HWBLK_VEU0] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 2, 0),
+       [HWBLK_VPU] = SH_CLK_MSTP32(&div4_clks[DIV4_B],     MSTPCR2, 1, 0),
+       [HWBLK_LCDC] = SH_CLK_MSTP32(&div4_clks[DIV4_B],    MSTPCR2, 0, 0),
 };
 
 static struct clk_lookup lookups[] = {
@@ -269,8 +285,8 @@ static struct clk_lookup lookups[] = {
 
        /* DIV6 clocks */
        CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
-       CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]),
-       CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]),
+       CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]),
+       CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]),
        CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),
        CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),
 
@@ -283,7 +299,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("l2c0", &mstp_clks[HWBLK_L2C]),
        CLKDEV_CON_ID("fpu0", &mstp_clks[HWBLK_FPU]),
        CLKDEV_CON_ID("intc0", &mstp_clks[HWBLK_INTC]),
-       CLKDEV_CON_ID("dmac0", &mstp_clks[HWBLK_DMAC0]),
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[HWBLK_DMAC0]),
        CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
        CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
        CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
@@ -294,26 +310,26 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
 
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
-       CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
-       CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
+       CLKDEV_DEV_ID("sh-wdt.0", &mstp_clks[HWBLK_RWDT]),
+       CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[HWBLK_DMAC1]),
 
        CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
        CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
-       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
-
-       CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
-       CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
-       CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
+       CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+       CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+       CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+
+       CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[HWBLK_MSIOF0]),
+       CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[HWBLK_MSIOF1]),
+       CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[HWBLK_KEYSC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
-       CLKDEV_CON_ID("mmc0", &mstp_clks[HWBLK_MMC]),
-       CLKDEV_CON_ID("eth0", &mstp_clks[HWBLK_ETHER]),
+       CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[HWBLK_MMC]),
+       CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[HWBLK_ETHER]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
        CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),
        CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
@@ -321,20 +337,20 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("usb1", &mstp_clks[HWBLK_USB1]),
        CLKDEV_CON_ID("usb0", &mstp_clks[HWBLK_USB0]),
        CLKDEV_CON_ID("2dg0", &mstp_clks[HWBLK_2DG]),
-       CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI0]),
-       CLKDEV_CON_ID("sdhi1", &mstp_clks[HWBLK_SDHI1]),
+       CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[HWBLK_SDHI0]),
+       CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[HWBLK_SDHI1]),
        CLKDEV_CON_ID("veu1", &mstp_clks[HWBLK_VEU1]),
-       CLKDEV_CON_ID("ceu1", &mstp_clks[HWBLK_CEU1]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[HWBLK_CEU1]),
        CLKDEV_CON_ID("beu1", &mstp_clks[HWBLK_BEU1]),
        CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]),
        CLKDEV_CON_ID("spu0", &mstp_clks[HWBLK_SPU]),
        CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]),
-       CLKDEV_CON_ID("vou0", &mstp_clks[HWBLK_VOU]),
+       CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]),
        CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]),
-       CLKDEV_CON_ID("ceu0", &mstp_clks[HWBLK_CEU0]),
+       CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]),
        CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]),
        CLKDEV_CON_ID("vpu0", &mstp_clks[HWBLK_VPU]),
-       CLKDEV_CON_ID("lcdc0", &mstp_clks[HWBLK_LCDC]),
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[HWBLK_LCDC]),
 };
 
 int __init arch_clk_init(void)
@@ -356,13 +372,10 @@ int __init arch_clk_init(void)
                ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 
        if (!ret)
-               ret = sh_clk_div6_register(div6_clks, DIV6_NR);
-
-       if (!ret)
-               ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
+               ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);
 
        if (!ret)
-               ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
+               ret = sh_clk_mstp32_register(mstp_clks, HWBLK_NR);
 
        return ret;
 }
index 19222dae8233ab7d8c3b754eca4d48af3aff6914..0fbff1422f5454c239a54bb77a182b30fc696a6c 100644 (file)
@@ -129,7 +129,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
 
        CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP103]),
-       CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
+       CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP102]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
 };
 
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
deleted file mode 100644 (file)
index a288b5d..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c
- *
- * SH7722 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7722.h>
-
-/* SH7722 registers */
-#define MSTPCR0                0xa4150030
-#define MSTPCR1                0xa4150034
-#define MSTPCR2                0xa4150038
-
-/* SH7722 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7722_hwblk_area[] = {
-       [CORE_AREA] = HWBLK_AREA(0, 0),
-       [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
-       [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7722_hwblk[HWBLK_NR] = {
-       [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
-       [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
-       [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
-       [HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA),
-       [HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA),
-       [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
-       [HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
-       [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
-       [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
-       [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
-       [HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA),
-       [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
-       [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
-       [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
-       [HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA),
-       [HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA),
-       [HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA),
-       [HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA),
-       [HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
-       [HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
-
-       [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
-       [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
-
-       [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
-       [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
-       [HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA),
-       [HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA),
-       [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
-       [HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA),
-       [HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA),
-       [HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
-       [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
-       [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
-       [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
-       [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
-       [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
-       [HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
-       [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
-       [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7722_hwblk_info = {
-       .areas = sh7722_hwblk_area,
-       .nr_areas = ARRAY_SIZE(sh7722_hwblk_area),
-       .hwblks = sh7722_hwblk,
-       .nr_hwblks = ARRAY_SIZE(sh7722_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
-       if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_STANDBY | SUSP_SH_SF;
-
-       if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_SLEEP | SUSP_SH_SF;
-
-       return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
-       return hwblk_register(&sh7722_hwblk_info);
-}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
deleted file mode 100644 (file)
index a7f4684..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c
- *
- * SH7723 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7723.h>
-
-/* SH7723 registers */
-#define MSTPCR0                0xa4150030
-#define MSTPCR1                0xa4150034
-#define MSTPCR2                0xa4150038
-
-/* SH7723 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7723_hwblk_area[] = {
-       [CORE_AREA] = HWBLK_AREA(0, 0),
-       [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
-       [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7723_hwblk[HWBLK_NR] = {
-       [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
-       [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
-       [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
-       [HWBLK_L2C] = HWBLK(MSTPCR0, 28, CORE_AREA),
-       [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
-       [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
-       [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
-       [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
-       [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
-       [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
-       [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
-       [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
-       [HWBLK_SUBC] = HWBLK(MSTPCR0, 16, CORE_AREA),
-       [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
-       [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
-       [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
-       [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
-       [HWBLK_TMU1] = HWBLK(MSTPCR0, 11, CORE_AREA),
-       [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA),
-       [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
-       [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
-       [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
-       [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
-       [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
-       [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
-       [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
-       [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
-       [HWBLK_MERAM] = HWBLK(MSTPCR0, 0, CORE_AREA),
-
-       [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA),
-       [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA),
-
-       [HWBLK_ATAPI] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
-       [HWBLK_ADC] = HWBLK(MSTPCR2, 27, CORE_AREA),
-       [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
-       [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
-       [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
-       [HWBLK_ICB] = HWBLK(MSTPCR2, 21, CORE_AREA_BM),
-       [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
-       [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
-       [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA),
-       [HWBLK_USB] = HWBLK(MSTPCR2, 11, CORE_AREA),
-       [HWBLK_2DG] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
-       [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA),
-       [HWBLK_VEU2H1] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
-       [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
-       [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
-       [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
-       [HWBLK_VEU2H0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
-       [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
-       [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7723_hwblk_info = {
-       .areas = sh7723_hwblk_area,
-       .nr_areas = ARRAY_SIZE(sh7723_hwblk_area),
-       .hwblks = sh7723_hwblk,
-       .nr_hwblks = ARRAY_SIZE(sh7723_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
-       if (!sh7723_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_STANDBY | SUSP_SH_SF;
-
-       if (!sh7723_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_SLEEP | SUSP_SH_SF;
-
-       return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
-       return hwblk_register(&sh7723_hwblk_info);
-}
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
deleted file mode 100644 (file)
index 1613ad6..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c
- *
- * SH7724 hardware block support
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <asm/suspend.h>
-#include <asm/hwblk.h>
-#include <cpu/sh7724.h>
-
-/* SH7724 registers */
-#define MSTPCR0                0xa4150030
-#define MSTPCR1                0xa4150034
-#define MSTPCR2                0xa4150038
-
-/* SH7724 Power Domains */
-enum { CORE_AREA, SUB_AREA, CORE_AREA_BM };
-static struct hwblk_area sh7724_hwblk_area[] = {
-       [CORE_AREA] = HWBLK_AREA(0, 0),
-       [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA),
-       [SUB_AREA] = HWBLK_AREA(0, 0),
-};
-
-/* Table mapping HWBLK to Module Stop Bit and Power Domain */
-static struct hwblk sh7724_hwblk[HWBLK_NR] = {
-       [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA),
-       [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA),
-       [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA),
-       [HWBLK_RSMEM] = HWBLK(MSTPCR0, 28, CORE_AREA),
-       [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA),
-       [HWBLK_L2C] = HWBLK(MSTPCR0, 26, CORE_AREA),
-       [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA),
-       [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA),
-       [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM),
-       [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA),
-       [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA),
-       [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA),
-       [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA),
-       [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA),
-       [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA),
-       [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA),
-       [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM),
-       [HWBLK_TMU1] = HWBLK(MSTPCR0, 10, CORE_AREA),
-       [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA),
-       [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA),
-       [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA),
-       [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA),
-       [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA),
-       [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA),
-       [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA),
-       [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA),
-
-       [HWBLK_KEYSC] = HWBLK(MSTPCR1, 12, SUB_AREA),
-       [HWBLK_RTC] = HWBLK(MSTPCR1, 11, SUB_AREA),
-       [HWBLK_IIC0] = HWBLK(MSTPCR1, 9, CORE_AREA),
-       [HWBLK_IIC1] = HWBLK(MSTPCR1, 8, CORE_AREA),
-
-       [HWBLK_MMC] = HWBLK(MSTPCR2, 29, CORE_AREA),
-       [HWBLK_ETHER] = HWBLK(MSTPCR2, 28, CORE_AREA_BM),
-       [HWBLK_ATAPI] = HWBLK(MSTPCR2, 26, CORE_AREA_BM),
-       [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA),
-       [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA),
-       [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA),
-       [HWBLK_USB1] = HWBLK(MSTPCR2, 21, CORE_AREA),
-       [HWBLK_USB0] = HWBLK(MSTPCR2, 20, CORE_AREA),
-       [HWBLK_2DG] = HWBLK(MSTPCR2, 19, CORE_AREA_BM),
-       [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA),
-       [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA),
-       [HWBLK_VEU1] = HWBLK(MSTPCR2, 15, CORE_AREA_BM),
-       [HWBLK_CEU1] = HWBLK(MSTPCR2, 13, CORE_AREA_BM),
-       [HWBLK_BEU1] = HWBLK(MSTPCR2, 12, CORE_AREA_BM),
-       [HWBLK_2DDMAC] = HWBLK(MSTPCR2, 10, CORE_AREA_BM),
-       [HWBLK_SPU] = HWBLK(MSTPCR2, 9, CORE_AREA_BM),
-       [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM),
-       [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM),
-       [HWBLK_BEU0] = HWBLK(MSTPCR2, 4, CORE_AREA_BM),
-       [HWBLK_CEU0] = HWBLK(MSTPCR2, 3, CORE_AREA_BM),
-       [HWBLK_VEU0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM),
-       [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM),
-       [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM),
-};
-
-static struct hwblk_info sh7724_hwblk_info = {
-       .areas = sh7724_hwblk_area,
-       .nr_areas = ARRAY_SIZE(sh7724_hwblk_area),
-       .hwblks = sh7724_hwblk,
-       .nr_hwblks = ARRAY_SIZE(sh7724_hwblk),
-};
-
-int arch_hwblk_sleep_mode(void)
-{
-       if (!sh7724_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_STANDBY | SUSP_SH_SF;
-
-       if (!sh7724_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE])
-               return SUSP_SH_SLEEP | SUSP_SH_SF;
-
-       return SUSP_SH_SLEEP;
-}
-
-int __init arch_hwblk_init(void)
-{
-       return hwblk_register(&sh7724_hwblk_info);
-}
index 278a0e572158697793d76404b6ffb87eb4c9a7c2..8420d4bc8bfc53ee9ff373ba0bb4a0afff358508 100644 (file)
@@ -146,7 +146,7 @@ static struct resource sh7722_dmae_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = 78,
                .end    = 78,
                .flags  = IORESOURCE_IRQ,
@@ -173,9 +173,6 @@ struct platform_device dma_device = {
        .dev            = {
                .platform_data  = &dma_platform_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_DMAC,
-       },
 };
 
 /* Serial */
@@ -264,9 +261,6 @@ static struct platform_device rtc_device = {
        .id             = -1,
        .num_resources  = ARRAY_SIZE(rtc_resources),
        .resource       = rtc_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_RTC,
-       },
 };
 
 static struct m66592_platdata usbf_platdata = {
@@ -297,9 +291,6 @@ static struct platform_device usbf_device = {
        },
        .num_resources  = ARRAY_SIZE(usbf_resources),
        .resource       = usbf_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_USBF,
-       },
 };
 
 static struct resource iic_resources[] = {
@@ -321,9 +312,6 @@ static struct platform_device iic_device = {
        .id             = 0, /* "i2c0" clock */
        .num_resources  = ARRAY_SIZE(iic_resources),
        .resource       = iic_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_IIC,
-       },
 };
 
 static struct uio_info vpu_platform_data = {
@@ -352,9 +340,6 @@ static struct platform_device vpu_device = {
        },
        .resource       = vpu_resources,
        .num_resources  = ARRAY_SIZE(vpu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VPU,
-       },
 };
 
 static struct uio_info veu_platform_data = {
@@ -383,9 +368,6 @@ static struct platform_device veu_device = {
        },
        .resource       = veu_resources,
        .num_resources  = ARRAY_SIZE(veu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VEU,
-       },
 };
 
 static struct uio_info jpu_platform_data = {
@@ -414,9 +396,6 @@ static struct platform_device jpu_device = {
        },
        .resource       = jpu_resources,
        .num_resources  = ARRAY_SIZE(jpu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_JPU,
-       },
 };
 
 static struct sh_timer_config cmt_platform_data = {
@@ -446,9 +425,6 @@ static struct platform_device cmt_device = {
        },
        .resource       = cmt_resources,
        .num_resources  = ARRAY_SIZE(cmt_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_CMT,
-       },
 };
 
 static struct sh_timer_config tmu0_platform_data = {
@@ -477,9 +453,6 @@ static struct platform_device tmu0_device = {
        },
        .resource       = tmu0_resources,
        .num_resources  = ARRAY_SIZE(tmu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU,
-       },
 };
 
 static struct sh_timer_config tmu1_platform_data = {
@@ -508,9 +481,6 @@ static struct platform_device tmu1_device = {
        },
        .resource       = tmu1_resources,
        .num_resources  = ARRAY_SIZE(tmu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU,
-       },
 };
 
 static struct sh_timer_config tmu2_platform_data = {
@@ -538,9 +508,6 @@ static struct platform_device tmu2_device = {
        },
        .resource       = tmu2_resources,
        .num_resources  = ARRAY_SIZE(tmu2_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU,
-       },
 };
 
 static struct siu_platform siu_platform_data = {
@@ -571,9 +538,6 @@ static struct platform_device siu_device = {
        },
        .resource       = siu_resources,
        .num_resources  = ARRAY_SIZE(siu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_SIU,
-       },
 };
 
 static struct platform_device *sh7722_devices[] __initdata = {
index 3c2810d8f72e3caf81643baef9fabff588747736..a188c9ea4393b3443b8564a020b7c6bb3ae9c1e1 100644 (file)
@@ -158,9 +158,6 @@ static struct platform_device vpu_device = {
        },
        .resource       = vpu_resources,
        .num_resources  = ARRAY_SIZE(vpu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VPU,
-       },
 };
 
 static struct uio_info veu0_platform_data = {
@@ -189,9 +186,6 @@ static struct platform_device veu0_device = {
        },
        .resource       = veu0_resources,
        .num_resources  = ARRAY_SIZE(veu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VEU2H0,
-       },
 };
 
 static struct uio_info veu1_platform_data = {
@@ -220,9 +214,6 @@ static struct platform_device veu1_device = {
        },
        .resource       = veu1_resources,
        .num_resources  = ARRAY_SIZE(veu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VEU2H1,
-       },
 };
 
 static struct sh_timer_config cmt_platform_data = {
@@ -252,9 +243,6 @@ static struct platform_device cmt_device = {
        },
        .resource       = cmt_resources,
        .num_resources  = ARRAY_SIZE(cmt_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_CMT,
-       },
 };
 
 static struct sh_timer_config tmu0_platform_data = {
@@ -283,9 +271,6 @@ static struct platform_device tmu0_device = {
        },
        .resource       = tmu0_resources,
        .num_resources  = ARRAY_SIZE(tmu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 static struct sh_timer_config tmu1_platform_data = {
@@ -314,9 +299,6 @@ static struct platform_device tmu1_device = {
        },
        .resource       = tmu1_resources,
        .num_resources  = ARRAY_SIZE(tmu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 static struct sh_timer_config tmu2_platform_data = {
@@ -344,9 +326,6 @@ static struct platform_device tmu2_device = {
        },
        .resource       = tmu2_resources,
        .num_resources  = ARRAY_SIZE(tmu2_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 static struct sh_timer_config tmu3_platform_data = {
@@ -374,9 +353,6 @@ static struct platform_device tmu3_device = {
        },
        .resource       = tmu3_resources,
        .num_resources  = ARRAY_SIZE(tmu3_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 static struct sh_timer_config tmu4_platform_data = {
@@ -404,9 +380,6 @@ static struct platform_device tmu4_device = {
        },
        .resource       = tmu4_resources,
        .num_resources  = ARRAY_SIZE(tmu4_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 static struct sh_timer_config tmu5_platform_data = {
@@ -434,9 +407,6 @@ static struct platform_device tmu5_device = {
        },
        .resource       = tmu5_resources,
        .num_resources  = ARRAY_SIZE(tmu5_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 static struct resource rtc_resources[] = {
@@ -467,9 +437,6 @@ static struct platform_device rtc_device = {
        .id             = -1,
        .num_resources  = ARRAY_SIZE(rtc_resources),
        .resource       = rtc_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_RTC,
-       },
 };
 
 static struct r8a66597_platdata r8a66597_data = {
@@ -499,9 +466,6 @@ static struct platform_device sh7723_usb_host_device = {
        },
        .num_resources  = ARRAY_SIZE(sh7723_usb_host_resources),
        .resource       = sh7723_usb_host_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_USB,
-       },
 };
 
 static struct resource iic_resources[] = {
@@ -523,9 +487,6 @@ static struct platform_device iic_device = {
        .id             = 0, /* "i2c0" clock */
        .num_resources  = ARRAY_SIZE(iic_resources),
        .resource       = iic_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_IIC,
-       },
 };
 
 static struct platform_device *sh7723_devices[] __initdata = {
index a37dd72c36719d06c938431691b48a9c56023790..4c671cfe68aaaf517b4087fb98b2a13c8d73db6c 100644 (file)
@@ -214,7 +214,7 @@ static struct resource sh7724_dmae0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = 78,
                .end    = 78,
                .flags  = IORESOURCE_IRQ,
@@ -248,7 +248,7 @@ static struct resource sh7724_dmae1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = 74,
                .end    = 74,
                .flags  = IORESOURCE_IRQ,
@@ -275,9 +275,6 @@ static struct platform_device dma0_device = {
        .dev            = {
                .platform_data  = &dma_platform_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_DMAC0,
-       },
 };
 
 static struct platform_device dma1_device = {
@@ -288,9 +285,6 @@ static struct platform_device dma1_device = {
        .dev            = {
                .platform_data  = &dma_platform_data,
        },
-       .archdata = {
-               .hwblk_id = HWBLK_DMAC1,
-       },
 };
 
 /* Serial */
@@ -434,9 +428,6 @@ static struct platform_device rtc_device = {
        .id             = -1,
        .num_resources  = ARRAY_SIZE(rtc_resources),
        .resource       = rtc_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_RTC,
-       },
 };
 
 /* I2C0 */
@@ -459,9 +450,6 @@ static struct platform_device iic0_device = {
        .id             = 0, /* "i2c0" clock */
        .num_resources  = ARRAY_SIZE(iic0_resources),
        .resource       = iic0_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_IIC0,
-       },
 };
 
 /* I2C1 */
@@ -484,9 +472,6 @@ static struct platform_device iic1_device = {
        .id             = 1, /* "i2c1" clock */
        .num_resources  = ARRAY_SIZE(iic1_resources),
        .resource       = iic1_resources,
-       .archdata = {
-               .hwblk_id = HWBLK_IIC1,
-       },
 };
 
 /* VPU */
@@ -516,9 +501,6 @@ static struct platform_device vpu_device = {
        },
        .resource       = vpu_resources,
        .num_resources  = ARRAY_SIZE(vpu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VPU,
-       },
 };
 
 /* VEU0 */
@@ -548,9 +530,6 @@ static struct platform_device veu0_device = {
        },
        .resource       = veu0_resources,
        .num_resources  = ARRAY_SIZE(veu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VEU0,
-       },
 };
 
 /* VEU1 */
@@ -580,9 +559,6 @@ static struct platform_device veu1_device = {
        },
        .resource       = veu1_resources,
        .num_resources  = ARRAY_SIZE(veu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_VEU1,
-       },
 };
 
 /* BEU0 */
@@ -612,9 +588,6 @@ static struct platform_device beu0_device = {
        },
        .resource       = beu0_resources,
        .num_resources  = ARRAY_SIZE(beu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_BEU0,
-       },
 };
 
 /* BEU1 */
@@ -644,9 +617,6 @@ static struct platform_device beu1_device = {
        },
        .resource       = beu1_resources,
        .num_resources  = ARRAY_SIZE(beu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_BEU1,
-       },
 };
 
 static struct sh_timer_config cmt_platform_data = {
@@ -676,9 +646,6 @@ static struct platform_device cmt_device = {
        },
        .resource       = cmt_resources,
        .num_resources  = ARRAY_SIZE(cmt_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_CMT,
-       },
 };
 
 static struct sh_timer_config tmu0_platform_data = {
@@ -707,9 +674,6 @@ static struct platform_device tmu0_device = {
        },
        .resource       = tmu0_resources,
        .num_resources  = ARRAY_SIZE(tmu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 static struct sh_timer_config tmu1_platform_data = {
@@ -738,9 +702,6 @@ static struct platform_device tmu1_device = {
        },
        .resource       = tmu1_resources,
        .num_resources  = ARRAY_SIZE(tmu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 static struct sh_timer_config tmu2_platform_data = {
@@ -768,9 +729,6 @@ static struct platform_device tmu2_device = {
        },
        .resource       = tmu2_resources,
        .num_resources  = ARRAY_SIZE(tmu2_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU0,
-       },
 };
 
 
@@ -799,9 +757,6 @@ static struct platform_device tmu3_device = {
        },
        .resource       = tmu3_resources,
        .num_resources  = ARRAY_SIZE(tmu3_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 static struct sh_timer_config tmu4_platform_data = {
@@ -829,9 +784,6 @@ static struct platform_device tmu4_device = {
        },
        .resource       = tmu4_resources,
        .num_resources  = ARRAY_SIZE(tmu4_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 static struct sh_timer_config tmu5_platform_data = {
@@ -859,9 +811,6 @@ static struct platform_device tmu5_device = {
        },
        .resource       = tmu5_resources,
        .num_resources  = ARRAY_SIZE(tmu5_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_TMU1,
-       },
 };
 
 /* JPU */
@@ -891,9 +840,6 @@ static struct platform_device jpu_device = {
        },
        .resource       = jpu_resources,
        .num_resources  = ARRAY_SIZE(jpu_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_JPU,
-       },
 };
 
 /* SPU2DSP0 */
@@ -923,9 +869,6 @@ static struct platform_device spu0_device = {
        },
        .resource       = spu0_resources,
        .num_resources  = ARRAY_SIZE(spu0_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_SPU,
-       },
 };
 
 /* SPU2DSP1 */
@@ -955,9 +898,6 @@ static struct platform_device spu1_device = {
        },
        .resource       = spu1_resources,
        .num_resources  = ARRAY_SIZE(spu1_resources),
-       .archdata = {
-               .hwblk_id = HWBLK_SPU,
-       },
 };
 
 static struct platform_device *sh7724_devices[] __initdata = {
index 05559295d2ca8e8fa184e50bcca0a4b224e9d308..a7b2da6b3a1a359953f7043d498288de59b7df55 100644 (file)
@@ -465,6 +465,7 @@ static struct resource sh7757_dmae0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
+               .name   = "error_irq",
                .start  = 34,
                .end    = 34,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
@@ -486,7 +487,7 @@ static struct resource sh7757_dmae1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error */
+               .name   = "error_irq",
                .start  = 34,
                .end    = 34,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
@@ -556,7 +557,7 @@ static struct resource sh7757_dmae2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error */
+               .name   = "error_irq",
                .start  = 323,
                .end    = 323,
                .flags  = IORESOURCE_IRQ,
@@ -590,7 +591,7 @@ static struct resource sh7757_dmae3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        {
-               /* DMA error */
+               .name   = "error_irq",
                .start  = 324,
                .end    = 324,
                .flags  = IORESOURCE_IRQ,
index 3d4d2075c19ad334ac40b8803b8e7ecffced0a96..d431b0052d0c87b58a75d175096068bcb2a70781 100644 (file)
@@ -322,6 +322,7 @@ static struct resource sh7780_dmae0_resources[] = {
        },
        {
                /* Real DMA error IRQ is 38, and channel IRQs are 34-37, 44-45 */
+               .name   = "error_irq",
                .start  = 34,
                .end    = 34,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
@@ -338,6 +339,7 @@ static struct resource sh7780_dmae1_resources[] = {
        /* DMAC1 has no DMARS */
        {
                /* Real DMA error IRQ is 38, and channel IRQs are 46-47, 92-95 */
+               .name   = "error_irq",
                .start  = 46,
                .end    = 46,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
index b29e6340414ab82ec54dd5f4c1c652eb50053aa5..81588ef15a6c09df110760888e33141f21633d6d 100644 (file)
@@ -376,6 +376,7 @@ static struct resource sh7785_dmae0_resources[] = {
        },
        {
                /* Real DMA error IRQ is 39, and channel IRQs are 33-38 */
+               .name   = "error_irq",
                .start  = 33,
                .end    = 33,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
@@ -392,6 +393,7 @@ static struct resource sh7785_dmae1_resources[] = {
        /* DMAC1 has no DMARS */
        {
                /* Real DMA error IRQ is 58, and channel IRQs are 52-57 */
+               .name   = "error_irq",
                .start  = 52,
                .end    = 52,
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
index dd5e709f982163f809e8650c791dd6668ddc3264..599022d73b283237413bb0a5a3f874fad4e2affc 100644 (file)
@@ -518,7 +518,7 @@ static struct resource dmac0_resources[] = {
                .end    = 0xfe00900b,
                .flags  = IORESOURCE_MEM,
        }, {
-               /* DMA error IRQ */
+               .name   = "error_irq",
                .start  = evt2irq(0x5c0),
                .end    = evt2irq(0x5c0),
                .flags  = IORESOURCE_IRQ,
index a39f88ea1a85b01dbd5240eded860e19b63acda8..e8a5111e848abd1ac463a62492736dbe7861bf30 100644 (file)
@@ -5,4 +5,3 @@
 # Power Management & Sleep mode
 obj-$(CONFIG_PM)       += pm.o sleep.o
 obj-$(CONFIG_CPU_IDLE) += cpuidle.o
-obj-$(CONFIG_PM_RUNTIME)       += pm_runtime.o
index 1cc257c9b1e311b806ed2defaa36b6db9ea5c920..6d62eb40e750a2d8ad00919c0d75de477155875f 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/export.h>
 #include <asm/suspend.h>
 #include <asm/uaccess.h>
-#include <asm/hwblk.h>
 
 static unsigned long cpuidle_mode[] = {
        SUSP_SH_SLEEP, /* regular sleep mode */
@@ -29,7 +28,7 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
                                int index)
 {
-       unsigned long allowed_mode = arch_hwblk_sleep_mode();
+       unsigned long allowed_mode = SUSP_SH_SLEEP;
        ktime_t before, after;
        int requested_state = index;
        int allowed_state;
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
deleted file mode 100644 (file)
index bf280c8..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * arch/sh/kernel/cpu/shmobile/pm_runtime.c
- *
- * Runtime PM support code for SuperH Mobile
- *
- *  Copyright (C) 2009 Magnus Damm
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <asm/hwblk.h>
-
-static DEFINE_SPINLOCK(hwblk_lock);
-static LIST_HEAD(hwblk_idle_list);
-static struct work_struct hwblk_work;
-
-extern struct hwblk_info *hwblk_info;
-
-static void platform_pm_runtime_not_idle(struct platform_device *pdev)
-{
-       unsigned long flags;
-
-       /* remove device from idle list */
-       spin_lock_irqsave(&hwblk_lock, flags);
-       if (test_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags)) {
-               list_del(&pdev->archdata.entry);
-               __clear_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags);
-       }
-       spin_unlock_irqrestore(&hwblk_lock, flags);
-}
-
-static int __platform_pm_runtime_resume(struct platform_device *pdev)
-{
-       struct device *d = &pdev->dev;
-       struct pdev_archdata *ad = &pdev->archdata;
-       int hwblk = ad->hwblk_id;
-       int ret = -ENOSYS;
-
-       dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk);
-
-       if (d->driver) {
-               hwblk_enable(hwblk_info, hwblk);
-               ret = 0;
-
-               if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) {
-                       if (d->driver->pm && d->driver->pm->runtime_resume)
-                               ret = d->driver->pm->runtime_resume(d);
-
-                       if (!ret)
-                               clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);
-                       else
-                               hwblk_disable(hwblk_info, hwblk);
-               }
-       }
-
-       dev_dbg(d, "__platform_pm_runtime_resume() [%d] - returns %d\n",
-               hwblk, ret);
-
-       return ret;
-}
-
-static int __platform_pm_runtime_suspend(struct platform_device *pdev)
-{
-       struct device *d = &pdev->dev;
-       struct pdev_archdata *ad = &pdev->archdata;
-       int hwblk = ad->hwblk_id;
-       int ret = -ENOSYS;
-
-       dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk);
-
-       if (d->driver) {
-               BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags));
-               ret = 0;
-
-               if (d->driver->pm && d->driver->pm->runtime_suspend) {
-                       hwblk_enable(hwblk_info, hwblk);
-                       ret = d->driver->pm->runtime_suspend(d);
-                       hwblk_disable(hwblk_info, hwblk);
-               }
-
-               if (!ret) {
-                       set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);
-                       platform_pm_runtime_not_idle(pdev);
-                       hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE);
-               }
-       }
-
-       dev_dbg(d, "__platform_pm_runtime_suspend() [%d] - returns %d\n",
-               hwblk, ret);
-
-       return ret;
-}
-
-static void platform_pm_runtime_work(struct work_struct *work)
-{
-       struct platform_device *pdev;
-       unsigned long flags;
-       int ret;
-
-       /* go through the idle list and suspend one device at a time */
-       do {
-               spin_lock_irqsave(&hwblk_lock, flags);
-               if (list_empty(&hwblk_idle_list))
-                       pdev = NULL;
-               else
-                       pdev = list_first_entry(&hwblk_idle_list,
-                                               struct platform_device,
-                                               archdata.entry);
-               spin_unlock_irqrestore(&hwblk_lock, flags);
-
-               if (pdev) {
-                       mutex_lock(&pdev->archdata.mutex);
-                       ret = __platform_pm_runtime_suspend(pdev);
-
-                       /* at this point the platform device may be:
-                        * suspended: ret = 0, FLAG_SUSP set, clock stopped
-                        * failed: ret < 0, FLAG_IDLE set, clock stopped
-                        */
-                       mutex_unlock(&pdev->archdata.mutex);
-               } else {
-                       ret = -ENODEV;
-               }
-       } while (!ret);
-}
-
-/* this function gets called from cpuidle context when all devices in the
- * main power domain are unused but some are counted as idle, ie the hwblk
- * counter values are (HWBLK_CNT_USAGE == 0) && (HWBLK_CNT_IDLE != 0)
- */
-void platform_pm_runtime_suspend_idle(void)
-{
-       queue_work(pm_wq, &hwblk_work);
-}
-
-static int default_platform_runtime_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct pdev_archdata *ad = &pdev->archdata;
-       unsigned long flags;
-       int hwblk = ad->hwblk_id;
-       int ret = 0;
-
-       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
-
-       /* ignore off-chip platform devices */
-       if (!hwblk)
-               goto out;
-
-       /* interrupt context not allowed */
-       might_sleep();
-
-       /* catch misconfigured drivers not starting with resume */
-       if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &ad->flags)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* serialize */
-       mutex_lock(&ad->mutex);
-
-       /* disable clock */
-       hwblk_disable(hwblk_info, hwblk);
-
-       /* put device on idle list */
-       spin_lock_irqsave(&hwblk_lock, flags);
-       list_add_tail(&ad->entry, &hwblk_idle_list);
-       __set_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags);
-       spin_unlock_irqrestore(&hwblk_lock, flags);
-
-       /* increase idle count */
-       hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_IDLE);
-
-       /* at this point the platform device is:
-        * idle: ret = 0, FLAG_IDLE set, clock stopped
-        */
-       mutex_unlock(&ad->mutex);
-
-out:
-       dev_dbg(dev, "%s() [%d] returns %d\n",
-                __func__, hwblk, ret);
-
-       return ret;
-}
-
-static int default_platform_runtime_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct pdev_archdata *ad = &pdev->archdata;
-       int hwblk = ad->hwblk_id;
-       int ret = 0;
-
-       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
-
-       /* ignore off-chip platform devices */
-       if (!hwblk)
-               goto out;
-
-       /* interrupt context not allowed */
-       might_sleep();
-
-       /* serialize */
-       mutex_lock(&ad->mutex);
-
-       /* make sure device is removed from idle list */
-       platform_pm_runtime_not_idle(pdev);
-
-       /* decrease idle count */
-       if (!test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags) &&
-           !test_bit(PDEV_ARCHDATA_FLAG_SUSP, &pdev->archdata.flags))
-               hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_IDLE);
-
-       /* resume the device if needed */
-       ret = __platform_pm_runtime_resume(pdev);
-
-       /* the driver has been initialized now, so clear the init flag */
-       clear_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
-
-       /* at this point the platform device may be:
-        * resumed: ret = 0, flags = 0, clock started
-        * failed: ret < 0, FLAG_SUSP set, clock stopped
-        */
-       mutex_unlock(&ad->mutex);
-out:
-       dev_dbg(dev, "%s() [%d] returns %d\n",
-               __func__, hwblk, ret);
-
-       return ret;
-}
-
-static int default_platform_runtime_idle(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       int hwblk = pdev->archdata.hwblk_id;
-       int ret = 0;
-
-       dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
-
-       /* ignore off-chip platform devices */
-       if (!hwblk)
-               goto out;
-
-       /* interrupt context not allowed, use pm_runtime_put()! */
-       might_sleep();
-
-       /* suspend synchronously to disable clocks immediately */
-       ret = pm_runtime_suspend(dev);
-out:
-       dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk);
-       return ret;
-}
-
-static struct dev_pm_domain default_pm_domain = {
-       .ops = {
-               .runtime_suspend = default_platform_runtime_suspend,
-               .runtime_resume = default_platform_runtime_resume,
-               .runtime_idle = default_platform_runtime_idle,
-               USE_PLATFORM_PM_SLEEP_OPS
-       },
-};
-
-static int platform_bus_notify(struct notifier_block *nb,
-                              unsigned long action, void *data)
-{
-       struct device *dev = data;
-       struct platform_device *pdev = to_platform_device(dev);
-       int hwblk = pdev->archdata.hwblk_id;
-
-       /* ignore off-chip platform devices */
-       if (!hwblk)
-               return 0;
-
-       switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               INIT_LIST_HEAD(&pdev->archdata.entry);
-               mutex_init(&pdev->archdata.mutex);
-               /* platform devices without drivers should be disabled */
-               hwblk_enable(hwblk_info, hwblk);
-               hwblk_disable(hwblk_info, hwblk);
-               /* make sure driver re-inits itself once */
-               __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
-               dev->pm_domain = &default_pm_domain;
-               break;
-       /* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */
-       case BUS_NOTIFY_BOUND_DRIVER:
-               /* keep track of number of devices in use per hwblk */
-               hwblk_cnt_inc(hwblk_info, hwblk, HWBLK_CNT_DEVICES);
-               break;
-       case BUS_NOTIFY_UNBOUND_DRIVER:
-               /* keep track of number of devices in use per hwblk */
-               hwblk_cnt_dec(hwblk_info, hwblk, HWBLK_CNT_DEVICES);
-               /* make sure driver re-inits itself once */
-               __set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
-               break;
-       case BUS_NOTIFY_DEL_DEVICE:
-               dev->pm_domain = NULL;
-               break;
-       }
-       return 0;
-}
-
-static struct notifier_block platform_bus_notifier = {
-       .notifier_call = platform_bus_notify
-};
-
-static int __init sh_pm_runtime_init(void)
-{
-       INIT_WORK(&hwblk_work, platform_pm_runtime_work);
-
-       bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
-       return 0;
-}
-core_initcall(sh_pm_runtime_init);
index 2b15ae60c3a0257ed1ea48b34da0044c6a4bfaf6..f67601cb3f1f47da13a49ae4948021800b9a2f4d 100644 (file)
@@ -145,6 +145,7 @@ work_notifysig:
         mov    r15, r4
        mov     r12, r5         ! set arg1(save_r0)
        mov     r0, r6
+       sti
        mov.l   2f, r1
        mov.l   3f, r0
        jmp     @r1
index aaf6d59c201227b52c431e6be891868d756a5fda..7ec6651781255e375f971c3645d73eb46f870063 100644 (file)
@@ -70,7 +70,7 @@ void show_regs(struct pt_regs * regs)
 /*
  * Create a kernel thread
  */
-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
 {
        do_exit(fn(arg));
 }
index 210c1cabcb7fd3fe0903442c40c56d37a34b2ccc..cbd4e4bb9fc526796fbbd8b79a60847e0493bfb2 100644 (file)
@@ -285,7 +285,7 @@ void show_regs(struct pt_regs *regs)
 /*
  * Create a kernel thread
  */
-ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
 {
        do_exit(fn(arg));
 }
index 579cd2ca358d8b786fa6c38e109238c5685807e2..a7a55ed43a596ee3b372efaa849d19b8c10b3bfc 100644 (file)
@@ -588,9 +588,6 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
        if (!user_mode(regs))
                return;
 
-       if (try_to_freeze())
-               goto no_signal;
-
        if (current_thread_info()->status & TS_RESTORE_SIGMASK)
                oldset = &current->saved_sigmask;
        else
@@ -618,7 +615,6 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
                return;
        }
 
-no_signal:
        /* Did we come from a system call? */
        if (regs->tra >= 0) {
                /* Restart the system call - no handlers present */
index 5a9f1f10ebf4b359f573a35f3e70ea34b88fc388..6b5603fe274bdbca92a94b15331553388dc2488a 100644 (file)
@@ -98,9 +98,6 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
        if (!user_mode(regs))
                return 1;
 
-       if (try_to_freeze())
-               goto no_signal;
-
        if (current_thread_info()->status & TS_RESTORE_SIGMASK)
                oldset = &current->saved_sigmask;
        else if (!oldset)
@@ -125,7 +122,6 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
                }
        }
 
-no_signal:
        /* Did we come from a system call? */
        if (regs->syscall_nr >= 0) {
                /* Restart the system call - no handlers present */
index 8a0072de2bcce23057c1f012a9fb078901c8a590..552c8fcf9416413f3b8ebf606371d88cb85eebeb 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/smp.h>
 #include <linux/rtc.h>
 #include <asm/clock.h>
-#include <asm/hwblk.h>
 #include <asm/rtc.h>
 
 /* Dummy RTC ops */
@@ -110,7 +109,6 @@ void __init time_init(void)
        if (board_time_init)
                board_time_init();
 
-       hwblk_init();
        clk_init();
 
        late_time_init = sh_late_time_init;
index 1f51225426a2124e9dcd9ef4769fa4cb9e73272e..ae08cbbfa5697559cfcb5e669086d9ddbe244d20 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/io.h>
 
+/*
+ * The maximum number of pages we support up to when doing ranged dcache
+ * flushing. Anything exceeding this will simply flush the dcache in its
+ * entirety.
+ */
+#define MAX_OCACHE_PAGES       32
+#define MAX_ICACHE_PAGES       32
+
+static void sh2a_flush_oc_line(unsigned long v, int way)
+{
+       unsigned long addr = (v & 0x000007f0) | (way << 11);
+       unsigned long data;
+
+       data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr);
+       if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
+               data &= ~SH_CACHE_UPDATED;
+               __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr);
+       }
+}
+
+static void sh2a_invalidate_line(unsigned long cache_addr, unsigned long v)
+{
+       /* Set associative bit to hit all ways */
+       unsigned long addr = (v & 0x000007f0) | SH_CACHE_ASSOC;
+       __raw_writel((addr & CACHE_PHYSADDR_MASK), cache_addr | addr);
+}
+
+/*
+ * Write back the dirty D-caches, but not invalidate them.
+ */
 static void sh2a__flush_wback_region(void *start, int size)
 {
+#ifdef CONFIG_CACHE_WRITEBACK
        unsigned long v;
        unsigned long begin, end;
        unsigned long flags;
+       int nr_ways;
 
        begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
        end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
                & ~(L1_CACHE_BYTES-1);
+       nr_ways = current_cpu_data.dcache.ways;
 
        local_irq_save(flags);
        jump_to_uncached();
 
-       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
-               unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0);
+       /* If there are too many pages then flush the entire cache */
+       if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
+               begin = CACHE_OC_ADDRESS_ARRAY;
+               end = begin + (nr_ways * current_cpu_data.dcache.way_size);
+
+               for (v = begin; v < end; v += L1_CACHE_BYTES) {
+                       unsigned long data = __raw_readl(v);
+                       if (data & SH_CACHE_UPDATED)
+                               __raw_writel(data & ~SH_CACHE_UPDATED, v);
+               }
+       } else {
                int way;
-               for (way = 0; way < 4; way++) {
-                       unsigned long data =  __raw_readl(addr | (way << 11));
-                       if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
-                               data &= ~SH_CACHE_UPDATED;
-                               __raw_writel(data, addr | (way << 11));
-                       }
+               for (way = 0; way < nr_ways; way++) {
+                       for (v = begin; v < end; v += L1_CACHE_BYTES)
+                               sh2a_flush_oc_line(v, way);
                }
        }
 
        back_to_cached();
        local_irq_restore(flags);
+#endif
 }
 
+/*
+ * Write back the dirty D-caches and invalidate them.
+ */
 static void sh2a__flush_purge_region(void *start, int size)
 {
        unsigned long v;
@@ -58,13 +101,22 @@ static void sh2a__flush_purge_region(void *start, int size)
        jump_to_uncached();
 
        for (v = begin; v < end; v+=L1_CACHE_BYTES) {
-               __raw_writel((v & CACHE_PHYSADDR_MASK),
-                         CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
+#ifdef CONFIG_CACHE_WRITEBACK
+               int way;
+               int nr_ways = current_cpu_data.dcache.ways;
+               for (way = 0; way < nr_ways; way++)
+                       sh2a_flush_oc_line(v, way);
+#endif
+               sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
        }
+
        back_to_cached();
        local_irq_restore(flags);
 }
 
+/*
+ * Invalidate the D-caches, but no write back please
+ */
 static void sh2a__flush_invalidate_region(void *start, int size)
 {
        unsigned long v;
@@ -74,29 +126,25 @@ static void sh2a__flush_invalidate_region(void *start, int size)
        begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
        end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
                & ~(L1_CACHE_BYTES-1);
+
        local_irq_save(flags);
        jump_to_uncached();
 
-#ifdef CONFIG_CACHE_WRITEBACK
-       __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
-       /* I-cache invalidate */
-       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
-               __raw_writel((v & CACHE_PHYSADDR_MASK),
-                         CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
-       }
-#else
-       for (v = begin; v < end; v+=L1_CACHE_BYTES) {
-               __raw_writel((v & CACHE_PHYSADDR_MASK),
-                         CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
-               __raw_writel((v & CACHE_PHYSADDR_MASK),
-                         CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
+       /* If there are too many pages then just blow the cache */
+       if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
+               __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+       } else {
+               for (v = begin; v < end; v += L1_CACHE_BYTES)
+                       sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
        }
-#endif
+
        back_to_cached();
        local_irq_restore(flags);
 }
 
-/* WBack O-Cache and flush I-Cache */
+/*
+ * Write back the range of D-cache, and purge the I-cache.
+ */
 static void sh2a_flush_icache_range(void *args)
 {
        struct flusher_data *data = args;
@@ -107,23 +155,20 @@ static void sh2a_flush_icache_range(void *args)
        start = data->addr1 & ~(L1_CACHE_BYTES-1);
        end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1);
 
+#ifdef CONFIG_CACHE_WRITEBACK
+       sh2a__flush_wback_region((void *)start, end-start);
+#endif
+
        local_irq_save(flags);
        jump_to_uncached();
 
-       for (v = start; v < end; v+=L1_CACHE_BYTES) {
-               unsigned long addr = (v & 0x000007f0);
-               int way;
-               /* O-Cache writeback */
-               for (way = 0; way < 4; way++) {
-                       unsigned long data =  __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
-                       if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
-                               data &= ~SH_CACHE_UPDATED;
-                               __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
-                       }
-               }
-               /* I-Cache invalidate */
-               __raw_writel(addr,
-                         CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008);
+       /* I-Cache invalidate */
+       /* If there are too many pages then just blow the cache */
+       if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
+               __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+       } else {
+               for (v = start; v < end; v += L1_CACHE_BYTES)
+                       sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
        }
 
        back_to_cached();
index 868ea08dff0ba55e29dd8a79e7f34b74b820fcb3..96657992a72eef8f69580cc9cdb12e2c184639ec 100644 (file)
@@ -28,6 +28,7 @@ config SPARC
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select USE_GENERIC_SMP_HELPERS if SMP
+       select GENERIC_PCI_IOMAP
 
 config SPARC32
        def_bool !64BIT
index c2ced21c9dc19a7c284960d6a180f30345e5120f..2006e5d359dfb5f602ab004208ea60d610e15a6d 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
+#include <asm-generic/pci_iomap.h>
 
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
@@ -324,7 +325,6 @@ extern void ioport_unmap(void __iomem *);
 
 /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
 /*
index 9c8965415f0a5187cd550435341029f553bdbfe2..9481e5a6fa90e218ffa2124a0feef91ffd228b4a 100644 (file)
@@ -8,6 +8,7 @@
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
 #include <asm/asi.h>
+#include <asm-generic/pci_iomap.h>
 
 /* PC crapola... */
 #define __SLOW_DOWN_IO do { } while (0)
@@ -514,7 +515,6 @@ extern void ioport_unmap(void __iomem *);
 
 /* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
 static inline int sbus_can_dma_64bit(void)
index 02939abd356cf80e26a0e93b0cba7861f9f7d946..6de7f7bf956abb8ec48dd6eebe8863443feb5393 100644 (file)
 
 #define PCI_IRQ_NONE           0xffffffff
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index 2614d96141c96a970b1d57959f68bff4fa0a3d96..755a4bb6bcd32278e62fbe4afc2977946495231d 100644 (file)
 
 #define PCI_IRQ_NONE           0xffffffff
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index e49b828a2471d57cca8e5aa723acc3a011a9d390..aa42fe30d5b96f0c3f1029274932d7bbbbd3da4d 100644 (file)
@@ -143,10 +143,11 @@ struct sigstack {
 #define SA_ONSTACK     _SV_SSTACK
 #define SA_RESTART     _SV_INTR
 #define SA_ONESHOT     _SV_RESET
-#define SA_NOMASK      0x20u
+#define SA_NODEFER     0x20u
 #define SA_NOCLDWAIT    0x100u
 #define SA_SIGINFO      0x200u
 
+#define SA_NOMASK      SA_NODEFER
 
 #define SIG_BLOCK          0x01        /* for blocking signals */
 #define SIG_UNBLOCK        0x02        /* for unblocking signals */
index f1cf6ef011a724b8f45dbff51dc09002b841637b..c7bec25fdb1c1b5d18d67c6882437c5475354d31 100644 (file)
  */
 void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
 {
+       LIST_HEAD(resources);
        struct pci_bus *root_bus;
 
-       root_bus = pci_scan_bus_parented(&ofdev->dev, 0, info->ops, info);
-       if (root_bus) {
-               root_bus->resource[0] = &info->io_space;
-               root_bus->resource[1] = &info->mem_space;
-               root_bus->resource[2] = NULL;
-
-               /* Init all PCI devices into PCI tree */
-               pci_bus_add_devices(root_bus);
+       pci_add_resource(&resources, &info->io_space);
+       pci_add_resource(&resources, &info->mem_space);
 
+       root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info,
+                                    &resources);
+       if (root_bus) {
                /* Setup IRQs of all devices using custom routines */
                pci_fixup_irqs(pci_common_swizzle, info->map_irq);
 
                /* Assign devices with resources */
                pci_assign_unassigned_resources();
+       } else {
+               pci_free_resource_list(&resources);
        }
 }
 
@@ -83,15 +83,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
        int i, has_io, has_mem;
        u16 cmd;
 
-       /* Generic PCI bus probing sets these to point at
-        * &io{port,mem}_resouce which is wrong for us.
-        */
-       if (pbus->self == NULL) {
-               pbus->resource[0] = &info->io_space;
-               pbus->resource[1] = &info->mem_space;
-               pbus->resource[2] = NULL;
-       }
-
        list_for_each_entry(dev, &pbus->devices, bus_list) {
                /*
                 * We can not rely on that the bootloader has enabled I/O
index 31111e35281e395b98104ef4b57ed0e062398cb0..bb8bc2e519ac03735f79361d7b400eccee08b8ba 100644 (file)
@@ -685,23 +685,25 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
 struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
                                            struct device *parent)
 {
+       LIST_HEAD(resources);
        struct device_node *node = pbm->op->dev.of_node;
        struct pci_bus *bus;
 
        printk("PCI: Scanning PBM %s\n", node->full_name);
 
-       bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
+       pci_add_resource(&resources, &pbm->io_space);
+       pci_add_resource(&resources, &pbm->mem_space);
+       bus = pci_create_root_bus(parent, pbm->pci_first_busno, pbm->pci_ops,
+                                 pbm, &resources);
        if (!bus) {
                printk(KERN_ERR "Failed to create bus for %s\n",
                       node->full_name);
+               pci_free_resource_list(&resources);
                return NULL;
        }
        bus->secondary = pbm->pci_first_busno;
        bus->subordinate = pbm->pci_last_busno;
 
-       bus->resource[0] = &pbm->io_space;
-       bus->resource[1] = &pbm->mem_space;
-
        pci_of_scan_bus(pbm, node, bus);
        pci_bus_add_devices(bus);
        pci_bus_register_of_sysfs(bus);
@@ -711,13 +713,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
 
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
-       struct pci_pbm_info *pbm = pbus->sysdata;
-
-       /* Generic PCI bus probing sets these to point at
-        * &io{port,mem}_resouce which is wrong for us.
-        */
-       pbus->resource[0] = &pbm->io_space;
-       pbus->resource[1] = &pbm->mem_space;
 }
 
 void pcibios_update_irq(struct pci_dev *pdev, int irq)
@@ -1083,6 +1078,11 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
        *end = rp->end - offset;
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
 static int __init pcibios_init(void)
 {
        pci_dfl_cache_line_size = 64 >> 2;
index 9ef37e13a920e28ba99e197dc50dff7b812c5972..c4d42a50ebc06d3f92fdae70aa7d1f1d64a5b6f7 100644 (file)
@@ -18,31 +18,8 @@ void ioport_unmap(void __iomem *addr)
 EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
 
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       /* What? */
-       return NULL;
-}
-
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
        /* nothing to do */
 }
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
index 70a0de46cd1be8e4bc4c193ef3b4d213f89a368f..11270ca22c0a7b880718cd832a3e890f0b69c28f 100644 (file)
@@ -321,6 +321,7 @@ config PCI
        bool "PCI support"
        default y
        select PCI_DOMAINS
+       select GENERIC_PCI_IOMAP
        ---help---
          Enable PCI root complex support, so PCIe endpoint devices can
          be attached to the Tile chip.  Many, but not all, PCI devices
index c9ea1652af03c609f355ec12c456a45e0dd826f3..d2152deb1f3cf6a3bc352d92d445df4157a0924e 100644 (file)
@@ -204,7 +204,8 @@ static inline long ioport_panic(void)
 
 static inline void __iomem *ioport_map(unsigned long port, unsigned int len)
 {
-       return (void __iomem *) ioport_panic();
+       pr_info("ioport_map: mapping IO resources is unsupported on tile.\n");
+       return NULL;
 }
 
 static inline void ioport_unmap(void __iomem *addr)
index 7f03cefed1b92079687a2ca838cd9d700a600a58..5d5a635530bd5ed527eb6387ce3a0170d605e0b0 100644 (file)
@@ -16,6 +16,7 @@
 #define _ASM_TILE_PCI_H
 
 #include <linux/pci.h>
+#include <asm-generic/pci_iomap.h>
 
 /*
  * Structure of a PCI controller (host bridge)
@@ -49,7 +50,6 @@ struct pci_controller {
 int __devinit tile_pci_init(void);
 int __devinit pcibios_init(void);
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
 
 void __devinit pcibios_fixup_bus(struct pci_bus *bus);
@@ -76,13 +76,6 @@ static inline int pcibios_assign_all_busses(void)
        return 1;
 }
 
-/*
- * No special bus mastering setup handling.
- */
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-}
-
 #define PCIBIOS_MIN_MEM                0
 #define PCIBIOS_MIN_IO         0
 
index e00d7179989e24946a20185709224d9afd97f1be..6255f2eab112c9fcae9f5f4cab1d9462a9e12477 100644 (file)
@@ -248,11 +248,11 @@ static void setup_quasi_va_is_pa(void)
 }
 
 
-NORET_TYPE void machine_kexec(struct kimage *image)
+void machine_kexec(struct kimage *image)
 {
        void *reboot_code_buffer;
-       NORET_TYPE void (*rnk)(unsigned long, void *, unsigned long)
-               ATTRIB_NORET;
+       void (*rnk)(unsigned long, void *, unsigned long)
+               __noreturn;
 
        /* Mask all interrupts before starting to reboot. */
        interrupt_mask_set_mask(~0ULL);
index 9d610d3fb11e9ac93c6e17875cff26257fa89e46..a1bb59eecc1850bcd7aedf6f1ec538498e0d1573 100644 (file)
@@ -395,6 +395,11 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
        /* Nothing needs to be done. */
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling. */
+}
+
 /*
  * This can be called from the generic PCI layer, but doesn't need to
  * do anything.
@@ -466,27 +471,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
-       unsigned long start = pci_resource_start(dev, bar);
-       unsigned long len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len)
-               return NULL;
-       if (max && len > max)
-               len = max;
-
-       if (!(flags & IORESOURCE_MEM)) {
-               pr_info("PCI: Trying to map invalid resource %#lx\n", flags);
-               start = 0;
-       }
-
-       return (void __iomem *)start;
-}
-EXPORT_SYMBOL(pci_iomap);
-
-
 /****************************************************************
  *
  * Tile PCI config space read/write routines
index a9234838e8a29826ea947beaef7bf493bba49c40..b37ae706af3ee4e6534dea8872aaef903ac19e0f 100644 (file)
@@ -8,6 +8,7 @@ config UML
        default y
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_CPU_DEVICES
 
 config MMU
        bool
index 942ed6174f1d073e565d52e5dc074c7e84d3b533..eeb8054c7cd84347d242bba052c44cd64a5da5af 100644 (file)
@@ -12,6 +12,7 @@ config UNICORE32
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_FRAME_POINTERS
+       select GENERIC_IOMAP
        help
          UniCore-32 is 32-bit Instruction Set Architecture,
          including a series of low-power-consumption RISC chip
@@ -30,9 +31,6 @@ config GENERIC_CLOCKEVENTS
 config GENERIC_CSUM
        def_bool y
 
-config GENERIC_IOMAP
-       def_bool y
-
 config NO_IOPORT
        bool
 
index 1a5c5a5eb39c8f0f27fa37c4fa526a16c5d9a6f2..adddf6d640771ac88ab0c5b016ad96769cca6a9e 100644 (file)
@@ -37,15 +37,9 @@ extern void __uc32_iounmap(volatile void __iomem *addr);
  */
 #define ioremap(cookie, size)          __uc32_ioremap(cookie, size)
 #define ioremap_cached(cookie, size)   __uc32_ioremap_cached(cookie, size)
+#define ioremap_nocache(cookie, size)  __uc32_ioremap(cookie, size)
 #define iounmap(cookie)                        __uc32_iounmap(cookie)
 
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#undef xlate_dev_mem_ptr
-#define xlate_dev_mem_ptr(p)   __va(p)
-
 #define HAVE_ARCH_PIO_SIZE
 #define PIO_OFFSET             (unsigned int)(PCI_IOBASE)
 #define PIO_MASK               (unsigned int)(IO_SPACE_LIMIT)
index c5b28b45953582106d0c4086588d5a594c2b00ab..dd3867727c3521138436c1a05bf8bd4b4a976ee4 100644 (file)
 #include <asm-generic/pci.h>
 #include <mach/hardware.h> /* for PCIBIOS_MIN_* */
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq, int active)
 {
        /* We don't do dynamic PCI IRQ allocation */
index 4892fbb54ebfd508a4c0738d2df73af2c3bbafae..a8f07fe10cad0e6284c99a6a9155629bf7da9b91 100644 (file)
@@ -309,6 +309,11 @@ char * __devinit pcibios_setup(char *str)
        return str;
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
 /*
  * From arch/i386/kernel/pci-i386.c:
  *
index 37b12a06b499ec0f1c4220aab59fe1473a0026d2..181108b8ecce766d0102b9e12ac070e6510337b0 100644 (file)
@@ -123,7 +123,7 @@ int __init mach_nb0916_init(void)
 
        if (request_irq(gpio_to_irq(GPI_LCD_CASE_OFF),
                &nb0916_lcdcaseoff_handler,
-               IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                "NB0916 lcd case off", NULL) < 0) {
 
                printk(KERN_DEBUG "LCD-Case-OFF IRQ %d not available\n",
@@ -131,7 +131,7 @@ int __init mach_nb0916_init(void)
        }
 
        if (request_irq(gpio_to_irq(GPI_OTP_INT), &nb0916_overheat_handler,
-               IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                "NB0916 overheating protection", NULL) < 0) {
 
                printk(KERN_DEBUG "Overheating Protection IRQ %d not available\n",
index 673d7a89d8fff0fd86573ac9dfede09d456c309c..87adbf5ebfe07cf7547bf3ff553ccf0766665519 100644 (file)
@@ -65,7 +65,7 @@ static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
  */
 static struct resource mem_res[] = {
        {
-               .name = "Kernel text",
+               .name = "Kernel code",
                .start = 0,
                .end = 0,
                .flags = IORESOURCE_MEM
index b163fca56789b2c5e55e86ce00f756f926ce737f..911b549a6df54d007954f287772c529d82e2759d 100644 (file)
@@ -63,10 +63,7 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
        err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
        if (err == 0) {
                sigdelsetmask(&set, ~_BLOCKABLE);
-               spin_lock_irq(&current->sighand->siglock);
-               current->blocked = set;
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+               set_current_blocked(&set);
        }
 
        err |= __get_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00);
@@ -321,6 +318,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
 {
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = current;
+       sigset_t blocked;
        int usig = sig;
        int ret;
 
@@ -372,13 +370,10 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
        /*
         * Block the signal if we were successful.
         */
-       spin_lock_irq(&tsk->sighand->siglock);
-       sigorsets(&tsk->blocked, &tsk->blocked,
-                 &ka->sa.sa_mask);
+       sigorsets(&blocked, &tsk->blocked, &ka->sa.sa_mask);
        if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&tsk->blocked, sig);
-       recalc_sigpending();
-       spin_unlock_irq(&tsk->sighand->siglock);
+               sigaddset(&blocked, sig);
+       set_current_blocked(&blocked);
 
        return 0;
 }
index 080710c092416f2ed6d259e0ef6e3c409149147c..d3824b2ff644b3975588b2220015a8bc17819dac 100644 (file)
@@ -86,7 +86,7 @@ static struct clocksource cksrc_puv3_oscr = {
 
 static struct irqaction puv3_timer_irq = {
        .name           = "ost0",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = puv3_ost0_interrupt,
        .dev_id         = &ckevt_puv3_osmr0,
 };
index 1d2a69dd36d89c32e16cbe19d6062d5da95f4d52..6c14ecd851d0b3ae9d32cbd73ce97419b1cb4a48 100644 (file)
@@ -60,8 +60,12 @@ config X86
        select PERF_EVENTS
        select HAVE_PERF_EVENTS_NMI
        select ANON_INODES
+       select HAVE_ALIGNED_STRUCT_PAGE if SLUB && !M386
+       select HAVE_CMPXCHG_LOCAL if !M386
+       select HAVE_CMPXCHG_DOUBLE
        select HAVE_ARCH_KMEMCHECK
        select HAVE_USER_RETURN_NOTIFIER
+       select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_TEXT_POKE_SMP
        select HAVE_GENERIC_HARDIRQS
@@ -77,6 +81,7 @@ config X86
        select HAVE_BPF_JIT if (X86_64 && NET)
        select CLKEVT_I8253
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select GENERIC_IOMAP
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@ -142,9 +147,6 @@ config NEED_SG_DMA_LENGTH
 config GENERIC_ISA_DMA
        def_bool ISA_DMA_API
 
-config GENERIC_IOMAP
-       def_bool y
-
 config GENERIC_BUG
        def_bool y
        depends on BUG
@@ -421,12 +423,14 @@ config X86_MRST
        depends on PCI
        depends on PCI_GOANY
        depends on X86_IO_APIC
+       select X86_INTEL_MID
+       select SFI
+       select DW_APB_TIMER
        select APB_TIMER
        select I2C
        select SPI
        select INTEL_SCU_IPC
        select X86_PLATFORM_DEVICES
-       select X86_INTEL_MID
        ---help---
          Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin
          Internet Device(MID) platform. Moorestown consists of two chips:
@@ -435,6 +439,26 @@ config X86_MRST
          nor standard legacy replacement devices/features. e.g. Moorestown does
          not contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
 
+config X86_MDFLD
+       bool "Medfield MID platform"
+       depends on PCI
+       depends on PCI_GOANY
+       depends on X86_IO_APIC
+       select X86_INTEL_MID
+       select SFI
+       select DW_APB_TIMER
+       select APB_TIMER
+       select I2C
+       select SPI
+       select INTEL_SCU_IPC
+       select X86_PLATFORM_DEVICES
+       ---help---
+         Medfield is Intel's Low Power Intel Architecture (LPIA) based Moblin
+         Internet Device(MID) platform. 
+         Unlike standard x86 PCs, Medfield does not have many legacy devices
+         nor standard legacy replacement devices/features. e.g. Medfield does
+         not contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
+
 endif
 
 config X86_RDC321X
@@ -632,7 +656,7 @@ config X86_SUMMIT_NUMA
 
 config X86_CYCLONE_TIMER
        def_bool y
-       depends on X86_32_NON_STANDARD
+       depends on X86_SUMMIT
 
 source "arch/x86/Kconfig.cpu"
 
@@ -660,9 +684,10 @@ config HPET_EMULATE_RTC
        depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y)
 
 config APB_TIMER
-       def_bool y if MRST
-       prompt "Langwell APB Timer Support" if X86_MRST
+       def_bool y if X86_INTEL_MID
+       prompt "Intel MID APB Timer Support" if X86_INTEL_MID
        select DW_APB_TIMER
+       depends on X86_INTEL_MID && SFI
        help
          APB timer is the replacement for 8254, HPET on X86 MID platforms.
          The APBT provides a stable time base on SMP
@@ -1490,6 +1515,13 @@ config EFI
          resultant kernel should continue to boot on existing non-EFI
          platforms.
 
+config EFI_STUB
+       bool "EFI stub support"
+       depends on EFI
+       ---help---
+          This kernel feature allows a bzImage to be loaded directly
+         by EFI firmware without the use of a bootloader.
+
 config SECCOMP
        def_bool y
        prompt "Enable seccomp to safely compute untrusted bytecode"
index e3ca7e0d858c9203fe787244b6022193c7bc7769..3c57033e22118f2ce7771d10fa8305193c94af20 100644 (file)
@@ -309,12 +309,6 @@ config X86_INTERNODE_CACHE_SHIFT
 config X86_CMPXCHG
        def_bool X86_64 || (X86_32 && !M386)
 
-config CMPXCHG_LOCAL
-       def_bool X86_64 || (X86_32 && !M386)
-
-config CMPXCHG_DOUBLE
-       def_bool y
-
 config X86_L1_CACHE_SHIFT
        int
        default "7" if MPENTIUM4 || MPSC
index bf56e1793272d70fdbf4be7b3911f87410e03f9b..e46c2147397f56ef25896f58139190dd9cb40899 100644 (file)
@@ -43,9 +43,9 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
-config EARLY_PRINTK_MRST
-       bool "Early printk for MRST platform support"
-       depends on EARLY_PRINTK && X86_MRST
+config EARLY_PRINTK_INTEL_MID
+       bool "Early printk for Intel MID platform support"
+       depends on EARLY_PRINTK && X86_INTEL_MID
 
 config EARLY_PRINTK_DBGP
        bool "Early printk via EHCI debug port"
@@ -63,8 +63,11 @@ config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL
        ---help---
-         This option will cause messages to be printed if free stack space
-         drops below a certain limit.
+         Say Y here if you want to check the overflows of kernel, IRQ
+         and exception stacks. This option will cause messages of the
+         stacks in detail when free stack space drops below a certain
+         limit.
+         If in doubt, say "N".
 
 config X86_PTDUMP
        bool "Export kernel pagetable layout to userspace via debugfs"
@@ -284,4 +287,16 @@ config DEBUG_STRICT_USER_COPY_CHECKS
 
          If unsure, or if you run an older (pre 4.4) gcc, say N.
 
+config DEBUG_NMI_SELFTEST
+       bool "NMI Selftest"
+       depends on DEBUG_KERNEL && X86_LOCAL_APIC
+       ---help---
+         Enabling this option turns on a quick NMI selftest to verify
+         that the NMI behaves correctly.
+
+         This might help diagnose strange hangs that rely on NMI to
+         function properly.
+
+         If unsure, say N.
+
 endmenu
index 09664efb9ceee4b128457f56d5fb72cb575d0ce4..b123b9a8f5b311232592f476d13ae093615b6644 100644 (file)
@@ -23,7 +23,15 @@ LDFLAGS_vmlinux := -T
 
 hostprogs-y    := mkpiggy
 
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o $(obj)/piggy.o FORCE
+VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
+       $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
+       $(obj)/piggy.o
+
+ifeq ($(CONFIG_EFI_STUB), y)
+       VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
+endif
+
+$(obj)/vmlinux: $(VMLINUX_OBJS) FORCE
        $(call if_changed,ld)
        @:
 
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
new file mode 100644 (file)
index 0000000..fec216f
--- /dev/null
@@ -0,0 +1,1022 @@
+/* -----------------------------------------------------------------------
+ *
+ *   Copyright 2011 Intel Corporation; author Matt Fleming
+ *
+ *   This file is part of the Linux kernel, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+
+#include "eboot.h"
+
+static efi_system_table_t *sys_table;
+
+static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size,
+                             unsigned long *desc_size)
+{
+       efi_memory_desc_t *m = NULL;
+       efi_status_t status;
+       unsigned long key;
+       u32 desc_version;
+
+       *map_size = sizeof(*m) * 32;
+again:
+       /*
+        * Add an additional efi_memory_desc_t because we're doing an
+        * allocation which may be in a new descriptor region.
+        */
+       *map_size += sizeof(*m);
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, *map_size, (void **)&m);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size,
+                               m, &key, desc_size, &desc_version);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               efi_call_phys1(sys_table->boottime->free_pool, m);
+               goto again;
+       }
+
+       if (status != EFI_SUCCESS)
+               efi_call_phys1(sys_table->boottime->free_pool, m);
+
+fail:
+       *map = m;
+       return status;
+}
+
+/*
+ * Allocate at the highest possible address that is not above 'max'.
+ */
+static efi_status_t high_alloc(unsigned long size, unsigned long align,
+                             unsigned long *addr, unsigned long max)
+{
+       unsigned long map_size, desc_size;
+       efi_memory_desc_t *map;
+       efi_status_t status;
+       unsigned long nr_pages;
+       u64 max_addr = 0;
+       int i;
+
+       status = __get_map(&map, &map_size, &desc_size);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+again:
+       for (i = 0; i < map_size / desc_size; i++) {
+               efi_memory_desc_t *desc;
+               unsigned long m = (unsigned long)map;
+               u64 start, end;
+
+               desc = (efi_memory_desc_t *)(m + (i * desc_size));
+               if (desc->type != EFI_CONVENTIONAL_MEMORY)
+                       continue;
+
+               if (desc->num_pages < nr_pages)
+                       continue;
+
+               start = desc->phys_addr;
+               end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
+
+               if ((start + size) > end || (start + size) > max)
+                       continue;
+
+               if (end - size > max)
+                       end = max;
+
+               if (round_down(end - size, align) < start)
+                       continue;
+
+               start = round_down(end - size, align);
+
+               /*
+                * Don't allocate at 0x0. It will confuse code that
+                * checks pointers against NULL.
+                */
+               if (start == 0x0)
+                       continue;
+
+               if (start > max_addr)
+                       max_addr = start;
+       }
+
+       if (!max_addr)
+               status = EFI_NOT_FOUND;
+       else {
+               status = efi_call_phys4(sys_table->boottime->allocate_pages,
+                                       EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+                                       nr_pages, &max_addr);
+               if (status != EFI_SUCCESS) {
+                       max = max_addr;
+                       max_addr = 0;
+                       goto again;
+               }
+
+               *addr = max_addr;
+       }
+
+free_pool:
+       efi_call_phys1(sys_table->boottime->free_pool, map);
+
+fail:
+       return status;
+}
+
+/*
+ * Allocate at the lowest possible address.
+ */
+static efi_status_t low_alloc(unsigned long size, unsigned long align,
+                             unsigned long *addr)
+{
+       unsigned long map_size, desc_size;
+       efi_memory_desc_t *map;
+       efi_status_t status;
+       unsigned long nr_pages;
+       int i;
+
+       status = __get_map(&map, &map_size, &desc_size);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+       for (i = 0; i < map_size / desc_size; i++) {
+               efi_memory_desc_t *desc;
+               unsigned long m = (unsigned long)map;
+               u64 start, end;
+
+               desc = (efi_memory_desc_t *)(m + (i * desc_size));
+
+               if (desc->type != EFI_CONVENTIONAL_MEMORY)
+                       continue;
+
+               if (desc->num_pages < nr_pages)
+                       continue;
+
+               start = desc->phys_addr;
+               end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT);
+
+               /*
+                * Don't allocate at 0x0. It will confuse code that
+                * checks pointers against NULL. Skip the first 8
+                * bytes so we start at a nice even number.
+                */
+               if (start == 0x0)
+                       start += 8;
+
+               start = round_up(start, align);
+               if ((start + size) > end)
+                       continue;
+
+               status = efi_call_phys4(sys_table->boottime->allocate_pages,
+                                       EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+                                       nr_pages, &start);
+               if (status == EFI_SUCCESS) {
+                       *addr = start;
+                       break;
+               }
+       }
+
+       if (i == map_size / desc_size)
+               status = EFI_NOT_FOUND;
+
+free_pool:
+       efi_call_phys1(sys_table->boottime->free_pool, map);
+fail:
+       return status;
+}
+
+static void low_free(unsigned long size, unsigned long addr)
+{
+       unsigned long nr_pages;
+
+       nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+       efi_call_phys2(sys_table->boottime->free_pages, addr, size);
+}
+
+static void find_bits(unsigned long mask, u8 *pos, u8 *size)
+{
+       u8 first, len;
+
+       first = 0;
+       len = 0;
+
+       if (mask) {
+               while (!(mask & 0x1)) {
+                       mask = mask >> 1;
+                       first++;
+               }
+
+               while (mask & 0x1) {
+                       mask = mask >> 1;
+                       len++;
+               }
+       }
+
+       *pos = first;
+       *size = len;
+}
+
+/*
+ * See if we have Graphics Output Protocol
+ */
+static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
+                             unsigned long size)
+{
+       struct efi_graphics_output_protocol *gop, *first_gop;
+       struct efi_pixel_bitmask pixel_info;
+       unsigned long nr_gops;
+       efi_status_t status;
+       void **gop_handle;
+       u16 width, height;
+       u32 fb_base, fb_size;
+       u32 pixels_per_scan_line;
+       int pixel_format;
+       int i;
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, size, &gop_handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_phys5(sys_table->boottime->locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL, proto,
+                               NULL, &size, gop_handle);
+       if (status != EFI_SUCCESS)
+               goto free_handle;
+
+       first_gop = NULL;
+
+       nr_gops = size / sizeof(void *);
+       for (i = 0; i < nr_gops; i++) {
+               struct efi_graphics_output_mode_info *info;
+               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+               void *pciio;
+               void *h = gop_handle[i];
+
+               status = efi_call_phys3(sys_table->boottime->handle_protocol,
+                                       h, proto, &gop);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               efi_call_phys3(sys_table->boottime->handle_protocol,
+                              h, &pciio_proto, &pciio);
+
+               status = efi_call_phys4(gop->query_mode, gop,
+                                       gop->mode->mode, &size, &info);
+               if (status == EFI_SUCCESS && (!first_gop || pciio)) {
+                       /*
+                        * Apple provide GOPs that are not backed by
+                        * real hardware (they're used to handle
+                        * multiple displays). The workaround is to
+                        * search for a GOP implementing the PCIIO
+                        * protocol, and if one isn't found, to just
+                        * fallback to the first GOP.
+                        */
+                       width = info->horizontal_resolution;
+                       height = info->vertical_resolution;
+                       fb_base = gop->mode->frame_buffer_base;
+                       fb_size = gop->mode->frame_buffer_size;
+                       pixel_format = info->pixel_format;
+                       pixel_info = info->pixel_information;
+                       pixels_per_scan_line = info->pixels_per_scan_line;
+
+                       /*
+                        * Once we've found a GOP supporting PCIIO,
+                        * don't bother looking any further.
+                        */
+                       if (pciio)
+                               break;
+
+                       first_gop = gop;
+               }
+       }
+
+       /* Did we find any GOPs? */
+       if (!first_gop)
+               goto free_handle;
+
+       /* EFI framebuffer */
+       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+       si->lfb_width = width;
+       si->lfb_height = height;
+       si->lfb_base = fb_base;
+       si->lfb_size = fb_size;
+       si->pages = 1;
+
+       if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
+               si->lfb_depth = 32;
+               si->lfb_linelength = pixels_per_scan_line * 4;
+               si->red_size = 8;
+               si->red_pos = 0;
+               si->green_size = 8;
+               si->green_pos = 8;
+               si->blue_size = 8;
+               si->blue_pos = 16;
+               si->rsvd_size = 8;
+               si->rsvd_pos = 24;
+       } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
+               si->lfb_depth = 32;
+               si->lfb_linelength = pixels_per_scan_line * 4;
+               si->red_size = 8;
+               si->red_pos = 16;
+               si->green_size = 8;
+               si->green_pos = 8;
+               si->blue_size = 8;
+               si->blue_pos = 0;
+               si->rsvd_size = 8;
+               si->rsvd_pos = 24;
+       } else if (pixel_format == PIXEL_BIT_MASK) {
+               find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
+               find_bits(pixel_info.green_mask, &si->green_pos,
+                         &si->green_size);
+               find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
+               find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
+                         &si->rsvd_size);
+               si->lfb_depth = si->red_size + si->green_size +
+                       si->blue_size + si->rsvd_size;
+               si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
+       } else {
+               si->lfb_depth = 4;
+               si->lfb_linelength = si->lfb_width / 2;
+               si->red_size = 0;
+               si->red_pos = 0;
+               si->green_size = 0;
+               si->green_pos = 0;
+               si->blue_size = 0;
+               si->blue_pos = 0;
+               si->rsvd_size = 0;
+               si->rsvd_pos = 0;
+       }
+
+free_handle:
+       efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
+       return status;
+}
+
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
+static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
+                             unsigned long size)
+{
+       struct efi_uga_draw_protocol *uga, *first_uga;
+       unsigned long nr_ugas;
+       efi_status_t status;
+       u32 width, height;
+       void **uga_handle = NULL;
+       int i;
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, size, &uga_handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_phys5(sys_table->boottime->locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL, uga_proto,
+                               NULL, &size, uga_handle);
+       if (status != EFI_SUCCESS)
+               goto free_handle;
+
+       first_uga = NULL;
+
+       nr_ugas = size / sizeof(void *);
+       for (i = 0; i < nr_ugas; i++) {
+               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
+               void *handle = uga_handle[i];
+               u32 w, h, depth, refresh;
+               void *pciio;
+
+               status = efi_call_phys3(sys_table->boottime->handle_protocol,
+                                       handle, uga_proto, &uga);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               efi_call_phys3(sys_table->boottime->handle_protocol,
+                              handle, &pciio_proto, &pciio);
+
+               status = efi_call_phys5(uga->get_mode, uga, &w, &h,
+                                       &depth, &refresh);
+               if (status == EFI_SUCCESS && (!first_uga || pciio)) {
+                       width = w;
+                       height = h;
+
+                       /*
+                        * Once we've found a UGA supporting PCIIO,
+                        * don't bother looking any further.
+                        */
+                       if (pciio)
+                               break;
+
+                       first_uga = uga;
+               }
+       }
+
+       if (!first_uga)
+               goto free_handle;
+
+       /* EFI framebuffer */
+       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+       si->lfb_depth = 32;
+       si->lfb_width = width;
+       si->lfb_height = height;
+
+       si->red_size = 8;
+       si->red_pos = 16;
+       si->green_size = 8;
+       si->green_pos = 8;
+       si->blue_size = 8;
+       si->blue_pos = 0;
+       si->rsvd_size = 8;
+       si->rsvd_pos = 24;
+
+
+free_handle:
+       efi_call_phys1(sys_table->boottime->free_pool, uga_handle);
+       return status;
+}
+
+void setup_graphics(struct boot_params *boot_params)
+{
+       efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+       struct screen_info *si;
+       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+       efi_status_t status;
+       unsigned long size;
+       void **gop_handle = NULL;
+       void **uga_handle = NULL;
+
+       si = &boot_params->screen_info;
+       memset(si, 0, sizeof(*si));
+
+       size = 0;
+       status = efi_call_phys5(sys_table->boottime->locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL, &graphics_proto,
+                               NULL, &size, gop_handle);
+       if (status == EFI_BUFFER_TOO_SMALL)
+               status = setup_gop(si, &graphics_proto, size);
+
+       if (status != EFI_SUCCESS) {
+               size = 0;
+               status = efi_call_phys5(sys_table->boottime->locate_handle,
+                                       EFI_LOCATE_BY_PROTOCOL, &uga_proto,
+                                       NULL, &size, uga_handle);
+               if (status == EFI_BUFFER_TOO_SMALL)
+                       setup_uga(si, &uga_proto, size);
+       }
+}
+
+struct initrd {
+       efi_file_handle_t *handle;
+       u64 size;
+};
+
+/*
+ * Check the cmdline for a LILO-style initrd= arguments.
+ *
+ * We only support loading an initrd from the same filesystem as the
+ * kernel image.
+ */
+static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
+                                   struct setup_header *hdr)
+{
+       struct initrd *initrds;
+       unsigned long initrd_addr;
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       u64 initrd_total;
+       efi_file_io_interface_t *io;
+       efi_file_handle_t *fh;
+       efi_status_t status;
+       int nr_initrds;
+       char *str;
+       int i, j, k;
+
+       initrd_addr = 0;
+       initrd_total = 0;
+
+       str = (char *)(unsigned long)hdr->cmd_line_ptr;
+
+       j = 0;                  /* See close_handles */
+
+       if (!str || !*str)
+               return EFI_SUCCESS;
+
+       for (nr_initrds = 0; *str; nr_initrds++) {
+               str = strstr(str, "initrd=");
+               if (!str)
+                       break;
+
+               str += 7;
+
+               /* Skip any leading slashes */
+               while (*str == '/' || *str == '\\')
+                       str++;
+
+               while (*str && *str != ' ' && *str != '\n')
+                       str++;
+       }
+
+       if (!nr_initrds)
+               return EFI_SUCCESS;
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA,
+                               nr_initrds * sizeof(*initrds),
+                               &initrds);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       str = (char *)(unsigned long)hdr->cmd_line_ptr;
+       for (i = 0; i < nr_initrds; i++) {
+               struct initrd *initrd;
+               efi_file_handle_t *h;
+               efi_file_info_t *info;
+               efi_char16_t filename[256];
+               unsigned long info_sz;
+               efi_guid_t info_guid = EFI_FILE_INFO_ID;
+               efi_char16_t *p;
+               u64 file_sz;
+
+               str = strstr(str, "initrd=");
+               if (!str)
+                       break;
+
+               str += 7;
+
+               initrd = &initrds[i];
+               p = filename;
+
+               /* Skip any leading slashes */
+               while (*str == '/' || *str == '\\')
+                       str++;
+
+               while (*str && *str != ' ' && *str != '\n') {
+                       if (p >= filename + sizeof(filename))
+                               break;
+
+                       *p++ = *str++;
+               }
+
+               *p = '\0';
+
+               /* Only open the volume once. */
+               if (!i) {
+                       efi_boot_services_t *boottime;
+
+                       boottime = sys_table->boottime;
+
+                       status = efi_call_phys3(boottime->handle_protocol,
+                                       image->device_handle, &fs_proto, &io);
+                       if (status != EFI_SUCCESS)
+                               goto free_initrds;
+
+                       status = efi_call_phys2(io->open_volume, io, &fh);
+                       if (status != EFI_SUCCESS)
+                               goto free_initrds;
+               }
+
+               status = efi_call_phys5(fh->open, fh, &h, filename,
+                                       EFI_FILE_MODE_READ, (u64)0);
+               if (status != EFI_SUCCESS)
+                       goto close_handles;
+
+               initrd->handle = h;
+
+               info_sz = 0;
+               status = efi_call_phys4(h->get_info, h, &info_guid,
+                                       &info_sz, NULL);
+               if (status != EFI_BUFFER_TOO_SMALL)
+                       goto close_handles;
+
+grow:
+               status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                                       EFI_LOADER_DATA, info_sz, &info);
+               if (status != EFI_SUCCESS)
+                       goto close_handles;
+
+               status = efi_call_phys4(h->get_info, h, &info_guid,
+                                       &info_sz, info);
+               if (status == EFI_BUFFER_TOO_SMALL) {
+                       efi_call_phys1(sys_table->boottime->free_pool, info);
+                       goto grow;
+               }
+
+               file_sz = info->file_size;
+               efi_call_phys1(sys_table->boottime->free_pool, info);
+
+               if (status != EFI_SUCCESS)
+                       goto close_handles;
+
+               initrd->size = file_sz;
+               initrd_total += file_sz;
+       }
+
+       if (initrd_total) {
+               unsigned long addr;
+
+               /*
+                * Multiple initrd's need to be at consecutive
+                * addresses in memory, so allocate enough memory for
+                * all the initrd's.
+                */
+               status = high_alloc(initrd_total, 0x1000,
+                                  &initrd_addr, hdr->initrd_addr_max);
+               if (status != EFI_SUCCESS)
+                       goto close_handles;
+
+               /* We've run out of free low memory. */
+               if (initrd_addr > hdr->initrd_addr_max) {
+                       status = EFI_INVALID_PARAMETER;
+                       goto free_initrd_total;
+               }
+
+               addr = initrd_addr;
+               for (j = 0; j < nr_initrds; j++) {
+                       u64 size;
+
+                       size = initrds[j].size;
+                       while (size) {
+                               u64 chunksize;
+                               if (size > EFI_READ_CHUNK_SIZE)
+                                       chunksize = EFI_READ_CHUNK_SIZE;
+                               else
+                                       chunksize = size;
+                               status = efi_call_phys3(fh->read,
+                                                       initrds[j].handle,
+                                                       &chunksize, addr);
+                               if (status != EFI_SUCCESS)
+                                       goto free_initrd_total;
+                               addr += chunksize;
+                               size -= chunksize;
+                       }
+
+                       efi_call_phys1(fh->close, initrds[j].handle);
+               }
+
+       }
+
+       efi_call_phys1(sys_table->boottime->free_pool, initrds);
+
+       hdr->ramdisk_image = initrd_addr;
+       hdr->ramdisk_size = initrd_total;
+
+       return status;
+
+free_initrd_total:
+       low_free(initrd_total, initrd_addr);
+
+close_handles:
+       for (k = j; k < nr_initrds; k++)
+               efi_call_phys1(fh->close, initrds[k].handle);
+free_initrds:
+       efi_call_phys1(sys_table->boottime->free_pool, initrds);
+fail:
+       hdr->ramdisk_image = 0;
+       hdr->ramdisk_size = 0;
+
+       return status;
+}
+
+/*
+ * Because the x86 boot code expects to be passed a boot_params we
+ * need to create one ourselves (usually the bootloader would create
+ * one for us).
+ */
+static efi_status_t make_boot_params(struct boot_params *boot_params,
+                                    efi_loaded_image_t *image,
+                                    void *handle)
+{
+       struct efi_info *efi = &boot_params->efi_info;
+       struct apm_bios_info *bi = &boot_params->apm_bios_info;
+       struct sys_desc_table *sdt = &boot_params->sys_desc_table;
+       struct e820entry *e820_map = &boot_params->e820_map[0];
+       struct e820entry *prev = NULL;
+       struct setup_header *hdr = &boot_params->hdr;
+       unsigned long size, key, desc_size, _size;
+       efi_memory_desc_t *mem_map;
+       void *options = image->load_options;
+       u32 load_options_size = image->load_options_size / 2; /* ASCII */
+       int options_size = 0;
+       efi_status_t status;
+       __u32 desc_version;
+       unsigned long cmdline;
+       u8 nr_entries;
+       u16 *s2;
+       u8 *s1;
+       int i;
+
+       hdr->type_of_loader = 0x21;
+
+       /* Convert unicode cmdline to ascii */
+       cmdline = 0;
+       s2 = (u16 *)options;
+
+       if (s2) {
+               while (*s2 && *s2 != '\n' && options_size < load_options_size) {
+                       s2++;
+                       options_size++;
+               }
+
+               if (options_size) {
+                       if (options_size > hdr->cmdline_size)
+                               options_size = hdr->cmdline_size;
+
+                       options_size++; /* NUL termination */
+
+                       status = low_alloc(options_size, 1, &cmdline);
+                       if (status != EFI_SUCCESS)
+                               goto fail;
+
+                       s1 = (u8 *)(unsigned long)cmdline;
+                       s2 = (u16 *)options;
+
+                       for (i = 0; i < options_size - 1; i++)
+                               *s1++ = *s2++;
+
+                       *s1 = '\0';
+               }
+       }
+
+       hdr->cmd_line_ptr = cmdline;
+
+       hdr->ramdisk_image = 0;
+       hdr->ramdisk_size = 0;
+
+       status = handle_ramdisks(image, hdr);
+       if (status != EFI_SUCCESS)
+               goto free_cmdline;
+
+       setup_graphics(boot_params);
+
+       /* Clear APM BIOS info */
+       memset(bi, 0, sizeof(*bi));
+
+       memset(sdt, 0, sizeof(*sdt));
+
+       memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
+
+       size = sizeof(*mem_map) * 32;
+
+again:
+       size += sizeof(*mem_map);
+       _size = size;
+       status = low_alloc(size, 1, (unsigned long *)&mem_map);
+       if (status != EFI_SUCCESS)
+               goto free_cmdline;
+
+       status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,
+                               mem_map, &key, &desc_size, &desc_version);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               low_free(_size, (unsigned long)mem_map);
+               goto again;
+       }
+
+       if (status != EFI_SUCCESS)
+               goto free_mem_map;
+
+       efi->efi_systab = (unsigned long)sys_table;
+       efi->efi_memdesc_size = desc_size;
+       efi->efi_memdesc_version = desc_version;
+       efi->efi_memmap = (unsigned long)mem_map;
+       efi->efi_memmap_size = size;
+
+#ifdef CONFIG_X86_64
+       efi->efi_systab_hi = (unsigned long)sys_table >> 32;
+       efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
+#endif
+
+       /* Might as well exit boot services now */
+       status = efi_call_phys2(sys_table->boottime->exit_boot_services,
+                               handle, key);
+       if (status != EFI_SUCCESS)
+               goto free_mem_map;
+
+       /* Historic? */
+       boot_params->alt_mem_k = 32 * 1024;
+
+       /*
+        * Convert the EFI memory map to E820.
+        */
+       nr_entries = 0;
+       for (i = 0; i < size / desc_size; i++) {
+               efi_memory_desc_t *d;
+               unsigned int e820_type = 0;
+               unsigned long m = (unsigned long)mem_map;
+
+               d = (efi_memory_desc_t *)(m + (i * desc_size));
+               switch (d->type) {
+               case EFI_RESERVED_TYPE:
+               case EFI_RUNTIME_SERVICES_CODE:
+               case EFI_RUNTIME_SERVICES_DATA:
+               case EFI_MEMORY_MAPPED_IO:
+               case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+               case EFI_PAL_CODE:
+                       e820_type = E820_RESERVED;
+                       break;
+
+               case EFI_UNUSABLE_MEMORY:
+                       e820_type = E820_UNUSABLE;
+                       break;
+
+               case EFI_ACPI_RECLAIM_MEMORY:
+                       e820_type = E820_ACPI;
+                       break;
+
+               case EFI_LOADER_CODE:
+               case EFI_LOADER_DATA:
+               case EFI_BOOT_SERVICES_CODE:
+               case EFI_BOOT_SERVICES_DATA:
+               case EFI_CONVENTIONAL_MEMORY:
+                       e820_type = E820_RAM;
+                       break;
+
+               case EFI_ACPI_MEMORY_NVS:
+                       e820_type = E820_NVS;
+                       break;
+
+               default:
+                       continue;
+               }
+
+               /* Merge adjacent mappings */
+               if (prev && prev->type == e820_type &&
+                   (prev->addr + prev->size) == d->phys_addr)
+                       prev->size += d->num_pages << 12;
+               else {
+                       e820_map->addr = d->phys_addr;
+                       e820_map->size = d->num_pages << 12;
+                       e820_map->type = e820_type;
+                       prev = e820_map++;
+                       nr_entries++;
+               }
+       }
+
+       boot_params->e820_entries = nr_entries;
+
+       return EFI_SUCCESS;
+
+free_mem_map:
+       low_free(_size, (unsigned long)mem_map);
+free_cmdline:
+       if (options_size)
+               low_free(options_size, hdr->cmd_line_ptr);
+fail:
+       return status;
+}
+
+/*
+ * On success we return a pointer to a boot_params structure, and NULL
+ * on failure.
+ */
+struct boot_params *efi_main(void *handle, efi_system_table_t *_table)
+{
+       struct boot_params *boot_params;
+       unsigned long start, nr_pages;
+       struct desc_ptr *gdt, *idt;
+       efi_loaded_image_t *image;
+       struct setup_header *hdr;
+       efi_status_t status;
+       efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
+       struct desc_struct *desc;
+
+       sys_table = _table;
+
+       /* Check if we were booted by the EFI firmware */
+       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+               goto fail;
+
+       status = efi_call_phys3(sys_table->boottime->handle_protocol,
+                               handle, &proto, (void *)&image);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       status = low_alloc(0x4000, 1, (unsigned long *)&boot_params);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       memset(boot_params, 0x0, 0x4000);
+
+       /* Copy first two sectors to boot_params */
+       memcpy(boot_params, image->image_base, 1024);
+
+       hdr = &boot_params->hdr;
+
+       /*
+        * The EFI firmware loader could have placed the kernel image
+        * anywhere in memory, but the kernel has various restrictions
+        * on the max physical address it can run at. Attempt to move
+        * the kernel to boot_params.pref_address, or as low as
+        * possible.
+        */
+       start = hdr->pref_address;
+       nr_pages = round_up(hdr->init_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+       status = efi_call_phys4(sys_table->boottime->allocate_pages,
+                               EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
+                               nr_pages, &start);
+       if (status != EFI_SUCCESS) {
+               status = low_alloc(hdr->init_size, hdr->kernel_alignment,
+                                  &start);
+               if (status != EFI_SUCCESS)
+                       goto fail;
+       }
+
+       hdr->code32_start = (__u32)start;
+       hdr->pref_address = (__u64)(unsigned long)image->image_base;
+
+       memcpy((void *)start, image->image_base, image->image_size);
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, sizeof(*gdt),
+                               (void **)&gdt);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       gdt->size = 0x800;
+       status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       status = efi_call_phys3(sys_table->boottime->allocate_pool,
+                               EFI_LOADER_DATA, sizeof(*idt),
+                               (void **)&idt);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       idt->size = 0;
+       idt->address = 0;
+
+       status = make_boot_params(boot_params, image, handle);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       memset((char *)gdt->address, 0x0, gdt->size);
+       desc = (struct desc_struct *)gdt->address;
+
+       /* The first GDT is a dummy and the second is unused. */
+       desc += 2;
+
+       desc->limit0 = 0xffff;
+       desc->base0 = 0x0000;
+       desc->base1 = 0x0000;
+       desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
+       desc->s = DESC_TYPE_CODE_DATA;
+       desc->dpl = 0;
+       desc->p = 1;
+       desc->limit = 0xf;
+       desc->avl = 0;
+       desc->l = 0;
+       desc->d = SEG_OP_SIZE_32BIT;
+       desc->g = SEG_GRANULARITY_4KB;
+       desc->base2 = 0x00;
+
+       desc++;
+       desc->limit0 = 0xffff;
+       desc->base0 = 0x0000;
+       desc->base1 = 0x0000;
+       desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
+       desc->s = DESC_TYPE_CODE_DATA;
+       desc->dpl = 0;
+       desc->p = 1;
+       desc->limit = 0xf;
+       desc->avl = 0;
+       desc->l = 0;
+       desc->d = SEG_OP_SIZE_32BIT;
+       desc->g = SEG_GRANULARITY_4KB;
+       desc->base2 = 0x00;
+
+#ifdef CONFIG_X86_64
+       /* Task segment value */
+       desc++;
+       desc->limit0 = 0x0000;
+       desc->base0 = 0x0000;
+       desc->base1 = 0x0000;
+       desc->type = SEG_TYPE_TSS;
+       desc->s = 0;
+       desc->dpl = 0;
+       desc->p = 1;
+       desc->limit = 0x0;
+       desc->avl = 0;
+       desc->l = 0;
+       desc->d = 0;
+       desc->g = SEG_GRANULARITY_4KB;
+       desc->base2 = 0x00;
+#endif /* CONFIG_X86_64 */
+
+       asm volatile ("lidt %0" : : "m" (*idt));
+       asm volatile ("lgdt %0" : : "m" (*gdt));
+
+       asm volatile("cli");
+
+       return boot_params;
+fail:
+       return NULL;
+}
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
new file mode 100644 (file)
index 0000000..3925166
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef BOOT_COMPRESSED_EBOOT_H
+#define BOOT_COMPRESSED_EBOOT_H
+
+#define SEG_TYPE_DATA          (0 << 3)
+#define SEG_TYPE_READ_WRITE    (1 << 1)
+#define SEG_TYPE_CODE          (1 << 3)
+#define SEG_TYPE_EXEC_READ     (1 << 1)
+#define SEG_TYPE_TSS           ((1 << 3) | (1 << 0))
+#define SEG_OP_SIZE_32BIT      (1 << 0)
+#define SEG_GRANULARITY_4KB    (1 << 0)
+
+#define DESC_TYPE_CODE_DATA    (1 << 0)
+
+#define EFI_PAGE_SIZE          (1UL << EFI_PAGE_SHIFT)
+#define EFI_READ_CHUNK_SIZE    (1024 * 1024)
+
+#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR              0
+#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR              1
+#define PIXEL_BIT_MASK                                 2
+#define PIXEL_BLT_ONLY                                 3
+#define PIXEL_FORMAT_MAX                               4
+
+struct efi_pixel_bitmask {
+       u32 red_mask;
+       u32 green_mask;
+       u32 blue_mask;
+       u32 reserved_mask;
+};
+
+struct efi_graphics_output_mode_info {
+       u32 version;
+       u32 horizontal_resolution;
+       u32 vertical_resolution;
+       int pixel_format;
+       struct efi_pixel_bitmask pixel_information;
+       u32 pixels_per_scan_line;
+} __packed;
+
+struct efi_graphics_output_protocol_mode {
+       u32 max_mode;
+       u32 mode;
+       unsigned long info;
+       unsigned long size_of_info;
+       u64 frame_buffer_base;
+       unsigned long frame_buffer_size;
+} __packed;
+
+struct efi_graphics_output_protocol {
+       void *query_mode;
+       unsigned long set_mode;
+       unsigned long blt;
+       struct efi_graphics_output_protocol_mode *mode;
+};
+
+struct efi_uga_draw_protocol {
+       void *get_mode;
+       void *set_mode;
+       void *blt;
+};
+
+#endif /* BOOT_COMPRESSED_EBOOT_H */
diff --git a/arch/x86/boot/compressed/efi_stub_32.S b/arch/x86/boot/compressed/efi_stub_32.S
new file mode 100644 (file)
index 0000000..a53440e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * EFI call stub for IA32.
+ *
+ * This stub allows us to make EFI calls in physical mode with interrupts
+ * turned off. Note that this implementation is different from the one in
+ * arch/x86/platform/efi/efi_stub_32.S because we're _already_ in physical
+ * mode at this point.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+/*
+ * efi_call_phys(void *, ...) is a function with variable parameters.
+ * All the callers of this function assure that all the parameters are 4-bytes.
+ */
+
+/*
+ * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
+ * So we'd better save all of them at the beginning of this function and restore
+ * at the end no matter how many we use, because we can not assure EFI runtime
+ * service functions will comply with gcc calling convention, too.
+ */
+
+.text
+ENTRY(efi_call_phys)
+       /*
+        * 0. The function can only be called in Linux kernel. So CS has been
+        * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
+        * the values of these registers are the same. And, the corresponding
+        * GDT entries are identical. So I will do nothing about segment reg
+        * and GDT, but change GDT base register in prelog and epilog.
+        */
+
+       /*
+        * 1. Because we haven't been relocated by this point we need to
+        * use relative addressing.
+        */
+       call    1f
+1:     popl    %edx
+       subl    $1b, %edx
+
+       /*
+        * 2. Now on the top of stack is the return
+        * address in the caller of efi_call_phys(), then parameter 1,
+        * parameter 2, ..., param n. To make things easy, we save the return
+        * address of efi_call_phys in a global variable.
+        */
+       popl    %ecx
+       movl    %ecx, saved_return_addr(%edx)
+       /* get the function pointer into ECX*/
+       popl    %ecx
+       movl    %ecx, efi_rt_function_ptr(%edx)
+
+       /*
+        * 3. Call the physical function.
+        */
+       call    *%ecx
+
+       /*
+        * 4. Balance the stack. And because EAX contain the return value,
+        * we'd better not clobber it. We need to calculate our address
+        * again because %ecx and %edx are not preserved across EFI function
+        * calls.
+        */
+       call    1f
+1:     popl    %edx
+       subl    $1b, %edx
+
+       movl    efi_rt_function_ptr(%edx), %ecx
+       pushl   %ecx
+
+       /*
+        * 10. Push the saved return address onto the stack and return.
+        */
+       movl    saved_return_addr(%edx), %ecx
+       pushl   %ecx
+       ret
+ENDPROC(efi_call_phys)
+.previous
+
+.data
+saved_return_addr:
+       .long 0
+efi_rt_function_ptr:
+       .long 0
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S
new file mode 100644 (file)
index 0000000..cedc60d
--- /dev/null
@@ -0,0 +1 @@
+#include "../../platform/efi/efi_stub_64.S"
index 67a655a39ce43d3da454b7fd8f230b70d8a9c6bc..a0559930a180ecb810df4b186d173d6fb11e3755 100644 (file)
 
        __HEAD
 ENTRY(startup_32)
+#ifdef CONFIG_EFI_STUB
+       /*
+        * We don't need the return address, so set up the stack so
+        * efi_main() can find its arugments.
+        */
+       add     $0x4, %esp
+
+       call    efi_main
+       cmpl    $0, %eax
+       je      preferred_addr
+       movl    %eax, %esi
+       call    1f
+1:
+       popl    %eax
+       subl    $1b, %eax
+       subl    BP_pref_address(%esi), %eax
+       add     BP_code32_start(%esi), %eax
+       leal    preferred_addr(%eax), %eax
+       jmp     *%eax
+
+preferred_addr:
+#endif
        cld
        /*
         * Test KEEP_SEGMENTS flag to see if the bootloader is asking
index 35af09d13dc13b5d41ec7e19e066c7b5b676f30a..558d76ce23bcf3518a4c9b32bced0ef717be000e 100644 (file)
@@ -199,6 +199,26 @@ ENTRY(startup_64)
         * an identity mapped page table being provied that maps our
         * entire text+data+bss and hopefully all of memory.
         */
+#ifdef CONFIG_EFI_STUB
+       pushq   %rsi
+       mov     %rcx, %rdi
+       mov     %rdx, %rsi
+       call    efi_main
+       popq    %rsi
+       cmpq    $0,%rax
+       je      preferred_addr
+       movq    %rax,%rsi
+       call    1f
+1:
+       popq    %rax
+       subq    $1b, %rax
+       subq    BP_pref_address(%rsi), %rax
+       add     BP_code32_start(%esi), %eax
+       leaq    preferred_addr(%rax), %rax
+       jmp     *%rax
+
+preferred_addr:
+#endif
 
        /* Setup data segments. */
        xorl    %eax, %eax
index 19b3e693cd72a5f84b6a52a034d9609a3ccbe239..ffb9c5c9d7486efb0a61fff5a73c5995aa9b32e0 100644 (file)
@@ -1,2 +1,11 @@
 #include "misc.h"
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+       u8 diff;
+       asm("repe; cmpsb; setnz %0"
+           : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+       return diff;
+}
+
 #include "../string.c"
index bdb4d458ec8c35e6dbc208e78ae83ed34b242941..f1bbeeb091489d43267975234b0c0403e9cbffe5 100644 (file)
@@ -45,6 +45,11 @@ SYSSEG               = 0x1000                /* historical load address >> 4 */
 
        .global bootsect_start
 bootsect_start:
+#ifdef CONFIG_EFI_STUB
+       # "MZ", MS-DOS header
+       .byte 0x4d
+       .byte 0x5a
+#endif
 
        # Normalize the start address
        ljmp    $BOOTSEG, $start2
@@ -79,6 +84,14 @@ bs_die:
        # invoke the BIOS reset code...
        ljmp    $0xf000,$0xfff0
 
+#ifdef CONFIG_EFI_STUB
+       .org    0x3c
+       #
+       # Offset to the PE header.
+       #
+       .long   pe_header
+#endif /* CONFIG_EFI_STUB */
+
        .section ".bsdata", "a"
 bugger_off_msg:
        .ascii  "Direct booting from floppy is no longer supported.\r\n"
@@ -87,6 +100,141 @@ bugger_off_msg:
        .ascii  "Remove disk and press any key to reboot . . .\r\n"
        .byte   0
 
+#ifdef CONFIG_EFI_STUB
+pe_header:
+       .ascii  "PE"
+       .word   0
+
+coff_header:
+#ifdef CONFIG_X86_32
+       .word   0x14c                           # i386
+#else
+       .word   0x8664                          # x86-64
+#endif
+       .word   2                               # nr_sections
+       .long   0                               # TimeDateStamp
+       .long   0                               # PointerToSymbolTable
+       .long   1                               # NumberOfSymbols
+       .word   section_table - optional_header # SizeOfOptionalHeader
+#ifdef CONFIG_X86_32
+       .word   0x306                           # Characteristics.
+                                               # IMAGE_FILE_32BIT_MACHINE |
+                                               # IMAGE_FILE_DEBUG_STRIPPED |
+                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
+                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
+#else
+       .word   0x206                           # Characteristics
+                                               # IMAGE_FILE_DEBUG_STRIPPED |
+                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
+                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
+#endif
+
+optional_header:
+#ifdef CONFIG_X86_32
+       .word   0x10b                           # PE32 format
+#else
+       .word   0x20b                           # PE32+ format
+#endif
+       .byte   0x02                            # MajorLinkerVersion
+       .byte   0x14                            # MinorLinkerVersion
+
+       # Filled in by build.c
+       .long   0                               # SizeOfCode
+
+       .long   0                               # SizeOfInitializedData
+       .long   0                               # SizeOfUninitializedData
+
+       # Filled in by build.c
+       .long   0x0000                          # AddressOfEntryPoint
+
+       .long   0x0000                          # BaseOfCode
+#ifdef CONFIG_X86_32
+       .long   0                               # data
+#endif
+
+extra_header_fields:
+#ifdef CONFIG_X86_32
+       .long   0                               # ImageBase
+#else
+       .quad   0                               # ImageBase
+#endif
+       .long   0x1000                          # SectionAlignment
+       .long   0x200                           # FileAlignment
+       .word   0                               # MajorOperatingSystemVersion
+       .word   0                               # MinorOperatingSystemVersion
+       .word   0                               # MajorImageVersion
+       .word   0                               # MinorImageVersion
+       .word   0                               # MajorSubsystemVersion
+       .word   0                               # MinorSubsystemVersion
+       .long   0                               # Win32VersionValue
+
+       #
+       # The size of the bzImage is written in tools/build.c
+       #
+       .long   0                               # SizeOfImage
+
+       .long   0x200                           # SizeOfHeaders
+       .long   0                               # CheckSum
+       .word   0xa                             # Subsystem (EFI application)
+       .word   0                               # DllCharacteristics
+#ifdef CONFIG_X86_32
+       .long   0                               # SizeOfStackReserve
+       .long   0                               # SizeOfStackCommit
+       .long   0                               # SizeOfHeapReserve
+       .long   0                               # SizeOfHeapCommit
+#else
+       .quad   0                               # SizeOfStackReserve
+       .quad   0                               # SizeOfStackCommit
+       .quad   0                               # SizeOfHeapReserve
+       .quad   0                               # SizeOfHeapCommit
+#endif
+       .long   0                               # LoaderFlags
+       .long   0x1                             # NumberOfRvaAndSizes
+
+       .quad   0                               # ExportTable
+       .quad   0                               # ImportTable
+       .quad   0                               # ResourceTable
+       .quad   0                               # ExceptionTable
+       .quad   0                               # CertificationTable
+       .quad   0                               # BaseRelocationTable
+
+       # Section table
+section_table:
+       .ascii  ".text"
+       .byte   0
+       .byte   0
+       .byte   0
+       .long   0
+       .long   0x0                             # startup_{32,64}
+       .long   0                               # Size of initialized data
+                                               # on disk
+       .long   0x0                             # startup_{32,64}
+       .long   0                               # PointerToRelocations
+       .long   0                               # PointerToLineNumbers
+       .word   0                               # NumberOfRelocations
+       .word   0                               # NumberOfLineNumbers
+       .long   0x60500020                      # Characteristics (section flags)
+
+       #
+       # The EFI application loader requires a relocation section
+       # because EFI applications are relocatable and not having
+       # this section seems to confuse it. But since we don't need
+       # the loader to fixup any relocs for us just fill it with a
+       # single dummy reloc.
+       #
+       .ascii  ".reloc"
+       .byte   0
+       .byte   0
+       .long   reloc_end - reloc_start
+       .long   reloc_start
+       .long   reloc_end - reloc_start         # SizeOfRawData
+       .long   reloc_start                     # PointerToRawData
+       .long   0                               # PointerToRelocations
+       .long   0                               # PointerToLineNumbers
+       .word   0                               # NumberOfRelocations
+       .word   0                               # NumberOfLineNumbers
+       .long   0x42100040                      # Characteristics (section flags)
+#endif /* CONFIG_EFI_STUB */
 
        # Kernel attributes; used by setup.  This is part 1 of the
        # header, from the old boot sector.
@@ -318,3 +466,13 @@ die:
 setup_corrupt:
        .byte   7
        .string "No setup signature found...\n"
+
+       .data
+dummy: .long   0
+
+       .section .reloc
+reloc_start:
+       .long   dummy - reloc_start
+       .long   10
+       .word   0
+reloc_end:
index 3cbc4058dd26c1e74e633b95680aa30667b5fff4..574dedfe28900c0445b24d51b09d168116cb205f 100644 (file)
@@ -111,3 +111,38 @@ unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int bas
 
        return result;
 }
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char *s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char *strstr(const char *s1, const char *s2)
+{
+       size_t l1, l2;
+
+       l2 = strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       l1 = strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
index fdc60a0b3c20c4adceefa378dac8a5f390241a12..4e9bd6bcafa6d078a0226fd8fed05902d71d0920 100644 (file)
@@ -135,6 +135,9 @@ static void usage(void)
 
 int main(int argc, char ** argv)
 {
+#ifdef CONFIG_EFI_STUB
+       unsigned int file_sz, pe_header;
+#endif
        unsigned int i, sz, setup_sectors;
        int c;
        u32 sys_size;
@@ -194,6 +197,42 @@ int main(int argc, char ** argv)
        buf[0x1f6] = sys_size >> 16;
        buf[0x1f7] = sys_size >> 24;
 
+#ifdef CONFIG_EFI_STUB
+       file_sz = sz + i + ((sys_size * 16) - sz);
+
+       pe_header = *(unsigned int *)&buf[0x3c];
+
+       /* Size of code */
+       *(unsigned int *)&buf[pe_header + 0x1c] = file_sz;
+
+       /* Size of image */
+       *(unsigned int *)&buf[pe_header + 0x50] = file_sz;
+
+#ifdef CONFIG_X86_32
+       /* Address of entry point */
+       *(unsigned int *)&buf[pe_header + 0x28] = i;
+
+       /* .text size */
+       *(unsigned int *)&buf[pe_header + 0xb0] = file_sz;
+
+       /* .text size of initialised data */
+       *(unsigned int *)&buf[pe_header + 0xb8] = file_sz;
+#else
+       /*
+        * Address of entry point. startup_32 is at the beginning and
+        * the 64-bit entry point (startup_64) is always 512 bytes
+        * after.
+        */
+       *(unsigned int *)&buf[pe_header + 0x28] = i + 512;
+
+       /* .text size */
+       *(unsigned int *)&buf[pe_header + 0xc0] = file_sz;
+
+       /* .text size of initialised data */
+       *(unsigned int *)&buf[pe_header + 0xc8] = file_sz;
+#endif /* CONFIG_X86_32 */
+#endif /* CONFIG_EFI_STUB */
+
        crc = partial_crc32(buf, i, crc);
        if (fwrite(buf, 1, i, stdout) != i)
                die("Writing setup failed");
index 3537d4b91f7407cd3e01c99ffd035a8beb2d629c..2b0b9631474b567daeb1a0f364869e6b2943bada 100644 (file)
@@ -5,12 +5,14 @@
 obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
 obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
 obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
+obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
 obj-$(CONFIG_CRYPTO_SALSA20_X86_64) += salsa20-x86_64.o
+obj-$(CONFIG_CRYPTO_SERPENT_SSE2_X86_64) += serpent-sse2-x86_64.o
 obj-$(CONFIG_CRYPTO_AES_NI_INTEL) += aesni-intel.o
 obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 
@@ -20,12 +22,14 @@ obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
 aes-i586-y := aes-i586-asm_32.o aes_glue.o
 twofish-i586-y := twofish-i586-asm_32.o twofish_glue.o
 salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o
+serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
 
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
 salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
+serpent-sse2-x86_64-y := serpent-sse2-x86_64-asm_64.o serpent_sse2_glue.o
 
 aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
 
diff --git a/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/arch/x86/crypto/serpent-sse2-i586-asm_32.S
new file mode 100644 (file)
index 0000000..4e37677
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * Serpent Cipher 4-way parallel algorithm (i586/SSE2)
+ *
+ * Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * Based on crypto/serpent.c by
+ *  Copyright (C) 2002 Dag Arne Osvik <osvik@ii.uib.no>
+ *                2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "serpent-sse2-i586-asm_32.S"
+.text
+
+#define arg_ctx 4
+#define arg_dst 8
+#define arg_src 12
+#define arg_xor 16
+
+/**********************************************************************
+  4-way SSE2 serpent
+ **********************************************************************/
+#define CTX %edx
+
+#define RA %xmm0
+#define RB %xmm1
+#define RC %xmm2
+#define RD %xmm3
+#define RE %xmm4
+
+#define RT0 %xmm5
+#define RT1 %xmm6
+
+#define RNOT %xmm7
+
+#define get_key(i, j, t) \
+       movd (4*(i)+(j))*4(CTX), t; \
+       pshufd $0, t, t;
+
+#define K(x0, x1, x2, x3, x4, i) \
+       get_key(i, 0, x4); \
+       get_key(i, 1, RT0); \
+       get_key(i, 2, RT1); \
+       pxor x4,                x0; \
+       pxor RT0,               x1; \
+       pxor RT1,               x2; \
+       get_key(i, 3, x4); \
+       pxor x4,                x3;
+
+#define LK(x0, x1, x2, x3, x4, i) \
+       movdqa x0,              x4; \
+       pslld $13,              x0; \
+       psrld $(32 - 13),       x4; \
+       por x4,                 x0; \
+       pxor x0,                x1; \
+       movdqa x2,              x4; \
+       pslld $3,               x2; \
+       psrld $(32 - 3),        x4; \
+       por x4,                 x2; \
+       pxor x2,                x1; \
+       movdqa x1,              x4; \
+       pslld $1,               x1; \
+       psrld $(32 - 1),        x4; \
+       por x4,                 x1; \
+       movdqa x0,              x4; \
+       pslld $3,               x4; \
+       pxor x2,                x3; \
+       pxor x4,                x3; \
+       movdqa x3,              x4; \
+       pslld $7,               x3; \
+       psrld $(32 - 7),        x4; \
+       por x4,                 x3; \
+       movdqa x1,              x4; \
+       pslld $7,               x4; \
+       pxor x1,                x0; \
+       pxor x3,                x0; \
+       pxor x3,                x2; \
+       pxor x4,                x2; \
+       movdqa x0,              x4; \
+       get_key(i, 1, RT0); \
+       pxor RT0,               x1; \
+       get_key(i, 3, RT0); \
+       pxor RT0,               x3; \
+       pslld $5,               x0; \
+       psrld $(32 - 5),        x4; \
+       por x4,                 x0; \
+       movdqa x2,              x4; \
+       pslld $22,              x2; \
+       psrld $(32 - 22),       x4; \
+       por x4,                 x2; \
+       get_key(i, 0, RT0); \
+       pxor RT0,               x0; \
+       get_key(i, 2, RT0); \
+       pxor RT0,               x2;
+
+#define KL(x0, x1, x2, x3, x4, i) \
+       K(x0, x1, x2, x3, x4, i); \
+       movdqa x0,              x4; \
+       psrld $5,               x0; \
+       pslld $(32 - 5),        x4; \
+       por x4,                 x0; \
+       movdqa x2,              x4; \
+       psrld $22,              x2; \
+       pslld $(32 - 22),       x4; \
+       por x4,                 x2; \
+       pxor x3,                x2; \
+       pxor x3,                x0; \
+       movdqa x1,              x4; \
+       pslld $7,               x4; \
+       pxor x1,                x0; \
+       pxor x4,                x2; \
+       movdqa x1,              x4; \
+       psrld $1,               x1; \
+       pslld $(32 - 1),        x4; \
+       por x4,                 x1; \
+       movdqa x3,              x4; \
+       psrld $7,               x3; \
+       pslld $(32 - 7),        x4; \
+       por x4,                 x3; \
+       pxor x0,                x1; \
+       movdqa x0,              x4; \
+       pslld $3,               x4; \
+       pxor x4,                x3; \
+       movdqa x0,              x4; \
+       psrld $13,              x0; \
+       pslld $(32 - 13),       x4; \
+       por x4,                 x0; \
+       pxor x2,                x1; \
+       pxor x2,                x3; \
+       movdqa x2,              x4; \
+       psrld $3,               x2; \
+       pslld $(32 - 3),        x4; \
+       por x4,                 x2;
+
+#define S0(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       por x0,                 x3; \
+       pxor x4,                x0; \
+       pxor x2,                x4; \
+       pxor RNOT,              x4; \
+       pxor x1,                x3; \
+       pand x0,                x1; \
+       pxor x4,                x1; \
+       pxor x0,                x2; \
+       pxor x3,                x0; \
+       por x0,                 x4; \
+       pxor x2,                x0; \
+       pand x1,                x2; \
+       pxor x2,                x3; \
+       pxor RNOT,              x1; \
+       pxor x4,                x2; \
+       pxor x2,                x1;
+
+#define S1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x0,                x1; \
+       pxor x3,                x0; \
+       pxor RNOT,              x3; \
+       pand x1,                x4; \
+       por x1,                 x0; \
+       pxor x2,                x3; \
+       pxor x3,                x0; \
+       pxor x3,                x1; \
+       pxor x4,                x3; \
+       por x4,                 x1; \
+       pxor x2,                x4; \
+       pand x0,                x2; \
+       pxor x1,                x2; \
+       por x0,                 x1; \
+       pxor RNOT,              x0; \
+       pxor x2,                x0; \
+       pxor x1,                x4;
+
+#define S2(x0, x1, x2, x3, x4) \
+       pxor RNOT,              x3; \
+       pxor x0,                x1; \
+       movdqa x0,              x4; \
+       pand x2,                x0; \
+       pxor x3,                x0; \
+       por x4,                 x3; \
+       pxor x1,                x2; \
+       pxor x1,                x3; \
+       pand x0,                x1; \
+       pxor x2,                x0; \
+       pand x3,                x2; \
+       por x1,                 x3; \
+       pxor RNOT,              x0; \
+       pxor x0,                x3; \
+       pxor x0,                x4; \
+       pxor x2,                x0; \
+       por x2,                 x1;
+
+#define S3(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x3,                x1; \
+       por x0,                 x3; \
+       pand x0,                x4; \
+       pxor x2,                x0; \
+       pxor x1,                x2; \
+       pand x3,                x1; \
+       pxor x3,                x2; \
+       por x4,                 x0; \
+       pxor x3,                x4; \
+       pxor x0,                x1; \
+       pand x3,                x0; \
+       pand x4,                x3; \
+       pxor x2,                x3; \
+       por x1,                 x4; \
+       pand x1,                x2; \
+       pxor x3,                x4; \
+       pxor x3,                x0; \
+       pxor x2,                x3;
+
+#define S4(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pand x0,                x3; \
+       pxor x4,                x0; \
+       pxor x2,                x3; \
+       por x4,                 x2; \
+       pxor x1,                x0; \
+       pxor x3,                x4; \
+       por x0,                 x2; \
+       pxor x1,                x2; \
+       pand x0,                x1; \
+       pxor x4,                x1; \
+       pand x2,                x4; \
+       pxor x3,                x2; \
+       pxor x0,                x4; \
+       por x1,                 x3; \
+       pxor RNOT,              x1; \
+       pxor x0,                x3;
+
+#define S5(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       por x0,                 x1; \
+       pxor x1,                x2; \
+       pxor RNOT,              x3; \
+       pxor x0,                x4; \
+       pxor x2,                x0; \
+       pand x4,                x1; \
+       por x3,                 x4; \
+       pxor x0,                x4; \
+       pand x3,                x0; \
+       pxor x3,                x1; \
+       pxor x2,                x3; \
+       pxor x1,                x0; \
+       pand x4,                x2; \
+       pxor x2,                x1; \
+       pand x0,                x2; \
+       pxor x2,                x3;
+
+#define S6(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x0,                x3; \
+       pxor x2,                x1; \
+       pxor x0,                x2; \
+       pand x3,                x0; \
+       por x3,                 x1; \
+       pxor RNOT,              x4; \
+       pxor x1,                x0; \
+       pxor x2,                x1; \
+       pxor x4,                x3; \
+       pxor x0,                x4; \
+       pand x0,                x2; \
+       pxor x1,                x4; \
+       pxor x3,                x2; \
+       pand x1,                x3; \
+       pxor x0,                x3; \
+       pxor x2,                x1;
+
+#define S7(x0, x1, x2, x3, x4) \
+       pxor RNOT,              x1; \
+       movdqa x1,              x4; \
+       pxor RNOT,              x0; \
+       pand x2,                x1; \
+       pxor x3,                x1; \
+       por x4,                 x3; \
+       pxor x2,                x4; \
+       pxor x3,                x2; \
+       pxor x0,                x3; \
+       por x1,                 x0; \
+       pand x0,                x2; \
+       pxor x4,                x0; \
+       pxor x3,                x4; \
+       pand x0,                x3; \
+       pxor x1,                x4; \
+       pxor x4,                x2; \
+       pxor x1,                x3; \
+       por x0,                 x4; \
+       pxor x1,                x4;
+
+#define SI0(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pxor x0,                x1; \
+       por x1,                 x3; \
+       pxor x1,                x4; \
+       pxor RNOT,              x0; \
+       pxor x3,                x2; \
+       pxor x0,                x3; \
+       pand x1,                x0; \
+       pxor x2,                x0; \
+       pand x3,                x2; \
+       pxor x4,                x3; \
+       pxor x3,                x2; \
+       pxor x3,                x1; \
+       pand x0,                x3; \
+       pxor x0,                x1; \
+       pxor x2,                x0; \
+       pxor x3,                x4;
+
+#define SI1(x0, x1, x2, x3, x4) \
+       pxor x3,                x1; \
+       movdqa x0,              x4; \
+       pxor x2,                x0; \
+       pxor RNOT,              x2; \
+       por x1,                 x4; \
+       pxor x3,                x4; \
+       pand x1,                x3; \
+       pxor x2,                x1; \
+       pand x4,                x2; \
+       pxor x1,                x4; \
+       por x3,                 x1; \
+       pxor x0,                x3; \
+       pxor x0,                x2; \
+       por x4,                 x0; \
+       pxor x4,                x2; \
+       pxor x0,                x1; \
+       pxor x1,                x4;
+
+#define SI2(x0, x1, x2, x3, x4) \
+       pxor x1,                x2; \
+       movdqa x3,              x4; \
+       pxor RNOT,              x3; \
+       por x2,                 x3; \
+       pxor x4,                x2; \
+       pxor x0,                x4; \
+       pxor x1,                x3; \
+       por x2,                 x1; \
+       pxor x0,                x2; \
+       pxor x4,                x1; \
+       por x3,                 x4; \
+       pxor x3,                x2; \
+       pxor x2,                x4; \
+       pand x1,                x2; \
+       pxor x3,                x2; \
+       pxor x4,                x3; \
+       pxor x0,                x4;
+
+#define SI3(x0, x1, x2, x3, x4) \
+       pxor x1,                x2; \
+       movdqa x1,              x4; \
+       pand x2,                x1; \
+       pxor x0,                x1; \
+       por x4,                 x0; \
+       pxor x3,                x4; \
+       pxor x3,                x0; \
+       por x1,                 x3; \
+       pxor x2,                x1; \
+       pxor x3,                x1; \
+       pxor x2,                x0; \
+       pxor x3,                x2; \
+       pand x1,                x3; \
+       pxor x0,                x1; \
+       pand x2,                x0; \
+       pxor x3,                x4; \
+       pxor x0,                x3; \
+       pxor x1,                x0;
+
+#define SI4(x0, x1, x2, x3, x4) \
+       pxor x3,                x2; \
+       movdqa x0,              x4; \
+       pand x1,                x0; \
+       pxor x2,                x0; \
+       por x3,                 x2; \
+       pxor RNOT,              x4; \
+       pxor x0,                x1; \
+       pxor x2,                x0; \
+       pand x4,                x2; \
+       pxor x0,                x2; \
+       por x4,                 x0; \
+       pxor x3,                x0; \
+       pand x2,                x3; \
+       pxor x3,                x4; \
+       pxor x1,                x3; \
+       pand x0,                x1; \
+       pxor x1,                x4; \
+       pxor x3,                x0;
+
+#define SI5(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       por x2,                 x1; \
+       pxor x4,                x2; \
+       pxor x3,                x1; \
+       pand x4,                x3; \
+       pxor x3,                x2; \
+       por x0,                 x3; \
+       pxor RNOT,              x0; \
+       pxor x2,                x3; \
+       por x0,                 x2; \
+       pxor x1,                x4; \
+       pxor x4,                x2; \
+       pand x0,                x4; \
+       pxor x1,                x0; \
+       pxor x3,                x1; \
+       pand x2,                x0; \
+       pxor x3,                x2; \
+       pxor x2,                x0; \
+       pxor x4,                x2; \
+       pxor x3,                x4;
+
+#define SI6(x0, x1, x2, x3, x4) \
+       pxor x2,                x0; \
+       movdqa x0,              x4; \
+       pand x3,                x0; \
+       pxor x3,                x2; \
+       pxor x2,                x0; \
+       pxor x1,                x3; \
+       por x4,                 x2; \
+       pxor x3,                x2; \
+       pand x0,                x3; \
+       pxor RNOT,              x0; \
+       pxor x1,                x3; \
+       pand x2,                x1; \
+       pxor x0,                x4; \
+       pxor x4,                x3; \
+       pxor x2,                x4; \
+       pxor x1,                x0; \
+       pxor x0,                x2;
+
+#define SI7(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pand x0,                x3; \
+       pxor x2,                x0; \
+       por x4,                 x2; \
+       pxor x1,                x4; \
+       pxor RNOT,              x0; \
+       por x3,                 x1; \
+       pxor x0,                x4; \
+       pand x2,                x0; \
+       pxor x1,                x0; \
+       pand x2,                x1; \
+       pxor x2,                x3; \
+       pxor x3,                x4; \
+       pand x3,                x2; \
+       por x0,                 x3; \
+       pxor x4,                x1; \
+       pxor x4,                x3; \
+       pand x0,                x4; \
+       pxor x2,                x4;
+
+#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
+       movdqa x2,              t3; \
+       movdqa x0,              t1; \
+       unpcklps x3,            t3; \
+       movdqa x0,              t2; \
+       unpcklps x1,            t1; \
+       unpckhps x1,            t2; \
+       movdqa t3,              x1; \
+       unpckhps x3,            x2; \
+       movdqa t1,              x0; \
+       movhlps t1,             x1; \
+       movdqa t2,              t1; \
+       movlhps t3,             x0; \
+       movlhps x2,             t1; \
+       movhlps t2,             x2; \
+       movdqa x2,              x3; \
+       movdqa t1,              x2;
+
+#define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
+       movdqu (0*4*4)(in),     x0; \
+       movdqu (1*4*4)(in),     x1; \
+       movdqu (2*4*4)(in),     x2; \
+       movdqu (3*4*4)(in),     x3; \
+       \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define write_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       movdqu x0, (0*4*4)(out); \
+       movdqu x1, (1*4*4)(out); \
+       movdqu x2, (2*4*4)(out); \
+       movdqu x3, (3*4*4)(out);
+
+#define xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       movdqu (0*4*4)(out),    t0; \
+       pxor t0,                x0; \
+       movdqu x0,              (0*4*4)(out); \
+       movdqu (1*4*4)(out),    t0; \
+       pxor t0,                x1; \
+       movdqu x1,              (1*4*4)(out); \
+       movdqu (2*4*4)(out),    t0; \
+       pxor t0,                x2; \
+       movdqu x2,              (2*4*4)(out); \
+       movdqu (3*4*4)(out),    t0; \
+       pxor t0,                x3; \
+       movdqu x3,              (3*4*4)(out);
+
+.align 8
+.global __serpent_enc_blk_4way
+.type   __serpent_enc_blk_4way,@function;
+
+__serpent_enc_blk_4way:
+       /* input:
+        *      arg_ctx(%esp): ctx, CTX
+        *      arg_dst(%esp): dst
+        *      arg_src(%esp): src
+        *      arg_xor(%esp): bool, if true: xor output
+        */
+
+       pcmpeqd RNOT, RNOT;
+
+       movl arg_ctx(%esp), CTX;
+
+       movl arg_src(%esp), %eax;
+       read_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
+
+                                        K(RA, RB, RC, RD, RE, 0);
+       S0(RA, RB, RC, RD, RE);         LK(RC, RB, RD, RA, RE, 1);
+       S1(RC, RB, RD, RA, RE);         LK(RE, RD, RA, RC, RB, 2);
+       S2(RE, RD, RA, RC, RB);         LK(RB, RD, RE, RC, RA, 3);
+       S3(RB, RD, RE, RC, RA);         LK(RC, RA, RD, RB, RE, 4);
+       S4(RC, RA, RD, RB, RE);         LK(RA, RD, RB, RE, RC, 5);
+       S5(RA, RD, RB, RE, RC);         LK(RC, RA, RD, RE, RB, 6);
+       S6(RC, RA, RD, RE, RB);         LK(RD, RB, RA, RE, RC, 7);
+       S7(RD, RB, RA, RE, RC);         LK(RC, RA, RE, RD, RB, 8);
+       S0(RC, RA, RE, RD, RB);         LK(RE, RA, RD, RC, RB, 9);
+       S1(RE, RA, RD, RC, RB);         LK(RB, RD, RC, RE, RA, 10);
+       S2(RB, RD, RC, RE, RA);         LK(RA, RD, RB, RE, RC, 11);
+       S3(RA, RD, RB, RE, RC);         LK(RE, RC, RD, RA, RB, 12);
+       S4(RE, RC, RD, RA, RB);         LK(RC, RD, RA, RB, RE, 13);
+       S5(RC, RD, RA, RB, RE);         LK(RE, RC, RD, RB, RA, 14);
+       S6(RE, RC, RD, RB, RA);         LK(RD, RA, RC, RB, RE, 15);
+       S7(RD, RA, RC, RB, RE);         LK(RE, RC, RB, RD, RA, 16);
+       S0(RE, RC, RB, RD, RA);         LK(RB, RC, RD, RE, RA, 17);
+       S1(RB, RC, RD, RE, RA);         LK(RA, RD, RE, RB, RC, 18);
+       S2(RA, RD, RE, RB, RC);         LK(RC, RD, RA, RB, RE, 19);
+       S3(RC, RD, RA, RB, RE);         LK(RB, RE, RD, RC, RA, 20);
+       S4(RB, RE, RD, RC, RA);         LK(RE, RD, RC, RA, RB, 21);
+       S5(RE, RD, RC, RA, RB);         LK(RB, RE, RD, RA, RC, 22);
+       S6(RB, RE, RD, RA, RC);         LK(RD, RC, RE, RA, RB, 23);
+       S7(RD, RC, RE, RA, RB);         LK(RB, RE, RA, RD, RC, 24);
+       S0(RB, RE, RA, RD, RC);         LK(RA, RE, RD, RB, RC, 25);
+       S1(RA, RE, RD, RB, RC);         LK(RC, RD, RB, RA, RE, 26);
+       S2(RC, RD, RB, RA, RE);         LK(RE, RD, RC, RA, RB, 27);
+       S3(RE, RD, RC, RA, RB);         LK(RA, RB, RD, RE, RC, 28);
+       S4(RA, RB, RD, RE, RC);         LK(RB, RD, RE, RC, RA, 29);
+       S5(RB, RD, RE, RC, RA);         LK(RA, RB, RD, RC, RE, 30);
+       S6(RA, RB, RD, RC, RE);         LK(RD, RE, RB, RC, RA, 31);
+       S7(RD, RE, RB, RC, RA);          K(RA, RB, RC, RD, RE, 32);
+
+       movl arg_dst(%esp), %eax;
+
+       cmpb $0, arg_xor(%esp);
+       jnz __enc_xor4;
+
+       write_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
+
+       ret;
+
+__enc_xor4:
+       xor_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
+
+       ret;
+
+.align 8
+.global serpent_dec_blk_4way
+.type   serpent_dec_blk_4way,@function;
+
+serpent_dec_blk_4way:
+       /* input:
+        *      arg_ctx(%esp): ctx, CTX
+        *      arg_dst(%esp): dst
+        *      arg_src(%esp): src
+        */
+
+       pcmpeqd RNOT, RNOT;
+
+       movl arg_ctx(%esp), CTX;
+
+       movl arg_src(%esp), %eax;
+       read_blocks(%eax, RA, RB, RC, RD, RT0, RT1, RE);
+
+                                        K(RA, RB, RC, RD, RE, 32);
+       SI7(RA, RB, RC, RD, RE);        KL(RB, RD, RA, RE, RC, 31);
+       SI6(RB, RD, RA, RE, RC);        KL(RA, RC, RE, RB, RD, 30);
+       SI5(RA, RC, RE, RB, RD);        KL(RC, RD, RA, RE, RB, 29);
+       SI4(RC, RD, RA, RE, RB);        KL(RC, RA, RB, RE, RD, 28);
+       SI3(RC, RA, RB, RE, RD);        KL(RB, RC, RD, RE, RA, 27);
+       SI2(RB, RC, RD, RE, RA);        KL(RC, RA, RE, RD, RB, 26);
+       SI1(RC, RA, RE, RD, RB);        KL(RB, RA, RE, RD, RC, 25);
+       SI0(RB, RA, RE, RD, RC);        KL(RE, RC, RA, RB, RD, 24);
+       SI7(RE, RC, RA, RB, RD);        KL(RC, RB, RE, RD, RA, 23);
+       SI6(RC, RB, RE, RD, RA);        KL(RE, RA, RD, RC, RB, 22);
+       SI5(RE, RA, RD, RC, RB);        KL(RA, RB, RE, RD, RC, 21);
+       SI4(RA, RB, RE, RD, RC);        KL(RA, RE, RC, RD, RB, 20);
+       SI3(RA, RE, RC, RD, RB);        KL(RC, RA, RB, RD, RE, 19);
+       SI2(RC, RA, RB, RD, RE);        KL(RA, RE, RD, RB, RC, 18);
+       SI1(RA, RE, RD, RB, RC);        KL(RC, RE, RD, RB, RA, 17);
+       SI0(RC, RE, RD, RB, RA);        KL(RD, RA, RE, RC, RB, 16);
+       SI7(RD, RA, RE, RC, RB);        KL(RA, RC, RD, RB, RE, 15);
+       SI6(RA, RC, RD, RB, RE);        KL(RD, RE, RB, RA, RC, 14);
+       SI5(RD, RE, RB, RA, RC);        KL(RE, RC, RD, RB, RA, 13);
+       SI4(RE, RC, RD, RB, RA);        KL(RE, RD, RA, RB, RC, 12);
+       SI3(RE, RD, RA, RB, RC);        KL(RA, RE, RC, RB, RD, 11);
+       SI2(RA, RE, RC, RB, RD);        KL(RE, RD, RB, RC, RA, 10);
+       SI1(RE, RD, RB, RC, RA);        KL(RA, RD, RB, RC, RE, 9);
+       SI0(RA, RD, RB, RC, RE);        KL(RB, RE, RD, RA, RC, 8);
+       SI7(RB, RE, RD, RA, RC);        KL(RE, RA, RB, RC, RD, 7);
+       SI6(RE, RA, RB, RC, RD);        KL(RB, RD, RC, RE, RA, 6);
+       SI5(RB, RD, RC, RE, RA);        KL(RD, RA, RB, RC, RE, 5);
+       SI4(RD, RA, RB, RC, RE);        KL(RD, RB, RE, RC, RA, 4);
+       SI3(RD, RB, RE, RC, RA);        KL(RE, RD, RA, RC, RB, 3);
+       SI2(RE, RD, RA, RC, RB);        KL(RD, RB, RC, RA, RE, 2);
+       SI1(RD, RB, RC, RA, RE);        KL(RE, RB, RC, RA, RD, 1);
+       SI0(RE, RB, RC, RA, RD);         K(RC, RD, RB, RE, RA, 0);
+
+       movl arg_dst(%esp), %eax;
+       write_blocks(%eax, RC, RD, RB, RE, RT0, RT1, RA);
+
+       ret;
diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S
new file mode 100644 (file)
index 0000000..7f24a15
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * Serpent Cipher 8-way parallel algorithm (x86_64/SSE2)
+ *
+ * Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * Based on crypto/serpent.c by
+ *  Copyright (C) 2002 Dag Arne Osvik <osvik@ii.uib.no>
+ *                2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "serpent-sse2-x86_64-asm_64.S"
+.text
+
+#define CTX %rdi
+
+/**********************************************************************
+  8-way SSE2 serpent
+ **********************************************************************/
+#define RA1 %xmm0
+#define RB1 %xmm1
+#define RC1 %xmm2
+#define RD1 %xmm3
+#define RE1 %xmm4
+
+#define RA2 %xmm5
+#define RB2 %xmm6
+#define RC2 %xmm7
+#define RD2 %xmm8
+#define RE2 %xmm9
+
+#define RNOT %xmm10
+
+#define RK0 %xmm11
+#define RK1 %xmm12
+#define RK2 %xmm13
+#define RK3 %xmm14
+
+#define S0_1(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       por x0,                 x3; \
+       pxor x4,                x0; \
+       pxor x2,                x4; \
+       pxor RNOT,              x4; \
+       pxor x1,                x3; \
+       pand x0,                x1; \
+       pxor x4,                x1; \
+       pxor x0,                x2;
+#define S0_2(x0, x1, x2, x3, x4) \
+       pxor x3,                x0; \
+       por x0,                 x4; \
+       pxor x2,                x0; \
+       pand x1,                x2; \
+       pxor x2,                x3; \
+       pxor RNOT,              x1; \
+       pxor x4,                x2; \
+       pxor x2,                x1;
+
+#define S1_1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x0,                x1; \
+       pxor x3,                x0; \
+       pxor RNOT,              x3; \
+       pand x1,                x4; \
+       por x1,                 x0; \
+       pxor x2,                x3; \
+       pxor x3,                x0; \
+       pxor x3,                x1;
+#define S1_2(x0, x1, x2, x3, x4) \
+       pxor x4,                x3; \
+       por x4,                 x1; \
+       pxor x2,                x4; \
+       pand x0,                x2; \
+       pxor x1,                x2; \
+       por x0,                 x1; \
+       pxor RNOT,              x0; \
+       pxor x2,                x0; \
+       pxor x1,                x4;
+
+#define S2_1(x0, x1, x2, x3, x4) \
+       pxor RNOT,              x3; \
+       pxor x0,                x1; \
+       movdqa x0,              x4; \
+       pand x2,                x0; \
+       pxor x3,                x0; \
+       por x4,                 x3; \
+       pxor x1,                x2; \
+       pxor x1,                x3; \
+       pand x0,                x1;
+#define S2_2(x0, x1, x2, x3, x4) \
+       pxor x2,                x0; \
+       pand x3,                x2; \
+       por x1,                 x3; \
+       pxor RNOT,              x0; \
+       pxor x0,                x3; \
+       pxor x0,                x4; \
+       pxor x2,                x0; \
+       por x2,                 x1;
+
+#define S3_1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x3,                x1; \
+       por x0,                 x3; \
+       pand x0,                x4; \
+       pxor x2,                x0; \
+       pxor x1,                x2; \
+       pand x3,                x1; \
+       pxor x3,                x2; \
+       por x4,                 x0; \
+       pxor x3,                x4;
+#define S3_2(x0, x1, x2, x3, x4) \
+       pxor x0,                x1; \
+       pand x3,                x0; \
+       pand x4,                x3; \
+       pxor x2,                x3; \
+       por x1,                 x4; \
+       pand x1,                x2; \
+       pxor x3,                x4; \
+       pxor x3,                x0; \
+       pxor x2,                x3;
+
+#define S4_1(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pand x0,                x3; \
+       pxor x4,                x0; \
+       pxor x2,                x3; \
+       por x4,                 x2; \
+       pxor x1,                x0; \
+       pxor x3,                x4; \
+       por x0,                 x2; \
+       pxor x1,                x2;
+#define S4_2(x0, x1, x2, x3, x4) \
+       pand x0,                x1; \
+       pxor x4,                x1; \
+       pand x2,                x4; \
+       pxor x3,                x2; \
+       pxor x0,                x4; \
+       por x1,                 x3; \
+       pxor RNOT,              x1; \
+       pxor x0,                x3;
+
+#define S5_1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       por x0,                 x1; \
+       pxor x1,                x2; \
+       pxor RNOT,              x3; \
+       pxor x0,                x4; \
+       pxor x2,                x0; \
+       pand x4,                x1; \
+       por x3,                 x4; \
+       pxor x0,                x4;
+#define S5_2(x0, x1, x2, x3, x4) \
+       pand x3,                x0; \
+       pxor x3,                x1; \
+       pxor x2,                x3; \
+       pxor x1,                x0; \
+       pand x4,                x2; \
+       pxor x2,                x1; \
+       pand x0,                x2; \
+       pxor x2,                x3;
+
+#define S6_1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       pxor x0,                x3; \
+       pxor x2,                x1; \
+       pxor x0,                x2; \
+       pand x3,                x0; \
+       por x3,                 x1; \
+       pxor RNOT,              x4; \
+       pxor x1,                x0; \
+       pxor x2,                x1;
+#define S6_2(x0, x1, x2, x3, x4) \
+       pxor x4,                x3; \
+       pxor x0,                x4; \
+       pand x0,                x2; \
+       pxor x1,                x4; \
+       pxor x3,                x2; \
+       pand x1,                x3; \
+       pxor x0,                x3; \
+       pxor x2,                x1;
+
+#define S7_1(x0, x1, x2, x3, x4) \
+       pxor RNOT,              x1; \
+       movdqa x1,              x4; \
+       pxor RNOT,              x0; \
+       pand x2,                x1; \
+       pxor x3,                x1; \
+       por x4,                 x3; \
+       pxor x2,                x4; \
+       pxor x3,                x2; \
+       pxor x0,                x3; \
+       por x1,                 x0;
+#define S7_2(x0, x1, x2, x3, x4) \
+       pand x0,                x2; \
+       pxor x4,                x0; \
+       pxor x3,                x4; \
+       pand x0,                x3; \
+       pxor x1,                x4; \
+       pxor x4,                x2; \
+       pxor x1,                x3; \
+       por x0,                 x4; \
+       pxor x1,                x4;
+
+#define SI0_1(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pxor x0,                x1; \
+       por x1,                 x3; \
+       pxor x1,                x4; \
+       pxor RNOT,              x0; \
+       pxor x3,                x2; \
+       pxor x0,                x3; \
+       pand x1,                x0; \
+       pxor x2,                x0;
+#define SI0_2(x0, x1, x2, x3, x4) \
+       pand x3,                x2; \
+       pxor x4,                x3; \
+       pxor x3,                x2; \
+       pxor x3,                x1; \
+       pand x0,                x3; \
+       pxor x0,                x1; \
+       pxor x2,                x0; \
+       pxor x3,                x4;
+
+#define SI1_1(x0, x1, x2, x3, x4) \
+       pxor x3,                x1; \
+       movdqa x0,              x4; \
+       pxor x2,                x0; \
+       pxor RNOT,              x2; \
+       por x1,                 x4; \
+       pxor x3,                x4; \
+       pand x1,                x3; \
+       pxor x2,                x1; \
+       pand x4,                x2;
+#define SI1_2(x0, x1, x2, x3, x4) \
+       pxor x1,                x4; \
+       por x3,                 x1; \
+       pxor x0,                x3; \
+       pxor x0,                x2; \
+       por x4,                 x0; \
+       pxor x4,                x2; \
+       pxor x0,                x1; \
+       pxor x1,                x4;
+
+#define SI2_1(x0, x1, x2, x3, x4) \
+       pxor x1,                x2; \
+       movdqa x3,              x4; \
+       pxor RNOT,              x3; \
+       por x2,                 x3; \
+       pxor x4,                x2; \
+       pxor x0,                x4; \
+       pxor x1,                x3; \
+       por x2,                 x1; \
+       pxor x0,                x2;
+#define SI2_2(x0, x1, x2, x3, x4) \
+       pxor x4,                x1; \
+       por x3,                 x4; \
+       pxor x3,                x2; \
+       pxor x2,                x4; \
+       pand x1,                x2; \
+       pxor x3,                x2; \
+       pxor x4,                x3; \
+       pxor x0,                x4;
+
+#define SI3_1(x0, x1, x2, x3, x4) \
+       pxor x1,                x2; \
+       movdqa x1,              x4; \
+       pand x2,                x1; \
+       pxor x0,                x1; \
+       por x4,                 x0; \
+       pxor x3,                x4; \
+       pxor x3,                x0; \
+       por x1,                 x3; \
+       pxor x2,                x1;
+#define SI3_2(x0, x1, x2, x3, x4) \
+       pxor x3,                x1; \
+       pxor x2,                x0; \
+       pxor x3,                x2; \
+       pand x1,                x3; \
+       pxor x0,                x1; \
+       pand x2,                x0; \
+       pxor x3,                x4; \
+       pxor x0,                x3; \
+       pxor x1,                x0;
+
+#define SI4_1(x0, x1, x2, x3, x4) \
+       pxor x3,                x2; \
+       movdqa x0,              x4; \
+       pand x1,                x0; \
+       pxor x2,                x0; \
+       por x3,                 x2; \
+       pxor RNOT,              x4; \
+       pxor x0,                x1; \
+       pxor x2,                x0; \
+       pand x4,                x2;
+#define SI4_2(x0, x1, x2, x3, x4) \
+       pxor x0,                x2; \
+       por x4,                 x0; \
+       pxor x3,                x0; \
+       pand x2,                x3; \
+       pxor x3,                x4; \
+       pxor x1,                x3; \
+       pand x0,                x1; \
+       pxor x1,                x4; \
+       pxor x3,                x0;
+
+#define SI5_1(x0, x1, x2, x3, x4) \
+       movdqa x1,              x4; \
+       por x2,                 x1; \
+       pxor x4,                x2; \
+       pxor x3,                x1; \
+       pand x4,                x3; \
+       pxor x3,                x2; \
+       por x0,                 x3; \
+       pxor RNOT,              x0; \
+       pxor x2,                x3; \
+       por x0,                 x2;
+#define SI5_2(x0, x1, x2, x3, x4) \
+       pxor x1,                x4; \
+       pxor x4,                x2; \
+       pand x0,                x4; \
+       pxor x1,                x0; \
+       pxor x3,                x1; \
+       pand x2,                x0; \
+       pxor x3,                x2; \
+       pxor x2,                x0; \
+       pxor x4,                x2; \
+       pxor x3,                x4;
+
+#define SI6_1(x0, x1, x2, x3, x4) \
+       pxor x2,                x0; \
+       movdqa x0,              x4; \
+       pand x3,                x0; \
+       pxor x3,                x2; \
+       pxor x2,                x0; \
+       pxor x1,                x3; \
+       por x4,                 x2; \
+       pxor x3,                x2; \
+       pand x0,                x3;
+#define SI6_2(x0, x1, x2, x3, x4) \
+       pxor RNOT,              x0; \
+       pxor x1,                x3; \
+       pand x2,                x1; \
+       pxor x0,                x4; \
+       pxor x4,                x3; \
+       pxor x2,                x4; \
+       pxor x1,                x0; \
+       pxor x0,                x2;
+
+#define SI7_1(x0, x1, x2, x3, x4) \
+       movdqa x3,              x4; \
+       pand x0,                x3; \
+       pxor x2,                x0; \
+       por x4,                 x2; \
+       pxor x1,                x4; \
+       pxor RNOT,              x0; \
+       por x3,                 x1; \
+       pxor x0,                x4; \
+       pand x2,                x0; \
+       pxor x1,                x0;
+#define SI7_2(x0, x1, x2, x3, x4) \
+       pand x2,                x1; \
+       pxor x2,                x3; \
+       pxor x3,                x4; \
+       pand x3,                x2; \
+       por x0,                 x3; \
+       pxor x4,                x1; \
+       pxor x4,                x3; \
+       pand x0,                x4; \
+       pxor x2,                x4;
+
+#define get_key(i, j, t) \
+       movd (4*(i)+(j))*4(CTX), t; \
+       pshufd $0, t, t;
+
+#define K2(x0, x1, x2, x3, x4, i) \
+       get_key(i, 0, RK0); \
+       get_key(i, 1, RK1); \
+       get_key(i, 2, RK2); \
+       get_key(i, 3, RK3); \
+       pxor RK0,               x0 ## 1; \
+       pxor RK1,               x1 ## 1; \
+       pxor RK2,               x2 ## 1; \
+       pxor RK3,               x3 ## 1; \
+               pxor RK0,               x0 ## 2; \
+               pxor RK1,               x1 ## 2; \
+               pxor RK2,               x2 ## 2; \
+               pxor RK3,               x3 ## 2;
+
+#define LK2(x0, x1, x2, x3, x4, i) \
+       movdqa x0 ## 1,         x4 ## 1; \
+       pslld $13,              x0 ## 1; \
+       psrld $(32 - 13),       x4 ## 1; \
+       por x4 ## 1,            x0 ## 1; \
+       pxor x0 ## 1,           x1 ## 1; \
+       movdqa x2 ## 1,         x4 ## 1; \
+       pslld $3,               x2 ## 1; \
+       psrld $(32 - 3),        x4 ## 1; \
+       por x4 ## 1,            x2 ## 1; \
+       pxor x2 ## 1,           x1 ## 1; \
+               movdqa x0 ## 2,         x4 ## 2; \
+               pslld $13,              x0 ## 2; \
+               psrld $(32 - 13),       x4 ## 2; \
+               por x4 ## 2,            x0 ## 2; \
+               pxor x0 ## 2,           x1 ## 2; \
+               movdqa x2 ## 2,         x4 ## 2; \
+               pslld $3,               x2 ## 2; \
+               psrld $(32 - 3),        x4 ## 2; \
+               por x4 ## 2,            x2 ## 2; \
+               pxor x2 ## 2,           x1 ## 2; \
+       movdqa x1 ## 1,         x4 ## 1; \
+       pslld $1,               x1 ## 1; \
+       psrld $(32 - 1),        x4 ## 1; \
+       por x4 ## 1,            x1 ## 1; \
+       movdqa x0 ## 1,         x4 ## 1; \
+       pslld $3,               x4 ## 1; \
+       pxor x2 ## 1,           x3 ## 1; \
+       pxor x4 ## 1,           x3 ## 1; \
+       movdqa x3 ## 1,         x4 ## 1; \
+       get_key(i, 1, RK1); \
+               movdqa x1 ## 2,         x4 ## 2; \
+               pslld $1,               x1 ## 2; \
+               psrld $(32 - 1),        x4 ## 2; \
+               por x4 ## 2,            x1 ## 2; \
+               movdqa x0 ## 2,         x4 ## 2; \
+               pslld $3,               x4 ## 2; \
+               pxor x2 ## 2,           x3 ## 2; \
+               pxor x4 ## 2,           x3 ## 2; \
+               movdqa x3 ## 2,         x4 ## 2; \
+               get_key(i, 3, RK3); \
+       pslld $7,               x3 ## 1; \
+       psrld $(32 - 7),        x4 ## 1; \
+       por x4 ## 1,            x3 ## 1; \
+       movdqa x1 ## 1,         x4 ## 1; \
+       pslld $7,               x4 ## 1; \
+       pxor x1 ## 1,           x0 ## 1; \
+       pxor x3 ## 1,           x0 ## 1; \
+       pxor x3 ## 1,           x2 ## 1; \
+       pxor x4 ## 1,           x2 ## 1; \
+       get_key(i, 0, RK0); \
+               pslld $7,               x3 ## 2; \
+               psrld $(32 - 7),        x4 ## 2; \
+               por x4 ## 2,            x3 ## 2; \
+               movdqa x1 ## 2,         x4 ## 2; \
+               pslld $7,               x4 ## 2; \
+               pxor x1 ## 2,           x0 ## 2; \
+               pxor x3 ## 2,           x0 ## 2; \
+               pxor x3 ## 2,           x2 ## 2; \
+               pxor x4 ## 2,           x2 ## 2; \
+               get_key(i, 2, RK2); \
+       pxor RK1,               x1 ## 1; \
+       pxor RK3,               x3 ## 1; \
+       movdqa x0 ## 1,         x4 ## 1; \
+       pslld $5,               x0 ## 1; \
+       psrld $(32 - 5),        x4 ## 1; \
+       por x4 ## 1,            x0 ## 1; \
+       movdqa x2 ## 1,         x4 ## 1; \
+       pslld $22,              x2 ## 1; \
+       psrld $(32 - 22),       x4 ## 1; \
+       por x4 ## 1,            x2 ## 1; \
+       pxor RK0,               x0 ## 1; \
+       pxor RK2,               x2 ## 1; \
+               pxor RK1,               x1 ## 2; \
+               pxor RK3,               x3 ## 2; \
+               movdqa x0 ## 2,         x4 ## 2; \
+               pslld $5,               x0 ## 2; \
+               psrld $(32 - 5),        x4 ## 2; \
+               por x4 ## 2,            x0 ## 2; \
+               movdqa x2 ## 2,         x4 ## 2; \
+               pslld $22,              x2 ## 2; \
+               psrld $(32 - 22),       x4 ## 2; \
+               por x4 ## 2,            x2 ## 2; \
+               pxor RK0,               x0 ## 2; \
+               pxor RK2,               x2 ## 2;
+
+#define KL2(x0, x1, x2, x3, x4, i) \
+       pxor RK0,               x0 ## 1; \
+       pxor RK2,               x2 ## 1; \
+       movdqa x0 ## 1,         x4 ## 1; \
+       psrld $5,               x0 ## 1; \
+       pslld $(32 - 5),        x4 ## 1; \
+       por x4 ## 1,            x0 ## 1; \
+       pxor RK3,               x3 ## 1; \
+       pxor RK1,               x1 ## 1; \
+       movdqa x2 ## 1,         x4 ## 1; \
+       psrld $22,              x2 ## 1; \
+       pslld $(32 - 22),       x4 ## 1; \
+       por x4 ## 1,            x2 ## 1; \
+       pxor x3 ## 1,           x2 ## 1; \
+               pxor RK0,               x0 ## 2; \
+               pxor RK2,               x2 ## 2; \
+               movdqa x0 ## 2,         x4 ## 2; \
+               psrld $5,               x0 ## 2; \
+               pslld $(32 - 5),        x4 ## 2; \
+               por x4 ## 2,            x0 ## 2; \
+               pxor RK3,               x3 ## 2; \
+               pxor RK1,               x1 ## 2; \
+               movdqa x2 ## 2,         x4 ## 2; \
+               psrld $22,              x2 ## 2; \
+               pslld $(32 - 22),       x4 ## 2; \
+               por x4 ## 2,            x2 ## 2; \
+               pxor x3 ## 2,           x2 ## 2; \
+       pxor x3 ## 1,           x0 ## 1; \
+       movdqa x1 ## 1,         x4 ## 1; \
+       pslld $7,               x4 ## 1; \
+       pxor x1 ## 1,           x0 ## 1; \
+       pxor x4 ## 1,           x2 ## 1; \
+       movdqa x1 ## 1,         x4 ## 1; \
+       psrld $1,               x1 ## 1; \
+       pslld $(32 - 1),        x4 ## 1; \
+       por x4 ## 1,            x1 ## 1; \
+               pxor x3 ## 2,           x0 ## 2; \
+               movdqa x1 ## 2,         x4 ## 2; \
+               pslld $7,               x4 ## 2; \
+               pxor x1 ## 2,           x0 ## 2; \
+               pxor x4 ## 2,           x2 ## 2; \
+               movdqa x1 ## 2,         x4 ## 2; \
+               psrld $1,               x1 ## 2; \
+               pslld $(32 - 1),        x4 ## 2; \
+               por x4 ## 2,            x1 ## 2; \
+       movdqa x3 ## 1,         x4 ## 1; \
+       psrld $7,               x3 ## 1; \
+       pslld $(32 - 7),        x4 ## 1; \
+       por x4 ## 1,            x3 ## 1; \
+       pxor x0 ## 1,           x1 ## 1; \
+       movdqa x0 ## 1,         x4 ## 1; \
+       pslld $3,               x4 ## 1; \
+       pxor x4 ## 1,           x3 ## 1; \
+       movdqa x0 ## 1,         x4 ## 1; \
+               movdqa x3 ## 2,         x4 ## 2; \
+               psrld $7,               x3 ## 2; \
+               pslld $(32 - 7),        x4 ## 2; \
+               por x4 ## 2,            x3 ## 2; \
+               pxor x0 ## 2,           x1 ## 2; \
+               movdqa x0 ## 2,         x4 ## 2; \
+               pslld $3,               x4 ## 2; \
+               pxor x4 ## 2,           x3 ## 2; \
+               movdqa x0 ## 2,         x4 ## 2; \
+       psrld $13,              x0 ## 1; \
+       pslld $(32 - 13),       x4 ## 1; \
+       por x4 ## 1,            x0 ## 1; \
+       pxor x2 ## 1,           x1 ## 1; \
+       pxor x2 ## 1,           x3 ## 1; \
+       movdqa x2 ## 1,         x4 ## 1; \
+       psrld $3,               x2 ## 1; \
+       pslld $(32 - 3),        x4 ## 1; \
+       por x4 ## 1,            x2 ## 1; \
+               psrld $13,              x0 ## 2; \
+               pslld $(32 - 13),       x4 ## 2; \
+               por x4 ## 2,            x0 ## 2; \
+               pxor x2 ## 2,           x1 ## 2; \
+               pxor x2 ## 2,           x3 ## 2; \
+               movdqa x2 ## 2,         x4 ## 2; \
+               psrld $3,               x2 ## 2; \
+               pslld $(32 - 3),        x4 ## 2; \
+               por x4 ## 2,            x2 ## 2;
+
+#define S(SBOX, x0, x1, x2, x3, x4) \
+       SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+       SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2);
+
+#define SP(SBOX, x0, x1, x2, x3, x4, i) \
+       get_key(i, 0, RK0); \
+       SBOX ## _1(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       get_key(i, 2, RK2); \
+       SBOX ## _1(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+       get_key(i, 3, RK3); \
+       SBOX ## _2(x0 ## 1, x1 ## 1, x2 ## 1, x3 ## 1, x4 ## 1); \
+       get_key(i, 1, RK1); \
+       SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \
+
+#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \
+       movdqa x2,              t3; \
+       movdqa x0,              t1; \
+       unpcklps x3,            t3; \
+       movdqa x0,              t2; \
+       unpcklps x1,            t1; \
+       unpckhps x1,            t2; \
+       movdqa t3,              x1; \
+       unpckhps x3,            x2; \
+       movdqa t1,              x0; \
+       movhlps t1,             x1; \
+       movdqa t2,              t1; \
+       movlhps t3,             x0; \
+       movlhps x2,             t1; \
+       movhlps t2,             x2; \
+       movdqa x2,              x3; \
+       movdqa t1,              x2;
+
+#define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
+       movdqu (0*4*4)(in),     x0; \
+       movdqu (1*4*4)(in),     x1; \
+       movdqu (2*4*4)(in),     x2; \
+       movdqu (3*4*4)(in),     x3; \
+       \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define write_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       movdqu x0,              (0*4*4)(out); \
+       movdqu x1,              (1*4*4)(out); \
+       movdqu x2,              (2*4*4)(out); \
+       movdqu x3,              (3*4*4)(out);
+
+#define xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       movdqu (0*4*4)(out),    t0; \
+       pxor t0,                x0; \
+       movdqu x0,              (0*4*4)(out); \
+       movdqu (1*4*4)(out),    t0; \
+       pxor t0,                x1; \
+       movdqu x1,              (1*4*4)(out); \
+       movdqu (2*4*4)(out),    t0; \
+       pxor t0,                x2; \
+       movdqu x2,              (2*4*4)(out); \
+       movdqu (3*4*4)(out),    t0; \
+       pxor t0,                x3; \
+       movdqu x3,              (3*4*4)(out);
+
+.align 8
+.global __serpent_enc_blk_8way
+.type   __serpent_enc_blk_8way,@function;
+
+__serpent_enc_blk_8way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: bool, if true: xor output
+        */
+
+       pcmpeqd RNOT, RNOT;
+
+       leaq (4*4*4)(%rdx), %rax;
+       read_blocks(%rdx, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       read_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+                                                K2(RA, RB, RC, RD, RE, 0);
+       S(S0, RA, RB, RC, RD, RE);              LK2(RC, RB, RD, RA, RE, 1);
+       S(S1, RC, RB, RD, RA, RE);              LK2(RE, RD, RA, RC, RB, 2);
+       S(S2, RE, RD, RA, RC, RB);              LK2(RB, RD, RE, RC, RA, 3);
+       S(S3, RB, RD, RE, RC, RA);              LK2(RC, RA, RD, RB, RE, 4);
+       S(S4, RC, RA, RD, RB, RE);              LK2(RA, RD, RB, RE, RC, 5);
+       S(S5, RA, RD, RB, RE, RC);              LK2(RC, RA, RD, RE, RB, 6);
+       S(S6, RC, RA, RD, RE, RB);              LK2(RD, RB, RA, RE, RC, 7);
+       S(S7, RD, RB, RA, RE, RC);              LK2(RC, RA, RE, RD, RB, 8);
+       S(S0, RC, RA, RE, RD, RB);              LK2(RE, RA, RD, RC, RB, 9);
+       S(S1, RE, RA, RD, RC, RB);              LK2(RB, RD, RC, RE, RA, 10);
+       S(S2, RB, RD, RC, RE, RA);              LK2(RA, RD, RB, RE, RC, 11);
+       S(S3, RA, RD, RB, RE, RC);              LK2(RE, RC, RD, RA, RB, 12);
+       S(S4, RE, RC, RD, RA, RB);              LK2(RC, RD, RA, RB, RE, 13);
+       S(S5, RC, RD, RA, RB, RE);              LK2(RE, RC, RD, RB, RA, 14);
+       S(S6, RE, RC, RD, RB, RA);              LK2(RD, RA, RC, RB, RE, 15);
+       S(S7, RD, RA, RC, RB, RE);              LK2(RE, RC, RB, RD, RA, 16);
+       S(S0, RE, RC, RB, RD, RA);              LK2(RB, RC, RD, RE, RA, 17);
+       S(S1, RB, RC, RD, RE, RA);              LK2(RA, RD, RE, RB, RC, 18);
+       S(S2, RA, RD, RE, RB, RC);              LK2(RC, RD, RA, RB, RE, 19);
+       S(S3, RC, RD, RA, RB, RE);              LK2(RB, RE, RD, RC, RA, 20);
+       S(S4, RB, RE, RD, RC, RA);              LK2(RE, RD, RC, RA, RB, 21);
+       S(S5, RE, RD, RC, RA, RB);              LK2(RB, RE, RD, RA, RC, 22);
+       S(S6, RB, RE, RD, RA, RC);              LK2(RD, RC, RE, RA, RB, 23);
+       S(S7, RD, RC, RE, RA, RB);              LK2(RB, RE, RA, RD, RC, 24);
+       S(S0, RB, RE, RA, RD, RC);              LK2(RA, RE, RD, RB, RC, 25);
+       S(S1, RA, RE, RD, RB, RC);              LK2(RC, RD, RB, RA, RE, 26);
+       S(S2, RC, RD, RB, RA, RE);              LK2(RE, RD, RC, RA, RB, 27);
+       S(S3, RE, RD, RC, RA, RB);              LK2(RA, RB, RD, RE, RC, 28);
+       S(S4, RA, RB, RD, RE, RC);              LK2(RB, RD, RE, RC, RA, 29);
+       S(S5, RB, RD, RE, RC, RA);              LK2(RA, RB, RD, RC, RE, 30);
+       S(S6, RA, RB, RD, RC, RE);              LK2(RD, RE, RB, RC, RA, 31);
+       S(S7, RD, RE, RB, RC, RA);               K2(RA, RB, RC, RD, RE, 32);
+
+       leaq (4*4*4)(%rsi), %rax;
+
+       testb %cl, %cl;
+       jnz __enc_xor8;
+
+       write_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       write_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+       ret;
+
+__enc_xor8:
+       xor_blocks(%rsi, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       xor_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+       ret;
+
+.align 8
+.global serpent_dec_blk_8way
+.type   serpent_dec_blk_8way,@function;
+
+serpent_dec_blk_8way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       pcmpeqd RNOT, RNOT;
+
+       leaq (4*4*4)(%rdx), %rax;
+       read_blocks(%rdx, RA1, RB1, RC1, RD1, RK0, RK1, RK2);
+       read_blocks(%rax, RA2, RB2, RC2, RD2, RK0, RK1, RK2);
+
+                                                K2(RA, RB, RC, RD, RE, 32);
+       SP(SI7, RA, RB, RC, RD, RE, 31);        KL2(RB, RD, RA, RE, RC, 31);
+       SP(SI6, RB, RD, RA, RE, RC, 30);        KL2(RA, RC, RE, RB, RD, 30);
+       SP(SI5, RA, RC, RE, RB, RD, 29);        KL2(RC, RD, RA, RE, RB, 29);
+       SP(SI4, RC, RD, RA, RE, RB, 28);        KL2(RC, RA, RB, RE, RD, 28);
+       SP(SI3, RC, RA, RB, RE, RD, 27);        KL2(RB, RC, RD, RE, RA, 27);
+       SP(SI2, RB, RC, RD, RE, RA, 26);        KL2(RC, RA, RE, RD, RB, 26);
+       SP(SI1, RC, RA, RE, RD, RB, 25);        KL2(RB, RA, RE, RD, RC, 25);
+       SP(SI0, RB, RA, RE, RD, RC, 24);        KL2(RE, RC, RA, RB, RD, 24);
+       SP(SI7, RE, RC, RA, RB, RD, 23);        KL2(RC, RB, RE, RD, RA, 23);
+       SP(SI6, RC, RB, RE, RD, RA, 22);        KL2(RE, RA, RD, RC, RB, 22);
+       SP(SI5, RE, RA, RD, RC, RB, 21);        KL2(RA, RB, RE, RD, RC, 21);
+       SP(SI4, RA, RB, RE, RD, RC, 20);        KL2(RA, RE, RC, RD, RB, 20);
+       SP(SI3, RA, RE, RC, RD, RB, 19);        KL2(RC, RA, RB, RD, RE, 19);
+       SP(SI2, RC, RA, RB, RD, RE, 18);        KL2(RA, RE, RD, RB, RC, 18);
+       SP(SI1, RA, RE, RD, RB, RC, 17);        KL2(RC, RE, RD, RB, RA, 17);
+       SP(SI0, RC, RE, RD, RB, RA, 16);        KL2(RD, RA, RE, RC, RB, 16);
+       SP(SI7, RD, RA, RE, RC, RB, 15);        KL2(RA, RC, RD, RB, RE, 15);
+       SP(SI6, RA, RC, RD, RB, RE, 14);        KL2(RD, RE, RB, RA, RC, 14);
+       SP(SI5, RD, RE, RB, RA, RC, 13);        KL2(RE, RC, RD, RB, RA, 13);
+       SP(SI4, RE, RC, RD, RB, RA, 12);        KL2(RE, RD, RA, RB, RC, 12);
+       SP(SI3, RE, RD, RA, RB, RC, 11);        KL2(RA, RE, RC, RB, RD, 11);
+       SP(SI2, RA, RE, RC, RB, RD, 10);        KL2(RE, RD, RB, RC, RA, 10);
+       SP(SI1, RE, RD, RB, RC, RA, 9);         KL2(RA, RD, RB, RC, RE, 9);
+       SP(SI0, RA, RD, RB, RC, RE, 8);         KL2(RB, RE, RD, RA, RC, 8);
+       SP(SI7, RB, RE, RD, RA, RC, 7);         KL2(RE, RA, RB, RC, RD, 7);
+       SP(SI6, RE, RA, RB, RC, RD, 6);         KL2(RB, RD, RC, RE, RA, 6);
+       SP(SI5, RB, RD, RC, RE, RA, 5);         KL2(RD, RA, RB, RC, RE, 5);
+       SP(SI4, RD, RA, RB, RC, RE, 4);         KL2(RD, RB, RE, RC, RA, 4);
+       SP(SI3, RD, RB, RE, RC, RA, 3);         KL2(RE, RD, RA, RC, RB, 3);
+       SP(SI2, RE, RD, RA, RC, RB, 2);         KL2(RD, RB, RC, RA, RE, 2);
+       SP(SI1, RD, RB, RC, RA, RE, 1);         KL2(RE, RB, RC, RA, RD, 1);
+       S(SI0, RE, RB, RC, RA, RD);              K2(RC, RD, RB, RE, RA, 0);
+
+       leaq (4*4*4)(%rsi), %rax;
+       write_blocks(%rsi, RC1, RD1, RB1, RE1, RK0, RK1, RK2);
+       write_blocks(%rax, RC2, RD2, RB2, RE2, RK0, RK1, RK2);
+
+       ret;
diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c
new file mode 100644 (file)
index 0000000..7955a9b
--- /dev/null
@@ -0,0 +1,1070 @@
+/*
+ * Glue Code for SSE2 assembler versions of Serpent Cipher
+ *
+ * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ *
+ * Glue code based on aesni-intel_glue.c by:
+ *  Copyright (C) 2008, Intel Corp.
+ *    Author: Huang Ying <ying.huang@intel.com>
+ *
+ * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
+ *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ * CTR part based on code (crypto/ctr.c) by:
+ *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/serpent.h>
+#include <crypto/cryptd.h>
+#include <crypto/b128ops.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/i387.h>
+#include <asm/serpent.h>
+#include <crypto/scatterwalk.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+
+struct async_serpent_ctx {
+       struct cryptd_ablkcipher *cryptd_tfm;
+};
+
+static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       if (fpu_enabled)
+               return true;
+
+       /* SSE2 is only used when chunk to be processed is large enough, so
+        * do not enable FPU until it is necessary.
+        */
+       if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS)
+               return false;
+
+       kernel_fpu_begin();
+       return true;
+}
+
+static inline void serpent_fpu_end(bool fpu_enabled)
+{
+       if (fpu_enabled)
+               kernel_fpu_end();
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+                    bool enc)
+{
+       bool fpu_enabled = false;
+       struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       unsigned int nbytes;
+       int err;
+
+       err = blkcipher_walk_virt(desc, walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk->nbytes)) {
+               u8 *wsrc = walk->src.virt.addr;
+               u8 *wdst = walk->dst.virt.addr;
+
+               fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+
+               /* Process multi-block batch */
+               if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+                       do {
+                               if (enc)
+                                       serpent_enc_blk_xway(ctx, wdst, wsrc);
+                               else
+                                       serpent_dec_blk_xway(ctx, wdst, wsrc);
+
+                               wsrc += bsize * SERPENT_PARALLEL_BLOCKS;
+                               wdst += bsize * SERPENT_PARALLEL_BLOCKS;
+                               nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+                       } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+
+               /* Handle leftovers */
+               do {
+                       if (enc)
+                               __serpent_encrypt(ctx, wdst, wsrc);
+                       else
+                               __serpent_decrypt(ctx, wdst, wsrc);
+
+                       wsrc += bsize;
+                       wdst += bsize;
+                       nbytes -= bsize;
+               } while (nbytes >= bsize);
+
+done:
+               err = blkcipher_walk_done(desc, walk, nbytes);
+       }
+
+       serpent_fpu_end(fpu_enabled);
+       return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, false);
+}
+
+static struct crypto_alg blk_ecb_alg = {
+       .cra_name               = "__ecb-serpent-sse2",
+       .cra_driver_name        = "__driver-ecb-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+};
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 *iv = (u128 *)walk->iv;
+
+       do {
+               u128_xor(dst, src, iv);
+               __serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst);
+               iv = dst;
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+       u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
+       return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while ((nbytes = walk.nbytes)) {
+               nbytes = __cbc_encrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
+       u128 last_iv;
+       int i;
+
+       /* Start of the last block. */
+       src += nbytes / bsize - 1;
+       dst += nbytes / bsize - 1;
+
+       last_iv = *src;
+
+       /* Process multi-block batch */
+       if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+               do {
+                       nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1);
+                       src -= SERPENT_PARALLEL_BLOCKS - 1;
+                       dst -= SERPENT_PARALLEL_BLOCKS - 1;
+
+                       for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
+                               ivs[i] = src[i];
+
+                       serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+                       for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
+                               u128_xor(dst + (i + 1), dst + (i + 1), ivs + i);
+
+                       nbytes -= bsize;
+                       if (nbytes < bsize)
+                               goto done;
+
+                       u128_xor(dst, dst, src - 1);
+                       src -= 1;
+                       dst -= 1;
+               } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       for (;;) {
+               __serpent_decrypt(ctx, (u8 *)dst, (u8 *)src);
+
+               nbytes -= bsize;
+               if (nbytes < bsize)
+                       break;
+
+               u128_xor(dst, dst, src - 1);
+               src -= 1;
+               dst -= 1;
+       }
+
+done:
+       u128_xor(dst, dst, (u128 *)walk->iv);
+       *(u128 *)walk->iv = last_iv;
+
+       return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes)) {
+               fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __cbc_decrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       serpent_fpu_end(fpu_enabled);
+       return err;
+}
+
+static struct crypto_alg blk_cbc_alg = {
+       .cra_name               = "__cbc-serpent-sse2",
+       .cra_driver_name        = "__driver-cbc-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+};
+
+static inline void u128_to_be128(be128 *dst, const u128 *src)
+{
+       dst->a = cpu_to_be64(src->a);
+       dst->b = cpu_to_be64(src->b);
+}
+
+static inline void be128_to_u128(u128 *dst, const be128 *src)
+{
+       dst->a = be64_to_cpu(src->a);
+       dst->b = be64_to_cpu(src->b);
+}
+
+static inline void u128_inc(u128 *i)
+{
+       i->b++;
+       if (!i->b)
+               i->a++;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+                           struct blkcipher_walk *walk)
+{
+       struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       u8 *ctrblk = walk->iv;
+       u8 keystream[SERPENT_BLOCK_SIZE];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       __serpent_encrypt(ctx, keystream, ctrblk);
+       crypto_xor(keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+
+       crypto_inc(ctrblk, SERPENT_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+                               struct blkcipher_walk *walk)
+{
+       struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u128 *src = (u128 *)walk->src.virt.addr;
+       u128 *dst = (u128 *)walk->dst.virt.addr;
+       u128 ctrblk;
+       be128 ctrblocks[SERPENT_PARALLEL_BLOCKS];
+       int i;
+
+       be128_to_u128(&ctrblk, (be128 *)walk->iv);
+
+       /* Process multi-block batch */
+       if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
+               do {
+                       /* create ctrblks for parallel encrypt */
+                       for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
+                               if (dst != src)
+                                       dst[i] = src[i];
+
+                               u128_to_be128(&ctrblocks[i], &ctrblk);
+                               u128_inc(&ctrblk);
+                       }
+
+                       serpent_enc_blk_xway_xor(ctx, (u8 *)dst,
+                                                (u8 *)ctrblocks);
+
+                       src += SERPENT_PARALLEL_BLOCKS;
+                       dst += SERPENT_PARALLEL_BLOCKS;
+                       nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
+               } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       do {
+               if (dst != src)
+                       *dst = *src;
+
+               u128_to_be128(&ctrblocks[0], &ctrblk);
+               u128_inc(&ctrblk);
+
+               __serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
+               u128_xor(dst, dst, (u128 *)ctrblocks);
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+done:
+       u128_to_be128((be128 *)walk->iv, &ctrblk);
+       return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) {
+               fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __ctr_crypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       serpent_fpu_end(fpu_enabled);
+
+       if (walk.nbytes) {
+               ctr_crypt_final(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+static struct crypto_alg blk_ctr_alg = {
+       .cra_name               = "__ctr-serpent-sse2",
+       .cra_driver_name        = "__driver-ctr-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_ctr_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = serpent_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+};
+
+struct crypt_priv {
+       struct serpent_ctx *ctx;
+       bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
+               serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __serpent_encrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = SERPENT_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
+               serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __serpent_decrypt(ctx->ctx, srcdst, srcdst);
+}
+
+struct serpent_lrw_ctx {
+       struct lrw_table_ctx lrw_table;
+       struct serpent_ctx serpent_ctx;
+};
+
+static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
+                                                       SERPENT_BLOCK_SIZE);
+       if (err)
+               return err;
+
+       return lrw_init_table(&ctx->lrw_table, key + keylen -
+                                               SERPENT_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->serpent_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->serpent_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       lrw_free_table(&ctx->lrw_table);
+}
+
+static struct crypto_alg blk_lrw_alg = {
+       .cra_name               = "__lrw-serpent-sse2",
+       .cra_driver_name        = "__driver-lrw-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_lrw_alg.cra_list),
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = lrw_serpent_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+};
+
+struct serpent_xts_ctx {
+       struct serpent_ctx tweak_ctx;
+       struct serpent_ctx crypt_ctx;
+};
+
+static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int err;
+
+       /* key consists of keys of equal size concatenated, therefore
+        * the length must be even
+        */
+       if (keylen % 2) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       /* first half of xts-key is for crypt */
+       err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
+       if (err)
+               return err;
+
+       /* second half of xts-key is for tweak */
+       return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->crypt_ctx,
+               .fpu_enabled = false,
+       };
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = xts_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[SERPENT_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->crypt_ctx,
+               .fpu_enabled = false,
+       };
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = xts_crypt(desc, dst, src, nbytes, &req);
+       serpent_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static struct crypto_alg blk_xts_alg = {
+       .cra_name               = "__xts-serpent-sse2",
+       .cra_driver_name        = "__driver-xts-serpent-sse2",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct serpent_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_xts_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = xts_serpent_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+};
+
+static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+                       unsigned int key_len)
+{
+       struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
+       int err;
+
+       crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
+                                   & CRYPTO_TFM_REQ_MASK);
+       err = crypto_ablkcipher_setkey(child, key, key_len);
+       crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
+                                   & CRYPTO_TFM_RES_MASK);
+       return err;
+}
+
+static int __ablk_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+       struct blkcipher_desc desc;
+
+       desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+       desc.info = req->info;
+       desc.flags = 0;
+
+       return crypto_blkcipher_crt(desc.tfm)->encrypt(
+               &desc, req->dst, req->src, req->nbytes);
+}
+
+static int ablk_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       if (!irq_fpu_usable()) {
+               struct ablkcipher_request *cryptd_req =
+                       ablkcipher_request_ctx(req);
+
+               memcpy(cryptd_req, req, sizeof(*req));
+               ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+               return crypto_ablkcipher_encrypt(cryptd_req);
+       } else {
+               return __ablk_encrypt(req);
+       }
+}
+
+static int ablk_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+       struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+       if (!irq_fpu_usable()) {
+               struct ablkcipher_request *cryptd_req =
+                       ablkcipher_request_ctx(req);
+
+               memcpy(cryptd_req, req, sizeof(*req));
+               ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
+
+               return crypto_ablkcipher_decrypt(cryptd_req);
+       } else {
+               struct blkcipher_desc desc;
+
+               desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
+               desc.info = req->info;
+               desc.flags = 0;
+
+               return crypto_blkcipher_crt(desc.tfm)->decrypt(
+                       &desc, req->dst, req->src, req->nbytes);
+       }
+}
+
+static void ablk_exit(struct crypto_tfm *tfm)
+{
+       struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       cryptd_free_ablkcipher(ctx->cryptd_tfm);
+}
+
+static void ablk_init_common(struct crypto_tfm *tfm,
+                            struct cryptd_ablkcipher *cryptd_tfm)
+{
+       struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->cryptd_tfm = cryptd_tfm;
+       tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+               crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+}
+
+static int ablk_ecb_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_ecb_alg = {
+       .cra_name               = "ecb(serpent)",
+       .cra_driver_name        = "ecb-serpent-sse2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
+       .cra_init               = ablk_ecb_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int ablk_cbc_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_cbc_alg = {
+       .cra_name               = "cbc(serpent)",
+       .cra_driver_name        = "cbc-serpent-sse2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
+       .cra_init               = ablk_cbc_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int ablk_ctr_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_ctr_alg = {
+       .cra_name               = "ctr(serpent)",
+       .cra_driver_name        = "ctr-serpent-sse2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
+       .cra_init               = ablk_ctr_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+};
+
+static int ablk_lrw_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_lrw_alg = {
+       .cra_name               = "lrw(serpent)",
+       .cra_driver_name        = "lrw-serpent-sse2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
+       .cra_init               = ablk_lrw_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE +
+                                         SERPENT_BLOCK_SIZE,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int ablk_xts_init(struct crypto_tfm *tfm)
+{
+       struct cryptd_ablkcipher *cryptd_tfm;
+
+       cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0);
+       if (IS_ERR(cryptd_tfm))
+               return PTR_ERR(cryptd_tfm);
+       ablk_init_common(tfm, cryptd_tfm);
+       return 0;
+}
+
+static struct crypto_alg ablk_xts_alg = {
+       .cra_name               = "xts(serpent)",
+       .cra_driver_name        = "xts-serpent-sse2",
+       .cra_priority           = 400,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_serpent_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
+       .cra_init               = ablk_xts_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
+                       .max_keysize    = SERPENT_MAX_KEY_SIZE * 2,
+                       .ivsize         = SERPENT_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+};
+
+static int __init serpent_sse2_init(void)
+{
+       int err;
+
+       if (!cpu_has_xmm2) {
+               printk(KERN_INFO "SSE2 instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       err = crypto_register_alg(&blk_ecb_alg);
+       if (err)
+               goto blk_ecb_err;
+       err = crypto_register_alg(&blk_cbc_alg);
+       if (err)
+               goto blk_cbc_err;
+       err = crypto_register_alg(&blk_ctr_alg);
+       if (err)
+               goto blk_ctr_err;
+       err = crypto_register_alg(&ablk_ecb_alg);
+       if (err)
+               goto ablk_ecb_err;
+       err = crypto_register_alg(&ablk_cbc_alg);
+       if (err)
+               goto ablk_cbc_err;
+       err = crypto_register_alg(&ablk_ctr_alg);
+       if (err)
+               goto ablk_ctr_err;
+       err = crypto_register_alg(&blk_lrw_alg);
+       if (err)
+               goto blk_lrw_err;
+       err = crypto_register_alg(&ablk_lrw_alg);
+       if (err)
+               goto ablk_lrw_err;
+       err = crypto_register_alg(&blk_xts_alg);
+       if (err)
+               goto blk_xts_err;
+       err = crypto_register_alg(&ablk_xts_alg);
+       if (err)
+               goto ablk_xts_err;
+       return err;
+
+       crypto_unregister_alg(&ablk_xts_alg);
+ablk_xts_err:
+       crypto_unregister_alg(&blk_xts_alg);
+blk_xts_err:
+       crypto_unregister_alg(&ablk_lrw_alg);
+ablk_lrw_err:
+       crypto_unregister_alg(&blk_lrw_alg);
+blk_lrw_err:
+       crypto_unregister_alg(&ablk_ctr_alg);
+ablk_ctr_err:
+       crypto_unregister_alg(&ablk_cbc_alg);
+ablk_cbc_err:
+       crypto_unregister_alg(&ablk_ecb_alg);
+ablk_ecb_err:
+       crypto_unregister_alg(&blk_ctr_alg);
+blk_ctr_err:
+       crypto_unregister_alg(&blk_cbc_alg);
+blk_cbc_err:
+       crypto_unregister_alg(&blk_ecb_alg);
+blk_ecb_err:
+       return err;
+}
+
+static void __exit serpent_sse2_exit(void)
+{
+       crypto_unregister_alg(&ablk_xts_alg);
+       crypto_unregister_alg(&blk_xts_alg);
+       crypto_unregister_alg(&ablk_lrw_alg);
+       crypto_unregister_alg(&blk_lrw_alg);
+       crypto_unregister_alg(&ablk_ctr_alg);
+       crypto_unregister_alg(&ablk_cbc_alg);
+       crypto_unregister_alg(&ablk_ecb_alg);
+       crypto_unregister_alg(&blk_ctr_alg);
+       crypto_unregister_alg(&blk_cbc_alg);
+       crypto_unregister_alg(&blk_ecb_alg);
+}
+
+module_init(serpent_sse2_init);
+module_exit(serpent_sse2_exit);
+
+MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("serpent");
index 5ede9c444c3e758a67ac5d970d786f54a3775cc8..7fee8c152f93c73d430b138a464dcb83f8cfaf0e 100644 (file)
@@ -32,6 +32,8 @@
 #include <crypto/algapi.h>
 #include <crypto/twofish.h>
 #include <crypto/b128ops.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
 
 /* regular block cipher functions from twofish_x86_64 module */
 asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst,
@@ -432,6 +434,209 @@ static struct crypto_alg blk_ctr_alg = {
        },
 };
 
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = TF_BLOCK_SIZE;
+       struct twofish_ctx *ctx = priv;
+       int i;
+
+       if (nbytes == 3 * bsize) {
+               twofish_enc_blk_3way(ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               twofish_enc_blk(ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = TF_BLOCK_SIZE;
+       struct twofish_ctx *ctx = priv;
+       int i;
+
+       if (nbytes == 3 * bsize) {
+               twofish_dec_blk_3way(ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               twofish_dec_blk(ctx, srcdst, srcdst);
+}
+
+struct twofish_lrw_ctx {
+       struct lrw_table_ctx lrw_table;
+       struct twofish_ctx twofish_ctx;
+};
+
+static int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       err = __twofish_setkey(&ctx->twofish_ctx, key, keylen - TF_BLOCK_SIZE,
+                              &tfm->crt_flags);
+       if (err)
+               return err;
+
+       return lrw_init_table(&ctx->lrw_table, key + keylen - TF_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[3];
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &ctx->twofish_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+
+       return lrw_crypt(desc, dst, src, nbytes, &req);
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[3];
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &ctx->twofish_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+
+       return lrw_crypt(desc, dst, src, nbytes, &req);
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       lrw_free_table(&ctx->lrw_table);
+}
+
+static struct crypto_alg blk_lrw_alg = {
+       .cra_name               = "lrw(twofish)",
+       .cra_driver_name        = "lrw-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = TF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct twofish_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_lrw_alg.cra_list),
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE,
+                       .max_keysize    = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE,
+                       .ivsize         = TF_BLOCK_SIZE,
+                       .setkey         = lrw_twofish_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+};
+
+struct twofish_xts_ctx {
+       struct twofish_ctx tweak_ctx;
+       struct twofish_ctx crypt_ctx;
+};
+
+static int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct twofish_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int err;
+
+       /* key consists of keys of equal size concatenated, therefore
+        * the length must be even
+        */
+       if (keylen % 2) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       /* first half of xts-key is for crypt */
+       err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+       if (err)
+               return err;
+
+       /* second half of xts-key is for tweak */
+       return __twofish_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+                               flags);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[3];
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
+               .crypt_ctx = &ctx->crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+
+       return xts_crypt(desc, dst, src, nbytes, &req);
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[3];
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
+               .crypt_ctx = &ctx->crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+
+       return xts_crypt(desc, dst, src, nbytes, &req);
+}
+
+static struct crypto_alg blk_xts_alg = {
+       .cra_name               = "xts(twofish)",
+       .cra_driver_name        = "xts-twofish-3way",
+       .cra_priority           = 300,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = TF_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct twofish_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(blk_xts_alg.cra_list),
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = TF_MIN_KEY_SIZE * 2,
+                       .max_keysize    = TF_MAX_KEY_SIZE * 2,
+                       .ivsize         = TF_BLOCK_SIZE,
+                       .setkey         = xts_twofish_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+};
+
 int __init init(void)
 {
        int err;
@@ -445,9 +650,20 @@ int __init init(void)
        err = crypto_register_alg(&blk_ctr_alg);
        if (err)
                goto ctr_err;
+       err = crypto_register_alg(&blk_lrw_alg);
+       if (err)
+               goto blk_lrw_err;
+       err = crypto_register_alg(&blk_xts_alg);
+       if (err)
+               goto blk_xts_err;
 
        return 0;
 
+       crypto_unregister_alg(&blk_xts_alg);
+blk_xts_err:
+       crypto_unregister_alg(&blk_lrw_alg);
+blk_lrw_err:
+       crypto_unregister_alg(&blk_ctr_alg);
 ctr_err:
        crypto_unregister_alg(&blk_cbc_alg);
 cbc_err:
@@ -458,6 +674,8 @@ ecb_err:
 
 void __exit fini(void)
 {
+       crypto_unregister_alg(&blk_xts_alg);
+       crypto_unregister_alg(&blk_lrw_alg);
        crypto_unregister_alg(&blk_ctr_alg);
        crypto_unregister_alg(&blk_cbc_alg);
        crypto_unregister_alg(&blk_ecb_alg);
index 8e41071704a5b84ec57c6d261410de9f3ffcb5fe..49ad773f4b9f5f4631e4e5bed590c8d6356e4e0f 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_AMD_NB_H
 #define _ASM_X86_AMD_NB_H
 
+#include <linux/ioport.h>
 #include <linux/pci.h>
 
 struct amd_nb_bus_dev_range {
@@ -13,6 +14,7 @@ extern const struct pci_device_id amd_nb_misc_ids[];
 extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
 
 extern bool early_is_amd_nb(u32 value);
+extern struct resource *amd_get_mmconfig_range(struct resource *res);
 extern int amd_cache_northbridges(void);
 extern void amd_flush_garts(void);
 extern int amd_numa_init(void);
index e020d88ec02dc2636800eee7203cf4a800dc2fb3..2f90c51cc49d740ed849cfc8775b3478fd6987f5 100644 (file)
@@ -64,6 +64,8 @@ struct setup_header {
        __u32   payload_offset;
        __u32   payload_length;
        __u64   setup_data;
+       __u64   pref_address;
+       __u32   init_size;
 } __attribute__((packed));
 
 struct sys_desc_table {
index 7093e4a6a0bc6dd5644b2b14cbef9ef5f4085eef..844f735fd63aa5763804e51710b7ed45ddf10e76 100644 (file)
@@ -3,6 +3,8 @@
 
 #ifdef CONFIG_X86_32
 
+#define EFI_LOADER_SIGNATURE   "EL32"
+
 extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #define efi_call_phys0(f)              efi_call_phys(f)
@@ -37,6 +39,8 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #else /* !CONFIG_X86_32 */
 
+#define EFI_LOADER_SIGNATURE   "EL64"
+
 extern u64 efi_call0(void *fp);
 extern u64 efi_call1(void *fp, u64 arg1);
 extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
index 460c74e4852c24ba0bb8dfbe6972dea7fcc63aa9..4da3c0c4c9741c38efd6418ec081404bb43d8fef 100644 (file)
@@ -117,7 +117,7 @@ enum fixed_addresses {
 #endif
        FIX_TEXT_POKE1, /* reserve 2 pages for text_poke() */
        FIX_TEXT_POKE0, /* first page is last, because allocation is backward */
-#ifdef CONFIG_X86_MRST
+#ifdef CONFIG_X86_INTEL_MID
        FIX_LNW_VRTC,
 #endif
        __end_of_permanent_fixed_addresses,
index 8dbe353e41e160a49da8b370f2f489e161aa8e11..adcc0ae73d0914b4fe7b816c4512d296b290ba70 100644 (file)
@@ -5,6 +5,8 @@
 extern void __init early_ioremap_page_table_range_init(void);
 #endif
 
+extern void __init zone_sizes_init(void);
+
 extern unsigned long __init
 kernel_physical_mapping_init(unsigned long start,
                             unsigned long end,
index d498943b906c6138ce51e38e49d4eae569428967..df75d07571ceacf69aef19bf243793048cf16c02 100644 (file)
@@ -112,19 +112,28 @@ static inline void x86_teardown_msi_irq(unsigned int irq)
 {
        x86_msi.teardown_msi_irq(irq);
 }
+static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq)
+{
+       x86_msi.restore_msi_irqs(dev, irq);
+}
 #define arch_setup_msi_irqs x86_setup_msi_irqs
 #define arch_teardown_msi_irqs x86_teardown_msi_irqs
 #define arch_teardown_msi_irq x86_teardown_msi_irq
+#define arch_restore_msi_irqs x86_restore_msi_irqs
 /* implemented in arch/x86/kernel/apic/io_apic. */
 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
 void native_teardown_msi_irq(unsigned int irq);
+void native_restore_msi_irqs(struct pci_dev *dev, int irq);
 /* default to the implementation in drivers/lib/msi.c */
 #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
+#define HAVE_DEFAULT_MSI_RESTORE_IRQS
 void default_teardown_msi_irqs(struct pci_dev *dev);
+void default_restore_msi_irqs(struct pci_dev *dev, int irq);
 #else
 #define native_setup_msi_irqs          NULL
 #define native_teardown_msi_irq                NULL
 #define default_teardown_msi_irqs      NULL
+#define default_restore_msi_irqs       NULL
 #endif
 
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
index e381978068533292e67ef9dfc613b1b939671bbb..b3a531746026105ba70b4d29293696bc02e32779 100644 (file)
@@ -44,8 +44,6 @@ enum pci_bf_sort_state {
 
 /* pci-i386.c */
 
-extern unsigned int pcibios_max_latency;
-
 void pcibios_resource_survey(void);
 void pcibios_set_cache_line_size(void);
 
diff --git a/arch/x86/include/asm/serpent.h b/arch/x86/include/asm/serpent.h
new file mode 100644 (file)
index 0000000..d3ef63f
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef ASM_X86_SERPENT_H
+#define ASM_X86_SERPENT_H
+
+#include <linux/crypto.h>
+#include <crypto/serpent.h>
+
+#ifdef CONFIG_X86_32
+
+#define SERPENT_PARALLEL_BLOCKS 4
+
+asmlinkage void __serpent_enc_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+                                      const u8 *src, bool xor);
+asmlinkage void serpent_dec_blk_4way(struct serpent_ctx *ctx, u8 *dst,
+                                    const u8 *src);
+
+static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+                                       const u8 *src)
+{
+       __serpent_enc_blk_4way(ctx, dst, src, false);
+}
+
+static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
+                                           const u8 *src)
+{
+       __serpent_enc_blk_4way(ctx, dst, src, true);
+}
+
+static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+                                       const u8 *src)
+{
+       serpent_dec_blk_4way(ctx, dst, src);
+}
+
+#else
+
+#define SERPENT_PARALLEL_BLOCKS 8
+
+asmlinkage void __serpent_enc_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+                                      const u8 *src, bool xor);
+asmlinkage void serpent_dec_blk_8way(struct serpent_ctx *ctx, u8 *dst,
+                                    const u8 *src);
+
+static inline void serpent_enc_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+                                  const u8 *src)
+{
+       __serpent_enc_blk_8way(ctx, dst, src, false);
+}
+
+static inline void serpent_enc_blk_xway_xor(struct serpent_ctx *ctx, u8 *dst,
+                                      const u8 *src)
+{
+       __serpent_enc_blk_8way(ctx, dst, src, true);
+}
+
+static inline void serpent_dec_blk_xway(struct serpent_ctx *ctx, u8 *dst,
+                                  const u8 *src)
+{
+       serpent_dec_blk_8way(ctx, dst, src);
+}
+
+#endif
+
+#endif
index 9756551ec76024dba4dbf7a4f09f988219ca6f0b..d0f19f9fb846956a0715e59e52836fd9bc767028 100644 (file)
@@ -47,7 +47,7 @@ extern void reserve_standard_io_resources(void);
 extern void i386_reserve_resources(void);
 extern void setup_default_timer_irq(void);
 
-#ifdef CONFIG_X86_MRST
+#ifdef CONFIG_X86_INTEL_MID
 extern void x86_mrst_early_setup(void);
 #else
 static inline void x86_mrst_early_setup(void) { }
index 73b11bc0ae6faeb8102ae1303ceaa8335d89e340..0434c400287cffa9c8d80075c5a31defa4097629 100644 (file)
@@ -225,5 +225,11 @@ extern int hard_smp_processor_id(void);
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
+#ifdef CONFIG_DEBUG_NMI_SELFTEST
+extern void nmi_selftest(void);
+#else
+#define nmi_selftest() do { } while (0)
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_X86_SMP_H */
index 74047159d0ab517acc0213d5fd8b7149efa26d57..bc817cd8b44359b615e34f9b08aa67a61425cf29 100644 (file)
@@ -40,8 +40,8 @@ struct thread_info {
                                                */
        __u8                    supervisor_stack[0];
 #endif
-       int                     sig_on_uaccess_error:1;
-       int                     uaccess_err:1;  /* uaccess failed */
+       unsigned int            sig_on_uaccess_error:1;
+       unsigned int            uaccess_err:1;  /* uaccess failed */
 };
 
 #define INIT_THREAD_INFO(tsk)                  \
index 800f77c600510e431947e2e92f32d950d3d6c6b7..b9676ae37ada7ddbf7c7d208653ecb892ca2a9c8 100644 (file)
@@ -172,7 +172,7 @@ static inline void arch_fix_phys_package_id(int num, u32 slot)
 }
 
 struct pci_bus;
-void x86_pci_root_bus_res_quirks(struct pci_bus *b);
+void x86_pci_root_bus_resources(int bus, struct list_head *resources);
 
 #ifdef CONFIG_SMP
 #define mc_capable()   ((boot_cpu_data.x86_max_cores > 1) && \
index 1ac860a098495e70421563d1bd0d9f2b3b848448..517d4767ffdda95e249cc5c173eb008a439cd346 100644 (file)
@@ -179,6 +179,7 @@ struct x86_msi_ops {
        int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
        void (*teardown_msi_irq)(unsigned int irq);
        void (*teardown_msi_irqs)(struct pci_dev *dev);
+       void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
 };
 
 extern struct x86_init_ops x86_init;
index 8baca3c4871c7fa1f4732a100d5819d52c75a1e9..02b2f05b371e9a8a8c84fb2f0bd5742b1d8d6963 100644 (file)
@@ -80,6 +80,7 @@ obj-$(CONFIG_APB_TIMER)               += apb_timer.o
 obj-$(CONFIG_AMD_NB)           += amd_nb.o
 obj-$(CONFIG_DEBUG_RODATA_TEST)        += test_rodata.o
 obj-$(CONFIG_DEBUG_NX_TEST)    += test_nx.o
+obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o
 
 obj-$(CONFIG_KVM_GUEST)                += kvm.o
 obj-$(CONFIG_KVM_CLOCK)                += kvmclock.o
index 013c1810ce72938c3bbe18a57f22664d1732f27b..be16854591cc26a2b0349b6f7d9e0cc446340e32 100644 (file)
@@ -119,6 +119,37 @@ bool __init early_is_amd_nb(u32 device)
        return false;
 }
 
+struct resource *amd_get_mmconfig_range(struct resource *res)
+{
+       u32 address;
+       u64 base, msr;
+       unsigned segn_busn_bits;
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               return NULL;
+
+       /* assume all cpus from fam10h have mmconfig */
+        if (boot_cpu_data.x86 < 0x10)
+               return NULL;
+
+       address = MSR_FAM10H_MMIO_CONF_BASE;
+       rdmsrl(address, msr);
+
+       /* mmconfig is not enabled */
+       if (!(msr & FAM10H_MMIO_CONF_ENABLE))
+               return NULL;
+
+       base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
+
+       segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+                        FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+       res->flags = IORESOURCE_MEM;
+       res->start = base;
+       res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
+       return res;
+}
+
 int amd_get_subcaches(int cpu)
 {
        struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
index 4f13fafc5264c8e18bd4f8f8e00b96927b69924c..68de2dc962ec0dc52a8721578aa0ca9aff40ba39 100644 (file)
@@ -67,4 +67,6 @@ void common(void) {
        OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
        OFFSET(BP_version, boot_params, hdr.version);
        OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
+       OFFSET(BP_pref_address, boot_params, hdr.pref_address);
+       OFFSET(BP_code32_start, boot_params, hdr.code32_start);
 }
index f22a9f7f6390a62ce3d028df8dba0723b232b28a..29ba3297e48006bea5987678bb4806d3c534fc2c 100644 (file)
@@ -2011,7 +2011,7 @@ static __cpuinit int mce_device_create(unsigned int cpu)
        if (!mce_available(&boot_cpu_data))
                return -EIO;
 
-       memset(&dev->kobj, 0, sizeof(struct kobject));
+       memset(dev, 0, sizeof(struct device));
        dev->id  = cpu;
        dev->bus = &mce_subsys;
 
index 8071e2f3d6eb5b6fa42c8cc4844f1b4f57966125..174d938d576b347365f4fdab2de8e7b85fd36f53 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/acpi.h>
 #include <linux/firmware-map.h>
 #include <linux/memblock.h>
+#include <linux/sort.h>
 
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -227,22 +228,38 @@ void __init e820_print_map(char *who)
  *        ____________________33__
  *        ______________________4_
  */
+struct change_member {
+       struct e820entry *pbios; /* pointer to original bios entry */
+       unsigned long long addr; /* address for this change point */
+};
+
+static int __init cpcompare(const void *a, const void *b)
+{
+       struct change_member * const *app = a, * const *bpp = b;
+       const struct change_member *ap = *app, *bp = *bpp;
+
+       /*
+        * Inputs are pointers to two elements of change_point[].  If their
+        * addresses are unequal, their difference dominates.  If the addresses
+        * are equal, then consider one that represents the end of its region
+        * to be greater than one that does not.
+        */
+       if (ap->addr != bp->addr)
+               return ap->addr > bp->addr ? 1 : -1;
+
+       return (ap->addr != ap->pbios->addr) - (bp->addr != bp->pbios->addr);
+}
 
 int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
                             u32 *pnr_map)
 {
-       struct change_member {
-               struct e820entry *pbios; /* pointer to original bios entry */
-               unsigned long long addr; /* address for this change point */
-       };
        static struct change_member change_point_list[2*E820_X_MAX] __initdata;
        static struct change_member *change_point[2*E820_X_MAX] __initdata;
        static struct e820entry *overlap_list[E820_X_MAX] __initdata;
        static struct e820entry new_bios[E820_X_MAX] __initdata;
-       struct change_member *change_tmp;
        unsigned long current_type, last_type;
        unsigned long long last_addr;
-       int chgidx, still_changing;
+       int chgidx;
        int overlap_entries;
        int new_bios_entry;
        int old_nr, new_nr, chg_nr;
@@ -279,35 +296,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map,
        chg_nr = chgidx;
 
        /* sort change-point list by memory addresses (low -> high) */
-       still_changing = 1;
-       while (still_changing)  {
-               still_changing = 0;
-               for (i = 1; i < chg_nr; i++)  {
-                       unsigned long long curaddr, lastaddr;
-                       unsigned long long curpbaddr, lastpbaddr;
-
-                       curaddr = change_point[i]->addr;
-                       lastaddr = change_point[i - 1]->addr;
-                       curpbaddr = change_point[i]->pbios->addr;
-                       lastpbaddr = change_point[i - 1]->pbios->addr;
-
-                       /*
-                        * swap entries, when:
-                        *
-                        * curaddr > lastaddr or
-                        * curaddr == lastaddr and curaddr == curpbaddr and
-                        * lastaddr != lastpbaddr
-                        */
-                       if (curaddr < lastaddr ||
-                           (curaddr == lastaddr && curaddr == curpbaddr &&
-                            lastaddr != lastpbaddr)) {
-                               change_tmp = change_point[i];
-                               change_point[i] = change_point[i-1];
-                               change_point[i-1] = change_tmp;
-                               still_changing = 1;
-                       }
-               }
-       }
+       sort(change_point, chg_nr, sizeof *change_point, cpcompare, NULL);
 
        /* create a new bios memory map, removing overlaps */
        overlap_entries = 0;     /* number of entries in the overlap table */
index 9d42a52d233150c40a1652c574212e67c0a68708..9b9f18b4991849f7cc1923441bea2d5f5359886c 100644 (file)
@@ -240,7 +240,7 @@ static int __init setup_early_printk(char *buf)
                if (!strncmp(buf, "xen", 3))
                        early_console_register(&xenboot_console, keep);
 #endif
-#ifdef CONFIG_EARLY_PRINTK_MRST
+#ifdef CONFIG_EARLY_PRINTK_INTEL_MID
                if (!strncmp(buf, "mrst", 4)) {
                        mrst_early_console_init();
                        early_console_register(&early_mrst_console, keep);
index 72090705a656a65c5167392b7c815577e6798356..40fc86161d92e10e8d8d8afe740bc5f06a0bfc80 100644 (file)
@@ -28,6 +28,9 @@ DEFINE_PER_CPU(struct pt_regs *, irq_regs);
 EXPORT_PER_CPU_SYMBOL(irq_regs);
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
+
+int sysctl_panic_on_stackoverflow __read_mostly;
+
 /* Debugging check for stack overflow: is there less than 1KB free? */
 static int check_stack_overflow(void)
 {
@@ -43,6 +46,8 @@ static void print_stack_overflow(void)
 {
        printk(KERN_WARNING "low stack detected by irq handler\n");
        dump_stack();
+       if (sysctl_panic_on_stackoverflow)
+               panic("low stack detected by irq handler - check messages\n");
 }
 
 #else
index 69bca468c47a8ffc22ea5811cb3bdf63caf0f44b..d04d3ecded6299ab2abb7183089908439c2a0e6a 100644 (file)
@@ -26,6 +26,8 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
 DEFINE_PER_CPU(struct pt_regs *, irq_regs);
 EXPORT_PER_CPU_SYMBOL(irq_regs);
 
+int sysctl_panic_on_stackoverflow;
+
 /*
  * Probabilistic stack overflow check:
  *
@@ -36,18 +38,39 @@ EXPORT_PER_CPU_SYMBOL(irq_regs);
 static inline void stack_overflow_check(struct pt_regs *regs)
 {
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
+#define STACK_TOP_MARGIN       128
+       struct orig_ist *oist;
+       u64 irq_stack_top, irq_stack_bottom;
+       u64 estack_top, estack_bottom;
        u64 curbase = (u64)task_stack_page(current);
 
        if (user_mode_vm(regs))
                return;
 
-       WARN_ONCE(regs->sp >= curbase &&
-                 regs->sp <= curbase + THREAD_SIZE &&
-                 regs->sp <  curbase + sizeof(struct thread_info) +
-                                       sizeof(struct pt_regs) + 128,
+       if (regs->sp >= curbase + sizeof(struct thread_info) +
+                                 sizeof(struct pt_regs) + STACK_TOP_MARGIN &&
+           regs->sp <= curbase + THREAD_SIZE)
+               return;
+
+       irq_stack_top = (u64)__get_cpu_var(irq_stack_union.irq_stack) +
+                       STACK_TOP_MARGIN;
+       irq_stack_bottom = (u64)__get_cpu_var(irq_stack_ptr);
+       if (regs->sp >= irq_stack_top && regs->sp <= irq_stack_bottom)
+               return;
+
+       oist = &__get_cpu_var(orig_ist);
+       estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN;
+       estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1];
+       if (regs->sp >= estack_top && regs->sp <= estack_bottom)
+               return;
+
+       WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx)\n",
+               current->comm, curbase, regs->sp,
+               irq_stack_top, irq_stack_bottom,
+               estack_top, estack_bottom);
 
-                 "do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n",
-                       current->comm, curbase, regs->sp);
+       if (sysctl_panic_on_stackoverflow)
+               panic("low stack detected by irq handler - check messages\n");
 #endif
 }
 
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
new file mode 100644 (file)
index 0000000..0d01a8e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * arch/x86/kernel/nmi-selftest.c
+ *
+ * Testsuite for NMI: IPIs
+ *
+ * Started by Don Zickus:
+ * (using lib/locking-selftest.c as a guide)
+ *
+ *   Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com>
+ */
+
+#include <linux/smp.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+
+#include <asm/apic.h>
+#include <asm/nmi.h>
+
+#define SUCCESS                0
+#define FAILURE                1
+#define TIMEOUT                2
+
+static int nmi_fail;
+
+/* check to see if NMI IPIs work on this machine */
+static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly;
+
+static int testcase_total;
+static int testcase_successes;
+static int expected_testcase_failures;
+static int unexpected_testcase_failures;
+static int unexpected_testcase_unknowns;
+
+static int nmi_unk_cb(unsigned int val, struct pt_regs *regs)
+{
+       unexpected_testcase_unknowns++;
+       return NMI_HANDLED;
+}
+
+static void init_nmi_testsuite(void)
+{
+       /* trap all the unknown NMIs we may generate */
+       register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk");
+}
+
+static void cleanup_nmi_testsuite(void)
+{
+       unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk");
+}
+
+static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs)
+{
+        int cpu = raw_smp_processor_id();
+
+        if (cpumask_test_and_clear_cpu(cpu, to_cpumask(nmi_ipi_mask)))
+                return NMI_HANDLED;
+
+        return NMI_DONE;
+}
+
+static void test_nmi_ipi(struct cpumask *mask)
+{
+       unsigned long timeout;
+
+       if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback,
+                                NMI_FLAG_FIRST, "nmi_selftest")) {
+               nmi_fail = FAILURE;
+               return;
+       }
+
+       /* sync above data before sending NMI */
+       wmb();
+
+       apic->send_IPI_mask(mask, NMI_VECTOR);
+
+       /* Don't wait longer than a second */
+       timeout = USEC_PER_SEC;
+       while (!cpumask_empty(mask) && timeout--)
+               udelay(1);
+
+       /* What happens if we timeout, do we still unregister?? */
+       unregister_nmi_handler(NMI_LOCAL, "nmi_selftest");
+
+       if (!timeout)
+               nmi_fail = TIMEOUT;
+       return;
+}
+
+static void remote_ipi(void)
+{
+       cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
+       if (!cpumask_empty(to_cpumask(nmi_ipi_mask)))
+               test_nmi_ipi(to_cpumask(nmi_ipi_mask));
+}
+
+static void local_ipi(void)
+{
+       cpumask_clear(to_cpumask(nmi_ipi_mask));
+       cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
+       test_nmi_ipi(to_cpumask(nmi_ipi_mask));
+}
+
+static void reset_nmi(void)
+{
+       nmi_fail = 0;
+}
+
+static void dotest(void (*testcase_fn)(void), int expected)
+{
+       testcase_fn();
+       /*
+        * Filter out expected failures:
+        */
+       if (nmi_fail != expected) {
+               unexpected_testcase_failures++;
+
+               if (nmi_fail == FAILURE)
+                       printk("FAILED |");
+               else if (nmi_fail == TIMEOUT)
+                       printk("TIMEOUT|");
+               else
+                       printk("ERROR  |");
+               dump_stack();
+       } else {
+               testcase_successes++;
+               printk("  ok  |");
+       }
+       testcase_total++;
+
+       reset_nmi();
+}
+
+static inline void print_testname(const char *testname)
+{
+       printk("%12s:", testname);
+}
+
+void nmi_selftest(void)
+{
+       init_nmi_testsuite();
+
+        /*
+        * Run the testsuite:
+        */
+       printk("----------------\n");
+       printk("| NMI testsuite:\n");
+       printk("--------------------\n");
+
+       print_testname("remote IPI");
+       dotest(remote_ipi, SUCCESS);
+       printk("\n");
+       print_testname("local IPI");
+       dotest(local_ipi, SUCCESS);
+       printk("\n");
+
+       cleanup_nmi_testsuite();
+
+       if (unexpected_testcase_failures) {
+               printk("--------------------\n");
+               printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n",
+                       unexpected_testcase_failures, testcase_total);
+               printk("-----------------------------------------------------------------\n");
+       } else if (expected_testcase_failures && testcase_successes) {
+               printk("--------------------\n");
+               printk("%3d out of %3d testcases failed, as expected. |\n",
+                       expected_testcase_failures, testcase_total);
+               printk("----------------------------------------------------\n");
+       } else if (expected_testcase_failures && !testcase_successes) {
+               printk("--------------------\n");
+               printk("All %3d testcases failed, as expected. |\n",
+                       expected_testcase_failures);
+               printk("----------------------------------------\n");
+       } else {
+               printk("--------------------\n");
+               printk("Good, all %3d testcases passed! |\n",
+                       testcase_successes);
+               printk("---------------------------------\n");
+       }
+}
index d05444ac2aea59378d1aac95e53c44f0a7a19a4e..d7d5099fe8746f4ea795bd58e8f1d42d511a6ca8 100644 (file)
@@ -749,12 +749,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #ifdef CONFIG_EFI
        if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
-#ifdef CONFIG_X86_32
-                    "EL32",
-#else
-                    "EL64",
-#endif
-        4)) {
+                    EFI_LOADER_SIGNATURE, 4)) {
                efi_enabled = 1;
                efi_memblock_x86_reserve_range();
        }
index 54ddaeb221c18cbd1ed06aa9a66c74752e4717b1..46a01bdc27e2846582d88fca80356506349e1074 100644 (file)
@@ -682,7 +682,6 @@ static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
                struct pt_regs *regs)
 {
-       sigset_t blocked;
        int ret;
 
        /* Are we from a system call? */
@@ -733,10 +732,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
         */
        regs->flags &= ~X86_EFLAGS_TF;
 
-       sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&blocked, sig);
-       set_current_blocked(&blocked);
+       block_sigmask(ka, sig);
 
        tracehook_signal_handler(sig, info, ka, regs,
                                 test_thread_flag(TIF_SINGLESTEP));
index 16204dc1548427d8895b6ce7da1436d81ecfe431..66c74f481cab36bca09f95aa68b98160a41a1fbc 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/mmu_context.h>
 #include <asm/proto.h>
 #include <asm/apic.h>
+#include <asm/nmi.h>
 /*
  *     Some notes on x86 processor bugs affecting SMP operation:
  *
@@ -148,6 +149,60 @@ void native_send_call_func_ipi(const struct cpumask *mask)
        free_cpumask_var(allbutself);
 }
 
+static atomic_t stopping_cpu = ATOMIC_INIT(-1);
+
+static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
+{
+       /* We are registered on stopping cpu too, avoid spurious NMI */
+       if (raw_smp_processor_id() == atomic_read(&stopping_cpu))
+               return NMI_HANDLED;
+
+       stop_this_cpu(NULL);
+
+       return NMI_HANDLED;
+}
+
+static void native_nmi_stop_other_cpus(int wait)
+{
+       unsigned long flags;
+       unsigned long timeout;
+
+       if (reboot_force)
+               return;
+
+       /*
+        * Use an own vector here because smp_call_function
+        * does lots of things not suitable in a panic situation.
+        */
+       if (num_online_cpus() > 1) {
+               /* did someone beat us here? */
+               if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1)
+                       return;
+
+               if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
+                                        NMI_FLAG_FIRST, "smp_stop"))
+                       /* Note: we ignore failures here */
+                       return;
+
+               /* sync above data before sending NMI */
+               wmb();
+
+               apic->send_IPI_allbutself(NMI_VECTOR);
+
+               /*
+                * Don't wait longer than a second if the caller
+                * didn't ask us to wait.
+                */
+               timeout = USEC_PER_SEC;
+               while (num_online_cpus() > 1 && (wait || timeout--))
+                       udelay(1);
+       }
+
+       local_irq_save(flags);
+       disable_local_APIC();
+       local_irq_restore(flags);
+}
+
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
  */
@@ -160,7 +215,7 @@ asmlinkage void smp_reboot_interrupt(void)
        irq_exit();
 }
 
-static void native_stop_other_cpus(int wait)
+static void native_irq_stop_other_cpus(int wait)
 {
        unsigned long flags;
        unsigned long timeout;
@@ -194,6 +249,11 @@ static void native_stop_other_cpus(int wait)
        local_irq_restore(flags);
 }
 
+static void native_smp_disable_nmi_ipi(void)
+{
+       smp_ops.stop_other_cpus = native_irq_stop_other_cpus;
+}
+
 /*
  * Reschedule call back.
  */
@@ -225,12 +285,20 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
+static int __init nonmi_ipi_setup(char *str)
+{
+        native_smp_disable_nmi_ipi();
+        return 1;
+}
+
+__setup("nonmi_ipi", nonmi_ipi_setup);
+
 struct smp_ops smp_ops = {
        .smp_prepare_boot_cpu   = native_smp_prepare_boot_cpu,
        .smp_prepare_cpus       = native_smp_prepare_cpus,
        .smp_cpus_done          = native_smp_cpus_done,
 
-       .stop_other_cpus        = native_stop_other_cpus,
+       .stop_other_cpus        = native_nmi_stop_other_cpus,
        .smp_send_reschedule    = native_smp_send_reschedule,
 
        .cpu_up                 = native_cpu_up,
index e38e21754eea79ff5aab8b23719511999a97e281..66d250c00d115bbaae4c7ab0917ce9c0dfe89643 100644 (file)
@@ -207,22 +207,28 @@ static void __cpuinit smp_callin(void)
         * Need to setup vector mappings before we enable interrupts.
         */
        setup_vector_irq(smp_processor_id());
+
+       /*
+        * Save our processor parameters. Note: this information
+        * is needed for clock calibration.
+        */
+       smp_store_cpu_info(cpuid);
+
        /*
         * Get our bogomips.
+        * Update loops_per_jiffy in cpu_data. Previous call to
+        * smp_store_cpu_info() stored a value that is close but not as
+        * accurate as the value just calculated.
         *
         * Need to enable IRQs because it can take longer and then
         * the NMI watchdog might kill us.
         */
        local_irq_enable();
        calibrate_delay();
+       cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy;
        local_irq_disable();
        pr_debug("Stack at about %p\n", &cpuid);
 
-       /*
-        * Save our processor parameters
-        */
-       smp_store_cpu_info(cpuid);
-
        /*
         * This must be done before setting cpu_online_mask
         * or calling notify_cpu_starting.
@@ -1143,6 +1149,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
 {
        pr_debug("Boot done.\n");
 
+       nmi_selftest();
        impress_friends();
 #ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
index 2c9cf0fd78f59a66d1c802d26a4956319f1b9c1b..c0dd5b603749057db73420caacc321d5d714338f 100644 (file)
@@ -995,3 +995,23 @@ void __init tsc_init(void)
        check_system_tsc_reliable();
 }
 
+#ifdef CONFIG_SMP
+/*
+ * If we have a constant TSC and are using the TSC for the delay loop,
+ * we can skip clock calibration if another cpu in the same socket has already
+ * been calibrated. This assumes that CONSTANT_TSC applies to all
+ * cpus in the socket - this should be a safe assumption.
+ */
+unsigned long __cpuinit calibrate_delay_is_known(void)
+{
+       int i, cpu = smp_processor_id();
+
+       if (!tsc_disabled && !cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC))
+               return 0;
+
+       for_each_online_cpu(i)
+               if (cpu_data(i).phys_proc_id == cpu_data(cpu).phys_proc_id)
+                       return cpu_data(i).loops_per_jiffy;
+       return 0;
+}
+#endif
index 91f83e21b989e54147b4e8750a4f2be909a8f78f..947a06ccc67305d014dd558a68be75f0f8a34c11 100644 (file)
@@ -115,4 +115,5 @@ struct x86_msi_ops x86_msi = {
        .setup_msi_irqs = native_setup_msi_irqs,
        .teardown_msi_irq = native_teardown_msi_irq,
        .teardown_msi_irqs = default_teardown_msi_irqs,
+       .restore_msi_irqs = default_restore_msi_irqs,
 };
index cf4603ba866f7a10549ee7acdaf6fb2866e464ba..642d8805bc1bb967f03715d3585a9cd0fa99e5bb 100644 (file)
@@ -856,18 +856,23 @@ static void __init lguest_init_IRQ(void)
 }
 
 /*
- * With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so
- * rather than set them in lguest_init_IRQ we are called here every time an
- * lguest device needs an interrupt.
- *
- * FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should
- * pass that up!
+ * Interrupt descriptors are allocated as-needed, but low-numbered ones are
+ * reserved by the generic x86 code.  So we ignore irq_alloc_desc_at if it
+ * tells us the irq is already used: other errors (ie. ENOMEM) we take
+ * seriously.
  */
-void lguest_setup_irq(unsigned int irq)
+int lguest_setup_irq(unsigned int irq)
 {
-       irq_alloc_desc_at(irq, 0);
+       int err;
+
+       /* Returns -ve error or vector number. */
+       err = irq_alloc_desc_at(irq, 0);
+       if (err < 0 && err != -EEXIST)
+               return err;
+
        irq_set_chip_and_handler_name(irq, &lguest_irq_controller,
                                      handle_level_irq, "level");
+       return 0;
 }
 
 /*
index a298914058f9c98ebeaba6a84725f7310a1e6f5d..6cabf6570d6481c76b34aed0d0f86106fae1f5db 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/ioport.h>
 #include <linux/swap.h>
 #include <linux/memblock.h>
+#include <linux/bootmem.h>     /* for max_low_pfn */
 
 #include <asm/cacheflush.h>
 #include <asm/e820.h>
@@ -15,6 +16,7 @@
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 #include <asm/proto.h>
+#include <asm/dma.h>           /* for MAX_DMA_PFN */
 
 unsigned long __initdata pgt_buf_start;
 unsigned long __meminitdata pgt_buf_end;
@@ -392,3 +394,24 @@ void free_initrd_mem(unsigned long start, unsigned long end)
        free_init_pages("initrd memory", start, PAGE_ALIGN(end));
 }
 #endif
+
+void __init zone_sizes_init(void)
+{
+       unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+#ifdef CONFIG_ZONE_DMA
+       max_zone_pfns[ZONE_DMA]         = MAX_DMA_PFN;
+#endif
+#ifdef CONFIG_ZONE_DMA32
+       max_zone_pfns[ZONE_DMA32]       = MAX_DMA32_PFN;
+#endif
+       max_zone_pfns[ZONE_NORMAL]      = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
+       max_zone_pfns[ZONE_HIGHMEM]     = max_pfn;
+#endif
+
+       free_area_init_nodes(max_zone_pfns);
+}
+
index 0c1da394a6347d3b26858f3e16fe54fa785812ad..8663f6c47ccbc920c58063633e2d67745448a3d2 100644 (file)
@@ -668,22 +668,6 @@ void __init initmem_init(void)
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
-static void __init zone_sizes_init(void)
-{
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-#ifdef CONFIG_ZONE_DMA
-       max_zone_pfns[ZONE_DMA] =
-               virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-#endif
-       max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
-#ifdef CONFIG_HIGHMEM
-       max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
-#endif
-
-       free_area_init_nodes(max_zone_pfns);
-}
-
 void __init setup_bootmem_allocator(void)
 {
        printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
@@ -754,6 +738,17 @@ void __init mem_init(void)
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
 #endif
+       /*
+        * With CONFIG_DEBUG_PAGEALLOC initialization of highmem pages has to
+        * be done before free_all_bootmem(). Memblock use free low memory for
+        * temporary data (see find_range_array()) and for this purpose can use
+        * pages that was already passed to the buddy allocator, hence marked as
+        * not accessible in the page tables when compiled with
+        * CONFIG_DEBUG_PAGEALLOC. Otherwise order of initialization is not
+        * important here.
+        */
+       set_highmem_pages_init();
+
        /* this will put all low memory onto the freelists */
        totalram_pages += free_all_bootmem();
 
@@ -765,8 +760,6 @@ void __init mem_init(void)
                if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
                        reservedpages++;
 
-       set_highmem_pages_init();
-
        codesize =  (unsigned long) &_etext - (unsigned long) &_text;
        datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
        initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
index a8a56ce3a962ad7c1c46285830dd8cb994695231..436a0309db332fe54c5a76dbf3952cadd5f16ece 100644 (file)
@@ -614,15 +614,6 @@ void __init initmem_init(void)
 
 void __init paging_init(void)
 {
-       unsigned long max_zone_pfns[MAX_NR_ZONES];
-
-       memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-#ifdef CONFIG_ZONE_DMA
-       max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
-#endif
-       max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
-       max_zone_pfns[ZONE_NORMAL] = max_pfn;
-
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
 
@@ -634,7 +625,7 @@ void __init paging_init(void)
         */
        node_clear_state(0, N_NORMAL_MEMORY);
 
-       free_area_init_nodes(max_zone_pfns);
+       zone_sizes_init();
 }
 
 /*
index 4b5ba85eb5c95ebb705f8ce420acbff85c052f47..845df6835f9ff5fc216ab01857100d41eba77fbf 100644 (file)
@@ -75,9 +75,9 @@ static unsigned long mmap_rnd(void)
        */
        if (current->flags & PF_RANDOMIZE) {
                if (mmap_is_ia32())
-                       rnd = (long)get_random_int() % (1<<8);
+                       rnd = get_random_int() % (1<<8);
                else
-                       rnd = (long)(get_random_int() % (1<<28));
+                       rnd = get_random_int() % (1<<28);
        }
        return rnd << PAGE_SHIFT;
 }
index 496f494593bf6cfa7f7069c58af5c153f6af1965..19d3fa08b1191493cda6415e56f8f26d86415bf7 100644 (file)
@@ -110,7 +110,7 @@ void __cpuinit numa_clear_node(int cpu)
  * Allocate node_to_cpumask_map based on number of available nodes
  * Requires node_possible_map to be valid.
  *
- * Note: node_to_cpumask() is not valid until after this is done.
+ * Note: cpumask_of_node() is not valid until after this is done.
  * (Use CONFIG_DEBUG_PER_CPU_MAPS to check this.)
  */
 void __init setup_node_to_cpumask_map(void)
@@ -422,8 +422,9 @@ static int __init numa_alloc_distance(void)
  * calls are ignored until the distance table is reset with
  * numa_reset_distance().
  *
- * If @from or @to is higher than the highest known node at the time of
- * table creation or @distance doesn't make sense, the call is ignored.
+ * If @from or @to is higher than the highest known node or lower than zero
+ * at the time of table creation or @distance doesn't make sense, the call
+ * is ignored.
  * This is to allow simplification of specific NUMA config implementations.
  */
 void __init numa_set_distance(int from, int to, int distance)
@@ -431,8 +432,9 @@ void __init numa_set_distance(int from, int to, int distance)
        if (!numa_distance && numa_alloc_distance() < 0)
                return;
 
-       if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
-               printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
+       if (from >= numa_distance_cnt || to >= numa_distance_cnt ||
+                       from < 0 || to < 0) {
+               pr_warn_once("NUMA: Warning: node ids are out of bound, from=%d to=%d distance=%d\n",
                            from, to, distance);
                return;
        }
index eda2acbb6e81b2895e7645bd21fc8624ad355e7e..e1ebde3152104840961fe6e953b28d628f4bab82 100644 (file)
@@ -1333,12 +1333,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
                                           numpages * PAGE_SIZE);
        }
 
-       /*
-        * If page allocator is not up yet then do not call c_p_a():
-        */
-       if (!debug_pagealloc_enabled)
-               return;
-
        /*
         * The return value is ignored as the calls cannot fail.
         * Large pages for identity mappings are not used at boot time
index 6b8759f7634e661de3983dbc7e6accb26e939a8c..e76e18c94a3cd7933e5ca6c720b6e0b131cf2ca8 100644 (file)
@@ -15,11 +15,12 @@ obj-$(CONFIG_X86_VISWS)             += visws.o
 
 obj-$(CONFIG_X86_NUMAQ)                += numaq_32.o
 
-obj-$(CONFIG_X86_MRST)         += mrst.o
+obj-$(CONFIG_X86_INTEL_MID)    += mrst.o
 
 obj-y                          += common.o early.o
-obj-y                          += amd_bus.o bus_numa.o
+obj-y                          += bus_numa.o
 
+obj-$(CONFIG_AMD_NB)           += amd_bus.o
 obj-$(CONFIG_PCI_CNB20LE_QUIRK)        += broadcom_bus.o
 
 ifeq ($(CONFIG_PCI_DEBUG),y)
index 404f21a3ff9e27fa1ef75a233559f2623f4507ab..a312e76063a7c4b1320eb80718cf81c33e7361dc 100644 (file)
@@ -12,7 +12,7 @@ struct pci_root_info {
        char *name;
        unsigned int res_num;
        struct resource *res;
-       struct pci_bus *bus;
+       struct list_head *resources;
        int busnum;
 };
 
@@ -24,6 +24,12 @@ static int __init set_use_crs(const struct dmi_system_id *id)
        return 0;
 }
 
+static int __init set_nouse_crs(const struct dmi_system_id *id)
+{
+       pci_use_crs = false;
+       return 0;
+}
+
 static const struct dmi_system_id pci_use_crs_table[] __initconst = {
        /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
        {
@@ -54,6 +60,29 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
                        DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
                },
        },
+
+       /* Now for the blacklist.. */
+
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */
+       {
+               .callback = set_nouse_crs,
+               .ident = "Dell Studio 1557",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "A09"),
+               },
+       },
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */
+       {
+               .callback = set_nouse_crs,
+               .ident = "Thinkpad SL510",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_BOARD_NAME, "2847DFG"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"),
+               },
+       },
        {}
 };
 
@@ -149,7 +178,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
        struct acpi_resource_address64 addr;
        acpi_status status;
        unsigned long flags;
-       u64 start, end;
+       u64 start, orig_end, end;
 
        status = resource_to_addr(acpi_res, &addr);
        if (!ACPI_SUCCESS(status))
@@ -165,7 +194,21 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
                return AE_OK;
 
        start = addr.minimum + addr.translation_offset;
-       end = addr.maximum + addr.translation_offset;
+       orig_end = end = addr.maximum + addr.translation_offset;
+
+       /* Exclude non-addressable range or non-addressable portion of range */
+       end = min(end, (u64)iomem_resource.end);
+       if (end <= start) {
+               dev_info(&info->bridge->dev,
+                       "host bridge window [%#llx-%#llx] "
+                       "(ignored, not CPU addressable)\n", start, orig_end);
+               return AE_OK;
+       } else if (orig_end != end) {
+               dev_info(&info->bridge->dev,
+                       "host bridge window [%#llx-%#llx] "
+                       "([%#llx-%#llx] ignored, not CPU addressable)\n", 
+                       start, orig_end, end + 1, orig_end);
+       }
 
        res = &info->res[info->res_num];
        res->name = info->name;
@@ -261,23 +304,20 @@ static void add_resources(struct pci_root_info *info)
                                 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
                                 res, conflict->name, conflict);
                else
-                       pci_bus_add_resource(info->bus, res, 0);
+                       pci_add_resource(info->resources, res);
        }
 }
 
 static void
 get_current_resources(struct acpi_device *device, int busnum,
-                       int domain, struct pci_bus *bus)
+                     int domain, struct list_head *resources)
 {
        struct pci_root_info info;
        size_t size;
 
-       if (pci_use_crs)
-               pci_bus_remove_resources(bus);
-
        info.bridge = device;
-       info.bus = bus;
        info.res_num = 0;
+       info.resources = resources;
        acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
                                &info);
        if (!info.res_num)
@@ -286,7 +326,7 @@ get_current_resources(struct acpi_device *device, int busnum,
        size = sizeof(*info.res) * info.res_num;
        info.res = kmalloc(size, GFP_KERNEL);
        if (!info.res)
-               goto res_alloc_fail;
+               return;
 
        info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
        if (!info.name)
@@ -301,8 +341,6 @@ get_current_resources(struct acpi_device *device, int busnum,
 
 name_alloc_fail:
        kfree(info.res);
-res_alloc_fail:
-       return;
 }
 
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
@@ -310,6 +348,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
        struct acpi_device *device = root->device;
        int domain = root->segment;
        int busnum = root->secondary.start;
+       LIST_HEAD(resources);
        struct pci_bus *bus;
        struct pci_sysdata *sd;
        int node;
@@ -364,11 +403,15 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
                memcpy(bus->sysdata, sd, sizeof(*sd));
                kfree(sd);
        } else {
-               bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
-               if (bus) {
-                       get_current_resources(device, busnum, domain, bus);
+               get_current_resources(device, busnum, domain, &resources);
+               if (list_empty(&resources))
+                       x86_pci_root_bus_resources(busnum, &resources);
+               bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
+                                         &resources);
+               if (bus)
                        bus->subordinate = pci_scan_child_bus(bus);
-               }
+               else
+                       pci_free_resource_list(&resources);
        }
 
        /* After the PCI-E bus has been walked and all devices discovered,
index 026e4931d16259fe624eef5b5bb269436ad3e81e..0567df3890e18932ae53fbb67c118e401ccb278f 100644 (file)
@@ -30,34 +30,6 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = {
        { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
 };
 
-static u64 __initdata fam10h_mmconf_start;
-static u64 __initdata fam10h_mmconf_end;
-static void __init get_pci_mmcfg_amd_fam10h_range(void)
-{
-       u32 address;
-       u64 base, msr;
-       unsigned segn_busn_bits;
-
-       /* assume all cpus from fam10h have mmconf */
-        if (boot_cpu_data.x86 < 0x10)
-               return;
-
-       address = MSR_FAM10H_MMIO_CONF_BASE;
-       rdmsrl(address, msr);
-
-       /* mmconfig is not enable */
-       if (!(msr & FAM10H_MMIO_CONF_ENABLE))
-               return;
-
-       base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
-
-       segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
-                        FAM10H_MMIO_CONF_BUSRANGE_MASK;
-
-       fam10h_mmconf_start = base;
-       fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
-}
-
 #define RANGE_NUM 16
 
 /**
@@ -85,6 +57,9 @@ static int __init early_fill_mp_bus_info(void)
        u64 val;
        u32 address;
        bool found;
+       struct resource fam10h_mmconf_res, *fam10h_mmconf;
+       u64 fam10h_mmconf_start;
+       u64 fam10h_mmconf_end;
 
        if (!early_pci_allowed())
                return -1;
@@ -211,12 +186,17 @@ static int __init early_fill_mp_bus_info(void)
                subtract_range(range, RANGE_NUM, 0, end);
 
        /* get mmconfig */
-       get_pci_mmcfg_amd_fam10h_range();
+       fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res);
        /* need to take out mmconf range */
-       if (fam10h_mmconf_end) {
-               printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end);
+       if (fam10h_mmconf) {
+               printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf);
+               fam10h_mmconf_start = fam10h_mmconf->start;
+               fam10h_mmconf_end = fam10h_mmconf->end;
                subtract_range(range, RANGE_NUM, fam10h_mmconf_start,
                                 fam10h_mmconf_end + 1);
+       } else {
+               fam10h_mmconf_start = 0;
+               fam10h_mmconf_end = 0;
        }
 
        /* mmio resource */
@@ -403,7 +383,6 @@ static void __init pci_enable_pci_io_ecs(void)
                        ++n;
                }
        }
-       pr_info("Extended Config Space enabled on %u nodes\n", n);
 #endif
 }
 
index ab8269b0da29e3c5ce000fefc5429f86cdd23dfd..f3a7c569a4033491cbf3affd51a40e63655f00d8 100644 (file)
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <asm/pci_x86.h>
+#include <asm/pci-direct.h>
 
 #include "bus_numa.h"
 
-static void __devinit cnb20le_res(struct pci_dev *dev)
+static void __init cnb20le_res(u8 bus, u8 slot, u8 func)
 {
        struct pci_root_info *info;
        struct resource res;
@@ -26,21 +27,12 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        u8 fbus, lbus;
        int i;
 
-#ifdef CONFIG_ACPI
-       /*
-        * We should get host bridge information from ACPI unless the BIOS
-        * doesn't support it.
-        */
-       if (acpi_os_get_root_pointer())
-               return;
-#endif
-
        info = &pci_root_info[pci_root_num];
        pci_root_num++;
 
        /* read the PCI bus numbers */
-       pci_read_config_byte(dev, 0x44, &fbus);
-       pci_read_config_byte(dev, 0x45, &lbus);
+       fbus = read_pci_config_byte(bus, slot, func, 0x44);
+       lbus = read_pci_config_byte(bus, slot, func, 0x45);
        info->bus_min = fbus;
        info->bus_max = lbus;
 
@@ -59,8 +51,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        }
 
        /* read the non-prefetchable memory window */
-       pci_read_config_word(dev, 0xc0, &word1);
-       pci_read_config_word(dev, 0xc2, &word2);
+       word1 = read_pci_config_16(bus, slot, func, 0xc0);
+       word2 = read_pci_config_16(bus, slot, func, 0xc2);
        if (word1 != word2) {
                res.start = (word1 << 16) | 0x0000;
                res.end   = (word2 << 16) | 0xffff;
@@ -69,8 +61,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        }
 
        /* read the prefetchable memory window */
-       pci_read_config_word(dev, 0xc4, &word1);
-       pci_read_config_word(dev, 0xc6, &word2);
+       word1 = read_pci_config_16(bus, slot, func, 0xc4);
+       word2 = read_pci_config_16(bus, slot, func, 0xc6);
        if (word1 != word2) {
                res.start = (word1 << 16) | 0x0000;
                res.end   = (word2 << 16) | 0xffff;
@@ -79,8 +71,8 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        }
 
        /* read the IO port window */
-       pci_read_config_word(dev, 0xd0, &word1);
-       pci_read_config_word(dev, 0xd2, &word2);
+       word1 = read_pci_config_16(bus, slot, func, 0xd0);
+       word2 = read_pci_config_16(bus, slot, func, 0xd2);
        if (word1 != word2) {
                res.start = word1;
                res.end   = word2;
@@ -92,13 +84,37 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
        res.start = fbus;
        res.end   = lbus;
        res.flags = IORESOURCE_BUS;
-       dev_info(&dev->dev, "CNB20LE PCI Host Bridge (domain %04x %pR)\n",
-                           pci_domain_nr(dev->bus), &res);
+       printk(KERN_INFO "CNB20LE PCI Host Bridge (domain 0000 %pR)\n", &res);
 
        for (i = 0; i < info->res_num; i++)
-               dev_info(&dev->dev, "host bridge window %pR\n", &info->res[i]);
+               printk(KERN_INFO "host bridge window %pR\n", &info->res[i]);
 }
 
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
-                       cnb20le_res);
+static int __init broadcom_postcore_init(void)
+{
+       u8 bus = 0, slot = 0;
+       u32 id;
+       u16 vendor, device;
+
+#ifdef CONFIG_ACPI
+       /*
+        * We should get host bridge information from ACPI unless the BIOS
+        * doesn't support it.
+        */
+       if (acpi_os_get_root_pointer())
+               return 0;
+#endif
+
+       id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
+       vendor = id & 0xffff;
+       device = (id >> 16) & 0xffff;
+
+       if (vendor == PCI_VENDOR_ID_SERVERWORKS &&
+           device == PCI_DEVICE_ID_SERVERWORKS_LE) {
+               cnb20le_res(bus, slot, 0);
+               cnb20le_res(bus, slot, 1);
+       }
+       return 0;
+}
 
+postcore_initcall(broadcom_postcore_init);
index 64a122883896af41f8d2187ba509de2e0e22d1b0..fd3f65510e9dac56650aa0cae859465a7d15c865 100644 (file)
@@ -7,45 +7,50 @@
 int pci_root_num;
 struct pci_root_info pci_root_info[PCI_ROOT_NR];
 
-void x86_pci_root_bus_res_quirks(struct pci_bus *b)
+void x86_pci_root_bus_resources(int bus, struct list_head *resources)
 {
        int i;
        int j;
        struct pci_root_info *info;
 
-       /* don't go for it if _CRS is used already */
-       if (b->resource[0] != &ioport_resource ||
-           b->resource[1] != &iomem_resource)
-               return;
-
        if (!pci_root_num)
-               return;
+               goto default_resources;
 
        for (i = 0; i < pci_root_num; i++) {
-               if (pci_root_info[i].bus_min == b->number)
+               if (pci_root_info[i].bus_min == bus)
                        break;
        }
 
        if (i == pci_root_num)
-               return;
+               goto default_resources;
 
-       printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
-                       b->number);
+       printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
+              bus);
 
-       pci_bus_remove_resources(b);
        info = &pci_root_info[i];
        for (j = 0; j < info->res_num; j++) {
                struct resource *res;
                struct resource *root;
 
                res = &info->res[j];
-               pci_bus_add_resource(b, res, 0);
+               pci_add_resource(resources, res);
                if (res->flags & IORESOURCE_IO)
                        root = &ioport_resource;
                else
                        root = &iomem_resource;
                insert_resource(root, res);
        }
+       return;
+
+default_resources:
+       /*
+        * We don't have any host bridge aperture information from the
+        * "native host bridge drivers," e.g., amd_bus or broadcom_bus,
+        * so fall back to the defaults historically used by pci_create_bus().
+        */
+       printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
+       pci_add_resource(resources, &ioport_resource);
+       pci_add_resource(resources, &iomem_resource);
 }
 
 void __devinit update_res(struct pci_root_info *info, resource_size_t start,
index 7962ccb4d9b26aeb3354d2ab1814d9d04a69d695..323481e06ef8cfa3f8aefa47d9b763a08f4aab92 100644 (file)
@@ -164,9 +164,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
 {
        struct pci_dev *dev;
 
-       /* root bus? */
-       if (!b->parent)
-               x86_pci_root_bus_res_quirks(b);
        pci_read_bridge_bases(b);
        list_for_each_entry(dev, &b->devices, bus_list)
                pcibios_fixup_device_resources(dev);
@@ -433,6 +430,7 @@ void __init dmi_check_pciprobe(void)
 
 struct pci_bus * __devinit pcibios_scan_root(int busnum)
 {
+       LIST_HEAD(resources);
        struct pci_bus *bus = NULL;
        struct pci_sysdata *sd;
 
@@ -456,9 +454,12 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
        sd->node = get_mp_bus_to_node(busnum);
 
        printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
-       bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
-       if (!bus)
+       x86_pci_root_bus_resources(busnum, &resources);
+       bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, sd, &resources);
+       if (!bus) {
+               pci_free_resource_list(&resources);
                kfree(sd);
+       }
 
        return bus;
 }
@@ -639,6 +640,7 @@ int pci_ext_cfg_avail(struct pci_dev *dev)
 
 struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
 {
+       LIST_HEAD(resources);
        struct pci_bus *bus = NULL;
        struct pci_sysdata *sd;
 
@@ -653,9 +655,12 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
                return NULL;
        }
        sd->node = node;
-       bus = pci_scan_bus(busno, ops, sd);
-       if (!bus)
+       x86_pci_root_bus_resources(busno, &resources);
+       bus = pci_scan_root_bus(NULL, busno, ops, sd, &resources);
+       if (!bus) {
+               pci_free_resource_list(&resources);
                kfree(sd);
+       }
 
        return bus;
 }
index 794b092d01aeb389ec9db257b00c03176066bd06..91821a1a0c3a7e1a7206eba6867dbe5dd8da769d 100644 (file)
@@ -254,26 +254,6 @@ void __init pcibios_resource_survey(void)
  */
 fs_initcall(pcibios_assign_resources);
 
-/*
- *  If we set up a device for bus mastering, we need to check the latency
- *  timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
-       u8 lat;
-       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-       if (lat < 16)
-               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
-       else if (lat > pcibios_max_latency)
-               lat = pcibios_max_latency;
-       else
-               return;
-       dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
-
 static const struct vm_operations_struct pci_mmap_ops = {
        .access = generic_access_phys,
 };
index 2c2aeabc2609bdd90fd78d1287d5648016a198d0..a1df191129d30154e3386dc46ba78e5b540bbb74 100644 (file)
@@ -31,9 +31,6 @@ int __init pci_legacy_init(void)
 
        printk("PCI: Probing PCI hardware\n");
        pci_root_bus = pcibios_scan_root(0);
-       if (pci_root_bus)
-               pci_bus_add_devices(pci_root_bus);
-
        return 0;
 }
 
index 51abf02f9226687c234945e1ff39fb9a8c13695b..83e125b95ca6d6502c9b6d12babbe5ea77a464d4 100644 (file)
@@ -153,8 +153,6 @@ int __init pci_numaq_init(void)
        raw_pci_ops = &pci_direct_conf1_mq;
 
        pci_root_bus = pcibios_scan_root(0);
-       if (pci_root_bus)
-               pci_bus_add_devices(pci_root_bus);
        if (num_online_nodes() > 1)
                for_each_online_node(quad) {
                        if (quad == 0)
index 1ea38775a6d32aadc23744a8a288b295eaaedf7c..7baed5135e0f96db02abfedde43339bad35b58b4 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_X86_MRST)         += mrst.o
-obj-$(CONFIG_X86_MRST)         += vrtc.o
-obj-$(CONFIG_EARLY_PRINTK_MRST)        += early_printk_mrst.o
+obj-$(CONFIG_X86_INTEL_MID)    += mrst.o
+obj-$(CONFIG_X86_INTEL_MID)    += vrtc.o
+obj-$(CONFIG_EARLY_PRINTK_INTEL_MID)   += early_printk_mrst.o
 obj-$(CONFIG_X86_MRST)         += pmu.o
index ad4ec1cb097ecfae17e4a99aed37cf985b03cb78..475e2cd0f3c3f5f10c668129f9ebd4a4e4754c0d 100644 (file)
@@ -848,8 +848,7 @@ static void __init sfi_handle_ipc_dev(struct sfi_device_table_entry *entry)
        if (mrst_has_msic())
                return;
 
-       /* ID as IRQ is a hack that will go away */
-       pdev = platform_device_alloc(entry->name, entry->irq);
+       pdev = platform_device_alloc(entry->name, 0);
        if (pdev == NULL) {
                pr_err("out of memory for SFI platform device '%s'.\n",
                        entry->name);
@@ -1030,6 +1029,7 @@ static int __init pb_keys_init(void)
        num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);
        for (i = 0; i < num; i++) {
                gb[i].gpio = get_gpio_by_name(gb[i].desc);
+               pr_debug("info[%2d]: name = %s, gpio = %d\n", i, gb[i].desc, gb[i].gpio);
                if (gb[i].gpio == -1)
                        continue;
 
index 1d97bd84b6fbcfe684b559cf271f7fe72d75f92b..b2b54d2edf53979fb7daf770c0d4bf0215a73fe0 100644 (file)
@@ -6,14 +6,6 @@ menu "UML-specific options"
 
 menu "Host processor type and features"
 
-config CMPXCHG_LOCAL
-       bool
-       default n
-
-config CMPXCHG_DOUBLE
-       bool
-       default n
-
 source "arch/x86/Kconfig.cpu"
 
 endmenu
index c346ccdce0df55043dbdac8c87096addc0dd5b37..8a3f8351f4380d5ff8da08978ceb83fd4d19d689 100644 (file)
@@ -9,6 +9,7 @@ config XTENSA
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_CPU_DEVICES
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
index 4609b0f15f1fb56232c6d80cd3e6e865037fadd4..05244f07dd31cc4a1fb32d5735e1f1d00920f551 100644 (file)
 
 extern struct pci_controller* pcibios_alloc_controller(void);
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
-       /* No special bus mastering setup handling */
-}
-
 static inline void pcibios_penalize_isa_irq(int irq)
 {
        /* We don't do dynamic PCI IRQ allocation */
index cd102693120372e1345f94b1f5fa90161b7c85d6..61045c192e886761055391ffffbf13a7e607e89f 100644 (file)
@@ -134,9 +134,46 @@ struct pci_controller * __init pcibios_alloc_controller(void)
        return pci_ctrl;
 }
 
+static void __init pci_controller_apertures(struct pci_controller *pci_ctrl,
+                                           struct list_head *resources)
+{
+       struct resource *res;
+       unsigned long io_offset;
+       int i;
+
+       io_offset = (unsigned long)pci_ctrl->io_space.base;
+       res = &pci_ctrl->io_resource;
+       if (!res->flags) {
+               if (io_offset)
+                       printk (KERN_ERR "I/O resource not set for host"
+                               " bridge %d\n", pci_ctrl->index);
+               res->start = 0;
+               res->end = IO_SPACE_LIMIT;
+               res->flags = IORESOURCE_IO;
+       }
+       res->start += io_offset;
+       res->end += io_offset;
+       pci_add_resource(resources, res);
+
+       for (i = 0; i < 3; i++) {
+               res = &pci_ctrl->mem_resources[i];
+               if (!res->flags) {
+                       if (i > 0)
+                               continue;
+                       printk(KERN_ERR "Memory resource not set for "
+                              "host bridge %d\n", pci_ctrl->index);
+                       res->start = 0;
+                       res->end = ~0U;
+                       res->flags = IORESOURCE_MEM;
+               }
+               pci_add_resource(resources, res);
+       }
+}
+
 static int __init pcibios_init(void)
 {
        struct pci_controller *pci_ctrl;
+       struct list_head resources;
        struct pci_bus *bus;
        int next_busno = 0, i;
 
@@ -145,19 +182,10 @@ static int __init pcibios_init(void)
        /* Scan all of the recorded PCI controllers.  */
        for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
                pci_ctrl->last_busno = 0xff;
-               bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
-                                  pci_ctrl);
-               if (pci_ctrl->io_resource.flags) {
-                       unsigned long offs;
-
-                       offs = (unsigned long)pci_ctrl->io_space.base;
-                       pci_ctrl->io_resource.start += offs;
-                       pci_ctrl->io_resource.end += offs;
-                       bus->resource[0] = &pci_ctrl->io_resource;
-               }
-               for (i = 0; i < 3; ++i)
-                       if (pci_ctrl->mem_resources[i].flags)
-                               bus->resource[i+1] =&pci_ctrl->mem_resources[i];
+               INIT_LIST_HEAD(&resources);
+               pci_controller_apertures(pci_ctrl, &resources);
+               bus = pci_scan_root_bus(NULL, pci_ctrl->first_busno,
+                                       pci_ctrl->ops, pci_ctrl, &resources);
                pci_ctrl->bus = bus;
                pci_ctrl->last_busno = bus->subordinate;
                if (next_busno <= pci_ctrl->last_busno)
@@ -178,36 +206,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
        int i;
 
        io_offset = (unsigned long)pci_ctrl->io_space.base;
-       if (bus->parent == NULL) {
-               /* this is a host bridge - fill in its resources */
-               pci_ctrl->bus = bus;
-
-               bus->resource[0] = res = &pci_ctrl->io_resource;
-               if (!res->flags) {
-                       if (io_offset)
-                               printk (KERN_ERR "I/O resource not set for host"
-                                       " bridge %d\n", pci_ctrl->index);
-                       res->start = 0;
-                       res->end = IO_SPACE_LIMIT;
-                       res->flags = IORESOURCE_IO;
-               }
-               res->start += io_offset;
-               res->end += io_offset;
-
-               for (i = 0; i < 3; i++) {
-                       res = &pci_ctrl->mem_resources[i];
-                       if (!res->flags) {
-                               if (i > 0)
-                                       continue;
-                               printk(KERN_ERR "Memory resource not set for "
-                                      "host bridge %d\n", pci_ctrl->index);
-                               res->start = 0;
-                               res->end = ~0U;
-                               res->flags = IORESOURCE_MEM;
-                       }
-                       bus->resource[i+1] = res;
-               }
-       } else {
+       if (bus->parent) {
                /* This is a subordinate bridge */
                pci_read_bridge_bases(bus);
 
@@ -227,6 +226,11 @@ char __init *pcibios_setup(char *str)
        return str;
 }
 
+void pcibios_set_master(struct pci_dev *dev)
+{
+       /* No special bus mastering setup handling */
+}
+
 /* the next one is stolen from the alpha port... */
 
 void __init
index ae9c3ceb2867a8e15700a539ec8d3bd0f1ce1e75..e6cfe1a2513729912270ad8b31d77d3f49db1615 100644 (file)
@@ -105,7 +105,7 @@ config CRYPTO_USER
        depends on NET
        select CRYPTO_MANAGER
        help
-         Userapace configuration for cryptographic instantiations such as
+         Userspace configuration for cryptographic instantiations such as
          cbc(aes).
 
 config CRYPTO_MANAGER_DISABLE_TESTS
@@ -117,7 +117,7 @@ config CRYPTO_MANAGER_DISABLE_TESTS
          algorithm registration.
 
 config CRYPTO_GF128MUL
-       tristate "GF(2^128) multiplication functions (EXPERIMENTAL)"
+       tristate "GF(2^128) multiplication functions"
        help
          Efficient table driven implementation of multiplications in the
          field GF(2^128).  This is needed by some cypher modes. This
@@ -241,8 +241,7 @@ config CRYPTO_ECB
          the input block by block.
 
 config CRYPTO_LRW
-       tristate "LRW support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "LRW support"
        select CRYPTO_BLKCIPHER
        select CRYPTO_MANAGER
        select CRYPTO_GF128MUL
@@ -262,8 +261,7 @@ config CRYPTO_PCBC
          This block cipher algorithm is required for RxRPC.
 
 config CRYPTO_XTS
-       tristate "XTS support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "XTS support"
        select CRYPTO_BLKCIPHER
        select CRYPTO_MANAGER
        select CRYPTO_GF128MUL
@@ -764,6 +762,46 @@ config CRYPTO_SERPENT
          See also:
          <http://www.cl.cam.ac.uk/~rja14/serpent.html>
 
+config CRYPTO_SERPENT_SSE2_X86_64
+       tristate "Serpent cipher algorithm (x86_64/SSE2)"
+       depends on X86 && 64BIT
+       select CRYPTO_ALGAPI
+       select CRYPTO_CRYPTD
+       select CRYPTO_SERPENT
+       select CRYPTO_LRW
+       select CRYPTO_XTS
+       help
+         Serpent cipher algorithm, by Anderson, Biham & Knudsen.
+
+         Keys are allowed to be from 0 to 256 bits in length, in steps
+         of 8 bits.
+
+         This module provides Serpent cipher algorithm that processes eigth
+         blocks parallel using SSE2 instruction set.
+
+         See also:
+         <http://www.cl.cam.ac.uk/~rja14/serpent.html>
+
+config CRYPTO_SERPENT_SSE2_586
+       tristate "Serpent cipher algorithm (i586/SSE2)"
+       depends on X86 && !64BIT
+       select CRYPTO_ALGAPI
+       select CRYPTO_CRYPTD
+       select CRYPTO_SERPENT
+       select CRYPTO_LRW
+       select CRYPTO_XTS
+       help
+         Serpent cipher algorithm, by Anderson, Biham & Knudsen.
+
+         Keys are allowed to be from 0 to 256 bits in length, in steps
+         of 8 bits.
+
+         This module provides Serpent cipher algorithm that processes four
+         blocks parallel using SSE2 instruction set.
+
+         See also:
+         <http://www.cl.cam.ac.uk/~rja14/serpent.html>
+
 config CRYPTO_TEA
        tristate "TEA, XTEA and XETA cipher algorithms"
        select CRYPTO_ALGAPI
@@ -840,6 +878,8 @@ config CRYPTO_TWOFISH_X86_64_3WAY
        select CRYPTO_ALGAPI
        select CRYPTO_TWOFISH_COMMON
        select CRYPTO_TWOFISH_X86_64
+       select CRYPTO_LRW
+       select CRYPTO_XTS
        help
          Twofish cipher algorithm (x86_64, 3-way parallel).
 
index 9e6eee2c05db0735363915db0742e01ff2dabf5f..f638063f4ea93925067aad0e6e7325c5124fedb0 100644 (file)
@@ -65,7 +65,7 @@ obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish_generic.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_COMMON) += blowfish_common.o
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
 obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
-obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
+obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
 obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o
 obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
index 54dd4e33b5d61a5049713ee74ad9dc94d40670b6..9d4a9fe913f859e5896a31db7ed4a8e93b70d286 100644 (file)
@@ -518,6 +518,35 @@ err:
 }
 EXPORT_SYMBOL_GPL(crypto_register_instance);
 
+int crypto_unregister_instance(struct crypto_alg *alg)
+{
+       int err;
+       struct crypto_instance *inst = (void *)alg;
+       struct crypto_template *tmpl = inst->tmpl;
+       LIST_HEAD(users);
+
+       if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
+               return -EINVAL;
+
+       BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
+
+       down_write(&crypto_alg_sem);
+
+       hlist_del_init(&inst->list);
+       err = crypto_remove_alg(alg, &users);
+
+       up_write(&crypto_alg_sem);
+
+       if (err)
+               return err;
+
+       tmpl->free(inst);
+       crypto_remove_final(&users);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_instance);
+
 int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
                      struct crypto_instance *inst, u32 mask)
 {
index ffa0245e2abceb5b79b7d2f46a7407b6ea03b971..6ddd99e6114b08fcef25cde0a3cfaa31885e9556 100644 (file)
@@ -414,10 +414,18 @@ static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
 static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 {
        u8 rdata[DEFAULT_BLK_SZ];
+       u8 *key = seed + DEFAULT_BLK_SZ;
        int rc;
 
        struct prng_context *prng = crypto_rng_ctx(tfm);
 
+       if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
+               return -EINVAL;
+
+       /* fips strictly requires seed != key */
+       if (!memcmp(seed, key, DEFAULT_PRNG_KSZ))
+               return -EINVAL;
+
        rc = cprng_reset(tfm, seed, slen);
 
        if (!rc)
index 0605a2bbba75e17e67e59f602f1d12c453404031..3ba6ef508869d104db2657423e451c3922db5f45 100644 (file)
@@ -298,7 +298,7 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (atomic_read(&alg->cra_refcnt) != 1)
                return -EBUSY;
 
-       return crypto_unregister_alg(alg);
+       return crypto_unregister_instance(alg);
 }
 
 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
index 358f80be2bf97d128ebd648887325a01ea051a70..ba42acc4deba8059c65dff053faef591e3175517 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2006 Rik Snel <rsnel@cube.dyndns.org>
  *
- * Based om ecb.c
+ * Based on ecb.c
  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -16,6 +16,7 @@
  * http://www.mail-archive.com/stds-p1619@listserv.ieee.org/msg00173.html
  *
  * The test vectors are included in the testing module tcrypt.[ch] */
+
 #include <crypto/algapi.h>
 #include <linux/err.h>
 #include <linux/init.h>
 
 #include <crypto/b128ops.h>
 #include <crypto/gf128mul.h>
+#include <crypto/lrw.h>
 
 struct priv {
        struct crypto_cipher *child;
-       /* optimizes multiplying a random (non incrementing, as at the
-        * start of a new sector) value with key2, we could also have
-        * used 4k optimization tables or no optimization at all. In the
-        * latter case we would have to store key2 here */
-       struct gf128mul_64k *table;
-       /* stores:
-        *  key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
-        *  key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
-        *  key2*{ 0,0,...1,1,1,1,1 }, etc
-        * needed for optimized multiplication of incrementing values
-        * with key2 */
-       be128 mulinc[128];
+       struct lrw_table_ctx table;
 };
 
 static inline void setbit128_bbe(void *b, int bit)
@@ -54,28 +45,16 @@ static inline void setbit128_bbe(void *b, int bit)
                        ), b);
 }
 
-static int setkey(struct crypto_tfm *parent, const u8 *key,
-                 unsigned int keylen)
+int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak)
 {
-       struct priv *ctx = crypto_tfm_ctx(parent);
-       struct crypto_cipher *child = ctx->child;
-       int err, i;
        be128 tmp = { 0 };
-       int bsize = crypto_cipher_blocksize(child);
-
-       crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
-       crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
-                                      CRYPTO_TFM_REQ_MASK);
-       if ((err = crypto_cipher_setkey(child, key, keylen - bsize)))
-               return err;
-       crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
-                                    CRYPTO_TFM_RES_MASK);
+       int i;
 
        if (ctx->table)
                gf128mul_free_64k(ctx->table);
 
        /* initialize multiplication table for Key2 */
-       ctx->table = gf128mul_init_64k_bbe((be128 *)(key + keylen - bsize));
+       ctx->table = gf128mul_init_64k_bbe((be128 *)tweak);
        if (!ctx->table)
                return -ENOMEM;
 
@@ -88,6 +67,34 @@ static int setkey(struct crypto_tfm *parent, const u8 *key,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(lrw_init_table);
+
+void lrw_free_table(struct lrw_table_ctx *ctx)
+{
+       if (ctx->table)
+               gf128mul_free_64k(ctx->table);
+}
+EXPORT_SYMBOL_GPL(lrw_free_table);
+
+static int setkey(struct crypto_tfm *parent, const u8 *key,
+                 unsigned int keylen)
+{
+       struct priv *ctx = crypto_tfm_ctx(parent);
+       struct crypto_cipher *child = ctx->child;
+       int err, bsize = LRW_BLOCK_SIZE;
+       const u8 *tweak = key + keylen - bsize;
+
+       crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+       crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) &
+                                      CRYPTO_TFM_REQ_MASK);
+       err = crypto_cipher_setkey(child, key, keylen - bsize);
+       if (err)
+               return err;
+       crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) &
+                                    CRYPTO_TFM_RES_MASK);
+
+       return lrw_init_table(&ctx->table, tweak);
+}
 
 struct sinfo {
        be128 t;
@@ -134,7 +141,7 @@ static int crypt(struct blkcipher_desc *d,
 {
        int err;
        unsigned int avail;
-       const int bs = crypto_cipher_blocksize(ctx->child);
+       const int bs = LRW_BLOCK_SIZE;
        struct sinfo s = {
                .tfm = crypto_cipher_tfm(ctx->child),
                .fn = fn
@@ -155,7 +162,7 @@ static int crypt(struct blkcipher_desc *d,
        s.t = *iv;
 
        /* T <- I*Key2 */
-       gf128mul_64k_bbe(&s.t, ctx->table);
+       gf128mul_64k_bbe(&s.t, ctx->table.table);
 
        goto first;
 
@@ -163,7 +170,8 @@ static int crypt(struct blkcipher_desc *d,
                do {
                        /* T <- I*Key2, using the optimization
                         * discussed in the specification */
-                       be128_xor(&s.t, &s.t, &ctx->mulinc[get_index128(iv)]);
+                       be128_xor(&s.t, &s.t,
+                                 &ctx->table.mulinc[get_index128(iv)]);
                        inc(iv);
 
 first:
@@ -206,6 +214,85 @@ static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                     crypto_cipher_alg(ctx->child)->cia_decrypt);
 }
 
+int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
+             struct scatterlist *ssrc, unsigned int nbytes,
+             struct lrw_crypt_req *req)
+{
+       const unsigned int bsize = LRW_BLOCK_SIZE;
+       const unsigned int max_blks = req->tbuflen / bsize;
+       struct lrw_table_ctx *ctx = req->table_ctx;
+       struct blkcipher_walk walk;
+       unsigned int nblocks;
+       be128 *iv, *src, *dst, *t;
+       be128 *t_buf = req->tbuf;
+       int err, i;
+
+       BUG_ON(max_blks < 1);
+
+       blkcipher_walk_init(&walk, sdst, ssrc, nbytes);
+
+       err = blkcipher_walk_virt(desc, &walk);
+       nbytes = walk.nbytes;
+       if (!nbytes)
+               return err;
+
+       nblocks = min(walk.nbytes / bsize, max_blks);
+       src = (be128 *)walk.src.virt.addr;
+       dst = (be128 *)walk.dst.virt.addr;
+
+       /* calculate first value of T */
+       iv = (be128 *)walk.iv;
+       t_buf[0] = *iv;
+
+       /* T <- I*Key2 */
+       gf128mul_64k_bbe(&t_buf[0], ctx->table);
+
+       i = 0;
+       goto first;
+
+       for (;;) {
+               do {
+                       for (i = 0; i < nblocks; i++) {
+                               /* T <- I*Key2, using the optimization
+                                * discussed in the specification */
+                               be128_xor(&t_buf[i], t,
+                                               &ctx->mulinc[get_index128(iv)]);
+                               inc(iv);
+first:
+                               t = &t_buf[i];
+
+                               /* PP <- T xor P */
+                               be128_xor(dst + i, t, src + i);
+                       }
+
+                       /* CC <- E(Key2,PP) */
+                       req->crypt_fn(req->crypt_ctx, (u8 *)dst,
+                                     nblocks * bsize);
+
+                       /* C <- T xor CC */
+                       for (i = 0; i < nblocks; i++)
+                               be128_xor(dst + i, dst + i, &t_buf[i]);
+
+                       src += nblocks;
+                       dst += nblocks;
+                       nbytes -= nblocks * bsize;
+                       nblocks = min(nbytes / bsize, max_blks);
+               } while (nblocks > 0);
+
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+               nbytes = walk.nbytes;
+               if (!nbytes)
+                       break;
+
+               nblocks = min(nbytes / bsize, max_blks);
+               src = (be128 *)walk.src.virt.addr;
+               dst = (be128 *)walk.dst.virt.addr;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(lrw_crypt);
+
 static int init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_cipher *cipher;
@@ -218,8 +305,9 @@ static int init_tfm(struct crypto_tfm *tfm)
        if (IS_ERR(cipher))
                return PTR_ERR(cipher);
 
-       if (crypto_cipher_blocksize(cipher) != 16) {
+       if (crypto_cipher_blocksize(cipher) != LRW_BLOCK_SIZE) {
                *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
+               crypto_free_cipher(cipher);
                return -EINVAL;
        }
 
@@ -230,8 +318,8 @@ static int init_tfm(struct crypto_tfm *tfm)
 static void exit_tfm(struct crypto_tfm *tfm)
 {
        struct priv *ctx = crypto_tfm_ctx(tfm);
-       if (ctx->table)
-               gf128mul_free_64k(ctx->table);
+
+       lrw_free_table(&ctx->table);
        crypto_free_cipher(ctx->child);
 }
 
diff --git a/crypto/serpent.c b/crypto/serpent.c
deleted file mode 100644 (file)
index b651a55..0000000
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Serpent Cipher Algorithm.
- *
- * Copyright (C) 2002 Dag Arne Osvik <osvik@ii.uib.no>
- *               2003 Herbert Valerio Riedel <hvr@gnu.org>
- *
- * Added tnepres support: Ruben Jesus Garcia Hernandez <ruben@ugr.es>, 18.10.2004
- *               Based on code by hvr
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-#include <linux/crypto.h>
-#include <linux/types.h>
-
-/* Key is padded to the maximum of 256 bits before round key generation.
- * Any key length <= 256 bits (32 bytes) is allowed by the algorithm.
- */
-
-#define SERPENT_MIN_KEY_SIZE             0
-#define SERPENT_MAX_KEY_SIZE            32
-#define SERPENT_EXPKEY_WORDS           132
-#define SERPENT_BLOCK_SIZE              16
-
-#define PHI 0x9e3779b9UL
-
-#define keyiter(a,b,c,d,i,j) \
-        b ^= d; b ^= c; b ^= a; b ^= PHI ^ i; b = rol32(b,11); k[j] = b;
-
-#define loadkeys(x0,x1,x2,x3,i) \
-       x0=k[i]; x1=k[i+1]; x2=k[i+2]; x3=k[i+3];
-
-#define storekeys(x0,x1,x2,x3,i) \
-       k[i]=x0; k[i+1]=x1; k[i+2]=x2; k[i+3]=x3;
-
-#define K(x0,x1,x2,x3,i)                               \
-       x3 ^= k[4*(i)+3];        x2 ^= k[4*(i)+2];      \
-       x1 ^= k[4*(i)+1];        x0 ^= k[4*(i)+0];
-
-#define LK(x0,x1,x2,x3,x4,i)                           \
-                                       x0=rol32(x0,13);\
-       x2=rol32(x2,3); x1 ^= x0;       x4  = x0 << 3;  \
-       x3 ^= x2;       x1 ^= x2;                       \
-       x1=rol32(x1,1); x3 ^= x4;                       \
-       x3=rol32(x3,7); x4  = x1;                       \
-       x0 ^= x1;       x4 <<= 7;       x2 ^= x3;       \
-       x0 ^= x3;       x2 ^= x4;       x3 ^= k[4*i+3]; \
-       x1 ^= k[4*i+1]; x0=rol32(x0,5); x2=rol32(x2,22);\
-       x0 ^= k[4*i+0]; x2 ^= k[4*i+2];
-
-#define KL(x0,x1,x2,x3,x4,i)                           \
-       x0 ^= k[4*i+0]; x1 ^= k[4*i+1]; x2 ^= k[4*i+2]; \
-       x3 ^= k[4*i+3]; x0=ror32(x0,5); x2=ror32(x2,22);\
-       x4 =  x1;       x2 ^= x3;       x0 ^= x3;       \
-       x4 <<= 7;       x0 ^= x1;       x1=ror32(x1,1); \
-       x2 ^= x4;       x3=ror32(x3,7); x4 = x0 << 3;   \
-       x1 ^= x0;       x3 ^= x4;       x0=ror32(x0,13);\
-       x1 ^= x2;       x3 ^= x2;       x2=ror32(x2,3);
-
-#define S0(x0,x1,x2,x3,x4)                             \
-                                       x4  = x3;       \
-       x3 |= x0;       x0 ^= x4;       x4 ^= x2;       \
-       x4 =~ x4;       x3 ^= x1;       x1 &= x0;       \
-       x1 ^= x4;       x2 ^= x0;       x0 ^= x3;       \
-       x4 |= x0;       x0 ^= x2;       x2 &= x1;       \
-       x3 ^= x2;       x1 =~ x1;       x2 ^= x4;       \
-       x1 ^= x2;
-
-#define S1(x0,x1,x2,x3,x4)                             \
-                                       x4  = x1;       \
-       x1 ^= x0;       x0 ^= x3;       x3 =~ x3;       \
-       x4 &= x1;       x0 |= x1;       x3 ^= x2;       \
-       x0 ^= x3;       x1 ^= x3;       x3 ^= x4;       \
-       x1 |= x4;       x4 ^= x2;       x2 &= x0;       \
-       x2 ^= x1;       x1 |= x0;       x0 =~ x0;       \
-       x0 ^= x2;       x4 ^= x1;
-
-#define S2(x0,x1,x2,x3,x4)                             \
-                                       x3 =~ x3;       \
-       x1 ^= x0;       x4  = x0;       x0 &= x2;       \
-       x0 ^= x3;       x3 |= x4;       x2 ^= x1;       \
-       x3 ^= x1;       x1 &= x0;       x0 ^= x2;       \
-       x2 &= x3;       x3 |= x1;       x0 =~ x0;       \
-       x3 ^= x0;       x4 ^= x0;       x0 ^= x2;       \
-       x1 |= x2;
-
-#define S3(x0,x1,x2,x3,x4)                             \
-                                       x4  = x1;       \
-       x1 ^= x3;       x3 |= x0;       x4 &= x0;       \
-       x0 ^= x2;       x2 ^= x1;       x1 &= x3;       \
-       x2 ^= x3;       x0 |= x4;       x4 ^= x3;       \
-       x1 ^= x0;       x0 &= x3;       x3 &= x4;       \
-       x3 ^= x2;       x4 |= x1;       x2 &= x1;       \
-       x4 ^= x3;       x0 ^= x3;       x3 ^= x2;
-
-#define S4(x0,x1,x2,x3,x4)                             \
-                                       x4  = x3;       \
-       x3 &= x0;       x0 ^= x4;                       \
-       x3 ^= x2;       x2 |= x4;       x0 ^= x1;       \
-       x4 ^= x3;       x2 |= x0;                       \
-       x2 ^= x1;       x1 &= x0;                       \
-       x1 ^= x4;       x4 &= x2;       x2 ^= x3;       \
-       x4 ^= x0;       x3 |= x1;       x1 =~ x1;       \
-       x3 ^= x0;
-
-#define S5(x0,x1,x2,x3,x4)                             \
-       x4  = x1;       x1 |= x0;                       \
-       x2 ^= x1;       x3 =~ x3;       x4 ^= x0;       \
-       x0 ^= x2;       x1 &= x4;       x4 |= x3;       \
-       x4 ^= x0;       x0 &= x3;       x1 ^= x3;       \
-       x3 ^= x2;       x0 ^= x1;       x2 &= x4;       \
-       x1 ^= x2;       x2 &= x0;                       \
-       x3 ^= x2;
-
-#define S6(x0,x1,x2,x3,x4)                             \
-                                       x4  = x1;       \
-       x3 ^= x0;       x1 ^= x2;       x2 ^= x0;       \
-       x0 &= x3;       x1 |= x3;       x4 =~ x4;       \
-       x0 ^= x1;       x1 ^= x2;                       \
-       x3 ^= x4;       x4 ^= x0;       x2 &= x0;       \
-       x4 ^= x1;       x2 ^= x3;       x3 &= x1;       \
-       x3 ^= x0;       x1 ^= x2;
-
-#define S7(x0,x1,x2,x3,x4)                             \
-                                       x1 =~ x1;       \
-       x4  = x1;       x0 =~ x0;       x1 &= x2;       \
-       x1 ^= x3;       x3 |= x4;       x4 ^= x2;       \
-       x2 ^= x3;       x3 ^= x0;       x0 |= x1;       \
-       x2 &= x0;       x0 ^= x4;       x4 ^= x3;       \
-       x3 &= x0;       x4 ^= x1;                       \
-       x2 ^= x4;       x3 ^= x1;       x4 |= x0;       \
-       x4 ^= x1;
-
-#define SI0(x0,x1,x2,x3,x4)                            \
-                       x4  = x3;       x1 ^= x0;       \
-       x3 |= x1;       x4 ^= x1;       x0 =~ x0;       \
-       x2 ^= x3;       x3 ^= x0;       x0 &= x1;       \
-       x0 ^= x2;       x2 &= x3;       x3 ^= x4;       \
-       x2 ^= x3;       x1 ^= x3;       x3 &= x0;       \
-       x1 ^= x0;       x0 ^= x2;       x4 ^= x3;
-
-#define SI1(x0,x1,x2,x3,x4)                            \
-       x1 ^= x3;       x4  = x0;                       \
-       x0 ^= x2;       x2 =~ x2;       x4 |= x1;       \
-       x4 ^= x3;       x3 &= x1;       x1 ^= x2;       \
-       x2 &= x4;       x4 ^= x1;       x1 |= x3;       \
-       x3 ^= x0;       x2 ^= x0;       x0 |= x4;       \
-       x2 ^= x4;       x1 ^= x0;                       \
-       x4 ^= x1;
-
-#define SI2(x0,x1,x2,x3,x4)                            \
-       x2 ^= x1;       x4  = x3;       x3 =~ x3;       \
-       x3 |= x2;       x2 ^= x4;       x4 ^= x0;       \
-       x3 ^= x1;       x1 |= x2;       x2 ^= x0;       \
-       x1 ^= x4;       x4 |= x3;       x2 ^= x3;       \
-       x4 ^= x2;       x2 &= x1;                       \
-       x2 ^= x3;       x3 ^= x4;       x4 ^= x0;
-
-#define SI3(x0,x1,x2,x3,x4)                            \
-                                       x2 ^= x1;       \
-       x4  = x1;       x1 &= x2;                       \
-       x1 ^= x0;       x0 |= x4;       x4 ^= x3;       \
-       x0 ^= x3;       x3 |= x1;       x1 ^= x2;       \
-       x1 ^= x3;       x0 ^= x2;       x2 ^= x3;       \
-       x3 &= x1;       x1 ^= x0;       x0 &= x2;       \
-       x4 ^= x3;       x3 ^= x0;       x0 ^= x1;
-
-#define SI4(x0,x1,x2,x3,x4)                            \
-       x2 ^= x3;       x4  = x0;       x0 &= x1;       \
-       x0 ^= x2;       x2 |= x3;       x4 =~ x4;       \
-       x1 ^= x0;       x0 ^= x2;       x2 &= x4;       \
-       x2 ^= x0;       x0 |= x4;                       \
-       x0 ^= x3;       x3 &= x2;                       \
-       x4 ^= x3;       x3 ^= x1;       x1 &= x0;       \
-       x4 ^= x1;       x0 ^= x3;
-
-#define SI5(x0,x1,x2,x3,x4)                            \
-                       x4  = x1;       x1 |= x2;       \
-       x2 ^= x4;       x1 ^= x3;       x3 &= x4;       \
-       x2 ^= x3;       x3 |= x0;       x0 =~ x0;       \
-       x3 ^= x2;       x2 |= x0;       x4 ^= x1;       \
-       x2 ^= x4;       x4 &= x0;       x0 ^= x1;       \
-       x1 ^= x3;       x0 &= x2;       x2 ^= x3;       \
-       x0 ^= x2;       x2 ^= x4;       x4 ^= x3;
-
-#define SI6(x0,x1,x2,x3,x4)                            \
-                       x0 ^= x2;                       \
-       x4  = x0;       x0 &= x3;       x2 ^= x3;       \
-       x0 ^= x2;       x3 ^= x1;       x2 |= x4;       \
-       x2 ^= x3;       x3 &= x0;       x0 =~ x0;       \
-       x3 ^= x1;       x1 &= x2;       x4 ^= x0;       \
-       x3 ^= x4;       x4 ^= x2;       x0 ^= x1;       \
-       x2 ^= x0;
-
-#define SI7(x0,x1,x2,x3,x4)                            \
-       x4  = x3;       x3 &= x0;       x0 ^= x2;       \
-       x2 |= x4;       x4 ^= x1;       x0 =~ x0;       \
-       x1 |= x3;       x4 ^= x0;       x0 &= x2;       \
-       x0 ^= x1;       x1 &= x2;       x3 ^= x2;       \
-       x4 ^= x3;       x2 &= x3;       x3 |= x0;       \
-       x1 ^= x4;       x3 ^= x4;       x4 &= x0;       \
-       x4 ^= x2;
-
-struct serpent_ctx {
-       u32 expkey[SERPENT_EXPKEY_WORDS];
-};
-
-
-static int serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
-                         unsigned int keylen)
-{
-       struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
-       u32 *k = ctx->expkey;
-       u8  *k8 = (u8 *)k;
-       u32 r0,r1,r2,r3,r4;
-       int i;
-
-       /* Copy key, add padding */
-
-       for (i = 0; i < keylen; ++i)
-               k8[i] = key[i];
-       if (i < SERPENT_MAX_KEY_SIZE)
-               k8[i++] = 1;
-       while (i < SERPENT_MAX_KEY_SIZE)
-               k8[i++] = 0;
-
-       /* Expand key using polynomial */
-
-       r0 = le32_to_cpu(k[3]);
-       r1 = le32_to_cpu(k[4]);
-       r2 = le32_to_cpu(k[5]);
-       r3 = le32_to_cpu(k[6]);
-       r4 = le32_to_cpu(k[7]);
-
-       keyiter(le32_to_cpu(k[0]),r0,r4,r2,0,0);
-       keyiter(le32_to_cpu(k[1]),r1,r0,r3,1,1);
-       keyiter(le32_to_cpu(k[2]),r2,r1,r4,2,2);
-       keyiter(le32_to_cpu(k[3]),r3,r2,r0,3,3);
-       keyiter(le32_to_cpu(k[4]),r4,r3,r1,4,4);
-       keyiter(le32_to_cpu(k[5]),r0,r4,r2,5,5);
-       keyiter(le32_to_cpu(k[6]),r1,r0,r3,6,6);
-       keyiter(le32_to_cpu(k[7]),r2,r1,r4,7,7);
-
-       keyiter(k[  0],r3,r2,r0,  8,  8); keyiter(k[  1],r4,r3,r1,  9,  9);
-       keyiter(k[  2],r0,r4,r2, 10, 10); keyiter(k[  3],r1,r0,r3, 11, 11);
-       keyiter(k[  4],r2,r1,r4, 12, 12); keyiter(k[  5],r3,r2,r0, 13, 13);
-       keyiter(k[  6],r4,r3,r1, 14, 14); keyiter(k[  7],r0,r4,r2, 15, 15);
-       keyiter(k[  8],r1,r0,r3, 16, 16); keyiter(k[  9],r2,r1,r4, 17, 17);
-       keyiter(k[ 10],r3,r2,r0, 18, 18); keyiter(k[ 11],r4,r3,r1, 19, 19);
-       keyiter(k[ 12],r0,r4,r2, 20, 20); keyiter(k[ 13],r1,r0,r3, 21, 21);
-       keyiter(k[ 14],r2,r1,r4, 22, 22); keyiter(k[ 15],r3,r2,r0, 23, 23);
-       keyiter(k[ 16],r4,r3,r1, 24, 24); keyiter(k[ 17],r0,r4,r2, 25, 25);
-       keyiter(k[ 18],r1,r0,r3, 26, 26); keyiter(k[ 19],r2,r1,r4, 27, 27);
-       keyiter(k[ 20],r3,r2,r0, 28, 28); keyiter(k[ 21],r4,r3,r1, 29, 29);
-       keyiter(k[ 22],r0,r4,r2, 30, 30); keyiter(k[ 23],r1,r0,r3, 31, 31);
-
-       k += 50;
-
-       keyiter(k[-26],r2,r1,r4, 32,-18); keyiter(k[-25],r3,r2,r0, 33,-17);
-       keyiter(k[-24],r4,r3,r1, 34,-16); keyiter(k[-23],r0,r4,r2, 35,-15);
-       keyiter(k[-22],r1,r0,r3, 36,-14); keyiter(k[-21],r2,r1,r4, 37,-13);
-       keyiter(k[-20],r3,r2,r0, 38,-12); keyiter(k[-19],r4,r3,r1, 39,-11);
-       keyiter(k[-18],r0,r4,r2, 40,-10); keyiter(k[-17],r1,r0,r3, 41, -9);
-       keyiter(k[-16],r2,r1,r4, 42, -8); keyiter(k[-15],r3,r2,r0, 43, -7);
-       keyiter(k[-14],r4,r3,r1, 44, -6); keyiter(k[-13],r0,r4,r2, 45, -5);
-       keyiter(k[-12],r1,r0,r3, 46, -4); keyiter(k[-11],r2,r1,r4, 47, -3);
-       keyiter(k[-10],r3,r2,r0, 48, -2); keyiter(k[ -9],r4,r3,r1, 49, -1);
-       keyiter(k[ -8],r0,r4,r2, 50,  0); keyiter(k[ -7],r1,r0,r3, 51,  1);
-       keyiter(k[ -6],r2,r1,r4, 52,  2); keyiter(k[ -5],r3,r2,r0, 53,  3);
-       keyiter(k[ -4],r4,r3,r1, 54,  4); keyiter(k[ -3],r0,r4,r2, 55,  5);
-       keyiter(k[ -2],r1,r0,r3, 56,  6); keyiter(k[ -1],r2,r1,r4, 57,  7);
-       keyiter(k[  0],r3,r2,r0, 58,  8); keyiter(k[  1],r4,r3,r1, 59,  9);
-       keyiter(k[  2],r0,r4,r2, 60, 10); keyiter(k[  3],r1,r0,r3, 61, 11);
-       keyiter(k[  4],r2,r1,r4, 62, 12); keyiter(k[  5],r3,r2,r0, 63, 13);
-       keyiter(k[  6],r4,r3,r1, 64, 14); keyiter(k[  7],r0,r4,r2, 65, 15);
-       keyiter(k[  8],r1,r0,r3, 66, 16); keyiter(k[  9],r2,r1,r4, 67, 17);
-       keyiter(k[ 10],r3,r2,r0, 68, 18); keyiter(k[ 11],r4,r3,r1, 69, 19);
-       keyiter(k[ 12],r0,r4,r2, 70, 20); keyiter(k[ 13],r1,r0,r3, 71, 21);
-       keyiter(k[ 14],r2,r1,r4, 72, 22); keyiter(k[ 15],r3,r2,r0, 73, 23);
-       keyiter(k[ 16],r4,r3,r1, 74, 24); keyiter(k[ 17],r0,r4,r2, 75, 25);
-       keyiter(k[ 18],r1,r0,r3, 76, 26); keyiter(k[ 19],r2,r1,r4, 77, 27);
-       keyiter(k[ 20],r3,r2,r0, 78, 28); keyiter(k[ 21],r4,r3,r1, 79, 29);
-       keyiter(k[ 22],r0,r4,r2, 80, 30); keyiter(k[ 23],r1,r0,r3, 81, 31);
-
-       k += 50;
-
-       keyiter(k[-26],r2,r1,r4, 82,-18); keyiter(k[-25],r3,r2,r0, 83,-17);
-       keyiter(k[-24],r4,r3,r1, 84,-16); keyiter(k[-23],r0,r4,r2, 85,-15);
-       keyiter(k[-22],r1,r0,r3, 86,-14); keyiter(k[-21],r2,r1,r4, 87,-13);
-       keyiter(k[-20],r3,r2,r0, 88,-12); keyiter(k[-19],r4,r3,r1, 89,-11);
-       keyiter(k[-18],r0,r4,r2, 90,-10); keyiter(k[-17],r1,r0,r3, 91, -9);
-       keyiter(k[-16],r2,r1,r4, 92, -8); keyiter(k[-15],r3,r2,r0, 93, -7);
-       keyiter(k[-14],r4,r3,r1, 94, -6); keyiter(k[-13],r0,r4,r2, 95, -5);
-       keyiter(k[-12],r1,r0,r3, 96, -4); keyiter(k[-11],r2,r1,r4, 97, -3);
-       keyiter(k[-10],r3,r2,r0, 98, -2); keyiter(k[ -9],r4,r3,r1, 99, -1);
-       keyiter(k[ -8],r0,r4,r2,100,  0); keyiter(k[ -7],r1,r0,r3,101,  1);
-       keyiter(k[ -6],r2,r1,r4,102,  2); keyiter(k[ -5],r3,r2,r0,103,  3);
-       keyiter(k[ -4],r4,r3,r1,104,  4); keyiter(k[ -3],r0,r4,r2,105,  5);
-       keyiter(k[ -2],r1,r0,r3,106,  6); keyiter(k[ -1],r2,r1,r4,107,  7);
-       keyiter(k[  0],r3,r2,r0,108,  8); keyiter(k[  1],r4,r3,r1,109,  9);
-       keyiter(k[  2],r0,r4,r2,110, 10); keyiter(k[  3],r1,r0,r3,111, 11);
-       keyiter(k[  4],r2,r1,r4,112, 12); keyiter(k[  5],r3,r2,r0,113, 13);
-       keyiter(k[  6],r4,r3,r1,114, 14); keyiter(k[  7],r0,r4,r2,115, 15);
-       keyiter(k[  8],r1,r0,r3,116, 16); keyiter(k[  9],r2,r1,r4,117, 17);
-       keyiter(k[ 10],r3,r2,r0,118, 18); keyiter(k[ 11],r4,r3,r1,119, 19);
-       keyiter(k[ 12],r0,r4,r2,120, 20); keyiter(k[ 13],r1,r0,r3,121, 21);
-       keyiter(k[ 14],r2,r1,r4,122, 22); keyiter(k[ 15],r3,r2,r0,123, 23);
-       keyiter(k[ 16],r4,r3,r1,124, 24); keyiter(k[ 17],r0,r4,r2,125, 25);
-       keyiter(k[ 18],r1,r0,r3,126, 26); keyiter(k[ 19],r2,r1,r4,127, 27);
-       keyiter(k[ 20],r3,r2,r0,128, 28); keyiter(k[ 21],r4,r3,r1,129, 29);
-       keyiter(k[ 22],r0,r4,r2,130, 30); keyiter(k[ 23],r1,r0,r3,131, 31);
-
-       /* Apply S-boxes */
-
-       S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3, 28); loadkeys(r1,r2,r4,r3, 24);
-       S4(r1,r2,r4,r3,r0); storekeys(r2,r4,r3,r0, 24); loadkeys(r2,r4,r3,r0, 20);
-       S5(r2,r4,r3,r0,r1); storekeys(r1,r2,r4,r0, 20); loadkeys(r1,r2,r4,r0, 16);
-       S6(r1,r2,r4,r0,r3); storekeys(r4,r3,r2,r0, 16); loadkeys(r4,r3,r2,r0, 12);
-       S7(r4,r3,r2,r0,r1); storekeys(r1,r2,r0,r4, 12); loadkeys(r1,r2,r0,r4,  8);
-       S0(r1,r2,r0,r4,r3); storekeys(r0,r2,r4,r1,  8); loadkeys(r0,r2,r4,r1,  4);
-       S1(r0,r2,r4,r1,r3); storekeys(r3,r4,r1,r0,  4); loadkeys(r3,r4,r1,r0,  0);
-       S2(r3,r4,r1,r0,r2); storekeys(r2,r4,r3,r0,  0); loadkeys(r2,r4,r3,r0, -4);
-       S3(r2,r4,r3,r0,r1); storekeys(r0,r1,r4,r2, -4); loadkeys(r0,r1,r4,r2, -8);
-       S4(r0,r1,r4,r2,r3); storekeys(r1,r4,r2,r3, -8); loadkeys(r1,r4,r2,r3,-12);
-       S5(r1,r4,r2,r3,r0); storekeys(r0,r1,r4,r3,-12); loadkeys(r0,r1,r4,r3,-16);
-       S6(r0,r1,r4,r3,r2); storekeys(r4,r2,r1,r3,-16); loadkeys(r4,r2,r1,r3,-20);
-       S7(r4,r2,r1,r3,r0); storekeys(r0,r1,r3,r4,-20); loadkeys(r0,r1,r3,r4,-24);
-       S0(r0,r1,r3,r4,r2); storekeys(r3,r1,r4,r0,-24); loadkeys(r3,r1,r4,r0,-28);
-       k -= 50;
-       S1(r3,r1,r4,r0,r2); storekeys(r2,r4,r0,r3, 22); loadkeys(r2,r4,r0,r3, 18);
-       S2(r2,r4,r0,r3,r1); storekeys(r1,r4,r2,r3, 18); loadkeys(r1,r4,r2,r3, 14);
-       S3(r1,r4,r2,r3,r0); storekeys(r3,r0,r4,r1, 14); loadkeys(r3,r0,r4,r1, 10);
-       S4(r3,r0,r4,r1,r2); storekeys(r0,r4,r1,r2, 10); loadkeys(r0,r4,r1,r2,  6);
-       S5(r0,r4,r1,r2,r3); storekeys(r3,r0,r4,r2,  6); loadkeys(r3,r0,r4,r2,  2);
-       S6(r3,r0,r4,r2,r1); storekeys(r4,r1,r0,r2,  2); loadkeys(r4,r1,r0,r2, -2);
-       S7(r4,r1,r0,r2,r3); storekeys(r3,r0,r2,r4, -2); loadkeys(r3,r0,r2,r4, -6);
-       S0(r3,r0,r2,r4,r1); storekeys(r2,r0,r4,r3, -6); loadkeys(r2,r0,r4,r3,-10);
-       S1(r2,r0,r4,r3,r1); storekeys(r1,r4,r3,r2,-10); loadkeys(r1,r4,r3,r2,-14);
-       S2(r1,r4,r3,r2,r0); storekeys(r0,r4,r1,r2,-14); loadkeys(r0,r4,r1,r2,-18);
-       S3(r0,r4,r1,r2,r3); storekeys(r2,r3,r4,r0,-18); loadkeys(r2,r3,r4,r0,-22);
-       k -= 50;
-       S4(r2,r3,r4,r0,r1); storekeys(r3,r4,r0,r1, 28); loadkeys(r3,r4,r0,r1, 24);
-       S5(r3,r4,r0,r1,r2); storekeys(r2,r3,r4,r1, 24); loadkeys(r2,r3,r4,r1, 20);
-       S6(r2,r3,r4,r1,r0); storekeys(r4,r0,r3,r1, 20); loadkeys(r4,r0,r3,r1, 16);
-       S7(r4,r0,r3,r1,r2); storekeys(r2,r3,r1,r4, 16); loadkeys(r2,r3,r1,r4, 12);
-       S0(r2,r3,r1,r4,r0); storekeys(r1,r3,r4,r2, 12); loadkeys(r1,r3,r4,r2,  8);
-       S1(r1,r3,r4,r2,r0); storekeys(r0,r4,r2,r1,  8); loadkeys(r0,r4,r2,r1,  4);
-       S2(r0,r4,r2,r1,r3); storekeys(r3,r4,r0,r1,  4); loadkeys(r3,r4,r0,r1,  0);
-       S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3,  0);
-
-       return 0;
-}
-
-static void serpent_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
-       const u32
-               *k = ctx->expkey;
-       const __le32 *s = (const __le32 *)src;
-       __le32  *d = (__le32 *)dst;
-       u32     r0, r1, r2, r3, r4;
-
-/*
- * Note: The conversions between u8* and u32* might cause trouble
- * on architectures with stricter alignment rules than x86
- */
-
-       r0 = le32_to_cpu(s[0]);
-       r1 = le32_to_cpu(s[1]);
-       r2 = le32_to_cpu(s[2]);
-       r3 = le32_to_cpu(s[3]);
-
-                                K(r0,r1,r2,r3,0);
-       S0(r0,r1,r2,r3,r4);     LK(r2,r1,r3,r0,r4,1);
-       S1(r2,r1,r3,r0,r4);     LK(r4,r3,r0,r2,r1,2);
-       S2(r4,r3,r0,r2,r1);     LK(r1,r3,r4,r2,r0,3);
-       S3(r1,r3,r4,r2,r0);     LK(r2,r0,r3,r1,r4,4);
-       S4(r2,r0,r3,r1,r4);     LK(r0,r3,r1,r4,r2,5);
-       S5(r0,r3,r1,r4,r2);     LK(r2,r0,r3,r4,r1,6);
-       S6(r2,r0,r3,r4,r1);     LK(r3,r1,r0,r4,r2,7);
-       S7(r3,r1,r0,r4,r2);     LK(r2,r0,r4,r3,r1,8);
-       S0(r2,r0,r4,r3,r1);     LK(r4,r0,r3,r2,r1,9);
-       S1(r4,r0,r3,r2,r1);     LK(r1,r3,r2,r4,r0,10);
-       S2(r1,r3,r2,r4,r0);     LK(r0,r3,r1,r4,r2,11);
-       S3(r0,r3,r1,r4,r2);     LK(r4,r2,r3,r0,r1,12);
-       S4(r4,r2,r3,r0,r1);     LK(r2,r3,r0,r1,r4,13);
-       S5(r2,r3,r0,r1,r4);     LK(r4,r2,r3,r1,r0,14);
-       S6(r4,r2,r3,r1,r0);     LK(r3,r0,r2,r1,r4,15);
-       S7(r3,r0,r2,r1,r4);     LK(r4,r2,r1,r3,r0,16);
-       S0(r4,r2,r1,r3,r0);     LK(r1,r2,r3,r4,r0,17);
-       S1(r1,r2,r3,r4,r0);     LK(r0,r3,r4,r1,r2,18);
-       S2(r0,r3,r4,r1,r2);     LK(r2,r3,r0,r1,r4,19);
-       S3(r2,r3,r0,r1,r4);     LK(r1,r4,r3,r2,r0,20);
-       S4(r1,r4,r3,r2,r0);     LK(r4,r3,r2,r0,r1,21);
-       S5(r4,r3,r2,r0,r1);     LK(r1,r4,r3,r0,r2,22);
-       S6(r1,r4,r3,r0,r2);     LK(r3,r2,r4,r0,r1,23);
-       S7(r3,r2,r4,r0,r1);     LK(r1,r4,r0,r3,r2,24);
-       S0(r1,r4,r0,r3,r2);     LK(r0,r4,r3,r1,r2,25);
-       S1(r0,r4,r3,r1,r2);     LK(r2,r3,r1,r0,r4,26);
-       S2(r2,r3,r1,r0,r4);     LK(r4,r3,r2,r0,r1,27);
-       S3(r4,r3,r2,r0,r1);     LK(r0,r1,r3,r4,r2,28);
-       S4(r0,r1,r3,r4,r2);     LK(r1,r3,r4,r2,r0,29);
-       S5(r1,r3,r4,r2,r0);     LK(r0,r1,r3,r2,r4,30);
-       S6(r0,r1,r3,r2,r4);     LK(r3,r4,r1,r2,r0,31);
-       S7(r3,r4,r1,r2,r0);      K(r0,r1,r2,r3,32);
-
-       d[0] = cpu_to_le32(r0);
-       d[1] = cpu_to_le32(r1);
-       d[2] = cpu_to_le32(r2);
-       d[3] = cpu_to_le32(r3);
-}
-
-static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
-       const u32
-               *k = ((struct serpent_ctx *)ctx)->expkey;
-       const __le32 *s = (const __le32 *)src;
-       __le32  *d = (__le32 *)dst;
-       u32     r0, r1, r2, r3, r4;
-
-       r0 = le32_to_cpu(s[0]);
-       r1 = le32_to_cpu(s[1]);
-       r2 = le32_to_cpu(s[2]);
-       r3 = le32_to_cpu(s[3]);
-
-                               K(r0,r1,r2,r3,32);
-       SI7(r0,r1,r2,r3,r4);    KL(r1,r3,r0,r4,r2,31);
-       SI6(r1,r3,r0,r4,r2);    KL(r0,r2,r4,r1,r3,30);
-       SI5(r0,r2,r4,r1,r3);    KL(r2,r3,r0,r4,r1,29);
-       SI4(r2,r3,r0,r4,r1);    KL(r2,r0,r1,r4,r3,28);
-       SI3(r2,r0,r1,r4,r3);    KL(r1,r2,r3,r4,r0,27);
-       SI2(r1,r2,r3,r4,r0);    KL(r2,r0,r4,r3,r1,26);
-       SI1(r2,r0,r4,r3,r1);    KL(r1,r0,r4,r3,r2,25);
-       SI0(r1,r0,r4,r3,r2);    KL(r4,r2,r0,r1,r3,24);
-       SI7(r4,r2,r0,r1,r3);    KL(r2,r1,r4,r3,r0,23);
-       SI6(r2,r1,r4,r3,r0);    KL(r4,r0,r3,r2,r1,22);
-       SI5(r4,r0,r3,r2,r1);    KL(r0,r1,r4,r3,r2,21);
-       SI4(r0,r1,r4,r3,r2);    KL(r0,r4,r2,r3,r1,20);
-       SI3(r0,r4,r2,r3,r1);    KL(r2,r0,r1,r3,r4,19);
-       SI2(r2,r0,r1,r3,r4);    KL(r0,r4,r3,r1,r2,18);
-       SI1(r0,r4,r3,r1,r2);    KL(r2,r4,r3,r1,r0,17);
-       SI0(r2,r4,r3,r1,r0);    KL(r3,r0,r4,r2,r1,16);
-       SI7(r3,r0,r4,r2,r1);    KL(r0,r2,r3,r1,r4,15);
-       SI6(r0,r2,r3,r1,r4);    KL(r3,r4,r1,r0,r2,14);
-       SI5(r3,r4,r1,r0,r2);    KL(r4,r2,r3,r1,r0,13);
-       SI4(r4,r2,r3,r1,r0);    KL(r4,r3,r0,r1,r2,12);
-       SI3(r4,r3,r0,r1,r2);    KL(r0,r4,r2,r1,r3,11);
-       SI2(r0,r4,r2,r1,r3);    KL(r4,r3,r1,r2,r0,10);
-       SI1(r4,r3,r1,r2,r0);    KL(r0,r3,r1,r2,r4,9);
-       SI0(r0,r3,r1,r2,r4);    KL(r1,r4,r3,r0,r2,8);
-       SI7(r1,r4,r3,r0,r2);    KL(r4,r0,r1,r2,r3,7);
-       SI6(r4,r0,r1,r2,r3);    KL(r1,r3,r2,r4,r0,6);
-       SI5(r1,r3,r2,r4,r0);    KL(r3,r0,r1,r2,r4,5);
-       SI4(r3,r0,r1,r2,r4);    KL(r3,r1,r4,r2,r0,4);
-       SI3(r3,r1,r4,r2,r0);    KL(r4,r3,r0,r2,r1,3);
-       SI2(r4,r3,r0,r2,r1);    KL(r3,r1,r2,r0,r4,2);
-       SI1(r3,r1,r2,r0,r4);    KL(r4,r1,r2,r0,r3,1);
-       SI0(r4,r1,r2,r0,r3);    K(r2,r3,r1,r4,0);
-
-       d[0] = cpu_to_le32(r2);
-       d[1] = cpu_to_le32(r3);
-       d[2] = cpu_to_le32(r1);
-       d[3] = cpu_to_le32(r4);
-}
-
-static struct crypto_alg serpent_alg = {
-       .cra_name               =       "serpent",
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct serpent_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
-       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
-       .cia_setkey             =       serpent_setkey,
-       .cia_encrypt            =       serpent_encrypt,
-       .cia_decrypt            =       serpent_decrypt } }
-};
-
-static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
-                         unsigned int keylen)
-{
-       u8 rev_key[SERPENT_MAX_KEY_SIZE];
-       int i;
-
-       for (i = 0; i < keylen; ++i)
-               rev_key[keylen - i - 1] = key[i];
-       return serpent_setkey(tfm, rev_key, keylen);
-}
-
-static void tnepres_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       const u32 * const s = (const u32 * const)src;
-       u32 * const d = (u32 * const)dst;
-
-       u32 rs[4], rd[4];
-
-       rs[0] = swab32(s[3]);
-       rs[1] = swab32(s[2]);
-       rs[2] = swab32(s[1]);
-       rs[3] = swab32(s[0]);
-
-       serpent_encrypt(tfm, (u8 *)rd, (u8 *)rs);
-
-       d[0] = swab32(rd[3]);
-       d[1] = swab32(rd[2]);
-       d[2] = swab32(rd[1]);
-       d[3] = swab32(rd[0]);
-}
-
-static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
-       const u32 * const s = (const u32 * const)src;
-       u32 * const d = (u32 * const)dst;
-
-       u32 rs[4], rd[4];
-
-       rs[0] = swab32(s[3]);
-       rs[1] = swab32(s[2]);
-       rs[2] = swab32(s[1]);
-       rs[3] = swab32(s[0]);
-
-       serpent_decrypt(tfm, (u8 *)rd, (u8 *)rs);
-
-       d[0] = swab32(rd[3]);
-       d[1] = swab32(rd[2]);
-       d[2] = swab32(rd[1]);
-       d[3] = swab32(rd[0]);
-}
-
-static struct crypto_alg tnepres_alg = {
-       .cra_name               =       "tnepres",
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct serpent_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
-       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
-       .cia_setkey             =       tnepres_setkey,
-       .cia_encrypt            =       tnepres_encrypt,
-       .cia_decrypt            =       tnepres_decrypt } }
-};
-
-static int __init serpent_mod_init(void)
-{
-       int ret = crypto_register_alg(&serpent_alg);
-
-       if (ret)
-               return ret;
-
-       ret = crypto_register_alg(&tnepres_alg);
-
-       if (ret)
-               crypto_unregister_alg(&serpent_alg);
-
-       return ret;
-}
-
-static void __exit serpent_mod_fini(void)
-{
-       crypto_unregister_alg(&tnepres_alg);
-       crypto_unregister_alg(&serpent_alg);
-}
-
-module_init(serpent_mod_init);
-module_exit(serpent_mod_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm");
-MODULE_AUTHOR("Dag Arne Osvik <osvik@ii.uib.no>");
-MODULE_ALIAS("tnepres");
diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c
new file mode 100644 (file)
index 0000000..8f32cf3
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ * Cryptographic API.
+ *
+ * Serpent Cipher Algorithm.
+ *
+ * Copyright (C) 2002 Dag Arne Osvik <osvik@ii.uib.no>
+ *               2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * Added tnepres support:
+ *             Ruben Jesus Garcia Hernandez <ruben@ugr.es>, 18.10.2004
+ *              Based on code by hvr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+#include <linux/crypto.h>
+#include <linux/types.h>
+#include <crypto/serpent.h>
+
+/* Key is padded to the maximum of 256 bits before round key generation.
+ * Any key length <= 256 bits (32 bytes) is allowed by the algorithm.
+ */
+
+#define PHI 0x9e3779b9UL
+
+#define keyiter(a, b, c, d, i, j) \
+       ({ b ^= d; b ^= c; b ^= a; b ^= PHI ^ i; b = rol32(b, 11); k[j] = b; })
+
+#define loadkeys(x0, x1, x2, x3, i) \
+       ({ x0 = k[i]; x1 = k[i+1]; x2 = k[i+2]; x3 = k[i+3]; })
+
+#define storekeys(x0, x1, x2, x3, i) \
+       ({ k[i] = x0; k[i+1] = x1; k[i+2] = x2; k[i+3] = x3; })
+
+#define store_and_load_keys(x0, x1, x2, x3, s, l) \
+       ({ storekeys(x0, x1, x2, x3, s); loadkeys(x0, x1, x2, x3, l); })
+
+#define K(x0, x1, x2, x3, i) ({                                \
+       x3 ^= k[4*(i)+3];        x2 ^= k[4*(i)+2];      \
+       x1 ^= k[4*(i)+1];        x0 ^= k[4*(i)+0];      \
+       })
+
+#define LK(x0, x1, x2, x3, x4, i) ({                                      \
+                                                       x0 = rol32(x0, 13);\
+       x2 = rol32(x2, 3);      x1 ^= x0;               x4  = x0 << 3;     \
+       x3 ^= x2;               x1 ^= x2;                                  \
+       x1 = rol32(x1, 1);      x3 ^= x4;                                  \
+       x3 = rol32(x3, 7);      x4  = x1;                                  \
+       x0 ^= x1;               x4 <<= 7;               x2 ^= x3;          \
+       x0 ^= x3;               x2 ^= x4;               x3 ^= k[4*i+3];    \
+       x1 ^= k[4*i+1];         x0 = rol32(x0, 5);      x2 = rol32(x2, 22);\
+       x0 ^= k[4*i+0];         x2 ^= k[4*i+2];                            \
+       })
+
+#define KL(x0, x1, x2, x3, x4, i) ({                                      \
+       x0 ^= k[4*i+0];         x1 ^= k[4*i+1];         x2 ^= k[4*i+2];    \
+       x3 ^= k[4*i+3];         x0 = ror32(x0, 5);      x2 = ror32(x2, 22);\
+       x4 =  x1;               x2 ^= x3;               x0 ^= x3;          \
+       x4 <<= 7;               x0 ^= x1;               x1 = ror32(x1, 1); \
+       x2 ^= x4;               x3 = ror32(x3, 7);      x4 = x0 << 3;      \
+       x1 ^= x0;               x3 ^= x4;               x0 = ror32(x0, 13);\
+       x1 ^= x2;               x3 ^= x2;               x2 = ror32(x2, 3); \
+       })
+
+#define S0(x0, x1, x2, x3, x4) ({                      \
+                                       x4  = x3;       \
+       x3 |= x0;       x0 ^= x4;       x4 ^= x2;       \
+       x4 = ~x4;       x3 ^= x1;       x1 &= x0;       \
+       x1 ^= x4;       x2 ^= x0;       x0 ^= x3;       \
+       x4 |= x0;       x0 ^= x2;       x2 &= x1;       \
+       x3 ^= x2;       x1 = ~x1;       x2 ^= x4;       \
+       x1 ^= x2;                                       \
+       })
+
+#define S1(x0, x1, x2, x3, x4) ({                      \
+                                       x4  = x1;       \
+       x1 ^= x0;       x0 ^= x3;       x3 = ~x3;       \
+       x4 &= x1;       x0 |= x1;       x3 ^= x2;       \
+       x0 ^= x3;       x1 ^= x3;       x3 ^= x4;       \
+       x1 |= x4;       x4 ^= x2;       x2 &= x0;       \
+       x2 ^= x1;       x1 |= x0;       x0 = ~x0;       \
+       x0 ^= x2;       x4 ^= x1;                       \
+       })
+
+#define S2(x0, x1, x2, x3, x4) ({                      \
+                                       x3 = ~x3;       \
+       x1 ^= x0;       x4  = x0;       x0 &= x2;       \
+       x0 ^= x3;       x3 |= x4;       x2 ^= x1;       \
+       x3 ^= x1;       x1 &= x0;       x0 ^= x2;       \
+       x2 &= x3;       x3 |= x1;       x0 = ~x0;       \
+       x3 ^= x0;       x4 ^= x0;       x0 ^= x2;       \
+       x1 |= x2;                                       \
+       })
+
+#define S3(x0, x1, x2, x3, x4) ({                      \
+                                       x4  = x1;       \
+       x1 ^= x3;       x3 |= x0;       x4 &= x0;       \
+       x0 ^= x2;       x2 ^= x1;       x1 &= x3;       \
+       x2 ^= x3;       x0 |= x4;       x4 ^= x3;       \
+       x1 ^= x0;       x0 &= x3;       x3 &= x4;       \
+       x3 ^= x2;       x4 |= x1;       x2 &= x1;       \
+       x4 ^= x3;       x0 ^= x3;       x3 ^= x2;       \
+       })
+
+#define S4(x0, x1, x2, x3, x4) ({                      \
+                                       x4  = x3;       \
+       x3 &= x0;       x0 ^= x4;                       \
+       x3 ^= x2;       x2 |= x4;       x0 ^= x1;       \
+       x4 ^= x3;       x2 |= x0;                       \
+       x2 ^= x1;       x1 &= x0;                       \
+       x1 ^= x4;       x4 &= x2;       x2 ^= x3;       \
+       x4 ^= x0;       x3 |= x1;       x1 = ~x1;       \
+       x3 ^= x0;                                       \
+       })
+
+#define S5(x0, x1, x2, x3, x4) ({                      \
+       x4  = x1;       x1 |= x0;                       \
+       x2 ^= x1;       x3 = ~x3;       x4 ^= x0;       \
+       x0 ^= x2;       x1 &= x4;       x4 |= x3;       \
+       x4 ^= x0;       x0 &= x3;       x1 ^= x3;       \
+       x3 ^= x2;       x0 ^= x1;       x2 &= x4;       \
+       x1 ^= x2;       x2 &= x0;                       \
+       x3 ^= x2;                                       \
+       })
+
+#define S6(x0, x1, x2, x3, x4) ({                      \
+                                       x4  = x1;       \
+       x3 ^= x0;       x1 ^= x2;       x2 ^= x0;       \
+       x0 &= x3;       x1 |= x3;       x4 = ~x4;       \
+       x0 ^= x1;       x1 ^= x2;                       \
+       x3 ^= x4;       x4 ^= x0;       x2 &= x0;       \
+       x4 ^= x1;       x2 ^= x3;       x3 &= x1;       \
+       x3 ^= x0;       x1 ^= x2;                       \
+       })
+
+#define S7(x0, x1, x2, x3, x4) ({                      \
+                                       x1 = ~x1;       \
+       x4  = x1;       x0 = ~x0;       x1 &= x2;       \
+       x1 ^= x3;       x3 |= x4;       x4 ^= x2;       \
+       x2 ^= x3;       x3 ^= x0;       x0 |= x1;       \
+       x2 &= x0;       x0 ^= x4;       x4 ^= x3;       \
+       x3 &= x0;       x4 ^= x1;                       \
+       x2 ^= x4;       x3 ^= x1;       x4 |= x0;       \
+       x4 ^= x1;                                       \
+       })
+
+#define SI0(x0, x1, x2, x3, x4) ({                     \
+                       x4  = x3;       x1 ^= x0;       \
+       x3 |= x1;       x4 ^= x1;       x0 = ~x0;       \
+       x2 ^= x3;       x3 ^= x0;       x0 &= x1;       \
+       x0 ^= x2;       x2 &= x3;       x3 ^= x4;       \
+       x2 ^= x3;       x1 ^= x3;       x3 &= x0;       \
+       x1 ^= x0;       x0 ^= x2;       x4 ^= x3;       \
+       })
+
+#define SI1(x0, x1, x2, x3, x4) ({                     \
+       x1 ^= x3;       x4  = x0;                       \
+       x0 ^= x2;       x2 = ~x2;       x4 |= x1;       \
+       x4 ^= x3;       x3 &= x1;       x1 ^= x2;       \
+       x2 &= x4;       x4 ^= x1;       x1 |= x3;       \
+       x3 ^= x0;       x2 ^= x0;       x0 |= x4;       \
+       x2 ^= x4;       x1 ^= x0;                       \
+       x4 ^= x1;                                       \
+       })
+
+#define SI2(x0, x1, x2, x3, x4) ({                     \
+       x2 ^= x1;       x4  = x3;       x3 = ~x3;       \
+       x3 |= x2;       x2 ^= x4;       x4 ^= x0;       \
+       x3 ^= x1;       x1 |= x2;       x2 ^= x0;       \
+       x1 ^= x4;       x4 |= x3;       x2 ^= x3;       \
+       x4 ^= x2;       x2 &= x1;                       \
+       x2 ^= x3;       x3 ^= x4;       x4 ^= x0;       \
+       })
+
+#define SI3(x0, x1, x2, x3, x4) ({                     \
+                                       x2 ^= x1;       \
+       x4  = x1;       x1 &= x2;                       \
+       x1 ^= x0;       x0 |= x4;       x4 ^= x3;       \
+       x0 ^= x3;       x3 |= x1;       x1 ^= x2;       \
+       x1 ^= x3;       x0 ^= x2;       x2 ^= x3;       \
+       x3 &= x1;       x1 ^= x0;       x0 &= x2;       \
+       x4 ^= x3;       x3 ^= x0;       x0 ^= x1;       \
+       })
+
+#define SI4(x0, x1, x2, x3, x4) ({                     \
+       x2 ^= x3;       x4  = x0;       x0 &= x1;       \
+       x0 ^= x2;       x2 |= x3;       x4 = ~x4;       \
+       x1 ^= x0;       x0 ^= x2;       x2 &= x4;       \
+       x2 ^= x0;       x0 |= x4;                       \
+       x0 ^= x3;       x3 &= x2;                       \
+       x4 ^= x3;       x3 ^= x1;       x1 &= x0;       \
+       x4 ^= x1;       x0 ^= x3;                       \
+       })
+
+#define SI5(x0, x1, x2, x3, x4) ({                     \
+                       x4  = x1;       x1 |= x2;       \
+       x2 ^= x4;       x1 ^= x3;       x3 &= x4;       \
+       x2 ^= x3;       x3 |= x0;       x0 = ~x0;       \
+       x3 ^= x2;       x2 |= x0;       x4 ^= x1;       \
+       x2 ^= x4;       x4 &= x0;       x0 ^= x1;       \
+       x1 ^= x3;       x0 &= x2;       x2 ^= x3;       \
+       x0 ^= x2;       x2 ^= x4;       x4 ^= x3;       \
+       })
+
+#define SI6(x0, x1, x2, x3, x4) ({                     \
+                       x0 ^= x2;                       \
+       x4  = x0;       x0 &= x3;       x2 ^= x3;       \
+       x0 ^= x2;       x3 ^= x1;       x2 |= x4;       \
+       x2 ^= x3;       x3 &= x0;       x0 = ~x0;       \
+       x3 ^= x1;       x1 &= x2;       x4 ^= x0;       \
+       x3 ^= x4;       x4 ^= x2;       x0 ^= x1;       \
+       x2 ^= x0;                                       \
+       })
+
+#define SI7(x0, x1, x2, x3, x4) ({                     \
+       x4  = x3;       x3 &= x0;       x0 ^= x2;       \
+       x2 |= x4;       x4 ^= x1;       x0 = ~x0;       \
+       x1 |= x3;       x4 ^= x0;       x0 &= x2;       \
+       x0 ^= x1;       x1 &= x2;       x3 ^= x2;       \
+       x4 ^= x3;       x2 &= x3;       x3 |= x0;       \
+       x1 ^= x4;       x3 ^= x4;       x4 &= x0;       \
+       x4 ^= x2;                                       \
+       })
+
+int __serpent_setkey(struct serpent_ctx *ctx, const u8 *key,
+                    unsigned int keylen)
+{
+       u32 *k = ctx->expkey;
+       u8  *k8 = (u8 *)k;
+       u32 r0, r1, r2, r3, r4;
+       int i;
+
+       /* Copy key, add padding */
+
+       for (i = 0; i < keylen; ++i)
+               k8[i] = key[i];
+       if (i < SERPENT_MAX_KEY_SIZE)
+               k8[i++] = 1;
+       while (i < SERPENT_MAX_KEY_SIZE)
+               k8[i++] = 0;
+
+       /* Expand key using polynomial */
+
+       r0 = le32_to_cpu(k[3]);
+       r1 = le32_to_cpu(k[4]);
+       r2 = le32_to_cpu(k[5]);
+       r3 = le32_to_cpu(k[6]);
+       r4 = le32_to_cpu(k[7]);
+
+       keyiter(le32_to_cpu(k[0]), r0, r4, r2, 0, 0);
+       keyiter(le32_to_cpu(k[1]), r1, r0, r3, 1, 1);
+       keyiter(le32_to_cpu(k[2]), r2, r1, r4, 2, 2);
+       keyiter(le32_to_cpu(k[3]), r3, r2, r0, 3, 3);
+       keyiter(le32_to_cpu(k[4]), r4, r3, r1, 4, 4);
+       keyiter(le32_to_cpu(k[5]), r0, r4, r2, 5, 5);
+       keyiter(le32_to_cpu(k[6]), r1, r0, r3, 6, 6);
+       keyiter(le32_to_cpu(k[7]), r2, r1, r4, 7, 7);
+
+       keyiter(k[0], r3, r2, r0, 8, 8);
+       keyiter(k[1], r4, r3, r1, 9, 9);
+       keyiter(k[2], r0, r4, r2, 10, 10);
+       keyiter(k[3], r1, r0, r3, 11, 11);
+       keyiter(k[4], r2, r1, r4, 12, 12);
+       keyiter(k[5], r3, r2, r0, 13, 13);
+       keyiter(k[6], r4, r3, r1, 14, 14);
+       keyiter(k[7], r0, r4, r2, 15, 15);
+       keyiter(k[8], r1, r0, r3, 16, 16);
+       keyiter(k[9], r2, r1, r4, 17, 17);
+       keyiter(k[10], r3, r2, r0, 18, 18);
+       keyiter(k[11], r4, r3, r1, 19, 19);
+       keyiter(k[12], r0, r4, r2, 20, 20);
+       keyiter(k[13], r1, r0, r3, 21, 21);
+       keyiter(k[14], r2, r1, r4, 22, 22);
+       keyiter(k[15], r3, r2, r0, 23, 23);
+       keyiter(k[16], r4, r3, r1, 24, 24);
+       keyiter(k[17], r0, r4, r2, 25, 25);
+       keyiter(k[18], r1, r0, r3, 26, 26);
+       keyiter(k[19], r2, r1, r4, 27, 27);
+       keyiter(k[20], r3, r2, r0, 28, 28);
+       keyiter(k[21], r4, r3, r1, 29, 29);
+       keyiter(k[22], r0, r4, r2, 30, 30);
+       keyiter(k[23], r1, r0, r3, 31, 31);
+
+       k += 50;
+
+       keyiter(k[-26], r2, r1, r4, 32, -18);
+       keyiter(k[-25], r3, r2, r0, 33, -17);
+       keyiter(k[-24], r4, r3, r1, 34, -16);
+       keyiter(k[-23], r0, r4, r2, 35, -15);
+       keyiter(k[-22], r1, r0, r3, 36, -14);
+       keyiter(k[-21], r2, r1, r4, 37, -13);
+       keyiter(k[-20], r3, r2, r0, 38, -12);
+       keyiter(k[-19], r4, r3, r1, 39, -11);
+       keyiter(k[-18], r0, r4, r2, 40, -10);
+       keyiter(k[-17], r1, r0, r3, 41, -9);
+       keyiter(k[-16], r2, r1, r4, 42, -8);
+       keyiter(k[-15], r3, r2, r0, 43, -7);
+       keyiter(k[-14], r4, r3, r1, 44, -6);
+       keyiter(k[-13], r0, r4, r2, 45, -5);
+       keyiter(k[-12], r1, r0, r3, 46, -4);
+       keyiter(k[-11], r2, r1, r4, 47, -3);
+       keyiter(k[-10], r3, r2, r0, 48, -2);
+       keyiter(k[-9], r4, r3, r1, 49, -1);
+       keyiter(k[-8], r0, r4, r2, 50, 0);
+       keyiter(k[-7], r1, r0, r3, 51, 1);
+       keyiter(k[-6], r2, r1, r4, 52, 2);
+       keyiter(k[-5], r3, r2, r0, 53, 3);
+       keyiter(k[-4], r4, r3, r1, 54, 4);
+       keyiter(k[-3], r0, r4, r2, 55, 5);
+       keyiter(k[-2], r1, r0, r3, 56, 6);
+       keyiter(k[-1], r2, r1, r4, 57, 7);
+       keyiter(k[0], r3, r2, r0, 58, 8);
+       keyiter(k[1], r4, r3, r1, 59, 9);
+       keyiter(k[2], r0, r4, r2, 60, 10);
+       keyiter(k[3], r1, r0, r3, 61, 11);
+       keyiter(k[4], r2, r1, r4, 62, 12);
+       keyiter(k[5], r3, r2, r0, 63, 13);
+       keyiter(k[6], r4, r3, r1, 64, 14);
+       keyiter(k[7], r0, r4, r2, 65, 15);
+       keyiter(k[8], r1, r0, r3, 66, 16);
+       keyiter(k[9], r2, r1, r4, 67, 17);
+       keyiter(k[10], r3, r2, r0, 68, 18);
+       keyiter(k[11], r4, r3, r1, 69, 19);
+       keyiter(k[12], r0, r4, r2, 70, 20);
+       keyiter(k[13], r1, r0, r3, 71, 21);
+       keyiter(k[14], r2, r1, r4, 72, 22);
+       keyiter(k[15], r3, r2, r0, 73, 23);
+       keyiter(k[16], r4, r3, r1, 74, 24);
+       keyiter(k[17], r0, r4, r2, 75, 25);
+       keyiter(k[18], r1, r0, r3, 76, 26);
+       keyiter(k[19], r2, r1, r4, 77, 27);
+       keyiter(k[20], r3, r2, r0, 78, 28);
+       keyiter(k[21], r4, r3, r1, 79, 29);
+       keyiter(k[22], r0, r4, r2, 80, 30);
+       keyiter(k[23], r1, r0, r3, 81, 31);
+
+       k += 50;
+
+       keyiter(k[-26], r2, r1, r4, 82, -18);
+       keyiter(k[-25], r3, r2, r0, 83, -17);
+       keyiter(k[-24], r4, r3, r1, 84, -16);
+       keyiter(k[-23], r0, r4, r2, 85, -15);
+       keyiter(k[-22], r1, r0, r3, 86, -14);
+       keyiter(k[-21], r2, r1, r4, 87, -13);
+       keyiter(k[-20], r3, r2, r0, 88, -12);
+       keyiter(k[-19], r4, r3, r1, 89, -11);
+       keyiter(k[-18], r0, r4, r2, 90, -10);
+       keyiter(k[-17], r1, r0, r3, 91, -9);
+       keyiter(k[-16], r2, r1, r4, 92, -8);
+       keyiter(k[-15], r3, r2, r0, 93, -7);
+       keyiter(k[-14], r4, r3, r1, 94, -6);
+       keyiter(k[-13], r0, r4, r2, 95, -5);
+       keyiter(k[-12], r1, r0, r3, 96, -4);
+       keyiter(k[-11], r2, r1, r4, 97, -3);
+       keyiter(k[-10], r3, r2, r0, 98, -2);
+       keyiter(k[-9], r4, r3, r1, 99, -1);
+       keyiter(k[-8], r0, r4, r2, 100, 0);
+       keyiter(k[-7], r1, r0, r3, 101, 1);
+       keyiter(k[-6], r2, r1, r4, 102, 2);
+       keyiter(k[-5], r3, r2, r0, 103, 3);
+       keyiter(k[-4], r4, r3, r1, 104, 4);
+       keyiter(k[-3], r0, r4, r2, 105, 5);
+       keyiter(k[-2], r1, r0, r3, 106, 6);
+       keyiter(k[-1], r2, r1, r4, 107, 7);
+       keyiter(k[0], r3, r2, r0, 108, 8);
+       keyiter(k[1], r4, r3, r1, 109, 9);
+       keyiter(k[2], r0, r4, r2, 110, 10);
+       keyiter(k[3], r1, r0, r3, 111, 11);
+       keyiter(k[4], r2, r1, r4, 112, 12);
+       keyiter(k[5], r3, r2, r0, 113, 13);
+       keyiter(k[6], r4, r3, r1, 114, 14);
+       keyiter(k[7], r0, r4, r2, 115, 15);
+       keyiter(k[8], r1, r0, r3, 116, 16);
+       keyiter(k[9], r2, r1, r4, 117, 17);
+       keyiter(k[10], r3, r2, r0, 118, 18);
+       keyiter(k[11], r4, r3, r1, 119, 19);
+       keyiter(k[12], r0, r4, r2, 120, 20);
+       keyiter(k[13], r1, r0, r3, 121, 21);
+       keyiter(k[14], r2, r1, r4, 122, 22);
+       keyiter(k[15], r3, r2, r0, 123, 23);
+       keyiter(k[16], r4, r3, r1, 124, 24);
+       keyiter(k[17], r0, r4, r2, 125, 25);
+       keyiter(k[18], r1, r0, r3, 126, 26);
+       keyiter(k[19], r2, r1, r4, 127, 27);
+       keyiter(k[20], r3, r2, r0, 128, 28);
+       keyiter(k[21], r4, r3, r1, 129, 29);
+       keyiter(k[22], r0, r4, r2, 130, 30);
+       keyiter(k[23], r1, r0, r3, 131, 31);
+
+       /* Apply S-boxes */
+
+       S3(r3, r4, r0, r1, r2); store_and_load_keys(r1, r2, r4, r3, 28, 24);
+       S4(r1, r2, r4, r3, r0); store_and_load_keys(r2, r4, r3, r0, 24, 20);
+       S5(r2, r4, r3, r0, r1); store_and_load_keys(r1, r2, r4, r0, 20, 16);
+       S6(r1, r2, r4, r0, r3); store_and_load_keys(r4, r3, r2, r0, 16, 12);
+       S7(r4, r3, r2, r0, r1); store_and_load_keys(r1, r2, r0, r4, 12, 8);
+       S0(r1, r2, r0, r4, r3); store_and_load_keys(r0, r2, r4, r1, 8, 4);
+       S1(r0, r2, r4, r1, r3); store_and_load_keys(r3, r4, r1, r0, 4, 0);
+       S2(r3, r4, r1, r0, r2); store_and_load_keys(r2, r4, r3, r0, 0, -4);
+       S3(r2, r4, r3, r0, r1); store_and_load_keys(r0, r1, r4, r2, -4, -8);
+       S4(r0, r1, r4, r2, r3); store_and_load_keys(r1, r4, r2, r3, -8, -12);
+       S5(r1, r4, r2, r3, r0); store_and_load_keys(r0, r1, r4, r3, -12, -16);
+       S6(r0, r1, r4, r3, r2); store_and_load_keys(r4, r2, r1, r3, -16, -20);
+       S7(r4, r2, r1, r3, r0); store_and_load_keys(r0, r1, r3, r4, -20, -24);
+       S0(r0, r1, r3, r4, r2); store_and_load_keys(r3, r1, r4, r0, -24, -28);
+       k -= 50;
+       S1(r3, r1, r4, r0, r2); store_and_load_keys(r2, r4, r0, r3, 22, 18);
+       S2(r2, r4, r0, r3, r1); store_and_load_keys(r1, r4, r2, r3, 18, 14);
+       S3(r1, r4, r2, r3, r0); store_and_load_keys(r3, r0, r4, r1, 14, 10);
+       S4(r3, r0, r4, r1, r2); store_and_load_keys(r0, r4, r1, r2, 10, 6);
+       S5(r0, r4, r1, r2, r3); store_and_load_keys(r3, r0, r4, r2, 6, 2);
+       S6(r3, r0, r4, r2, r1); store_and_load_keys(r4, r1, r0, r2, 2, -2);
+       S7(r4, r1, r0, r2, r3); store_and_load_keys(r3, r0, r2, r4, -2, -6);
+       S0(r3, r0, r2, r4, r1); store_and_load_keys(r2, r0, r4, r3, -6, -10);
+       S1(r2, r0, r4, r3, r1); store_and_load_keys(r1, r4, r3, r2, -10, -14);
+       S2(r1, r4, r3, r2, r0); store_and_load_keys(r0, r4, r1, r2, -14, -18);
+       S3(r0, r4, r1, r2, r3); store_and_load_keys(r2, r3, r4, r0, -18, -22);
+       k -= 50;
+       S4(r2, r3, r4, r0, r1); store_and_load_keys(r3, r4, r0, r1, 28, 24);
+       S5(r3, r4, r0, r1, r2); store_and_load_keys(r2, r3, r4, r1, 24, 20);
+       S6(r2, r3, r4, r1, r0); store_and_load_keys(r4, r0, r3, r1, 20, 16);
+       S7(r4, r0, r3, r1, r2); store_and_load_keys(r2, r3, r1, r4, 16, 12);
+       S0(r2, r3, r1, r4, r0); store_and_load_keys(r1, r3, r4, r2, 12, 8);
+       S1(r1, r3, r4, r2, r0); store_and_load_keys(r0, r4, r2, r1, 8, 4);
+       S2(r0, r4, r2, r1, r3); store_and_load_keys(r3, r4, r0, r1, 4, 0);
+       S3(r3, r4, r0, r1, r2); storekeys(r1, r2, r4, r3, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__serpent_setkey);
+
+int serpent_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+       return __serpent_setkey(crypto_tfm_ctx(tfm), key, keylen);
+}
+EXPORT_SYMBOL_GPL(serpent_setkey);
+
+void __serpent_encrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src)
+{
+       const u32 *k = ctx->expkey;
+       const __le32 *s = (const __le32 *)src;
+       __le32  *d = (__le32 *)dst;
+       u32     r0, r1, r2, r3, r4;
+
+/*
+ * Note: The conversions between u8* and u32* might cause trouble
+ * on architectures with stricter alignment rules than x86
+ */
+
+       r0 = le32_to_cpu(s[0]);
+       r1 = le32_to_cpu(s[1]);
+       r2 = le32_to_cpu(s[2]);
+       r3 = le32_to_cpu(s[3]);
+
+                                       K(r0, r1, r2, r3, 0);
+       S0(r0, r1, r2, r3, r4);         LK(r2, r1, r3, r0, r4, 1);
+       S1(r2, r1, r3, r0, r4);         LK(r4, r3, r0, r2, r1, 2);
+       S2(r4, r3, r0, r2, r1);         LK(r1, r3, r4, r2, r0, 3);
+       S3(r1, r3, r4, r2, r0);         LK(r2, r0, r3, r1, r4, 4);
+       S4(r2, r0, r3, r1, r4);         LK(r0, r3, r1, r4, r2, 5);
+       S5(r0, r3, r1, r4, r2);         LK(r2, r0, r3, r4, r1, 6);
+       S6(r2, r0, r3, r4, r1);         LK(r3, r1, r0, r4, r2, 7);
+       S7(r3, r1, r0, r4, r2);         LK(r2, r0, r4, r3, r1, 8);
+       S0(r2, r0, r4, r3, r1);         LK(r4, r0, r3, r2, r1, 9);
+       S1(r4, r0, r3, r2, r1);         LK(r1, r3, r2, r4, r0, 10);
+       S2(r1, r3, r2, r4, r0);         LK(r0, r3, r1, r4, r2, 11);
+       S3(r0, r3, r1, r4, r2);         LK(r4, r2, r3, r0, r1, 12);
+       S4(r4, r2, r3, r0, r1);         LK(r2, r3, r0, r1, r4, 13);
+       S5(r2, r3, r0, r1, r4);         LK(r4, r2, r3, r1, r0, 14);
+       S6(r4, r2, r3, r1, r0);         LK(r3, r0, r2, r1, r4, 15);
+       S7(r3, r0, r2, r1, r4);         LK(r4, r2, r1, r3, r0, 16);
+       S0(r4, r2, r1, r3, r0);         LK(r1, r2, r3, r4, r0, 17);
+       S1(r1, r2, r3, r4, r0);         LK(r0, r3, r4, r1, r2, 18);
+       S2(r0, r3, r4, r1, r2);         LK(r2, r3, r0, r1, r4, 19);
+       S3(r2, r3, r0, r1, r4);         LK(r1, r4, r3, r2, r0, 20);
+       S4(r1, r4, r3, r2, r0);         LK(r4, r3, r2, r0, r1, 21);
+       S5(r4, r3, r2, r0, r1);         LK(r1, r4, r3, r0, r2, 22);
+       S6(r1, r4, r3, r0, r2);         LK(r3, r2, r4, r0, r1, 23);
+       S7(r3, r2, r4, r0, r1);         LK(r1, r4, r0, r3, r2, 24);
+       S0(r1, r4, r0, r3, r2);         LK(r0, r4, r3, r1, r2, 25);
+       S1(r0, r4, r3, r1, r2);         LK(r2, r3, r1, r0, r4, 26);
+       S2(r2, r3, r1, r0, r4);         LK(r4, r3, r2, r0, r1, 27);
+       S3(r4, r3, r2, r0, r1);         LK(r0, r1, r3, r4, r2, 28);
+       S4(r0, r1, r3, r4, r2);         LK(r1, r3, r4, r2, r0, 29);
+       S5(r1, r3, r4, r2, r0);         LK(r0, r1, r3, r2, r4, 30);
+       S6(r0, r1, r3, r2, r4);         LK(r3, r4, r1, r2, r0, 31);
+       S7(r3, r4, r1, r2, r0);         K(r0, r1, r2, r3, 32);
+
+       d[0] = cpu_to_le32(r0);
+       d[1] = cpu_to_le32(r1);
+       d[2] = cpu_to_le32(r2);
+       d[3] = cpu_to_le32(r3);
+}
+EXPORT_SYMBOL_GPL(__serpent_encrypt);
+
+static void serpent_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       __serpent_encrypt(ctx, dst, src);
+}
+
+void __serpent_decrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src)
+{
+       const u32 *k = ctx->expkey;
+       const __le32 *s = (const __le32 *)src;
+       __le32  *d = (__le32 *)dst;
+       u32     r0, r1, r2, r3, r4;
+
+       r0 = le32_to_cpu(s[0]);
+       r1 = le32_to_cpu(s[1]);
+       r2 = le32_to_cpu(s[2]);
+       r3 = le32_to_cpu(s[3]);
+
+                                       K(r0, r1, r2, r3, 32);
+       SI7(r0, r1, r2, r3, r4);        KL(r1, r3, r0, r4, r2, 31);
+       SI6(r1, r3, r0, r4, r2);        KL(r0, r2, r4, r1, r3, 30);
+       SI5(r0, r2, r4, r1, r3);        KL(r2, r3, r0, r4, r1, 29);
+       SI4(r2, r3, r0, r4, r1);        KL(r2, r0, r1, r4, r3, 28);
+       SI3(r2, r0, r1, r4, r3);        KL(r1, r2, r3, r4, r0, 27);
+       SI2(r1, r2, r3, r4, r0);        KL(r2, r0, r4, r3, r1, 26);
+       SI1(r2, r0, r4, r3, r1);        KL(r1, r0, r4, r3, r2, 25);
+       SI0(r1, r0, r4, r3, r2);        KL(r4, r2, r0, r1, r3, 24);
+       SI7(r4, r2, r0, r1, r3);        KL(r2, r1, r4, r3, r0, 23);
+       SI6(r2, r1, r4, r3, r0);        KL(r4, r0, r3, r2, r1, 22);
+       SI5(r4, r0, r3, r2, r1);        KL(r0, r1, r4, r3, r2, 21);
+       SI4(r0, r1, r4, r3, r2);        KL(r0, r4, r2, r3, r1, 20);
+       SI3(r0, r4, r2, r3, r1);        KL(r2, r0, r1, r3, r4, 19);
+       SI2(r2, r0, r1, r3, r4);        KL(r0, r4, r3, r1, r2, 18);
+       SI1(r0, r4, r3, r1, r2);        KL(r2, r4, r3, r1, r0, 17);
+       SI0(r2, r4, r3, r1, r0);        KL(r3, r0, r4, r2, r1, 16);
+       SI7(r3, r0, r4, r2, r1);        KL(r0, r2, r3, r1, r4, 15);
+       SI6(r0, r2, r3, r1, r4);        KL(r3, r4, r1, r0, r2, 14);
+       SI5(r3, r4, r1, r0, r2);        KL(r4, r2, r3, r1, r0, 13);
+       SI4(r4, r2, r3, r1, r0);        KL(r4, r3, r0, r1, r2, 12);
+       SI3(r4, r3, r0, r1, r2);        KL(r0, r4, r2, r1, r3, 11);
+       SI2(r0, r4, r2, r1, r3);        KL(r4, r3, r1, r2, r0, 10);
+       SI1(r4, r3, r1, r2, r0);        KL(r0, r3, r1, r2, r4, 9);
+       SI0(r0, r3, r1, r2, r4);        KL(r1, r4, r3, r0, r2, 8);
+       SI7(r1, r4, r3, r0, r2);        KL(r4, r0, r1, r2, r3, 7);
+       SI6(r4, r0, r1, r2, r3);        KL(r1, r3, r2, r4, r0, 6);
+       SI5(r1, r3, r2, r4, r0);        KL(r3, r0, r1, r2, r4, 5);
+       SI4(r3, r0, r1, r2, r4);        KL(r3, r1, r4, r2, r0, 4);
+       SI3(r3, r1, r4, r2, r0);        KL(r4, r3, r0, r2, r1, 3);
+       SI2(r4, r3, r0, r2, r1);        KL(r3, r1, r2, r0, r4, 2);
+       SI1(r3, r1, r2, r0, r4);        KL(r4, r1, r2, r0, r3, 1);
+       SI0(r4, r1, r2, r0, r3);        K(r2, r3, r1, r4, 0);
+
+       d[0] = cpu_to_le32(r2);
+       d[1] = cpu_to_le32(r3);
+       d[2] = cpu_to_le32(r1);
+       d[3] = cpu_to_le32(r4);
+}
+EXPORT_SYMBOL_GPL(__serpent_decrypt);
+
+static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       __serpent_decrypt(ctx, dst, src);
+}
+
+static struct crypto_alg serpent_alg = {
+       .cra_name               =       "serpent",
+       .cra_driver_name        =       "serpent-generic",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct serpent_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
+       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
+       .cia_setkey             =       serpent_setkey,
+       .cia_encrypt            =       serpent_encrypt,
+       .cia_decrypt            =       serpent_decrypt } }
+};
+
+static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
+                         unsigned int keylen)
+{
+       u8 rev_key[SERPENT_MAX_KEY_SIZE];
+       int i;
+
+       for (i = 0; i < keylen; ++i)
+               rev_key[keylen - i - 1] = key[i];
+
+       return serpent_setkey(tfm, rev_key, keylen);
+}
+
+static void tnepres_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const u32 * const s = (const u32 * const)src;
+       u32 * const d = (u32 * const)dst;
+
+       u32 rs[4], rd[4];
+
+       rs[0] = swab32(s[3]);
+       rs[1] = swab32(s[2]);
+       rs[2] = swab32(s[1]);
+       rs[3] = swab32(s[0]);
+
+       serpent_encrypt(tfm, (u8 *)rd, (u8 *)rs);
+
+       d[0] = swab32(rd[3]);
+       d[1] = swab32(rd[2]);
+       d[2] = swab32(rd[1]);
+       d[3] = swab32(rd[0]);
+}
+
+static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const u32 * const s = (const u32 * const)src;
+       u32 * const d = (u32 * const)dst;
+
+       u32 rs[4], rd[4];
+
+       rs[0] = swab32(s[3]);
+       rs[1] = swab32(s[2]);
+       rs[2] = swab32(s[1]);
+       rs[3] = swab32(s[0]);
+
+       serpent_decrypt(tfm, (u8 *)rd, (u8 *)rs);
+
+       d[0] = swab32(rd[3]);
+       d[1] = swab32(rd[2]);
+       d[2] = swab32(rd[1]);
+       d[3] = swab32(rd[0]);
+}
+
+static struct crypto_alg tnepres_alg = {
+       .cra_name               =       "tnepres",
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct serpent_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
+       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
+       .cia_setkey             =       tnepres_setkey,
+       .cia_encrypt            =       tnepres_encrypt,
+       .cia_decrypt            =       tnepres_decrypt } }
+};
+
+static int __init serpent_mod_init(void)
+{
+       int ret = crypto_register_alg(&serpent_alg);
+
+       if (ret)
+               return ret;
+
+       ret = crypto_register_alg(&tnepres_alg);
+
+       if (ret)
+               crypto_unregister_alg(&serpent_alg);
+
+       return ret;
+}
+
+static void __exit serpent_mod_fini(void)
+{
+       crypto_unregister_alg(&tnepres_alg);
+       crypto_unregister_alg(&serpent_alg);
+}
+
+module_init(serpent_mod_init);
+module_exit(serpent_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Cipher Algorithm");
+MODULE_AUTHOR("Dag Arne Osvik <osvik@ii.uib.no>");
+MODULE_ALIAS("tnepres");
+MODULE_ALIAS("serpent");
index 0c4e80f34651bd01dabaed7632a42922fa3dca7e..7736a9f05aba42fdc5a9c2c833c97a15aecb7502 100644 (file)
@@ -719,6 +719,207 @@ out:
        crypto_free_ahash(tfm);
 }
 
+static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret)
+{
+       if (ret == -EINPROGRESS || ret == -EBUSY) {
+               struct tcrypt_result *tr = req->base.data;
+
+               ret = wait_for_completion_interruptible(&tr->completion);
+               if (!ret)
+                       ret = tr->err;
+               INIT_COMPLETION(tr->completion);
+       }
+
+       return ret;
+}
+
+static int test_acipher_jiffies(struct ablkcipher_request *req, int enc,
+                               int blen, int sec)
+{
+       unsigned long start, end;
+       int bcount;
+       int ret;
+
+       for (start = jiffies, end = start + sec * HZ, bcount = 0;
+            time_before(jiffies, end); bcount++) {
+               if (enc)
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_encrypt(req));
+               else
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_decrypt(req));
+
+               if (ret)
+                       return ret;
+       }
+
+       pr_cont("%d operations in %d seconds (%ld bytes)\n",
+               bcount, sec, (long)bcount * blen);
+       return 0;
+}
+
+static int test_acipher_cycles(struct ablkcipher_request *req, int enc,
+                              int blen)
+{
+       unsigned long cycles = 0;
+       int ret = 0;
+       int i;
+
+       /* Warm-up run. */
+       for (i = 0; i < 4; i++) {
+               if (enc)
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_encrypt(req));
+               else
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_decrypt(req));
+
+               if (ret)
+                       goto out;
+       }
+
+       /* The real thing. */
+       for (i = 0; i < 8; i++) {
+               cycles_t start, end;
+
+               start = get_cycles();
+               if (enc)
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_encrypt(req));
+               else
+                       ret = do_one_acipher_op(req,
+                                               crypto_ablkcipher_decrypt(req));
+               end = get_cycles();
+
+               if (ret)
+                       goto out;
+
+               cycles += end - start;
+       }
+
+out:
+       if (ret == 0)
+               pr_cont("1 operation in %lu cycles (%d bytes)\n",
+                       (cycles + 4) / 8, blen);
+
+       return ret;
+}
+
+static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
+                              struct cipher_speed_template *template,
+                              unsigned int tcount, u8 *keysize)
+{
+       unsigned int ret, i, j, iv_len;
+       struct tcrypt_result tresult;
+       const char *key;
+       char iv[128];
+       struct ablkcipher_request *req;
+       struct crypto_ablkcipher *tfm;
+       const char *e;
+       u32 *b_size;
+
+       if (enc == ENCRYPT)
+               e = "encryption";
+       else
+               e = "decryption";
+
+       pr_info("\ntesting speed of async %s %s\n", algo, e);
+
+       init_completion(&tresult.completion);
+
+       tfm = crypto_alloc_ablkcipher(algo, 0, 0);
+
+       if (IS_ERR(tfm)) {
+               pr_err("failed to load transform for %s: %ld\n", algo,
+                      PTR_ERR(tfm));
+               return;
+       }
+
+       req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               pr_err("tcrypt: skcipher: Failed to allocate request for %s\n",
+                      algo);
+               goto out;
+       }
+
+       ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                       tcrypt_complete, &tresult);
+
+       i = 0;
+       do {
+               b_size = block_sizes;
+
+               do {
+                       struct scatterlist sg[TVMEMSIZE];
+
+                       if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {
+                               pr_err("template (%u) too big for "
+                                      "tvmem (%lu)\n", *keysize + *b_size,
+                                      TVMEMSIZE * PAGE_SIZE);
+                               goto out_free_req;
+                       }
+
+                       pr_info("test %u (%d bit key, %d byte blocks): ", i,
+                               *keysize * 8, *b_size);
+
+                       memset(tvmem[0], 0xff, PAGE_SIZE);
+
+                       /* set key, plain text and IV */
+                       key = tvmem[0];
+                       for (j = 0; j < tcount; j++) {
+                               if (template[j].klen == *keysize) {
+                                       key = template[j].key;
+                                       break;
+                               }
+                       }
+
+                       crypto_ablkcipher_clear_flags(tfm, ~0);
+
+                       ret = crypto_ablkcipher_setkey(tfm, key, *keysize);
+                       if (ret) {
+                               pr_err("setkey() failed flags=%x\n",
+                                       crypto_ablkcipher_get_flags(tfm));
+                               goto out_free_req;
+                       }
+
+                       sg_init_table(sg, TVMEMSIZE);
+                       sg_set_buf(sg, tvmem[0] + *keysize,
+                                  PAGE_SIZE - *keysize);
+                       for (j = 1; j < TVMEMSIZE; j++) {
+                               sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
+                               memset(tvmem[j], 0xff, PAGE_SIZE);
+                       }
+
+                       iv_len = crypto_ablkcipher_ivsize(tfm);
+                       if (iv_len)
+                               memset(&iv, 0xff, iv_len);
+
+                       ablkcipher_request_set_crypt(req, sg, sg, *b_size, iv);
+
+                       if (sec)
+                               ret = test_acipher_jiffies(req, enc,
+                                                          *b_size, sec);
+                       else
+                               ret = test_acipher_cycles(req, enc,
+                                                         *b_size);
+
+                       if (ret) {
+                               pr_err("%s() failed flags=%x\n", e,
+                                       crypto_ablkcipher_get_flags(tfm));
+                               break;
+                       }
+                       b_size++;
+                       i++;
+               } while (*b_size);
+               keysize++;
+       } while (*keysize);
+
+out_free_req:
+       ablkcipher_request_free(req);
+out:
+       crypto_free_ablkcipher(tfm);
+}
+
 static void test_available(void)
 {
        char **name = check;
@@ -789,10 +990,16 @@ static int do_test(int m)
                ret += tcrypt_test("ecb(twofish)");
                ret += tcrypt_test("cbc(twofish)");
                ret += tcrypt_test("ctr(twofish)");
+               ret += tcrypt_test("lrw(twofish)");
+               ret += tcrypt_test("xts(twofish)");
                break;
 
        case 9:
                ret += tcrypt_test("ecb(serpent)");
+               ret += tcrypt_test("cbc(serpent)");
+               ret += tcrypt_test("ctr(serpent)");
+               ret += tcrypt_test("lrw(serpent)");
+               ret += tcrypt_test("xts(serpent)");
                break;
 
        case 10:
@@ -1045,6 +1252,14 @@ static int do_test(int m)
                                speed_template_16_24_32);
                test_cipher_speed("ctr(twofish)", DECRYPT, sec, NULL, 0,
                                speed_template_16_24_32);
+               test_cipher_speed("lrw(twofish)", ENCRYPT, sec, NULL, 0,
+                               speed_template_32_40_48);
+               test_cipher_speed("lrw(twofish)", DECRYPT, sec, NULL, 0,
+                               speed_template_32_40_48);
+               test_cipher_speed("xts(twofish)", ENCRYPT, sec, NULL, 0,
+                               speed_template_32_48_64);
+               test_cipher_speed("xts(twofish)", DECRYPT, sec, NULL, 0,
+                               speed_template_32_48_64);
                break;
 
        case 203:
@@ -1089,6 +1304,29 @@ static int do_test(int m)
                                  speed_template_16_32);
                break;
 
+       case 207:
+               test_cipher_speed("ecb(serpent)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ecb(serpent)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("cbc(serpent)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("cbc(serpent)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ctr(serpent)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ctr(serpent)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("lrw(serpent)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_32_48);
+               test_cipher_speed("lrw(serpent)", DECRYPT, sec, NULL, 0,
+                                 speed_template_32_48);
+               test_cipher_speed("xts(serpent)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_32_64);
+               test_cipher_speed("xts(serpent)", DECRYPT, sec, NULL, 0,
+                                 speed_template_32_64);
+               break;
+
        case 300:
                /* fall through */
 
@@ -1241,6 +1479,78 @@ static int do_test(int m)
        case 499:
                break;
 
+       case 500:
+               test_acipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               test_acipher_speed("ecb(aes)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               test_acipher_speed("cbc(aes)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               test_acipher_speed("cbc(aes)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               test_acipher_speed("lrw(aes)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_40_48);
+               test_acipher_speed("lrw(aes)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_40_48);
+               test_acipher_speed("xts(aes)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_48_64);
+               test_acipher_speed("xts(aes)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_48_64);
+               test_acipher_speed("ctr(aes)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_24_32);
+               break;
+
+       case 501:
+               test_acipher_speed("ecb(des3_ede)", ENCRYPT, sec,
+                                  des3_speed_template, DES3_SPEED_VECTORS,
+                                  speed_template_24);
+               test_acipher_speed("ecb(des3_ede)", DECRYPT, sec,
+                                  des3_speed_template, DES3_SPEED_VECTORS,
+                                  speed_template_24);
+               test_acipher_speed("cbc(des3_ede)", ENCRYPT, sec,
+                                  des3_speed_template, DES3_SPEED_VECTORS,
+                                  speed_template_24);
+               test_acipher_speed("cbc(des3_ede)", DECRYPT, sec,
+                                  des3_speed_template, DES3_SPEED_VECTORS,
+                                  speed_template_24);
+               break;
+
+       case 502:
+               test_acipher_speed("ecb(des)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_8);
+               test_acipher_speed("ecb(des)", DECRYPT, sec, NULL, 0,
+                                  speed_template_8);
+               test_acipher_speed("cbc(des)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_8);
+               test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0,
+                                  speed_template_8);
+               break;
+
+       case 503:
+               test_acipher_speed("ecb(serpent)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ecb(serpent)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("cbc(serpent)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("cbc(serpent)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ctr(serpent)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ctr(serpent)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("lrw(serpent)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_48);
+               test_acipher_speed("lrw(serpent)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_48);
+               test_acipher_speed("xts(serpent)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_64);
+               test_acipher_speed("xts(serpent)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_64);
+               break;
+
        case 1000:
                test_available();
                break;
index 10cb925132c9ddb68f1303c78dfb925909db400a..5be1fc8c1ab349e051bbb18efc4f37737abe1d5d 100644 (file)
@@ -51,7 +51,9 @@ static u8 speed_template_8_32[] = {8, 32, 0};
 static u8 speed_template_16_32[] = {16, 32, 0};
 static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
 static u8 speed_template_32_40_48[] = {32, 40, 48, 0};
+static u8 speed_template_32_48[] = {32, 48, 0};
 static u8 speed_template_32_48_64[] = {32, 48, 64, 0};
+static u8 speed_template_32_64[] = {32, 64, 0};
 
 /*
  * Digest speed tests
index e91c1eb1722a9b3c604f53d84cec306615761fd6..bb54b882d7380187371c9596411656bdd9af75be 100644 (file)
@@ -1534,6 +1534,21 @@ static int alg_test_null(const struct alg_test_desc *desc,
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
        {
+               .alg = "__cbc-serpent-sse2",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
                .alg = "__driver-cbc-aes-aesni",
                .test = alg_test_null,
                .suite = {
@@ -1548,6 +1563,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "__driver-cbc-serpent-sse2",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "__driver-ecb-aes-aesni",
                .test = alg_test_null,
@@ -1563,6 +1593,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "__driver-ecb-serpent-sse2",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "__ghash-pclmulqdqni",
                .test = alg_test_null,
@@ -1674,6 +1719,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "cbc(serpent)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = serpent_cbc_enc_tv_template,
+                                       .count = SERPENT_CBC_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = serpent_cbc_dec_tv_template,
+                                       .count = SERPENT_CBC_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "cbc(twofish)",
                .test = alg_test_skcipher,
@@ -1730,6 +1790,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "cryptd(__driver-ecb-serpent-sse2)",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "cryptd(__ghash-pclmulqdqni)",
                .test = alg_test_null,
@@ -1770,6 +1845,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "ctr(serpent)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = serpent_ctr_enc_tv_template,
+                                       .count = SERPENT_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = serpent_ctr_dec_tv_template,
+                                       .count = SERPENT_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "ctr(twofish)",
                .test = alg_test_skcipher,
@@ -2206,6 +2296,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "lrw(serpent)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = serpent_lrw_enc_tv_template,
+                                       .count = SERPENT_LRW_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = serpent_lrw_dec_tv_template,
+                                       .count = SERPENT_LRW_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "lrw(twofish)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = tf_lrw_enc_tv_template,
+                                       .count = TF_LRW_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = tf_lrw_dec_tv_template,
+                                       .count = TF_LRW_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "lzo",
                .test = alg_test_comp,
@@ -2513,6 +2633,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "xts(serpent)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = serpent_xts_enc_tv_template,
+                                       .count = SERPENT_XTS_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = serpent_xts_dec_tv_template,
+                                       .count = SERPENT_XTS_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "xts(twofish)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = tf_xts_enc_tv_template,
+                                       .count = TF_XTS_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = tf_xts_dec_tv_template,
+                                       .count = TF_XTS_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "zlib",
                .test = alg_test_pcomp,
index 37b4d8f4544750e520cda8cc56af887f632701a0..43e84d32b341ff58b12d3f80a3924a2296b56f5a 100644 (file)
@@ -2717,6 +2717,10 @@ static struct cipher_testvec bf_ctr_dec_tv_template[] = {
 #define TF_CBC_DEC_TEST_VECTORS                5
 #define TF_CTR_ENC_TEST_VECTORS                2
 #define TF_CTR_DEC_TEST_VECTORS                2
+#define TF_LRW_ENC_TEST_VECTORS                8
+#define TF_LRW_DEC_TEST_VECTORS                8
+#define TF_XTS_ENC_TEST_VECTORS                5
+#define TF_XTS_DEC_TEST_VECTORS                5
 
 static struct cipher_testvec tf_enc_tv_template[] = {
        {
@@ -3092,189 +3096,2940 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = {
        },
 };
 
-/*
- * Serpent test vectors.  These are backwards because Serpent writes
- * octet sequences in right-to-left mode.
- */
-#define SERPENT_ENC_TEST_VECTORS       4
-#define SERPENT_DEC_TEST_VECTORS       4
-
-#define TNEPRES_ENC_TEST_VECTORS       4
-#define TNEPRES_DEC_TEST_VECTORS       4
-
-static struct cipher_testvec serpent_enc_tv_template[] = {
+static struct cipher_testvec tf_lrw_enc_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
        {
-               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
-                         "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+               .result = "\xa1\x6c\x50\x69\x26\xa4\xef\x7b"
+                         "\x7c\xc6\x91\xeb\x72\xdd\x9b\xee",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-               .klen   = 16,
-               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
-                         "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+               .result = "\xab\x72\x0a\xad\x3b\x0c\xf0\xc9"
+                         "\x42\x2f\xf1\xae\xf1\x3c\xb1\xbd",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17"
-                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
                .klen   = 32,
-               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
-                         "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+               .result = "\x85\xa7\x56\x67\x08\xfa\x42\xe1"
+                         "\x22\xe6\x82\xfc\xd9\xb4\xd7\xd4",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-               .klen   = 16,
-               .input  = zeroed_string,
-               .ilen   = 16,
-               .result = "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
-                         "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
-               .rlen   = 16,
-       },
-};
-
-static struct cipher_testvec tnepres_enc_tv_template[] = {
-       { /* KeySize=128, PT=0, I=1 */
-               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
-               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
-               .klen   = 16,
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\x49\xaf\xbf\xad\x9d\x5a\x34\x05"
-                         "\x2c\xd8\xff\xa5\x98\x6b\xd2\xdd",
+               .result = "\xd2\xaf\x69\x35\x24\x1d\x0e\x1c"
+                         "\x84\x8b\x05\xe4\xa2\x2f\x16\xf5",
                .rlen   = 16,
-       }, { /* KeySize=192, PT=0, I=1 */
-               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
-               .klen   = 24,
-               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+       }, {
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\xe7\x8e\x54\x02\xc7\x19\x55\x68"
-                         "\xac\x36\x78\xf7\xa3\xf6\x0c\x66",
+               .result = "\x4a\x23\x56\xd7\xff\x90\xd0\x9a"
+                         "\x0d\x7c\x26\xfc\xf0\xf0\xf6\xe4",
                .rlen   = 16,
-       }, { /* KeySize=256, PT=0, I=1 */
-               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
-               .klen   = 32,
-               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
-                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\xab\xed\x96\xe7\x66\xbf\x28\xcb"
-                         "\xc0\xeb\xd2\x1a\x82\xef\x08\x19",
+               .result = "\x30\xaf\x26\x05\x9d\x5d\x0a\x58"
+                         "\xe2\xe7\xce\x8a\xb2\x56\x6d\x76",
                .rlen   = 16,
-       }, { /* KeySize=256, I=257 */
-               .key    = "\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18"
-                         "\x17\x16\x15\x14\x13\x12\x11\x10"
-                         "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
-                         "\x07\x06\x05\x04\x03\x02\x01\x00",
-               .klen   = 32,
-               .input  = "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
-                         "\x07\x06\x05\x04\x03\x02\x01\x00",
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .ilen   = 16,
-               .result = "\x5c\xe7\x1c\x70\xd2\x88\x2e\x5b"
-                         "\xb8\x32\xe4\x33\xf8\x9f\x26\xde",
+               .result = "\xdf\xcf\xdc\xd2\xe1\xcf\x86\x75"
+                         "\x17\x66\x5e\x0c\x14\xa1\x3d\x40",
                .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .ilen   = 512,
+               .result = "\x30\x38\xeb\xaf\x12\x43\x1a\x89"
+                         "\x62\xa2\x36\xe5\xcf\x77\x1e\xd9"
+                         "\x08\xc3\x0d\xdd\x95\xab\x19\x96"
+                         "\x27\x52\x41\xc3\xca\xfb\xf6\xee"
+                         "\x40\x2d\xdf\xdd\x00\x0c\xb9\x0a"
+                         "\x3a\xf0\xc0\xd1\xda\x63\x9e\x45"
+                         "\x42\xe9\x29\xc0\xb4\x07\xb4\x31"
+                         "\x66\x77\x72\xb5\xb6\xb3\x57\x46"
+                         "\x34\x9a\xfe\x03\xaf\x6b\x36\x07"
+                         "\x63\x8e\xc2\x5d\xa6\x0f\xb6\x7d"
+                         "\xfb\x6d\x82\x51\xb6\x98\xd0\x71"
+                         "\xe7\x10\x7a\xdf\xb2\xbd\xf1\x1d"
+                         "\x72\x2b\x54\x13\xe3\x6d\x79\x37"
+                         "\xa9\x39\x2c\xdf\x21\xab\x87\xd5"
+                         "\xee\xef\x9a\x12\x50\x39\x2e\x1b"
+                         "\x7d\xe6\x6a\x27\x48\xb9\xe7\xac"
+                         "\xaa\xcd\x79\x5f\xf2\xf3\xa0\x08"
+                         "\x6f\x2c\xf4\x0e\xd1\xb8\x89\x25"
+                         "\x31\x9d\xef\xb1\x1d\x27\x55\x04"
+                         "\xc9\x8c\xb7\x68\xdc\xb6\x67\x8a"
+                         "\xdb\xcf\x22\xf2\x3b\x6f\xce\xbb"
+                         "\x26\xbe\x4f\x27\x04\x42\xd1\x44"
+                         "\x4c\x08\xa3\x95\x4c\x7f\x1a\xaf"
+                         "\x1d\x28\x14\xfd\xb1\x1a\x34\x18"
+                         "\xf5\x1e\x28\x69\x95\x6a\x5a\xba"
+                         "\x8e\xb2\x58\x1d\x28\x17\x13\x3d"
+                         "\x38\x7d\x14\x8d\xab\x5d\xf9\xe8"
+                         "\x3c\x0f\x2b\x0d\x2b\x08\xb4\x4b"
+                         "\x6b\x0d\xc8\xa7\x84\xc2\x3a\x1a"
+                         "\xb7\xbd\xda\x92\x29\xb8\x5b\x5a"
+                         "\x63\xa5\x99\x82\x09\x72\x8f\xc6"
+                         "\xa4\x62\x24\x69\x8c\x2d\x26\x00"
+                         "\x99\x83\x91\xd6\xc6\xcf\x57\x67"
+                         "\x38\xea\xf2\xfc\x29\xe0\x73\x39"
+                         "\xf9\x13\x94\x6d\xe2\x58\x28\x75"
+                         "\x3e\xae\x71\x90\x07\x70\x1c\x38"
+                         "\x5b\x4c\x1e\xb5\xa5\x3b\x20\xef"
+                         "\xb1\x4c\x3e\x1a\x72\x62\xbb\x22"
+                         "\x82\x09\xe3\x18\x3f\x4f\x48\xfc"
+                         "\xdd\xac\xfc\xb6\x09\xdb\xd2\x7b"
+                         "\xd6\xb7\x7e\x41\x2f\x14\xf5\x0e"
+                         "\xc3\xac\x4a\xed\xe7\x82\xef\x31"
+                         "\x1f\x1a\x51\x1e\x29\x60\xc8\x98"
+                         "\x93\x51\x1d\x3d\x62\x59\x83\x82"
+                         "\x0c\xf1\xd7\x8d\xac\x33\x44\x81"
+                         "\x3c\x59\xb7\xd4\x5b\x65\x82\xc4"
+                         "\xec\xdc\x24\xfd\x0e\x1a\x79\x94"
+                         "\x34\xb0\x62\xfa\x98\x49\x26\x1f"
+                         "\xf4\x9e\x40\x44\x5b\x1f\xf8\xbe"
+                         "\x36\xff\xc6\xc6\x9d\xf2\xd6\xcc"
+                         "\x63\x93\x29\xb9\x0b\x6d\xd7\x6c"
+                         "\xdb\xf6\x21\x80\xf7\x5a\x37\x15"
+                         "\x0c\xe3\x36\xc8\x74\x75\x20\x91"
+                         "\xdf\x52\x2d\x0c\xe7\x45\xff\x46"
+                         "\xb3\xf4\xec\xc2\xbd\xd3\x37\xb6"
+                         "\x26\xa2\x5d\x7d\x61\xbf\x10\x46"
+                         "\x57\x8d\x05\x96\x70\x0b\xd6\x41"
+                         "\x5c\xe9\xd3\x54\x81\x39\x3a\xdd"
+                         "\x5f\x92\x81\x6e\x35\x03\xd4\x72"
+                         "\x3d\x5a\xe7\xb9\x3b\x0c\x84\x23"
+                         "\x45\x5d\xec\x72\xc1\x52\xef\x2e"
+                         "\x81\x00\xd3\xfe\x4c\x3c\x05\x61"
+                         "\x80\x18\xc4\x6c\x03\xd3\xb7\xba"
+                         "\x11\xd7\xb8\x6e\xea\xe1\x80\x30",
+               .rlen   = 512,
        },
 };
 
-
-static struct cipher_testvec serpent_dec_tv_template[] = {
+static struct cipher_testvec tf_lrw_dec_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
+       /* same as enc vectors with input and result reversed */
        {
-               .input  = "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
-                         "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\xa1\x6c\x50\x69\x26\xa4\xef\x7b"
+                         "\x7c\xc6\x91\xeb\x72\xdd\x9b\xee",
                .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-               .klen   = 16,
-               .input  = "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
-                         "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\xab\x72\x0a\xad\x3b\x0c\xf0\xc9"
+                         "\x42\x2f\xf1\xae\xf1\x3c\xb1\xbd",
                .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17"
-                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
                .klen   = 32,
-               .input  = "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
-                         "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x85\xa7\x56\x67\x08\xfa\x42\xe1"
+                         "\x22\xe6\x82\xfc\xd9\xb4\xd7\xd4",
                .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-               .klen   = 16,
-               .input  = "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
-                         "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\xd2\xaf\x69\x35\x24\x1d\x0e\x1c"
+                         "\x84\x8b\x05\xe4\xa2\x2f\x16\xf5",
                .ilen   = 16,
-               .result = zeroed_string,
-               .rlen   = 16,
-       },
-};
-
-static struct cipher_testvec tnepres_dec_tv_template[] = {
-       {
-               .input  = "\x41\xcc\x6b\x31\x59\x31\x45\x97"
-                         "\x6d\x6f\xbb\x38\x4b\x37\x21\x28",
-               .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-               .klen   = 16,
-               .input  = "\xea\xf4\xd7\xfc\xd8\x01\x34\x47"
-                         "\x81\x45\x0b\xfa\x0c\xd6\xad\x6e",
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x4a\x23\x56\xd7\xff\x90\xd0\x9a"
+                         "\x0d\x7c\x26\xfc\xf0\xf0\xf6\xe4",
                .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
        }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17"
-                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
-               .klen   = 32,
-               .input  = "\x64\xa9\x1a\x37\xed\x9f\xe7\x49"
-                         "\xa8\x4e\x76\xd6\xf5\x0d\x78\xee",
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\xaf\x26\x05\x9d\x5d\x0a\x58"
+                         "\xe2\xe7\xce\x8a\xb2\x56\x6d\x76",
                .ilen   = 16,
-               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
-       }, { /* KeySize=128, I=121 */
-               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
-               .klen   = 16,
-               .input  = "\x3d\xda\xbf\xc0\x06\xda\xab\x06"
-                         "\x46\x2a\xf4\xef\x81\x54\x4e\x26",
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\xdf\xcf\xdc\xd2\xe1\xcf\x86\x75"
+                         "\x17\x66\x5e\x0c\x14\xa1\x3d\x40",
                .ilen   = 16,
-               .result = zeroed_string,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
                .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x38\xeb\xaf\x12\x43\x1a\x89"
+                         "\x62\xa2\x36\xe5\xcf\x77\x1e\xd9"
+                         "\x08\xc3\x0d\xdd\x95\xab\x19\x96"
+                         "\x27\x52\x41\xc3\xca\xfb\xf6\xee"
+                         "\x40\x2d\xdf\xdd\x00\x0c\xb9\x0a"
+                         "\x3a\xf0\xc0\xd1\xda\x63\x9e\x45"
+                         "\x42\xe9\x29\xc0\xb4\x07\xb4\x31"
+                         "\x66\x77\x72\xb5\xb6\xb3\x57\x46"
+                         "\x34\x9a\xfe\x03\xaf\x6b\x36\x07"
+                         "\x63\x8e\xc2\x5d\xa6\x0f\xb6\x7d"
+                         "\xfb\x6d\x82\x51\xb6\x98\xd0\x71"
+                         "\xe7\x10\x7a\xdf\xb2\xbd\xf1\x1d"
+                         "\x72\x2b\x54\x13\xe3\x6d\x79\x37"
+                         "\xa9\x39\x2c\xdf\x21\xab\x87\xd5"
+                         "\xee\xef\x9a\x12\x50\x39\x2e\x1b"
+                         "\x7d\xe6\x6a\x27\x48\xb9\xe7\xac"
+                         "\xaa\xcd\x79\x5f\xf2\xf3\xa0\x08"
+                         "\x6f\x2c\xf4\x0e\xd1\xb8\x89\x25"
+                         "\x31\x9d\xef\xb1\x1d\x27\x55\x04"
+                         "\xc9\x8c\xb7\x68\xdc\xb6\x67\x8a"
+                         "\xdb\xcf\x22\xf2\x3b\x6f\xce\xbb"
+                         "\x26\xbe\x4f\x27\x04\x42\xd1\x44"
+                         "\x4c\x08\xa3\x95\x4c\x7f\x1a\xaf"
+                         "\x1d\x28\x14\xfd\xb1\x1a\x34\x18"
+                         "\xf5\x1e\x28\x69\x95\x6a\x5a\xba"
+                         "\x8e\xb2\x58\x1d\x28\x17\x13\x3d"
+                         "\x38\x7d\x14\x8d\xab\x5d\xf9\xe8"
+                         "\x3c\x0f\x2b\x0d\x2b\x08\xb4\x4b"
+                         "\x6b\x0d\xc8\xa7\x84\xc2\x3a\x1a"
+                         "\xb7\xbd\xda\x92\x29\xb8\x5b\x5a"
+                         "\x63\xa5\x99\x82\x09\x72\x8f\xc6"
+                         "\xa4\x62\x24\x69\x8c\x2d\x26\x00"
+                         "\x99\x83\x91\xd6\xc6\xcf\x57\x67"
+                         "\x38\xea\xf2\xfc\x29\xe0\x73\x39"
+                         "\xf9\x13\x94\x6d\xe2\x58\x28\x75"
+                         "\x3e\xae\x71\x90\x07\x70\x1c\x38"
+                         "\x5b\x4c\x1e\xb5\xa5\x3b\x20\xef"
+                         "\xb1\x4c\x3e\x1a\x72\x62\xbb\x22"
+                         "\x82\x09\xe3\x18\x3f\x4f\x48\xfc"
+                         "\xdd\xac\xfc\xb6\x09\xdb\xd2\x7b"
+                         "\xd6\xb7\x7e\x41\x2f\x14\xf5\x0e"
+                         "\xc3\xac\x4a\xed\xe7\x82\xef\x31"
+                         "\x1f\x1a\x51\x1e\x29\x60\xc8\x98"
+                         "\x93\x51\x1d\x3d\x62\x59\x83\x82"
+                         "\x0c\xf1\xd7\x8d\xac\x33\x44\x81"
+                         "\x3c\x59\xb7\xd4\x5b\x65\x82\xc4"
+                         "\xec\xdc\x24\xfd\x0e\x1a\x79\x94"
+                         "\x34\xb0\x62\xfa\x98\x49\x26\x1f"
+                         "\xf4\x9e\x40\x44\x5b\x1f\xf8\xbe"
+                         "\x36\xff\xc6\xc6\x9d\xf2\xd6\xcc"
+                         "\x63\x93\x29\xb9\x0b\x6d\xd7\x6c"
+                         "\xdb\xf6\x21\x80\xf7\x5a\x37\x15"
+                         "\x0c\xe3\x36\xc8\x74\x75\x20\x91"
+                         "\xdf\x52\x2d\x0c\xe7\x45\xff\x46"
+                         "\xb3\xf4\xec\xc2\xbd\xd3\x37\xb6"
+                         "\x26\xa2\x5d\x7d\x61\xbf\x10\x46"
+                         "\x57\x8d\x05\x96\x70\x0b\xd6\x41"
+                         "\x5c\xe9\xd3\x54\x81\x39\x3a\xdd"
+                         "\x5f\x92\x81\x6e\x35\x03\xd4\x72"
+                         "\x3d\x5a\xe7\xb9\x3b\x0c\x84\x23"
+                         "\x45\x5d\xec\x72\xc1\x52\xef\x2e"
+                         "\x81\x00\xd3\xfe\x4c\x3c\x05\x61"
+                         "\x80\x18\xc4\x6c\x03\xd3\xb7\xba"
+                         "\x11\xd7\xb8\x6e\xea\xe1\x80\x30",
+               .ilen   = 512,
+               .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .rlen   = 512,
        },
 };
 
+static struct cipher_testvec tf_xts_enc_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+{
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 32,
+               .result = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
+                         "\x30\x74\xe4\x44\x52\x77\x97\x43"
+                         "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
+                         "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x57\x0e\x8f\xe5\x2a\x35\x61\x4f"
+                         "\x32\xd3\xbd\x36\x05\x15\x44\x2c"
+                         "\x58\x06\xf7\xf8\x00\xa8\xb6\xd5"
+                         "\xc6\x28\x92\xdb\xd8\x34\xa2\xe9",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x96\x45\x8f\x8d\x7a\x75\xb1\xde"
+                         "\x40\x0c\x89\x56\xf6\x4d\xa7\x07"
+                         "\x38\xbb\x5b\xe9\xcd\x84\xae\xb2"
+                         "\x7b\x6a\x62\xf4\x8c\xb5\x37\xea",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xa9\x78\xae\x1e\xea\xa2\x44\x4c"
+                         "\xa2\x7a\x64\x1f\xaf\x46\xc1\xe0"
+                         "\x6c\xb2\xf3\x92\x9a\xd6\x7d\x58"
+                         "\xb8\x2d\xb9\x5d\x58\x07\x66\x50"
+                         "\xea\x35\x35\x8c\xb2\x46\x61\x06"
+                         "\x5d\x65\xfc\x57\x8f\x69\x74\xab"
+                         "\x8a\x06\x69\xb5\x6c\xda\x66\xc7"
+                         "\x52\x90\xbb\x8e\x6d\x8b\xb5\xa2"
+                         "\x78\x1d\xc2\xa9\xc2\x73\x00\xc3"
+                         "\x32\x36\x7c\x97\x6b\x4e\x8a\x50"
+                         "\xe4\x91\x83\x96\x8f\xf4\x94\x1a"
+                         "\xa6\x27\xe1\x33\xcb\x91\xc6\x5f"
+                         "\x94\x75\xbc\xd7\x3e\x3e\x6f\x9e"
+                         "\xa9\x31\x80\x5e\xe5\xdb\xc8\x53"
+                         "\x01\x73\x68\x32\x25\x19\xfa\xfb"
+                         "\xe4\xcf\xb9\x3e\xa2\xa0\x8f\x31"
+                         "\xbf\x54\x06\x93\xa8\xb1\x0f\xb6"
+                         "\x7c\x3c\xde\x6f\x0f\xfb\x0c\x11"
+                         "\x39\x80\x39\x09\x97\x65\xf2\x83"
+                         "\xae\xe6\xa1\x6f\x47\xb8\x49\xde"
+                         "\x99\x36\x20\x7d\x97\x3b\xec\xfa"
+                         "\xb4\x33\x6e\x7a\xc7\x46\x84\x49"
+                         "\x91\xcd\xe1\x57\x0d\xed\x40\x08"
+                         "\x13\xf1\x4e\x3e\xa4\xa4\x5c\xe6"
+                         "\xd2\x0c\x20\x8f\x3e\xdf\x3f\x47"
+                         "\x9a\x2f\xde\x6d\x66\xc9\x99\x4a"
+                         "\x2d\x9e\x9d\x4b\x1a\x27\xa2\x12"
+                         "\x99\xf0\xf8\xb1\xb6\xf6\x57\xc3"
+                         "\xca\x1c\xa3\x8e\xed\x39\x28\xb5"
+                         "\x10\x1b\x4b\x08\x42\x00\x4a\xd3"
+                         "\xad\x5a\xc6\x8e\xc8\xbb\x95\xc4"
+                         "\x4b\xaa\xfe\xd5\x42\xa8\xa3\x6d"
+                         "\x3c\xf3\x34\x91\x2d\xb4\xdd\x20"
+                         "\x0c\x90\x6d\xa3\x9b\x66\x9d\x24"
+                         "\x02\xa6\xa9\x3f\x3f\x58\x5d\x47"
+                         "\x24\x65\x63\x7e\xbd\x8c\xe6\x52"
+                         "\x7d\xef\x33\x53\x63\xec\xaa\x0b"
+                         "\x64\x15\xa9\xa6\x1f\x10\x00\x38"
+                         "\x35\xa8\xe7\xbe\x23\x70\x22\xe0"
+                         "\xd3\xb9\xe6\xfd\xe6\xaa\x03\x50"
+                         "\xf3\x3c\x27\x36\x8b\xcc\xfe\x9c"
+                         "\x9c\xa3\xb3\xe7\x68\x9b\xa2\x71"
+                         "\xe0\x07\xd9\x1f\x68\x1f\xac\x5e"
+                         "\x7a\x74\x85\xa9\x6a\x90\xab\x2c"
+                         "\x38\x51\xbc\x1f\x43\x4a\x56\x1c"
+                         "\xf8\x47\x03\x4e\x67\xa8\x1f\x99"
+                         "\x04\x39\x73\x32\xb2\x86\x79\xe7"
+                         "\x14\x28\x70\xb8\xe2\x7d\x69\x85"
+                         "\xb6\x0f\xc5\xd0\xd0\x01\x5c\xe6"
+                         "\x09\x0f\x75\xf7\xb6\x81\xd2\x11"
+                         "\x20\x9c\xa1\xee\x11\x44\x79\xd0"
+                         "\xb2\x34\x77\xda\x10\x9a\x6f\x6f"
+                         "\xef\x7c\xd9\xdc\x35\xb7\x61\xdd"
+                         "\xf1\xa4\xc6\x1c\xbf\x05\x22\xac"
+                         "\xfe\x2f\x85\x00\x44\xdf\x33\x16"
+                         "\x35\xb6\xa3\xd3\x70\xdf\x69\x35"
+                         "\x6a\xc7\xb4\x99\x45\x27\xc8\x8e"
+                         "\x5a\x14\x30\xd0\x55\x3e\x4f\x64"
+                         "\x0d\x38\xe3\xdf\x8b\xa8\x93\x26"
+                         "\x75\xae\xf6\xb5\x23\x0b\x17\x31"
+                         "\xbf\x27\xb8\xb5\x94\x31\xa7\x8f"
+                         "\x43\xc4\x46\x24\x22\x4f\x8f\x7e"
+                         "\xe5\xf4\x6d\x1e\x0e\x18\x7a\xbb"
+                         "\xa6\x8f\xfb\x49\x49\xd8\x7e\x5a",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xd7\x4b\x93\x7d\x13\xa2\xa2\xe1"
+                         "\x35\x39\x71\x88\x76\x1e\xc9\xea"
+                         "\x86\xad\xf3\x14\x48\x3d\x5e\xe9"
+                         "\xe9\x2d\xb2\x56\x59\x35\x9d\xec"
+                         "\x84\xfa\x7e\x9d\x6d\x33\x36\x8f"
+                         "\xce\xf4\xa9\x21\x0b\x5f\x96\xec"
+                         "\xcb\xf9\x57\x68\x33\x88\x39\xbf"
+                         "\x2f\xbb\x59\x03\xbd\x66\x8b\x11"
+                         "\x11\x65\x51\x2e\xb8\x67\x05\xd1"
+                         "\x27\x11\x5c\xd4\xcc\x97\xc2\xb3"
+                         "\xa9\x55\xaf\x07\x56\xd1\xdc\xf5"
+                         "\x85\xdc\x46\xe6\xf0\x24\xeb\x93"
+                         "\x4d\xf0\x9b\xf5\x73\x1c\xda\x03"
+                         "\x22\xc8\x3a\x4f\xb4\x19\x91\x09"
+                         "\x54\x0b\xf6\xfe\x17\x3d\x1a\x53"
+                         "\x72\x60\x79\xcb\x0e\x32\x8a\x77"
+                         "\xd5\xed\xdb\x33\xd7\x62\x16\x69"
+                         "\x63\xe0\xab\xb5\xf6\x9c\x5f\x3d"
+                         "\x69\x35\x61\x86\xf8\x86\xb9\x89"
+                         "\x6e\x59\x35\xac\xf6\x6b\x33\xa0"
+                         "\xea\xef\x96\x62\xd8\xa9\xcf\x56"
+                         "\xbf\xdb\x8a\xfd\xa1\x82\x77\x73"
+                         "\x3d\x94\x4a\x49\x42\x6d\x08\x60"
+                         "\xa1\xea\xab\xb6\x88\x13\x94\xb8"
+                         "\x51\x98\xdb\x35\x85\xdf\xf6\xb9"
+                         "\x8f\xcd\xdf\x80\xd3\x40\x2d\x72"
+                         "\xb8\xb2\x6c\x02\x43\x35\x22\x2a"
+                         "\x31\xed\xcd\x16\x19\xdf\x62\x0f"
+                         "\x29\xcf\x87\x04\xec\x02\x4f\xe4"
+                         "\xa2\xed\x73\xc6\x69\xd3\x7e\x89"
+                         "\x0b\x76\x10\x7c\xd6\xf9\x6a\x25"
+                         "\xed\xcc\x60\x5d\x61\x20\xc1\x97"
+                         "\x56\x91\x57\x28\xbe\x71\x0d\xcd"
+                         "\xde\xc4\x9e\x55\x91\xbe\xd1\x28"
+                         "\x9b\x90\xeb\x73\xf3\x68\x51\xc6"
+                         "\xdf\x82\xcc\xd8\x1f\xce\x5b\x27"
+                         "\xc0\x60\x5e\x33\xd6\xa7\x20\xea"
+                         "\xb2\x54\xc7\x5d\x6a\x3b\x67\x47"
+                         "\xcf\xa0\xe3\xab\x86\xaf\xc1\x42"
+                         "\xe6\xb0\x23\x4a\xaf\x53\xdf\xa0"
+                         "\xad\x12\x32\x31\x03\xf7\x21\xbe"
+                         "\x2d\xd5\x82\x42\xb6\x4a\x3d\xcd"
+                         "\xd8\x81\x77\xa9\x49\x98\x6c\x09"
+                         "\xc5\xa3\x61\x12\x62\x85\x6b\xcd"
+                         "\xb3\xf4\x20\x0c\x41\xc4\x05\x37"
+                         "\x46\x5f\xeb\x71\x8b\xf1\xaf\x6e"
+                         "\xba\xf3\x50\x2e\xfe\xa8\x37\xeb"
+                         "\xe8\x8c\x4f\xa4\x0c\xf1\x31\xc8"
+                         "\x6e\x71\x4f\xa5\xd7\x97\x73\xe0"
+                         "\x93\x4a\x2f\xda\x7b\xe0\x20\x54"
+                         "\x1f\x8d\x85\x79\x0b\x7b\x5e\x75"
+                         "\xb9\x07\x67\xcc\xc8\xe7\x21\x15"
+                         "\xa7\xc8\x98\xff\x4b\x80\x1c\x12"
+                         "\xa8\x54\xe1\x38\x52\xe6\x74\x81"
+                         "\x97\x47\xa1\x41\x0e\xc0\x50\xe3"
+                         "\x55\x0e\xc3\xa7\x70\x77\xce\x07"
+                         "\xed\x8c\x88\xe6\xa1\x5b\x14\xec"
+                         "\xe6\xde\x06\x6d\x74\xc5\xd9\xfa"
+                         "\xe5\x2f\x5a\xff\xc8\x05\xee\x27"
+                         "\x35\x61\xbf\x0b\x19\x78\x9b\xd2"
+                         "\x04\xc7\x05\xb1\x79\xb4\xff\x5f"
+                         "\xf3\xea\x67\x52\x78\xc2\xce\x70"
+                         "\xa4\x05\x0b\xb2\xb3\xa8\x30\x97"
+                         "\x37\x30\xe1\x91\x8d\xb3\x2a\xff",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec tf_xts_dec_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+       /* same as enc vectors with input and result reversed */
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
+                         "\x30\x74\xe4\x44\x52\x77\x97\x43"
+                         "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
+                         "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
+               .ilen   = 32,
+               .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x57\x0e\x8f\xe5\x2a\x35\x61\x4f"
+                         "\x32\xd3\xbd\x36\x05\x15\x44\x2c"
+                         "\x58\x06\xf7\xf8\x00\xa8\xb6\xd5"
+                         "\xc6\x28\x92\xdb\xd8\x34\xa2\xe9",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x96\x45\x8f\x8d\x7a\x75\xb1\xde"
+                         "\x40\x0c\x89\x56\xf6\x4d\xa7\x07"
+                         "\x38\xbb\x5b\xe9\xcd\x84\xae\xb2"
+                         "\x7b\x6a\x62\xf4\x8c\xb5\x37\xea",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xa9\x78\xae\x1e\xea\xa2\x44\x4c"
+                         "\xa2\x7a\x64\x1f\xaf\x46\xc1\xe0"
+                         "\x6c\xb2\xf3\x92\x9a\xd6\x7d\x58"
+                         "\xb8\x2d\xb9\x5d\x58\x07\x66\x50"
+                         "\xea\x35\x35\x8c\xb2\x46\x61\x06"
+                         "\x5d\x65\xfc\x57\x8f\x69\x74\xab"
+                         "\x8a\x06\x69\xb5\x6c\xda\x66\xc7"
+                         "\x52\x90\xbb\x8e\x6d\x8b\xb5\xa2"
+                         "\x78\x1d\xc2\xa9\xc2\x73\x00\xc3"
+                         "\x32\x36\x7c\x97\x6b\x4e\x8a\x50"
+                         "\xe4\x91\x83\x96\x8f\xf4\x94\x1a"
+                         "\xa6\x27\xe1\x33\xcb\x91\xc6\x5f"
+                         "\x94\x75\xbc\xd7\x3e\x3e\x6f\x9e"
+                         "\xa9\x31\x80\x5e\xe5\xdb\xc8\x53"
+                         "\x01\x73\x68\x32\x25\x19\xfa\xfb"
+                         "\xe4\xcf\xb9\x3e\xa2\xa0\x8f\x31"
+                         "\xbf\x54\x06\x93\xa8\xb1\x0f\xb6"
+                         "\x7c\x3c\xde\x6f\x0f\xfb\x0c\x11"
+                         "\x39\x80\x39\x09\x97\x65\xf2\x83"
+                         "\xae\xe6\xa1\x6f\x47\xb8\x49\xde"
+                         "\x99\x36\x20\x7d\x97\x3b\xec\xfa"
+                         "\xb4\x33\x6e\x7a\xc7\x46\x84\x49"
+                         "\x91\xcd\xe1\x57\x0d\xed\x40\x08"
+                         "\x13\xf1\x4e\x3e\xa4\xa4\x5c\xe6"
+                         "\xd2\x0c\x20\x8f\x3e\xdf\x3f\x47"
+                         "\x9a\x2f\xde\x6d\x66\xc9\x99\x4a"
+                         "\x2d\x9e\x9d\x4b\x1a\x27\xa2\x12"
+                         "\x99\xf0\xf8\xb1\xb6\xf6\x57\xc3"
+                         "\xca\x1c\xa3\x8e\xed\x39\x28\xb5"
+                         "\x10\x1b\x4b\x08\x42\x00\x4a\xd3"
+                         "\xad\x5a\xc6\x8e\xc8\xbb\x95\xc4"
+                         "\x4b\xaa\xfe\xd5\x42\xa8\xa3\x6d"
+                         "\x3c\xf3\x34\x91\x2d\xb4\xdd\x20"
+                         "\x0c\x90\x6d\xa3\x9b\x66\x9d\x24"
+                         "\x02\xa6\xa9\x3f\x3f\x58\x5d\x47"
+                         "\x24\x65\x63\x7e\xbd\x8c\xe6\x52"
+                         "\x7d\xef\x33\x53\x63\xec\xaa\x0b"
+                         "\x64\x15\xa9\xa6\x1f\x10\x00\x38"
+                         "\x35\xa8\xe7\xbe\x23\x70\x22\xe0"
+                         "\xd3\xb9\xe6\xfd\xe6\xaa\x03\x50"
+                         "\xf3\x3c\x27\x36\x8b\xcc\xfe\x9c"
+                         "\x9c\xa3\xb3\xe7\x68\x9b\xa2\x71"
+                         "\xe0\x07\xd9\x1f\x68\x1f\xac\x5e"
+                         "\x7a\x74\x85\xa9\x6a\x90\xab\x2c"
+                         "\x38\x51\xbc\x1f\x43\x4a\x56\x1c"
+                         "\xf8\x47\x03\x4e\x67\xa8\x1f\x99"
+                         "\x04\x39\x73\x32\xb2\x86\x79\xe7"
+                         "\x14\x28\x70\xb8\xe2\x7d\x69\x85"
+                         "\xb6\x0f\xc5\xd0\xd0\x01\x5c\xe6"
+                         "\x09\x0f\x75\xf7\xb6\x81\xd2\x11"
+                         "\x20\x9c\xa1\xee\x11\x44\x79\xd0"
+                         "\xb2\x34\x77\xda\x10\x9a\x6f\x6f"
+                         "\xef\x7c\xd9\xdc\x35\xb7\x61\xdd"
+                         "\xf1\xa4\xc6\x1c\xbf\x05\x22\xac"
+                         "\xfe\x2f\x85\x00\x44\xdf\x33\x16"
+                         "\x35\xb6\xa3\xd3\x70\xdf\x69\x35"
+                         "\x6a\xc7\xb4\x99\x45\x27\xc8\x8e"
+                         "\x5a\x14\x30\xd0\x55\x3e\x4f\x64"
+                         "\x0d\x38\xe3\xdf\x8b\xa8\x93\x26"
+                         "\x75\xae\xf6\xb5\x23\x0b\x17\x31"
+                         "\xbf\x27\xb8\xb5\x94\x31\xa7\x8f"
+                         "\x43\xc4\x46\x24\x22\x4f\x8f\x7e"
+                         "\xe5\xf4\x6d\x1e\x0e\x18\x7a\xbb"
+                         "\xa6\x8f\xfb\x49\x49\xd8\x7e\x5a",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xd7\x4b\x93\x7d\x13\xa2\xa2\xe1"
+                         "\x35\x39\x71\x88\x76\x1e\xc9\xea"
+                         "\x86\xad\xf3\x14\x48\x3d\x5e\xe9"
+                         "\xe9\x2d\xb2\x56\x59\x35\x9d\xec"
+                         "\x84\xfa\x7e\x9d\x6d\x33\x36\x8f"
+                         "\xce\xf4\xa9\x21\x0b\x5f\x96\xec"
+                         "\xcb\xf9\x57\x68\x33\x88\x39\xbf"
+                         "\x2f\xbb\x59\x03\xbd\x66\x8b\x11"
+                         "\x11\x65\x51\x2e\xb8\x67\x05\xd1"
+                         "\x27\x11\x5c\xd4\xcc\x97\xc2\xb3"
+                         "\xa9\x55\xaf\x07\x56\xd1\xdc\xf5"
+                         "\x85\xdc\x46\xe6\xf0\x24\xeb\x93"
+                         "\x4d\xf0\x9b\xf5\x73\x1c\xda\x03"
+                         "\x22\xc8\x3a\x4f\xb4\x19\x91\x09"
+                         "\x54\x0b\xf6\xfe\x17\x3d\x1a\x53"
+                         "\x72\x60\x79\xcb\x0e\x32\x8a\x77"
+                         "\xd5\xed\xdb\x33\xd7\x62\x16\x69"
+                         "\x63\xe0\xab\xb5\xf6\x9c\x5f\x3d"
+                         "\x69\x35\x61\x86\xf8\x86\xb9\x89"
+                         "\x6e\x59\x35\xac\xf6\x6b\x33\xa0"
+                         "\xea\xef\x96\x62\xd8\xa9\xcf\x56"
+                         "\xbf\xdb\x8a\xfd\xa1\x82\x77\x73"
+                         "\x3d\x94\x4a\x49\x42\x6d\x08\x60"
+                         "\xa1\xea\xab\xb6\x88\x13\x94\xb8"
+                         "\x51\x98\xdb\x35\x85\xdf\xf6\xb9"
+                         "\x8f\xcd\xdf\x80\xd3\x40\x2d\x72"
+                         "\xb8\xb2\x6c\x02\x43\x35\x22\x2a"
+                         "\x31\xed\xcd\x16\x19\xdf\x62\x0f"
+                         "\x29\xcf\x87\x04\xec\x02\x4f\xe4"
+                         "\xa2\xed\x73\xc6\x69\xd3\x7e\x89"
+                         "\x0b\x76\x10\x7c\xd6\xf9\x6a\x25"
+                         "\xed\xcc\x60\x5d\x61\x20\xc1\x97"
+                         "\x56\x91\x57\x28\xbe\x71\x0d\xcd"
+                         "\xde\xc4\x9e\x55\x91\xbe\xd1\x28"
+                         "\x9b\x90\xeb\x73\xf3\x68\x51\xc6"
+                         "\xdf\x82\xcc\xd8\x1f\xce\x5b\x27"
+                         "\xc0\x60\x5e\x33\xd6\xa7\x20\xea"
+                         "\xb2\x54\xc7\x5d\x6a\x3b\x67\x47"
+                         "\xcf\xa0\xe3\xab\x86\xaf\xc1\x42"
+                         "\xe6\xb0\x23\x4a\xaf\x53\xdf\xa0"
+                         "\xad\x12\x32\x31\x03\xf7\x21\xbe"
+                         "\x2d\xd5\x82\x42\xb6\x4a\x3d\xcd"
+                         "\xd8\x81\x77\xa9\x49\x98\x6c\x09"
+                         "\xc5\xa3\x61\x12\x62\x85\x6b\xcd"
+                         "\xb3\xf4\x20\x0c\x41\xc4\x05\x37"
+                         "\x46\x5f\xeb\x71\x8b\xf1\xaf\x6e"
+                         "\xba\xf3\x50\x2e\xfe\xa8\x37\xeb"
+                         "\xe8\x8c\x4f\xa4\x0c\xf1\x31\xc8"
+                         "\x6e\x71\x4f\xa5\xd7\x97\x73\xe0"
+                         "\x93\x4a\x2f\xda\x7b\xe0\x20\x54"
+                         "\x1f\x8d\x85\x79\x0b\x7b\x5e\x75"
+                         "\xb9\x07\x67\xcc\xc8\xe7\x21\x15"
+                         "\xa7\xc8\x98\xff\x4b\x80\x1c\x12"
+                         "\xa8\x54\xe1\x38\x52\xe6\x74\x81"
+                         "\x97\x47\xa1\x41\x0e\xc0\x50\xe3"
+                         "\x55\x0e\xc3\xa7\x70\x77\xce\x07"
+                         "\xed\x8c\x88\xe6\xa1\x5b\x14\xec"
+                         "\xe6\xde\x06\x6d\x74\xc5\xd9\xfa"
+                         "\xe5\x2f\x5a\xff\xc8\x05\xee\x27"
+                         "\x35\x61\xbf\x0b\x19\x78\x9b\xd2"
+                         "\x04\xc7\x05\xb1\x79\xb4\xff\x5f"
+                         "\xf3\xea\x67\x52\x78\xc2\xce\x70"
+                         "\xa4\x05\x0b\xb2\xb3\xa8\x30\x97"
+                         "\x37\x30\xe1\x91\x8d\xb3\x2a\xff",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       },
+};
+
+/*
+ * Serpent test vectors.  These are backwards because Serpent writes
+ * octet sequences in right-to-left mode.
+ */
+#define SERPENT_ENC_TEST_VECTORS       5
+#define SERPENT_DEC_TEST_VECTORS       5
+
+#define TNEPRES_ENC_TEST_VECTORS       4
+#define TNEPRES_DEC_TEST_VECTORS       4
+
+#define SERPENT_CBC_ENC_TEST_VECTORS   1
+#define SERPENT_CBC_DEC_TEST_VECTORS   1
+
+#define SERPENT_CTR_ENC_TEST_VECTORS   2
+#define SERPENT_CTR_DEC_TEST_VECTORS   2
+
+#define SERPENT_LRW_ENC_TEST_VECTORS   8
+#define SERPENT_LRW_DEC_TEST_VECTORS   8
+
+#define SERPENT_XTS_ENC_TEST_VECTORS   5
+#define SERPENT_XTS_DEC_TEST_VECTORS   5
+
+static struct cipher_testvec serpent_enc_tv_template[] = {
+       {
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .ilen   = 16,
+               .result = "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
+                         "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .ilen   = 16,
+               .result = "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
+                         "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .ilen   = 16,
+               .result = "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
+                         "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+               .klen   = 16,
+               .input  = zeroed_string,
+               .ilen   = 16,
+               .result = "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
+                         "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
+               .rlen   = 16,
+       }, { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .ilen   = 144,
+               .result = "\xFB\xB0\x5D\xDE\xC0\xFE\xFC\xEB"
+                         "\xB1\x80\x10\x43\xDE\x62\x70\xBD"
+                         "\xFA\x8A\x93\xEA\x6B\xF7\xC5\xD7"
+                         "\x0C\xD1\xBB\x29\x25\x14\x4C\x22"
+                         "\x77\xA6\x38\x00\xDB\xB9\xE2\x07"
+                         "\xD1\xAC\x82\xBA\xEA\x67\xAA\x39"
+                         "\x99\x34\x89\x5B\x54\xE9\x12\x13"
+                         "\x3B\x04\xE5\x12\x42\xC5\x79\xAB"
+                         "\x0D\xC7\x3C\x58\x2D\xA3\x98\xF6"
+                         "\xE4\x61\x9E\x17\x0B\xCE\xE8\xAA"
+                         "\xB5\x6C\x1A\x3A\x67\x52\x81\x6A"
+                         "\x04\xFF\x8A\x1B\x96\xFE\xE6\x87"
+                         "\x3C\xD4\x39\x7D\x36\x9B\x03\xD5"
+                         "\xB6\xA0\x75\x3C\x83\xE6\x1C\x73"
+                         "\x9D\x74\x2B\x77\x53\x2D\xE5\xBD"
+                         "\x69\xDA\x7A\x01\xF5\x6A\x70\x39"
+                         "\x30\xD4\x2C\xF2\x8E\x06\x4B\x39"
+                         "\xB3\x12\x1D\xB3\x17\x46\xE6\xD6",
+               .rlen   = 144,
+       },
+};
+
+static struct cipher_testvec tnepres_enc_tv_template[] = {
+       { /* KeySize=128, PT=0, I=1 */
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 16,
+               .ilen   = 16,
+               .result = "\x49\xaf\xbf\xad\x9d\x5a\x34\x05"
+                         "\x2c\xd8\xff\xa5\x98\x6b\xd2\xdd",
+               .rlen   = 16,
+       }, { /* KeySize=192, PT=0, I=1 */
+               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 24,
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 16,
+               .result = "\xe7\x8e\x54\x02\xc7\x19\x55\x68"
+                         "\xac\x36\x78\xf7\xa3\xf6\x0c\x66",
+               .rlen   = 16,
+       }, { /* KeySize=256, PT=0, I=1 */
+               .key    = "\x80\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 16,
+               .result = "\xab\xed\x96\xe7\x66\xbf\x28\xcb"
+                         "\xc0\xeb\xd2\x1a\x82\xef\x08\x19",
+               .rlen   = 16,
+       }, { /* KeySize=256, I=257 */
+               .key    = "\x1f\x1e\x1d\x1c\x1b\x1a\x19\x18"
+                         "\x17\x16\x15\x14\x13\x12\x11\x10"
+                         "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
+                         "\x07\x06\x05\x04\x03\x02\x01\x00",
+               .klen   = 32,
+               .input  = "\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08"
+                         "\x07\x06\x05\x04\x03\x02\x01\x00",
+               .ilen   = 16,
+               .result = "\x5c\xe7\x1c\x70\xd2\x88\x2e\x5b"
+                         "\xb8\x32\xe4\x33\xf8\x9f\x26\xde",
+               .rlen   = 16,
+       },
+};
+
+
+static struct cipher_testvec serpent_dec_tv_template[] = {
+       {
+               .input  = "\x12\x07\xfc\xce\x9b\xd0\xd6\x47"
+                         "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x4c\x7d\x8a\x32\x80\x72\xa2\x2c"
+                         "\x82\x3e\x4a\x1f\x3a\xcd\xa1\x6d",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\xde\x26\x9f\xf8\x33\xe4\x32\xb8"
+                         "\x5b\x2e\x88\xd2\x70\x1c\xe7\x5c",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+               .klen   = 16,
+               .input  = "\xdd\xd2\x6b\x98\xa5\xff\xd8\x2c"
+                         "\x05\x34\x5a\x9d\xad\xbf\xaf\x49",
+               .ilen   = 16,
+               .result = zeroed_string,
+               .rlen   = 16,
+       }, { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .input  = "\xFB\xB0\x5D\xDE\xC0\xFE\xFC\xEB"
+                         "\xB1\x80\x10\x43\xDE\x62\x70\xBD"
+                         "\xFA\x8A\x93\xEA\x6B\xF7\xC5\xD7"
+                         "\x0C\xD1\xBB\x29\x25\x14\x4C\x22"
+                         "\x77\xA6\x38\x00\xDB\xB9\xE2\x07"
+                         "\xD1\xAC\x82\xBA\xEA\x67\xAA\x39"
+                         "\x99\x34\x89\x5B\x54\xE9\x12\x13"
+                         "\x3B\x04\xE5\x12\x42\xC5\x79\xAB"
+                         "\x0D\xC7\x3C\x58\x2D\xA3\x98\xF6"
+                         "\xE4\x61\x9E\x17\x0B\xCE\xE8\xAA"
+                         "\xB5\x6C\x1A\x3A\x67\x52\x81\x6A"
+                         "\x04\xFF\x8A\x1B\x96\xFE\xE6\x87"
+                         "\x3C\xD4\x39\x7D\x36\x9B\x03\xD5"
+                         "\xB6\xA0\x75\x3C\x83\xE6\x1C\x73"
+                         "\x9D\x74\x2B\x77\x53\x2D\xE5\xBD"
+                         "\x69\xDA\x7A\x01\xF5\x6A\x70\x39"
+                         "\x30\xD4\x2C\xF2\x8E\x06\x4B\x39"
+                         "\xB3\x12\x1D\xB3\x17\x46\xE6\xD6",
+               .ilen   = 144,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .rlen   = 144,
+       },
+};
+
+static struct cipher_testvec tnepres_dec_tv_template[] = {
+       {
+               .input  = "\x41\xcc\x6b\x31\x59\x31\x45\x97"
+                         "\x6d\x6f\xbb\x38\x4b\x37\x21\x28",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\xea\xf4\xd7\xfc\xd8\x01\x34\x47"
+                         "\x81\x45\x0b\xfa\x0c\xd6\xad\x6e",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x64\xa9\x1a\x37\xed\x9f\xe7\x49"
+                         "\xa8\x4e\x76\xd6\xf5\x0d\x78\xee",
+               .ilen   = 16,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .rlen   = 16,
+       }, { /* KeySize=128, I=121 */
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80",
+               .klen   = 16,
+               .input  = "\x3d\xda\xbf\xc0\x06\xda\xab\x06"
+                         "\x46\x2a\xf4\xef\x81\x54\x4e\x26",
+               .ilen   = 16,
+               .result = zeroed_string,
+               .rlen   = 16,
+       },
+};
+
+static struct cipher_testvec serpent_cbc_enc_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .ilen   = 144,
+               .result = "\x80\xCF\x11\x41\x1A\xB9\x4B\x9C"
+                         "\xFF\xB7\x6C\xEA\xF0\xAF\x77\x6E"
+                         "\x71\x75\x95\x9D\x4E\x1C\xCF\xAD"
+                         "\x81\x34\xE9\x8F\xAE\x5A\x91\x1C"
+                         "\x38\x63\x35\x7E\x79\x18\x0A\xE8"
+                         "\x67\x06\x76\xD5\xFF\x22\x2F\xDA"
+                         "\xB6\x2D\x57\x13\xB6\x3C\xBC\x97"
+                         "\xFE\x53\x75\x35\x97\x7F\x51\xEA"
+                         "\xDF\x5D\xE8\x9D\xCC\xD9\xAE\xE7"
+                         "\x62\x67\xFF\x04\xC2\x18\x22\x5F"
+                         "\x2E\x06\xC1\xE2\x26\xCD\xC6\x1E"
+                         "\xE5\x2C\x4E\x87\x23\xDD\xF0\x41"
+                         "\x08\xA5\xB4\x3E\x07\x1E\x0B\xBB"
+                         "\x72\x84\xF8\x0A\x3F\x38\x5E\x91"
+                         "\x15\x26\xE1\xDB\xA4\x3D\x74\xD2"
+                         "\x41\x1E\x3F\xA9\xC6\x7D\x2A\xAB"
+                         "\x27\xDF\x89\x1D\x86\x3E\xF7\x5A"
+                         "\xF6\xE3\x0F\xC7\x6B\x4C\x96\x7C",
+               .rlen   = 144,
+       },
+};
+
+static struct cipher_testvec serpent_cbc_dec_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x80\xCF\x11\x41\x1A\xB9\x4B\x9C"
+                         "\xFF\xB7\x6C\xEA\xF0\xAF\x77\x6E"
+                         "\x71\x75\x95\x9D\x4E\x1C\xCF\xAD"
+                         "\x81\x34\xE9\x8F\xAE\x5A\x91\x1C"
+                         "\x38\x63\x35\x7E\x79\x18\x0A\xE8"
+                         "\x67\x06\x76\xD5\xFF\x22\x2F\xDA"
+                         "\xB6\x2D\x57\x13\xB6\x3C\xBC\x97"
+                         "\xFE\x53\x75\x35\x97\x7F\x51\xEA"
+                         "\xDF\x5D\xE8\x9D\xCC\xD9\xAE\xE7"
+                         "\x62\x67\xFF\x04\xC2\x18\x22\x5F"
+                         "\x2E\x06\xC1\xE2\x26\xCD\xC6\x1E"
+                         "\xE5\x2C\x4E\x87\x23\xDD\xF0\x41"
+                         "\x08\xA5\xB4\x3E\x07\x1E\x0B\xBB"
+                         "\x72\x84\xF8\x0A\x3F\x38\x5E\x91"
+                         "\x15\x26\xE1\xDB\xA4\x3D\x74\xD2"
+                         "\x41\x1E\x3F\xA9\xC6\x7D\x2A\xAB"
+                         "\x27\xDF\x89\x1D\x86\x3E\xF7\x5A"
+                         "\xF6\xE3\x0F\xC7\x6B\x4C\x96\x7C",
+               .ilen   = 144,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .rlen   = 144,
+       },
+};
+
+static struct cipher_testvec serpent_ctr_enc_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .ilen   = 144,
+               .result = "\x84\x68\xEC\xF2\x1C\x88\x20\xCA"
+                         "\x37\x69\xE3\x3A\x22\x85\x48\x46"
+                         "\x70\xAA\x25\xB4\xCD\x8B\x04\x4E"
+                         "\x8D\x15\x2B\x98\xDF\x7B\x6D\xB9"
+                         "\xE0\x4A\x73\x00\x65\xB6\x1A\x0D"
+                         "\x5C\x60\xDF\x34\xDC\x60\x4C\xDF"
+                         "\xB5\x1F\x26\x8C\xDA\xC1\x11\xA8"
+                         "\x80\xFA\x37\x7A\x89\xAA\xAE\x7B"
+                         "\x92\x6E\xB9\xDC\xC9\x62\x4F\x88"
+                         "\x0A\x5D\x97\x2F\x6B\xAC\x03\x7C"
+                         "\x22\xF6\x55\x5A\xFA\x35\xA5\x17"
+                         "\xA1\x5C\x5E\x2B\x63\x2D\xB9\x91"
+                         "\x3E\x83\x26\x00\x4E\xD5\xBE\xCE"
+                         "\x79\xC4\x3D\xFC\x70\xA0\xAD\x96"
+                         "\xBA\x58\x2A\x1C\xDF\xC2\x3A\xA5"
+                         "\x7C\xB5\x12\x89\xED\xBF\xB6\x09"
+                         "\x13\x4F\x7D\x61\x3C\x5C\x27\xFC"
+                         "\x5D\xE1\x4F\xA1\xEA\xB3\xCA\xB9",
+               .rlen   = 144,
+       }, { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC",
+               .ilen   = 147,
+               .result = "\x84\x68\xEC\xF2\x1C\x88\x20\xCA"
+                         "\x37\x69\xE3\x3A\x22\x85\x48\x46"
+                         "\x70\xAA\x25\xB4\xCD\x8B\x04\x4E"
+                         "\x8D\x15\x2B\x98\xDF\x7B\x6D\xB9"
+                         "\xE0\x4A\x73\x00\x65\xB6\x1A\x0D"
+                         "\x5C\x60\xDF\x34\xDC\x60\x4C\xDF"
+                         "\xB5\x1F\x26\x8C\xDA\xC1\x11\xA8"
+                         "\x80\xFA\x37\x7A\x89\xAA\xAE\x7B"
+                         "\x92\x6E\xB9\xDC\xC9\x62\x4F\x88"
+                         "\x0A\x5D\x97\x2F\x6B\xAC\x03\x7C"
+                         "\x22\xF6\x55\x5A\xFA\x35\xA5\x17"
+                         "\xA1\x5C\x5E\x2B\x63\x2D\xB9\x91"
+                         "\x3E\x83\x26\x00\x4E\xD5\xBE\xCE"
+                         "\x79\xC4\x3D\xFC\x70\xA0\xAD\x96"
+                         "\xBA\x58\x2A\x1C\xDF\xC2\x3A\xA5"
+                         "\x7C\xB5\x12\x89\xED\xBF\xB6\x09"
+                         "\x13\x4F\x7D\x61\x3C\x5C\x27\xFC"
+                         "\x5D\xE1\x4F\xA1\xEA\xB3\xCA\xB9"
+                         "\xE6\xD0\x97",
+               .rlen   = 147,
+       },
+};
+
+static struct cipher_testvec serpent_ctr_dec_tv_template[] = {
+       { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x84\x68\xEC\xF2\x1C\x88\x20\xCA"
+                         "\x37\x69\xE3\x3A\x22\x85\x48\x46"
+                         "\x70\xAA\x25\xB4\xCD\x8B\x04\x4E"
+                         "\x8D\x15\x2B\x98\xDF\x7B\x6D\xB9"
+                         "\xE0\x4A\x73\x00\x65\xB6\x1A\x0D"
+                         "\x5C\x60\xDF\x34\xDC\x60\x4C\xDF"
+                         "\xB5\x1F\x26\x8C\xDA\xC1\x11\xA8"
+                         "\x80\xFA\x37\x7A\x89\xAA\xAE\x7B"
+                         "\x92\x6E\xB9\xDC\xC9\x62\x4F\x88"
+                         "\x0A\x5D\x97\x2F\x6B\xAC\x03\x7C"
+                         "\x22\xF6\x55\x5A\xFA\x35\xA5\x17"
+                         "\xA1\x5C\x5E\x2B\x63\x2D\xB9\x91"
+                         "\x3E\x83\x26\x00\x4E\xD5\xBE\xCE"
+                         "\x79\xC4\x3D\xFC\x70\xA0\xAD\x96"
+                         "\xBA\x58\x2A\x1C\xDF\xC2\x3A\xA5"
+                         "\x7C\xB5\x12\x89\xED\xBF\xB6\x09"
+                         "\x13\x4F\x7D\x61\x3C\x5C\x27\xFC"
+                         "\x5D\xE1\x4F\xA1\xEA\xB3\xCA\xB9",
+               .ilen   = 144,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A",
+               .rlen   = 144,
+       }, { /* Generated with Crypto++ */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x84\x68\xEC\xF2\x1C\x88\x20\xCA"
+                         "\x37\x69\xE3\x3A\x22\x85\x48\x46"
+                         "\x70\xAA\x25\xB4\xCD\x8B\x04\x4E"
+                         "\x8D\x15\x2B\x98\xDF\x7B\x6D\xB9"
+                         "\xE0\x4A\x73\x00\x65\xB6\x1A\x0D"
+                         "\x5C\x60\xDF\x34\xDC\x60\x4C\xDF"
+                         "\xB5\x1F\x26\x8C\xDA\xC1\x11\xA8"
+                         "\x80\xFA\x37\x7A\x89\xAA\xAE\x7B"
+                         "\x92\x6E\xB9\xDC\xC9\x62\x4F\x88"
+                         "\x0A\x5D\x97\x2F\x6B\xAC\x03\x7C"
+                         "\x22\xF6\x55\x5A\xFA\x35\xA5\x17"
+                         "\xA1\x5C\x5E\x2B\x63\x2D\xB9\x91"
+                         "\x3E\x83\x26\x00\x4E\xD5\xBE\xCE"
+                         "\x79\xC4\x3D\xFC\x70\xA0\xAD\x96"
+                         "\xBA\x58\x2A\x1C\xDF\xC2\x3A\xA5"
+                         "\x7C\xB5\x12\x89\xED\xBF\xB6\x09"
+                         "\x13\x4F\x7D\x61\x3C\x5C\x27\xFC"
+                         "\x5D\xE1\x4F\xA1\xEA\xB3\xCA\xB9"
+                         "\xE6\xD0\x97",
+               .ilen   = 147,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC",
+               .rlen   = 147,
+       },
+};
+
+static struct cipher_testvec serpent_lrw_enc_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
+       {
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x6f\xbf\xd4\xa4\x5d\x71\x16\x79"
+                         "\x63\x9c\xa6\x8e\x40\xbe\x0d\x8a",
+               .rlen   = 16,
+       }, {
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\xfd\xb2\x66\x98\x80\x96\x55\xad"
+                         "\x08\x94\x54\x9c\x21\x7c\x69\xe3",
+               .rlen   = 16,
+       }, {
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x14\x5e\x3d\x70\xc0\x6e\x9c\x34"
+                         "\x5b\x5e\xcf\x0f\xe4\x8c\x21\x5c",
+               .rlen   = 16,
+       }, {
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x25\x39\xaa\xa5\xf0\x65\xc8\xdc"
+                         "\x5d\x45\x95\x30\x8f\xff\x2f\x1b",
+               .rlen   = 16,
+       }, {
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x0c\x20\x20\x63\xd6\x8b\xfc\x8f"
+                         "\xc0\xe2\x17\xbb\xd2\x59\x6f\x26",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\xc1\x35\x2e\x53\xf0\x96\x4d\x9c"
+                         "\x2e\x18\xe6\x99\xcd\xd3\x15\x68",
+               .rlen   = 16,
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .ilen   = 16,
+               .result = "\x86\x0a\xc6\xa9\x1a\x9f\xe7\xe6"
+                         "\x64\x3b\x33\xd6\xd5\x84\xd6\xdf",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .ilen   = 512,
+               .result = "\xe3\x5a\x38\x0f\x4d\x92\x3a\x74"
+                         "\x15\xb1\x50\x8c\x9a\xd8\x99\x1d"
+                         "\x82\xec\xf1\x5f\x03\x6d\x02\x58"
+                         "\x90\x67\xfc\xdd\x8d\xe1\x38\x08"
+                         "\x7b\xc9\x9b\x4b\x04\x09\x50\x15"
+                         "\xce\xab\xda\x33\x30\x20\x12\xfa"
+                         "\x83\xc4\xa6\x9a\x2e\x7d\x90\xd9"
+                         "\xa6\xa6\x67\x43\xb4\xa7\xa8\x5c"
+                         "\xbb\x6a\x49\x2b\x8b\xf8\xd0\x22"
+                         "\xe5\x9e\xba\xe8\x8c\x67\xb8\x5b"
+                         "\x60\xbc\xf5\xa4\x95\x4e\x66\xe5"
+                         "\x6d\x8e\xa9\xf6\x65\x2e\x04\xf5"
+                         "\xba\xb5\xdb\x88\xc2\xf6\x7a\x4b"
+                         "\x89\x58\x7c\x9a\xae\x26\xe8\xb7"
+                         "\xb7\x28\xcc\xd6\xcc\xa5\x98\x4d"
+                         "\xb9\x91\xcb\xb4\xe4\x8b\x96\x47"
+                         "\x5f\x03\x8b\xdd\x94\xd1\xee\x12"
+                         "\xa7\x83\x80\xf2\xc1\x15\x74\x4f"
+                         "\x49\xf9\xb0\x7e\x6f\xdc\x73\x2f"
+                         "\xe2\xcf\xe0\x1b\x34\xa5\xa0\x52"
+                         "\xfb\x3c\x5d\x85\x91\xe6\x6d\x98"
+                         "\x04\xd6\xdd\x4c\x00\x64\xd9\x54"
+                         "\x5c\x3c\x08\x1d\x4c\x06\x9f\xb8"
+                         "\x1c\x4d\x8d\xdc\xa4\x3c\xb9\x3b"
+                         "\x9e\x85\xce\xc3\xa8\x4a\x0c\xd9"
+                         "\x04\xc3\x6f\x17\x66\xa9\x1f\x59"
+                         "\xd9\xe2\x19\x36\xa3\x88\xb8\x0b"
+                         "\x0f\x4a\x4d\xf8\xc8\x6f\xd5\x43"
+                         "\xeb\xa0\xab\x1f\x61\xc0\x06\xeb"
+                         "\x93\xb7\xb8\x6f\x0d\xbd\x07\x49"
+                         "\xb3\xac\x5d\xcf\x31\xa0\x27\x26"
+                         "\x21\xbe\x94\x2e\x19\xea\xf4\xee"
+                         "\xb5\x13\x89\xf7\x94\x0b\xef\x59"
+                         "\x44\xc5\x78\x8b\x3c\x3b\x71\x20"
+                         "\xf9\x35\x0c\x70\x74\xdc\x5b\xc2"
+                         "\xb4\x11\x0e\x2c\x61\xa1\x52\x46"
+                         "\x18\x11\x16\xc6\x86\x44\xa7\xaf"
+                         "\xd5\x0c\x7d\xa6\x9e\x25\x2d\x1b"
+                         "\x9a\x8f\x0f\xf8\x6a\x61\xa0\xea"
+                         "\x3f\x0e\x90\xd6\x8f\x83\x30\x64"
+                         "\xb5\x51\x2d\x08\x3c\xcd\x99\x36"
+                         "\x96\xd4\xb1\xb5\x48\x30\xca\x48"
+                         "\xf7\x11\xa8\xf5\x97\x8a\x6a\x6d"
+                         "\x12\x33\x2f\xc0\xe8\xda\xec\x8a"
+                         "\xe1\x88\x72\x63\xde\x20\xa3\xe1"
+                         "\x8e\xac\x84\x37\x35\xf5\xf7\x3f"
+                         "\x00\x02\x0e\xe4\xc1\x53\x68\x3f"
+                         "\xaa\xd5\xac\x52\x3d\x20\x2f\x4d"
+                         "\x7c\x83\xd0\xbd\xaa\x97\x35\x36"
+                         "\x98\x88\x59\x5d\xe7\x24\xe3\x90"
+                         "\x9d\x30\x47\xa7\xc3\x60\x35\xf4"
+                         "\xd5\xdb\x0e\x4d\x44\xc1\x81\x8b"
+                         "\xfd\xbd\xc3\x2b\xba\x68\xfe\x8d"
+                         "\x49\x5a\x3c\x8a\xa3\x01\xae\x25"
+                         "\x42\xab\xd2\x87\x1b\x35\xd6\xd2"
+                         "\xd7\x70\x1c\x1f\x72\xd1\xe1\x39"
+                         "\x1c\x58\xa2\xb4\xd0\x78\x55\x72"
+                         "\x76\x59\xea\xd9\xd7\x6e\x63\x8b"
+                         "\xcc\x9b\xa7\x74\x89\xfc\xa3\x68"
+                         "\x86\x28\xd1\xbb\x54\x8d\x66\xad"
+                         "\x2a\x92\xf9\x4e\x04\x3d\xae\xfd"
+                         "\x1b\x2b\x7f\xc3\x2f\x1a\x78\x0a"
+                         "\x5c\xc6\x84\xfe\x7c\xcb\x26\xfd"
+                         "\xd9\x51\x0f\xd7\x94\x2f\xc5\xa7",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec serpent_lrw_dec_tv_template[] = {
+       /* Generated from AES-LRW test vectors */
+       /* same as enc vectors with input and result reversed */
+       {
+               .key    = "\x45\x62\xac\x25\xf8\x28\x17\x6d"
+                         "\x4c\x26\x84\x14\xb5\x68\x01\x85"
+                         "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03"
+                         "\xee\x5a\x83\x0c\xcc\x09\x4c\x87",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x6f\xbf\xd4\xa4\x5d\x71\x16\x79"
+                         "\x63\x9c\xa6\x8e\x40\xbe\x0d\x8a",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x59\x70\x47\x14\xf5\x57\x47\x8c"
+                         "\xd7\x79\xe8\x0f\x54\x88\x79\x44"
+                         "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea"
+                         "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x02",
+               .input  = "\xfd\xb2\x66\x98\x80\x96\x55\xad"
+                         "\x08\x94\x54\x9c\x21\x7c\x69\xe3",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50"
+                         "\x30\xfe\x69\xe2\x37\x7f\x98\x47"
+                         "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6"
+                         "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x14\x5e\x3d\x70\xc0\x6e\x9c\x34"
+                         "\x5b\x5e\xcf\x0f\xe4\x8c\x21\x5c",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15"
+                         "\x25\x83\xf7\x3c\x1f\x01\x28\x74"
+                         "\xca\xc6\xbc\x35\x4d\x4a\x65\x54"
+                         "\x90\xae\x61\xcf\x7b\xae\xbd\xcc"
+                         "\xad\xe4\x94\xc5\x4a\x29\xae\x70",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x25\x39\xaa\xa5\xf0\x65\xc8\xdc"
+                         "\x5d\x45\x95\x30\x8f\xff\x2f\x1b",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff"
+                         "\xf8\x86\xce\xac\x93\xc5\xad\xc6"
+                         "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd"
+                         "\x52\x13\xb2\xb7\xf0\xff\x11\xd8"
+                         "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f",
+               .klen   = 40,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x0c\x20\x20\x63\xd6\x8b\xfc\x8f"
+                         "\xc0\xe2\x17\xbb\xd2\x59\x6f\x26",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\xc1\x35\x2e\x53\xf0\x96\x4d\x9c"
+                         "\x2e\x18\xe6\x99\xcd\xd3\x15\x68",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d"
+                         "\xd4\x70\x98\x0b\xc7\x95\x84\xc8"
+                         "\xb2\xfb\x64\xce\x60\x97\x87\x8d"
+                         "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7"
+                         "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4"
+                         "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x02\x00\x00\x00\x00",
+               .input  = "\x86\x0a\xc6\xa9\x1a\x9f\xe7\xe6"
+                         "\x64\x3b\x33\xd6\xd5\x84\xd6\xdf",
+               .ilen   = 16,
+               .result = "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x41\x42\x43\x44\x45\x46",
+               .rlen   = 16,
+       }, {
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\xe3\x5a\x38\x0f\x4d\x92\x3a\x74"
+                         "\x15\xb1\x50\x8c\x9a\xd8\x99\x1d"
+                         "\x82\xec\xf1\x5f\x03\x6d\x02\x58"
+                         "\x90\x67\xfc\xdd\x8d\xe1\x38\x08"
+                         "\x7b\xc9\x9b\x4b\x04\x09\x50\x15"
+                         "\xce\xab\xda\x33\x30\x20\x12\xfa"
+                         "\x83\xc4\xa6\x9a\x2e\x7d\x90\xd9"
+                         "\xa6\xa6\x67\x43\xb4\xa7\xa8\x5c"
+                         "\xbb\x6a\x49\x2b\x8b\xf8\xd0\x22"
+                         "\xe5\x9e\xba\xe8\x8c\x67\xb8\x5b"
+                         "\x60\xbc\xf5\xa4\x95\x4e\x66\xe5"
+                         "\x6d\x8e\xa9\xf6\x65\x2e\x04\xf5"
+                         "\xba\xb5\xdb\x88\xc2\xf6\x7a\x4b"
+                         "\x89\x58\x7c\x9a\xae\x26\xe8\xb7"
+                         "\xb7\x28\xcc\xd6\xcc\xa5\x98\x4d"
+                         "\xb9\x91\xcb\xb4\xe4\x8b\x96\x47"
+                         "\x5f\x03\x8b\xdd\x94\xd1\xee\x12"
+                         "\xa7\x83\x80\xf2\xc1\x15\x74\x4f"
+                         "\x49\xf9\xb0\x7e\x6f\xdc\x73\x2f"
+                         "\xe2\xcf\xe0\x1b\x34\xa5\xa0\x52"
+                         "\xfb\x3c\x5d\x85\x91\xe6\x6d\x98"
+                         "\x04\xd6\xdd\x4c\x00\x64\xd9\x54"
+                         "\x5c\x3c\x08\x1d\x4c\x06\x9f\xb8"
+                         "\x1c\x4d\x8d\xdc\xa4\x3c\xb9\x3b"
+                         "\x9e\x85\xce\xc3\xa8\x4a\x0c\xd9"
+                         "\x04\xc3\x6f\x17\x66\xa9\x1f\x59"
+                         "\xd9\xe2\x19\x36\xa3\x88\xb8\x0b"
+                         "\x0f\x4a\x4d\xf8\xc8\x6f\xd5\x43"
+                         "\xeb\xa0\xab\x1f\x61\xc0\x06\xeb"
+                         "\x93\xb7\xb8\x6f\x0d\xbd\x07\x49"
+                         "\xb3\xac\x5d\xcf\x31\xa0\x27\x26"
+                         "\x21\xbe\x94\x2e\x19\xea\xf4\xee"
+                         "\xb5\x13\x89\xf7\x94\x0b\xef\x59"
+                         "\x44\xc5\x78\x8b\x3c\x3b\x71\x20"
+                         "\xf9\x35\x0c\x70\x74\xdc\x5b\xc2"
+                         "\xb4\x11\x0e\x2c\x61\xa1\x52\x46"
+                         "\x18\x11\x16\xc6\x86\x44\xa7\xaf"
+                         "\xd5\x0c\x7d\xa6\x9e\x25\x2d\x1b"
+                         "\x9a\x8f\x0f\xf8\x6a\x61\xa0\xea"
+                         "\x3f\x0e\x90\xd6\x8f\x83\x30\x64"
+                         "\xb5\x51\x2d\x08\x3c\xcd\x99\x36"
+                         "\x96\xd4\xb1\xb5\x48\x30\xca\x48"
+                         "\xf7\x11\xa8\xf5\x97\x8a\x6a\x6d"
+                         "\x12\x33\x2f\xc0\xe8\xda\xec\x8a"
+                         "\xe1\x88\x72\x63\xde\x20\xa3\xe1"
+                         "\x8e\xac\x84\x37\x35\xf5\xf7\x3f"
+                         "\x00\x02\x0e\xe4\xc1\x53\x68\x3f"
+                         "\xaa\xd5\xac\x52\x3d\x20\x2f\x4d"
+                         "\x7c\x83\xd0\xbd\xaa\x97\x35\x36"
+                         "\x98\x88\x59\x5d\xe7\x24\xe3\x90"
+                         "\x9d\x30\x47\xa7\xc3\x60\x35\xf4"
+                         "\xd5\xdb\x0e\x4d\x44\xc1\x81\x8b"
+                         "\xfd\xbd\xc3\x2b\xba\x68\xfe\x8d"
+                         "\x49\x5a\x3c\x8a\xa3\x01\xae\x25"
+                         "\x42\xab\xd2\x87\x1b\x35\xd6\xd2"
+                         "\xd7\x70\x1c\x1f\x72\xd1\xe1\x39"
+                         "\x1c\x58\xa2\xb4\xd0\x78\x55\x72"
+                         "\x76\x59\xea\xd9\xd7\x6e\x63\x8b"
+                         "\xcc\x9b\xa7\x74\x89\xfc\xa3\x68"
+                         "\x86\x28\xd1\xbb\x54\x8d\x66\xad"
+                         "\x2a\x92\xf9\x4e\x04\x3d\xae\xfd"
+                         "\x1b\x2b\x7f\xc3\x2f\x1a\x78\x0a"
+                         "\x5c\xc6\x84\xfe\x7c\xcb\x26\xfd"
+                         "\xd9\x51\x0f\xd7\x94\x2f\xc5\xa7",
+               .ilen   = 512,
+               .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec serpent_xts_enc_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .ilen   = 32,
+               .result = "\xe1\x08\xb8\x1d\x2c\xf5\x33\x64"
+                         "\xc8\x12\x04\xc7\xb3\x70\xe8\xc4"
+                         "\x6a\x31\xc5\xf3\x00\xca\xb9\x16"
+                         "\xde\xe2\x77\x66\xf7\xfe\x62\x08",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\x1a\x0a\x09\x5f\xcd\x07\x07\x98"
+                         "\x41\x86\x12\xaf\xb3\xd7\x68\x13"
+                         "\xed\x81\xcd\x06\x87\x43\x1a\xbb"
+                         "\x13\x3d\xd6\x1e\x2b\xe1\x77\xbe",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .ilen   = 32,
+               .result = "\xf9\x9b\x28\xb8\x5c\xaf\x8c\x61"
+                         "\xb6\x1c\x81\x8f\x2c\x87\x60\x89"
+                         "\x0d\x8d\x7a\xe8\x60\x48\xcc\x86"
+                         "\xc1\x68\x45\xaa\x00\xe9\x24\xc5",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xfe\x47\x4a\xc8\x60\x7e\xb4\x8b"
+                         "\x0d\x10\xf4\xb0\x0d\xba\xf8\x53"
+                         "\x65\x6e\x38\x4b\xdb\xaa\xb1\x9e"
+                         "\x28\xca\xb0\x22\xb3\x85\x75\xf4"
+                         "\x00\x5c\x75\x14\x06\xd6\x25\x82"
+                         "\xe6\xcb\x08\xf7\x29\x90\x23\x8e"
+                         "\xa4\x68\x57\xe4\xf0\xd8\x32\xf3"
+                         "\x80\x51\x67\xb5\x0b\x85\x69\xe8"
+                         "\x19\xfe\xc4\xc7\x3e\xea\x90\xd3"
+                         "\x8f\xa3\xf2\x0a\xac\x17\x4b\xa0"
+                         "\x63\x5a\x16\x0f\xf0\xce\x66\x1f"
+                         "\x2c\x21\x07\xf1\xa4\x03\xa3\x44"
+                         "\x41\x61\x87\x5d\x6b\xb3\xef\xd4"
+                         "\xfc\xaa\x32\x7e\x55\x58\x04\x41"
+                         "\xc9\x07\x33\xc6\xa2\x68\xd6\x5a"
+                         "\x55\x79\x4b\x6f\xcf\x89\xb9\x19"
+                         "\xe5\x54\x13\x15\xb2\x1a\xfa\x15"
+                         "\xc2\xf0\x06\x59\xfa\xa0\x25\x05"
+                         "\x58\xfa\x43\x91\x16\x85\x40\xbb"
+                         "\x0d\x34\x4d\xc5\x1e\x20\xd5\x08"
+                         "\xcd\x22\x22\x41\x11\x9f\x6c\x7c"
+                         "\x8d\x57\xc9\xba\x57\xe8\x2c\xf7"
+                         "\xa0\x42\xa8\xde\xfc\xa3\xca\x98"
+                         "\x4b\x43\xb1\xce\x4b\xbf\x01\x67"
+                         "\x6e\x29\x60\xbd\x10\x14\x84\x82"
+                         "\x83\x82\x0c\x63\x73\x92\x02\x7c"
+                         "\x55\x37\x20\x80\x17\x51\xc8\xbc"
+                         "\x46\x02\xcb\x38\x07\x6d\xe2\x85"
+                         "\xaa\x29\xaf\x24\x58\x0d\xf0\x75"
+                         "\x08\x0a\xa5\x34\x25\x16\xf3\x74"
+                         "\xa7\x0b\x97\xbe\xc1\xa9\xdc\x29"
+                         "\x1a\x0a\x56\xc1\x1a\x91\x97\x8c"
+                         "\x0b\xc7\x16\xed\x5a\x22\xa6\x2e"
+                         "\x8c\x2b\x4f\x54\x76\x47\x53\x8e"
+                         "\xe8\x00\xec\x92\xb9\x55\xe6\xa2"
+                         "\xf3\xe2\x4f\x6a\x66\x60\xd0\x87"
+                         "\xe6\xd1\xcc\xe3\x6a\xc5\x2d\x21"
+                         "\xcc\x9d\x6a\xb6\x75\xaa\xe2\x19"
+                         "\x21\x9f\xa1\x5e\x4c\xfd\x72\xf9"
+                         "\x94\x4e\x63\xc7\xae\xfc\xed\x47"
+                         "\xe2\xfe\x7a\x63\x77\xfe\x97\x82"
+                         "\xb1\x10\x6e\x36\x1d\xe1\xc4\x80"
+                         "\xec\x69\x41\xec\xa7\x8a\xe0\x2f"
+                         "\xe3\x49\x26\xa2\x41\xb2\x08\x0f"
+                         "\x28\xb4\xa7\x39\xa1\x99\x2d\x1e"
+                         "\x43\x42\x35\xd0\xcf\xec\x77\x67"
+                         "\xb2\x3b\x9e\x1c\x35\xde\x4f\x5e"
+                         "\x73\x3f\x5d\x6f\x07\x4b\x2e\x50"
+                         "\xab\x6c\x6b\xff\xea\x00\x67\xaa"
+                         "\x0e\x82\x32\xdd\x3d\xb5\xe5\x76"
+                         "\x2b\x77\x3f\xbe\x12\x75\xfb\x92"
+                         "\xc6\x89\x67\x4d\xca\xf7\xd4\x50"
+                         "\xc0\x74\x47\xcc\xd9\x0a\xd4\xc6"
+                         "\x3b\x17\x2e\xe3\x35\xbb\x53\xb5"
+                         "\x86\xad\x51\xcc\xd5\x96\xb8\xdc"
+                         "\x03\x57\xe6\x98\x52\x2f\x61\x62"
+                         "\xc4\x5c\x9c\x36\x71\x07\xfb\x94"
+                         "\xe3\x02\xc4\x2b\x08\x75\xc7\x35"
+                         "\xfb\x2e\x88\x7b\xbb\x67\x00\xe1"
+                         "\xc9\xdd\x99\xb2\x13\x53\x1a\x4e"
+                         "\x76\x87\x19\x04\x1a\x2f\x38\x3e"
+                         "\xef\x91\x64\x1d\x18\x07\x4e\x31"
+                         "\x88\x21\x7c\xb0\xa5\x12\x4c\x3c"
+                         "\xb0\x20\xbd\xda\xdf\xf9\x7c\xdd",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\x2b\xc9\xb4\x6b\x10\x94\xa9\x32"
+                         "\xaa\xb0\x20\xc6\x44\x3d\x74\x1f"
+                         "\x75\x01\xa7\xf6\xf5\xf7\x62\x1b"
+                         "\x80\x1b\x82\xcb\x01\x59\x91\x7f"
+                         "\x80\x3a\x98\xf0\xd2\xca\xc4\xc3"
+                         "\x34\xfd\xe6\x11\xf9\x33\x45\x12"
+                         "\x48\xc5\x8c\x25\xf1\xc5\xc5\x23"
+                         "\xd3\x44\xb4\x73\xd5\x04\xc0\xb7"
+                         "\xca\x2f\xf5\xcd\xc5\xb4\xdd\xb0"
+                         "\xf4\x60\xe8\xfb\xc6\x9c\xc5\x78"
+                         "\xcd\xec\x7d\xdc\x19\x9c\x72\x64"
+                         "\x63\x0b\x38\x2e\x76\xdd\x2d\x36"
+                         "\x49\xb0\x1d\xea\x78\x9e\x00\xca"
+                         "\x20\xcc\x1b\x1e\x98\x74\xab\xed"
+                         "\x79\xf7\xd0\x6c\xd8\x93\x80\x29"
+                         "\xac\xa5\x5e\x34\xa9\xab\xa0\x55"
+                         "\x9a\xea\xaa\x95\x4d\x7b\xfe\x46"
+                         "\x26\x8a\xfd\x88\xa2\xa8\xa6\xae"
+                         "\x25\x42\x17\xbf\x76\x8f\x1c\x3d"
+                         "\xec\x9a\xda\x64\x96\xb5\x61\xff"
+                         "\x99\xeb\x12\x96\x85\x82\x9d\xd5"
+                         "\x81\x85\x14\xa8\x59\xac\x8c\x94"
+                         "\xbb\x3b\x85\x2b\xdf\xb3\x0c\xba"
+                         "\x82\xc6\x4d\xca\x86\xea\x53\x28"
+                         "\x4c\xe0\x4e\x31\xe3\x73\x2f\x79"
+                         "\x9d\x42\xe1\x03\xe3\x8b\xc4\xff"
+                         "\x05\xca\x81\x7b\xda\xa2\xde\x63"
+                         "\x3a\x10\xbe\xc2\xac\x32\xc4\x05"
+                         "\x47\x7e\xef\x67\xe2\x5f\x5b\xae"
+                         "\xed\xf1\x70\x34\x16\x9a\x07\x7b"
+                         "\xf2\x25\x2b\xb0\xf8\x3c\x15\x9a"
+                         "\xa6\x59\x55\x5f\xc1\xf4\x1e\xcd"
+                         "\x93\x1f\x06\xba\xd4\x9a\x22\x69"
+                         "\xfa\x8e\x95\x0d\xf3\x23\x59\x2c"
+                         "\xfe\x00\xba\xf0\x0e\xbc\x6d\xd6"
+                         "\x62\xf0\x7a\x0e\x83\x3e\xdb\x32"
+                         "\xfd\x43\x7d\xda\x42\x51\x87\x43"
+                         "\x9d\xf9\xef\xf4\x30\x97\xf8\x09"
+                         "\x88\xfc\x3f\x93\x70\xc1\x4a\xec"
+                         "\x27\x5f\x11\xac\x71\xc7\x48\x46"
+                         "\x2f\xf9\xdf\x8d\x9f\xf7\x2e\x56"
+                         "\x0d\x4e\xb0\x32\x76\xce\x86\x81"
+                         "\xcd\xdf\xe4\x00\xbf\xfd\x5f\x24"
+                         "\xaf\xf7\x9a\xde\xff\x18\xac\x14"
+                         "\x90\xc5\x01\x39\x34\x0f\x24\xf3"
+                         "\x13\x2f\x5e\x4f\x30\x9a\x36\x40"
+                         "\xec\xea\xbc\xcd\x9e\x0e\x5b\x23"
+                         "\x50\x88\x97\x40\x69\xb1\x37\xf5"
+                         "\xc3\x15\xf9\x3f\xb7\x79\x64\xe8"
+                         "\x7b\x10\x20\xb9\x2b\x46\x83\x5b"
+                         "\xd8\x39\xfc\xe4\xfa\x88\x52\xf2"
+                         "\x72\xb0\x97\x4e\x89\xb3\x48\x00"
+                         "\xc1\x16\x73\x50\x77\xba\xa6\x65"
+                         "\x20\x2d\xb0\x02\x27\x89\xda\x99"
+                         "\x45\xfb\xe9\xd3\x1d\x39\x2f\xd6"
+                         "\x2a\xda\x09\x12\x11\xaf\xe6\x57"
+                         "\x01\x04\x8a\xff\x86\x8b\xac\xf8"
+                         "\xee\xe4\x1c\x98\x5b\xcf\x6b\x76"
+                         "\xa3\x0e\x33\x74\x40\x18\x39\x72"
+                         "\x66\x50\x31\xfd\x70\xdf\xe8\x51"
+                         "\x96\x21\x36\xb2\x9b\xfa\x85\xd1"
+                         "\x30\x05\xc8\x92\x98\x80\xff\x7a"
+                         "\xaf\x43\x0b\xc5\x20\x41\x92\x20"
+                         "\xd4\xa0\x91\x98\x11\x5f\x4d\xb1",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec serpent_xts_dec_tv_template[] = {
+       /* Generated from AES-XTS test vectors */
+       /* same as enc vectors with input and result reversed */
+       {
+               .key    = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xe1\x08\xb8\x1d\x2c\xf5\x33\x64"
+                         "\xc8\x12\x04\xc7\xb3\x70\xe8\xc4"
+                         "\x6a\x31\xc5\xf3\x00\xca\xb9\x16"
+                         "\xde\xe2\x77\x66\xf7\xfe\x62\x08",
+               .ilen   = 32,
+               .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .rlen   = 32,
+       }, {
+               .key    = "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x11\x11\x11\x11\x11\x11\x11\x11"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x1a\x0a\x09\x5f\xcd\x07\x07\x98"
+                         "\x41\x86\x12\xaf\xb3\xd7\x68\x13"
+                         "\xed\x81\xcd\x06\x87\x43\x1a\xbb"
+                         "\x13\x3d\xd6\x1e\x2b\xe1\x77\xbe",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8"
+                         "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22"
+                         "\x22\x22\x22\x22\x22\x22\x22\x22",
+               .klen   = 32,
+               .iv     = "\x33\x33\x33\x33\x33\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xf9\x9b\x28\xb8\x5c\xaf\x8c\x61"
+                         "\xb6\x1c\x81\x8f\x2c\x87\x60\x89"
+                         "\x0d\x8d\x7a\xe8\x60\x48\xcc\x86"
+                         "\xc1\x68\x45\xaa\x00\xe9\x24\xc5",
+               .ilen   = 32,
+               .result = "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44"
+                         "\x44\x44\x44\x44\x44\x44\x44\x44",
+               .rlen   = 32,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95",
+               .klen   = 32,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xfe\x47\x4a\xc8\x60\x7e\xb4\x8b"
+                         "\x0d\x10\xf4\xb0\x0d\xba\xf8\x53"
+                         "\x65\x6e\x38\x4b\xdb\xaa\xb1\x9e"
+                         "\x28\xca\xb0\x22\xb3\x85\x75\xf4"
+                         "\x00\x5c\x75\x14\x06\xd6\x25\x82"
+                         "\xe6\xcb\x08\xf7\x29\x90\x23\x8e"
+                         "\xa4\x68\x57\xe4\xf0\xd8\x32\xf3"
+                         "\x80\x51\x67\xb5\x0b\x85\x69\xe8"
+                         "\x19\xfe\xc4\xc7\x3e\xea\x90\xd3"
+                         "\x8f\xa3\xf2\x0a\xac\x17\x4b\xa0"
+                         "\x63\x5a\x16\x0f\xf0\xce\x66\x1f"
+                         "\x2c\x21\x07\xf1\xa4\x03\xa3\x44"
+                         "\x41\x61\x87\x5d\x6b\xb3\xef\xd4"
+                         "\xfc\xaa\x32\x7e\x55\x58\x04\x41"
+                         "\xc9\x07\x33\xc6\xa2\x68\xd6\x5a"
+                         "\x55\x79\x4b\x6f\xcf\x89\xb9\x19"
+                         "\xe5\x54\x13\x15\xb2\x1a\xfa\x15"
+                         "\xc2\xf0\x06\x59\xfa\xa0\x25\x05"
+                         "\x58\xfa\x43\x91\x16\x85\x40\xbb"
+                         "\x0d\x34\x4d\xc5\x1e\x20\xd5\x08"
+                         "\xcd\x22\x22\x41\x11\x9f\x6c\x7c"
+                         "\x8d\x57\xc9\xba\x57\xe8\x2c\xf7"
+                         "\xa0\x42\xa8\xde\xfc\xa3\xca\x98"
+                         "\x4b\x43\xb1\xce\x4b\xbf\x01\x67"
+                         "\x6e\x29\x60\xbd\x10\x14\x84\x82"
+                         "\x83\x82\x0c\x63\x73\x92\x02\x7c"
+                         "\x55\x37\x20\x80\x17\x51\xc8\xbc"
+                         "\x46\x02\xcb\x38\x07\x6d\xe2\x85"
+                         "\xaa\x29\xaf\x24\x58\x0d\xf0\x75"
+                         "\x08\x0a\xa5\x34\x25\x16\xf3\x74"
+                         "\xa7\x0b\x97\xbe\xc1\xa9\xdc\x29"
+                         "\x1a\x0a\x56\xc1\x1a\x91\x97\x8c"
+                         "\x0b\xc7\x16\xed\x5a\x22\xa6\x2e"
+                         "\x8c\x2b\x4f\x54\x76\x47\x53\x8e"
+                         "\xe8\x00\xec\x92\xb9\x55\xe6\xa2"
+                         "\xf3\xe2\x4f\x6a\x66\x60\xd0\x87"
+                         "\xe6\xd1\xcc\xe3\x6a\xc5\x2d\x21"
+                         "\xcc\x9d\x6a\xb6\x75\xaa\xe2\x19"
+                         "\x21\x9f\xa1\x5e\x4c\xfd\x72\xf9"
+                         "\x94\x4e\x63\xc7\xae\xfc\xed\x47"
+                         "\xe2\xfe\x7a\x63\x77\xfe\x97\x82"
+                         "\xb1\x10\x6e\x36\x1d\xe1\xc4\x80"
+                         "\xec\x69\x41\xec\xa7\x8a\xe0\x2f"
+                         "\xe3\x49\x26\xa2\x41\xb2\x08\x0f"
+                         "\x28\xb4\xa7\x39\xa1\x99\x2d\x1e"
+                         "\x43\x42\x35\xd0\xcf\xec\x77\x67"
+                         "\xb2\x3b\x9e\x1c\x35\xde\x4f\x5e"
+                         "\x73\x3f\x5d\x6f\x07\x4b\x2e\x50"
+                         "\xab\x6c\x6b\xff\xea\x00\x67\xaa"
+                         "\x0e\x82\x32\xdd\x3d\xb5\xe5\x76"
+                         "\x2b\x77\x3f\xbe\x12\x75\xfb\x92"
+                         "\xc6\x89\x67\x4d\xca\xf7\xd4\x50"
+                         "\xc0\x74\x47\xcc\xd9\x0a\xd4\xc6"
+                         "\x3b\x17\x2e\xe3\x35\xbb\x53\xb5"
+                         "\x86\xad\x51\xcc\xd5\x96\xb8\xdc"
+                         "\x03\x57\xe6\x98\x52\x2f\x61\x62"
+                         "\xc4\x5c\x9c\x36\x71\x07\xfb\x94"
+                         "\xe3\x02\xc4\x2b\x08\x75\xc7\x35"
+                         "\xfb\x2e\x88\x7b\xbb\x67\x00\xe1"
+                         "\xc9\xdd\x99\xb2\x13\x53\x1a\x4e"
+                         "\x76\x87\x19\x04\x1a\x2f\x38\x3e"
+                         "\xef\x91\x64\x1d\x18\x07\x4e\x31"
+                         "\x88\x21\x7c\xb0\xa5\x12\x4c\x3c"
+                         "\xb0\x20\xbd\xda\xdf\xf9\x7c\xdd",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       }, {
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x2b\xc9\xb4\x6b\x10\x94\xa9\x32"
+                         "\xaa\xb0\x20\xc6\x44\x3d\x74\x1f"
+                         "\x75\x01\xa7\xf6\xf5\xf7\x62\x1b"
+                         "\x80\x1b\x82\xcb\x01\x59\x91\x7f"
+                         "\x80\x3a\x98\xf0\xd2\xca\xc4\xc3"
+                         "\x34\xfd\xe6\x11\xf9\x33\x45\x12"
+                         "\x48\xc5\x8c\x25\xf1\xc5\xc5\x23"
+                         "\xd3\x44\xb4\x73\xd5\x04\xc0\xb7"
+                         "\xca\x2f\xf5\xcd\xc5\xb4\xdd\xb0"
+                         "\xf4\x60\xe8\xfb\xc6\x9c\xc5\x78"
+                         "\xcd\xec\x7d\xdc\x19\x9c\x72\x64"
+                         "\x63\x0b\x38\x2e\x76\xdd\x2d\x36"
+                         "\x49\xb0\x1d\xea\x78\x9e\x00\xca"
+                         "\x20\xcc\x1b\x1e\x98\x74\xab\xed"
+                         "\x79\xf7\xd0\x6c\xd8\x93\x80\x29"
+                         "\xac\xa5\x5e\x34\xa9\xab\xa0\x55"
+                         "\x9a\xea\xaa\x95\x4d\x7b\xfe\x46"
+                         "\x26\x8a\xfd\x88\xa2\xa8\xa6\xae"
+                         "\x25\x42\x17\xbf\x76\x8f\x1c\x3d"
+                         "\xec\x9a\xda\x64\x96\xb5\x61\xff"
+                         "\x99\xeb\x12\x96\x85\x82\x9d\xd5"
+                         "\x81\x85\x14\xa8\x59\xac\x8c\x94"
+                         "\xbb\x3b\x85\x2b\xdf\xb3\x0c\xba"
+                         "\x82\xc6\x4d\xca\x86\xea\x53\x28"
+                         "\x4c\xe0\x4e\x31\xe3\x73\x2f\x79"
+                         "\x9d\x42\xe1\x03\xe3\x8b\xc4\xff"
+                         "\x05\xca\x81\x7b\xda\xa2\xde\x63"
+                         "\x3a\x10\xbe\xc2\xac\x32\xc4\x05"
+                         "\x47\x7e\xef\x67\xe2\x5f\x5b\xae"
+                         "\xed\xf1\x70\x34\x16\x9a\x07\x7b"
+                         "\xf2\x25\x2b\xb0\xf8\x3c\x15\x9a"
+                         "\xa6\x59\x55\x5f\xc1\xf4\x1e\xcd"
+                         "\x93\x1f\x06\xba\xd4\x9a\x22\x69"
+                         "\xfa\x8e\x95\x0d\xf3\x23\x59\x2c"
+                         "\xfe\x00\xba\xf0\x0e\xbc\x6d\xd6"
+                         "\x62\xf0\x7a\x0e\x83\x3e\xdb\x32"
+                         "\xfd\x43\x7d\xda\x42\x51\x87\x43"
+                         "\x9d\xf9\xef\xf4\x30\x97\xf8\x09"
+                         "\x88\xfc\x3f\x93\x70\xc1\x4a\xec"
+                         "\x27\x5f\x11\xac\x71\xc7\x48\x46"
+                         "\x2f\xf9\xdf\x8d\x9f\xf7\x2e\x56"
+                         "\x0d\x4e\xb0\x32\x76\xce\x86\x81"
+                         "\xcd\xdf\xe4\x00\xbf\xfd\x5f\x24"
+                         "\xaf\xf7\x9a\xde\xff\x18\xac\x14"
+                         "\x90\xc5\x01\x39\x34\x0f\x24\xf3"
+                         "\x13\x2f\x5e\x4f\x30\x9a\x36\x40"
+                         "\xec\xea\xbc\xcd\x9e\x0e\x5b\x23"
+                         "\x50\x88\x97\x40\x69\xb1\x37\xf5"
+                         "\xc3\x15\xf9\x3f\xb7\x79\x64\xe8"
+                         "\x7b\x10\x20\xb9\x2b\x46\x83\x5b"
+                         "\xd8\x39\xfc\xe4\xfa\x88\x52\xf2"
+                         "\x72\xb0\x97\x4e\x89\xb3\x48\x00"
+                         "\xc1\x16\x73\x50\x77\xba\xa6\x65"
+                         "\x20\x2d\xb0\x02\x27\x89\xda\x99"
+                         "\x45\xfb\xe9\xd3\x1d\x39\x2f\xd6"
+                         "\x2a\xda\x09\x12\x11\xaf\xe6\x57"
+                         "\x01\x04\x8a\xff\x86\x8b\xac\xf8"
+                         "\xee\xe4\x1c\x98\x5b\xcf\x6b\x76"
+                         "\xa3\x0e\x33\x74\x40\x18\x39\x72"
+                         "\x66\x50\x31\xfd\x70\xdf\xe8\x51"
+                         "\x96\x21\x36\xb2\x9b\xfa\x85\xd1"
+                         "\x30\x05\xc8\x92\x98\x80\xff\x7a"
+                         "\xaf\x43\x0b\xc5\x20\x41\x92\x20"
+                         "\xd4\xa0\x91\x98\x11\x5f\x4d\xb1",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       },
+};
 
 /* Cast6 test vectors from RFC 2612 */
 #define CAST6_ENC_TEST_VECTORS 3
index 0af216c75d7ea8f41666be90c201f757e029ef1b..5f62c4f9f6e0a50f01f86026180fec0cce301305 100644 (file)
@@ -580,12 +580,9 @@ static const u8 calc_sb_tbl[512] = {
    ctx->a[(j) + 1] = rol32(y, 9)
 
 /* Perform the key setup. */
-int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
+int __twofish_setkey(struct twofish_ctx *ctx, const u8 *key,
+                    unsigned int key_len, u32 *flags)
 {
-
-       struct twofish_ctx *ctx = crypto_tfm_ctx(tfm);
-       u32 *flags = &tfm->crt_flags;
-
        int i, j, k;
 
        /* Temporaries for CALC_K. */
@@ -701,7 +698,13 @@ int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(__twofish_setkey);
 
+int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
+{
+       return __twofish_setkey(crypto_tfm_ctx(tfm), key, key_len,
+                               &tfm->crt_flags);
+}
 EXPORT_SYMBOL_GPL(twofish_setkey);
 
 MODULE_LICENSE("GPL");
index 851705446c8201f13232ff3d8fce6956c99d72e4..ca1608f44cb56617d1b9e1d721d4a6dc12bca041 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 
+#include <crypto/xts.h>
 #include <crypto/b128ops.h>
 #include <crypto/gf128mul.h>
 
@@ -96,7 +97,7 @@ static int crypt(struct blkcipher_desc *d,
 {
        int err;
        unsigned int avail;
-       const int bs = crypto_cipher_blocksize(ctx->child);
+       const int bs = XTS_BLOCK_SIZE;
        struct sinfo s = {
                .tfm = crypto_cipher_tfm(ctx->child),
                .fn = fn
@@ -165,6 +166,78 @@ static int decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
                     crypto_cipher_alg(ctx->child)->cia_decrypt);
 }
 
+int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *sdst,
+             struct scatterlist *ssrc, unsigned int nbytes,
+             struct xts_crypt_req *req)
+{
+       const unsigned int bsize = XTS_BLOCK_SIZE;
+       const unsigned int max_blks = req->tbuflen / bsize;
+       struct blkcipher_walk walk;
+       unsigned int nblocks;
+       be128 *src, *dst, *t;
+       be128 *t_buf = req->tbuf;
+       int err, i;
+
+       BUG_ON(max_blks < 1);
+
+       blkcipher_walk_init(&walk, sdst, ssrc, nbytes);
+
+       err = blkcipher_walk_virt(desc, &walk);
+       nbytes = walk.nbytes;
+       if (!nbytes)
+               return err;
+
+       nblocks = min(nbytes / bsize, max_blks);
+       src = (be128 *)walk.src.virt.addr;
+       dst = (be128 *)walk.dst.virt.addr;
+
+       /* calculate first value of T */
+       req->tweak_fn(req->tweak_ctx, (u8 *)&t_buf[0], walk.iv);
+
+       i = 0;
+       goto first;
+
+       for (;;) {
+               do {
+                       for (i = 0; i < nblocks; i++) {
+                               gf128mul_x_ble(&t_buf[i], t);
+first:
+                               t = &t_buf[i];
+
+                               /* PP <- T xor P */
+                               be128_xor(dst + i, t, src + i);
+                       }
+
+                       /* CC <- E(Key2,PP) */
+                       req->crypt_fn(req->crypt_ctx, (u8 *)dst,
+                                     nblocks * bsize);
+
+                       /* C <- T xor CC */
+                       for (i = 0; i < nblocks; i++)
+                               be128_xor(dst + i, dst + i, &t_buf[i]);
+
+                       src += nblocks;
+                       dst += nblocks;
+                       nbytes -= nblocks * bsize;
+                       nblocks = min(nbytes / bsize, max_blks);
+               } while (nblocks > 0);
+
+               *(be128 *)walk.iv = *t;
+
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+               nbytes = walk.nbytes;
+               if (!nbytes)
+                       break;
+
+               nblocks = min(nbytes / bsize, max_blks);
+               src = (be128 *)walk.src.virt.addr;
+               dst = (be128 *)walk.dst.virt.addr;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(xts_crypt);
+
 static int init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_cipher *cipher;
@@ -177,7 +250,7 @@ static int init_tfm(struct crypto_tfm *tfm)
        if (IS_ERR(cipher))
                return PTR_ERR(cipher);
 
-       if (crypto_cipher_blocksize(cipher) != 16) {
+       if (crypto_cipher_blocksize(cipher) != XTS_BLOCK_SIZE) {
                *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
                crypto_free_cipher(cipher);
                return -EINVAL;
@@ -192,7 +265,7 @@ static int init_tfm(struct crypto_tfm *tfm)
        }
 
        /* this check isn't really needed, leave it here just in case */
-       if (crypto_cipher_blocksize(cipher) != 16) {
+       if (crypto_cipher_blocksize(cipher) != XTS_BLOCK_SIZE) {
                crypto_free_cipher(cipher);
                crypto_free_cipher(ctx->child);
                *flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
index 1b3142127bf5f7308f3e7fc9fb83ff88a4730f2e..c07be024b962aa9ad8cce1ef635f37acd0a18fae 100644 (file)
@@ -97,7 +97,7 @@ obj-$(CONFIG_EISA)            += eisa/
 obj-y                          += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
-obj-$(CONFIG_MMC)              += mmc/
+obj-y                          += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-y                          += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
index 7f9eba9a0b02ce98a9a7bc9aa5ecf865ece618bf..0eefa12e648ca67f04aebaaaf0b1f3ade5095662 100644 (file)
@@ -487,10 +487,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
        else
                link_desc[0] = '\0';
 
-       dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
-                pin_name(pin), link_desc, gsi,
-                (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
-                (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
+       dev_dbg(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
+               pin_name(pin), link_desc, gsi,
+               (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+               (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
 
        return 0;
 }
@@ -524,6 +524,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
         * (e.g. PCI_UNDEFINED_IRQ).
         */
 
-       dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
+       dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
        acpi_unregister_gsi(gsi);
 }
index e95c67edb2cba54f4f314f36716f47bb71bfa5ae..7be9f79018e9e722439a0055c8a23dcf58f79e97 100644 (file)
@@ -172,10 +172,14 @@ config SYS_HYPERVISOR
        bool
        default n
 
+config GENERIC_CPU_DEVICES
+       bool
+       default n
+
 source "drivers/base/regmap/Kconfig"
 
 config DMA_SHARED_BUFFER
-       bool "Buffer framework to be shared between drivers"
+       bool
        default n
        select ANON_INODES
        depends on EXPERIMENTAL
index 7a6ae4228761542bdc2e1f35ee8e446b38d57375..b858dfd9a37c93df9f39ba86cd0f7f6087b15c5b 100644 (file)
@@ -94,7 +94,7 @@ extern int hypervisor_init(void);
 static inline int hypervisor_init(void) { return 0; }
 #endif
 extern int platform_bus_init(void);
-extern int cpu_dev_init(void);
+extern void cpu_dev_init(void);
 
 extern int bus_add_device(struct device *dev);
 extern void bus_probe_device(struct device *dev);
index 9a5578efbc9368437c559ba4ed358560721b512b..db87e78d745940a3ba19332799930057edfd0615 100644 (file)
@@ -2,6 +2,7 @@
  * CPU subsystem support
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -10,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/node.h>
 #include <linux/gfp.h>
+#include <linux/percpu.h>
 
 #include "base.h"
 
@@ -274,16 +276,30 @@ bool cpu_is_hotpluggable(unsigned cpu)
 }
 EXPORT_SYMBOL_GPL(cpu_is_hotpluggable);
 
-int __init cpu_dev_init(void)
+#ifdef CONFIG_GENERIC_CPU_DEVICES
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+#endif
+
+static void __init cpu_dev_register_generic(void)
+{
+#ifdef CONFIG_GENERIC_CPU_DEVICES
+       int i;
+
+       for_each_possible_cpu(i) {
+               if (register_cpu(&per_cpu(cpu_devices, i), i))
+                       panic("Failed to register CPU device");
+       }
+#endif
+}
+
+void __init cpu_dev_init(void)
 {
-       int err;
+       if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
+               panic("Failed to register CPU subsystem");
 
-       err = subsys_system_register(&cpu_subsys, cpu_root_attr_groups);
-       if (err)
-               return err;
+       cpu_dev_register_generic();
 
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-       err = sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
+       sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
 #endif
-       return err;
 }
index f17e3ea041c0565bc3b9e2af2798c196eeb4c4b2..ed5de58c340f25e7c20b6db4189b279dd3110a2f 100644 (file)
@@ -295,11 +295,22 @@ static int memory_block_change_state(struct memory_block *mem,
 
        ret = memory_block_action(mem->start_section_nr, to_state);
 
-       if (ret)
+       if (ret) {
                mem->state = from_state_req;
-       else
-               mem->state = to_state;
+               goto out;
+       }
 
+       mem->state = to_state;
+       switch (mem->state) {
+       case MEM_OFFLINE:
+               kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
+               break;
+       case MEM_ONLINE:
+               kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
+               break;
+       default:
+               break;
+       }
 out:
        mutex_unlock(&mem->state_mutex);
        return ret;
index 148ab944378d57bdaec596e96bed6dc131777a28..3fd31dec8c9c1980fcdc8f7aa95b28d23addcb5b 100644 (file)
@@ -2184,6 +2184,8 @@ static ssize_t rbd_add(struct bus_type *bus,
        INIT_LIST_HEAD(&rbd_dev->node);
        INIT_LIST_HEAD(&rbd_dev->snaps);
 
+       init_rwsem(&rbd_dev->header.snap_rwsem);
+
        /* generate unique id: find highest unique id, add one */
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
 
index 4d0b70adf5f73356bb79fafc06927b5f33207a64..ffd5ca919295fd171b6dcc9217f0aed0a600375f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
 #include <linux/scatterlist.h>
@@ -36,6 +37,12 @@ struct virtio_blk
        /* Process context for config space updates */
        struct work_struct config_work;
 
+       /* Lock for config space updates */
+       struct mutex config_lock;
+
+       /* enable config space updates */
+       bool config_enable;
+
        /* What host tells us, plus 2 for header & tailer. */
        unsigned int sg_elems;
 
@@ -172,7 +179,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
                }
        }
 
-       if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
+       if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr, GFP_ATOMIC)<0) {
                mempool_free(vbr, vblk->pool);
                return false;
        }
@@ -318,6 +325,10 @@ static void virtblk_config_changed_work(struct work_struct *work)
        char cap_str_2[10], cap_str_10[10];
        u64 capacity, size;
 
+       mutex_lock(&vblk->config_lock);
+       if (!vblk->config_enable)
+               goto done;
+
        /* Host must always specify the capacity. */
        vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
                          &capacity, sizeof(capacity));
@@ -340,6 +351,8 @@ static void virtblk_config_changed_work(struct work_struct *work)
                  cap_str_10, cap_str_2);
 
        set_capacity(vblk->disk, capacity);
+done:
+       mutex_unlock(&vblk->config_lock);
 }
 
 static void virtblk_config_changed(struct virtio_device *vdev)
@@ -349,6 +362,18 @@ static void virtblk_config_changed(struct virtio_device *vdev)
        queue_work(virtblk_wq, &vblk->config_work);
 }
 
+static int init_vq(struct virtio_blk *vblk)
+{
+       int err = 0;
+
+       /* We expect one virtqueue, for output. */
+       vblk->vq = virtio_find_single_vq(vblk->vdev, blk_done, "requests");
+       if (IS_ERR(vblk->vq))
+               err = PTR_ERR(vblk->vq);
+
+       return err;
+}
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -388,14 +413,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->vdev = vdev;
        vblk->sg_elems = sg_elems;
        sg_init_table(vblk->sg, vblk->sg_elems);
+       mutex_init(&vblk->config_lock);
        INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
+       vblk->config_enable = true;
 
-       /* We expect one virtqueue, for output. */
-       vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
-       if (IS_ERR(vblk->vq)) {
-               err = PTR_ERR(vblk->vq);
+       err = init_vq(vblk);
+       if (err)
                goto out_free_vblk;
-       }
 
        vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
        if (!vblk->pool) {
@@ -542,7 +566,10 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        struct virtio_blk *vblk = vdev->priv;
        int index = vblk->index;
 
-       flush_work(&vblk->config_work);
+       /* Prevent config work handler from accessing the device. */
+       mutex_lock(&vblk->config_lock);
+       vblk->config_enable = false;
+       mutex_unlock(&vblk->config_lock);
 
        /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
@@ -550,6 +577,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        /* Stop all the virtqueues. */
        vdev->config->reset(vdev);
 
+       flush_work(&vblk->config_work);
+
        del_gendisk(vblk->disk);
        blk_cleanup_queue(vblk->disk->queue);
        put_disk(vblk->disk);
@@ -559,6 +588,46 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
        ida_simple_remove(&vd_index_ida, index);
 }
 
+#ifdef CONFIG_PM
+static int virtblk_freeze(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+
+       /* Ensure we don't receive any more interrupts */
+       vdev->config->reset(vdev);
+
+       /* Prevent config work handler from accessing the device. */
+       mutex_lock(&vblk->config_lock);
+       vblk->config_enable = false;
+       mutex_unlock(&vblk->config_lock);
+
+       flush_work(&vblk->config_work);
+
+       spin_lock_irq(vblk->disk->queue->queue_lock);
+       blk_stop_queue(vblk->disk->queue);
+       spin_unlock_irq(vblk->disk->queue->queue_lock);
+       blk_sync_queue(vblk->disk->queue);
+
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int virtblk_restore(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+       int ret;
+
+       vblk->config_enable = true;
+       ret = init_vq(vdev->priv);
+       if (!ret) {
+               spin_lock_irq(vblk->disk->queue->queue_lock);
+               blk_start_queue(vblk->disk->queue);
+               spin_unlock_irq(vblk->disk->queue->queue_lock);
+       }
+       return ret;
+}
+#endif
+
 static const struct virtio_device_id id_table[] = {
        { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -584,6 +653,10 @@ static struct virtio_driver __refdata virtio_blk = {
        .probe                  = virtblk_probe,
        .remove                 = __devexit_p(virtblk_remove),
        .config_changed         = virtblk_config_changed,
+#ifdef CONFIG_PM
+       .freeze                 = virtblk_freeze,
+       .restore                = virtblk_restore,
+#endif
 };
 
 static int __init init(void)
index fb1975d82a73abbf6cab4d76d1ea593da7093e57..1a17e338735e363b3ebdf7624aca334d507144c9 100644 (file)
@@ -456,7 +456,7 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace)
 {
        dev_dbg(ace->dev, "ace_fsm_yieldirq()\n");
 
-       if (ace->irq == NO_IRQ)
+       if (!ace->irq)
                /* No IRQ assigned, so need to poll */
                tasklet_schedule(&ace->fsm_tasklet);
        ace->fsm_continue_flag = 0;
@@ -1034,12 +1034,12 @@ static int __devinit ace_setup(struct ace_device *ace)
                ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
 
        /* Now we can hook up the irq handler */
-       if (ace->irq != NO_IRQ) {
+       if (ace->irq) {
                rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
                if (rc) {
                        /* Failure - fall back to polled mode */
                        dev_err(ace->dev, "request_irq failed\n");
-                       ace->irq = NO_IRQ;
+                       ace->irq = 0;
                }
        }
 
@@ -1086,7 +1086,7 @@ static void __devexit ace_teardown(struct ace_device *ace)
 
        tasklet_kill(&ace->fsm_tasklet);
 
-       if (ace->irq != NO_IRQ)
+       if (ace->irq)
                free_irq(ace->irq, ace);
 
        iounmap(ace->baseaddr);
@@ -1156,7 +1156,7 @@ static int __devinit ace_probe(struct platform_device *dev)
        resource_size_t physaddr = 0;
        int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
        u32 id = dev->id;
-       int irq = NO_IRQ;
+       int irq = 0;
        int i;
 
        dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
index 241df2e76aba2604d24d8cc451df52d0e1bafac5..f518b99f53f5b995a3c8f9cd5d8ff616a62d3855 100644 (file)
@@ -141,17 +141,7 @@ static struct platform_driver atmel_trng_driver = {
        },
 };
 
-static int __init atmel_trng_init(void)
-{
-       return platform_driver_register(&atmel_trng_driver);
-}
-module_init(atmel_trng_init);
-
-static void __exit atmel_trng_exit(void)
-{
-       platform_driver_unregister(&atmel_trng_driver);
-}
-module_exit(atmel_trng_exit);
+module_platform_driver(atmel_trng_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
index c3de70de00d4c13f4d50e2a7e455bda2a4434fc6..ebd48f0135dae66dfd313ed9024b32f53bb4e125 100644 (file)
@@ -770,15 +770,4 @@ static struct platform_driver n2rng_driver = {
        .remove         = __devexit_p(n2rng_remove),
 };
 
-static int __init n2rng_init(void)
-{
-       return platform_driver_register(&n2rng_driver);
-}
-
-static void __exit n2rng_exit(void)
-{
-       platform_driver_unregister(&n2rng_driver);
-}
-
-module_init(n2rng_init);
-module_exit(n2rng_exit);
+module_platform_driver(n2rng_driver);
index 9cd0feca318c3e5f7f9bde8bce6932dbc0be4eba..0943edc782a16fcf789df1d2c7f12e4ffe54659e 100644 (file)
@@ -131,18 +131,7 @@ static struct platform_driver octeon_rng_driver = {
        .remove         = __exit_p(octeon_rng_remove),
 };
 
-static int __init octeon_rng_mod_init(void)
-{
-       return platform_driver_register(&octeon_rng_driver);
-}
-
-static void __exit octeon_rng_mod_exit(void)
-{
-       platform_driver_unregister(&octeon_rng_driver);
-}
-
-module_init(octeon_rng_mod_init);
-module_exit(octeon_rng_mod_exit);
+module_platform_driver(octeon_rng_driver);
 
 MODULE_AUTHOR("David Daney");
 MODULE_LICENSE("GPL");
index 1d504815e6db2cb8f4a77d35ed096ecd58c7f09f..3a632673aed5e10b2b574a14f24f6c1637e5ba1f 100644 (file)
@@ -148,17 +148,7 @@ static struct platform_driver rng_driver = {
        .remove         = rng_remove,
 };
 
-static int __init rng_init(void)
-{
-       return platform_driver_register(&rng_driver);
-}
-module_init(rng_init);
-
-static void __exit rng_exit(void)
-{
-       platform_driver_unregister(&rng_driver);
-}
-module_exit(rng_exit);
+module_platform_driver(rng_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
index 990d55a5e3e878afabd14294b5852465764f259a..97bd891422c77511c1c506518bd55584457b76d4 100644 (file)
@@ -191,17 +191,7 @@ static struct platform_driver picoxcell_trng_driver = {
        },
 };
 
-static int __init picoxcell_trng_init(void)
-{
-       return platform_driver_register(&picoxcell_trng_driver);
-}
-module_init(picoxcell_trng_init);
-
-static void __exit picoxcell_trng_exit(void)
-{
-       platform_driver_unregister(&picoxcell_trng_driver);
-}
-module_exit(picoxcell_trng_exit);
+module_platform_driver(picoxcell_trng_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jamie Iles");
index b8afa6a4ff67161372269056c79741d44226e08b..c51762c13031928d57e307dff56f31cd638aad73 100644 (file)
@@ -139,17 +139,7 @@ static struct platform_driver ppc4xx_rng_driver = {
        .remove = ppc4xx_rng_remove,
 };
 
-static int __init ppc4xx_rng_init(void)
-{
-       return platform_driver_register(&ppc4xx_rng_driver);
-}
-module_init(ppc4xx_rng_init);
-
-static void __exit ppc4xx_rng_exit(void)
-{
-       platform_driver_unregister(&ppc4xx_rng_driver);
-}
-module_exit(ppc4xx_rng_exit);
+module_platform_driver(ppc4xx_rng_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Josh Boyer <jwboyer@linux.vnet.ibm.com>");
index a8428e6f64a9117ac03ef50963415217350d3239..f1a1618db1fb1e39912d9c59bb7901fddef7f0fd 100644 (file)
@@ -149,18 +149,7 @@ static struct platform_driver timeriomem_rng_driver = {
        .remove         = __devexit_p(timeriomem_rng_remove),
 };
 
-static int __init timeriomem_rng_init(void)
-{
-       return platform_driver_register(&timeriomem_rng_driver);
-}
-
-static void __exit timeriomem_rng_exit(void)
-{
-       platform_driver_unregister(&timeriomem_rng_driver);
-}
-
-module_init(timeriomem_rng_init);
-module_exit(timeriomem_rng_exit);
+module_platform_driver(timeriomem_rng_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
index fd699ccecf5b83efb694734ef5a137c8d20a2217..723725bbb96b774036f9fee05562b207d1cecfc0 100644 (file)
@@ -47,7 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
        sg_init_one(&sg, buf, size);
 
        /* There should always be room for one buffer. */
-       if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)
+       if (virtqueue_add_buf(vq, &sg, 0, 1, buf, GFP_KERNEL) < 0)
                BUG();
 
        virtqueue_kick(vq);
index 7c7f42a1f880cc81af6dafd89b73810c7eca34aa..9fec3232b7361b102ff5e05e55f2444eeab6ffb8 100644 (file)
@@ -83,8 +83,7 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper,
        struct timeval timestamp;
 
        if (reason != KMSG_DUMP_OOPS &&
-           reason != KMSG_DUMP_PANIC &&
-           reason != KMSG_DUMP_KEXEC)
+           reason != KMSG_DUMP_PANIC)
                return;
 
        /* Only dump oopses if dump_oops is set */
@@ -126,8 +125,8 @@ static int __init ramoops_probe(struct platform_device *pdev)
                goto fail3;
        }
 
-       rounddown_pow_of_two(pdata->mem_size);
-       rounddown_pow_of_two(pdata->record_size);
+       pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
+       pdata->record_size = rounddown_pow_of_two(pdata->record_size);
 
        /* Check for the minimum memory size */
        if (pdata->mem_size < MIN_MEM_SIZE &&
@@ -148,14 +147,6 @@ static int __init ramoops_probe(struct platform_device *pdev)
        cxt->phys_addr = pdata->mem_address;
        cxt->record_size = pdata->record_size;
        cxt->dump_oops = pdata->dump_oops;
-       /*
-        * Update the module parameter variables as well so they are visible
-        * through /sys/module/ramoops/parameters/
-        */
-       mem_size = pdata->mem_size;
-       mem_address = pdata->mem_address;
-       record_size = pdata->record_size;
-       dump_oops = pdata->dump_oops;
 
        if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
                pr_err("request mem region failed\n");
@@ -176,6 +167,15 @@ static int __init ramoops_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       /*
+        * Update the module parameter variables as well so they are visible
+        * through /sys/module/ramoops/parameters/
+        */
+       mem_size = pdata->mem_size;
+       mem_address = pdata->mem_address;
+       record_size = pdata->record_size;
+       dump_oops = pdata->dump_oops;
+
        return 0;
 
 fail1:
index fa567f1158c2f77bcfc2c495258bb48a777ccbdd..7fc75e47e6d029fc5b1c4a5fb0a0a5d8a6157b2b 100644 (file)
@@ -27,6 +27,7 @@ if TCG_TPM
 
 config TCG_TIS
        tristate "TPM Interface Specification 1.2 Interface"
+       depends on X86
        ---help---
          If you have a TPM security chip that is compliant with the
          TCG TIS 1.2 TPM specification say Yes and it will be accessible
@@ -35,6 +36,7 @@ config TCG_TIS
 
 config TCG_NSC
        tristate "National Semiconductor TPM Interface"
+       depends on X86
        ---help---
          If you have a TPM security chip from National Semiconductor 
          say Yes and it will be accessible from within Linux.  To 
index 361a1dff8f772e9d1aa2d855300046ca50291c03..6a8771f47a55c799866468fe80946a479a0440f8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
+#include <linux/freezer.h>
 
 #include "tpm.h"
 
@@ -440,7 +441,6 @@ out:
 }
 
 #define TPM_DIGEST_SIZE 20
-#define TPM_ERROR_SIZE 10
 #define TPM_RET_CODE_IDX 6
 
 enum tpm_capabilities {
@@ -469,12 +469,14 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
        len = tpm_transmit(chip,(u8 *) cmd, len);
        if (len <  0)
                return len;
-       if (len == TPM_ERROR_SIZE) {
-               err = be32_to_cpu(cmd->header.out.return_code);
-               dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
-               return err;
-       }
-       return 0;
+       else if (len < TPM_HEADER_SIZE)
+               return -EFAULT;
+
+       err = be32_to_cpu(cmd->header.out.return_code);
+       if (err != 0)
+               dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+
+       return err;
 }
 
 #define TPM_INTERNAL_RESULT_SIZE 200
@@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
-void tpm_get_timeouts(struct tpm_chip *chip)
+int tpm_get_timeouts(struct tpm_chip *chip)
 {
        struct tpm_cmd_t tpm_cmd;
        struct timeout_t *timeout_cap;
@@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
        if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
            be32_to_cpu(tpm_cmd.header.out.length)
            != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
-               return;
+               return -EINVAL;
 
        timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
        /* Don't overwrite default if value is 0 */
@@ -583,12 +585,12 @@ duration:
        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
                        "attempting to determine the durations");
        if (rc)
-               return;
+               return rc;
 
        if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
            be32_to_cpu(tpm_cmd.header.out.length)
            != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
-               return;
+               return -EINVAL;
 
        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
        chip->vendor.duration[TPM_SHORT] =
@@ -610,20 +612,36 @@ duration:
                chip->vendor.duration_adjusted = true;
                dev_info(chip->dev, "Adjusting TPM timeout parameters.");
        }
+       return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_get_timeouts);
 
-void tpm_continue_selftest(struct tpm_chip *chip)
+#define TPM_ORD_CONTINUE_SELFTEST 83
+#define CONTINUE_SELFTEST_RESULT_SIZE 10
+
+static struct tpm_input_header continue_selftest_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(10),
+       .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
+};
+
+/**
+ * tpm_continue_selftest -- run TPM's selftest
+ * @chip: TPM chip to use
+ *
+ * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
+ * a TPM error code.
+ */
+static int tpm_continue_selftest(struct tpm_chip *chip)
 {
-       u8 data[] = {
-               0, 193,                 /* TPM_TAG_RQU_COMMAND */
-               0, 0, 0, 10,            /* length */
-               0, 0, 0, 83,            /* TPM_ORD_ContinueSelfTest */
-       };
+       int rc;
+       struct tpm_cmd_t cmd;
 
-       tpm_transmit(chip, data, sizeof(data));
+       cmd.header.in = continue_selftest_header;
+       rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+                         "continue selftest");
+       return rc;
 }
-EXPORT_SYMBOL_GPL(tpm_continue_selftest);
 
 ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
                        char *buf)
@@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = {
        .ordinal = TPM_ORDINAL_PCRREAD
 };
 
-int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
+static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 {
        int rc;
        struct tpm_cmd_t cmd;
@@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
 }
 EXPORT_SYMBOL_GPL(tpm_pcr_extend);
 
+/**
+ * tpm_do_selftest - have the TPM continue its selftest and wait until it
+ *                   can receive further commands
+ * @chip: TPM chip to use
+ *
+ * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
+ * a TPM error code.
+ */
+int tpm_do_selftest(struct tpm_chip *chip)
+{
+       int rc;
+       u8 digest[TPM_DIGEST_SIZE];
+       unsigned int loops;
+       unsigned int delay_msec = 1000;
+       unsigned long duration;
+
+       duration = tpm_calc_ordinal_duration(chip,
+                                            TPM_ORD_CONTINUE_SELFTEST);
+
+       loops = jiffies_to_msecs(duration) / delay_msec;
+
+       rc = tpm_continue_selftest(chip);
+       /* This may fail if there was no TPM driver during a suspend/resume
+        * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
+        */
+       if (rc)
+               return rc;
+
+       do {
+               rc = __tpm_pcr_read(chip, 0, digest);
+               if (rc != TPM_WARN_DOING_SELFTEST)
+                       return rc;
+               msleep(delay_msec);
+       } while (--loops > 0);
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_do_selftest);
+
 int tpm_send(u32 chip_num, void *cmd, size_t buflen)
 {
        struct tpm_chip *chip;
@@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
 }
 EXPORT_SYMBOL_GPL(tpm_store_cancel);
 
+int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+                        wait_queue_head_t *queue)
+{
+       unsigned long stop;
+       long rc;
+       u8 status;
+
+       /* check current status */
+       status = chip->vendor.status(chip);
+       if ((status & mask) == mask)
+               return 0;
+
+       stop = jiffies + timeout;
+
+       if (chip->vendor.irq) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -ETIME;
+               rc = wait_event_interruptible_timeout(*queue,
+                                                     ((chip->vendor.status(chip)
+                                                     & mask) == mask),
+                                                     timeout);
+               if (rc > 0)
+                       return 0;
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
+       } else {
+               do {
+                       msleep(TPM_TIMEOUT);
+                       status = chip->vendor.status(chip);
+                       if ((status & mask) == mask)
+                               return 0;
+               } while (time_before(jiffies, stop));
+       }
+       return -ETIME;
+}
+EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
 /*
  * Device file system interface to the TPM
  *
index 9c4163cfa3ce94ab230ff3b9a58d568206634561..8c1df302fbb6ce17cd9580cca1aaeca84f785745 100644 (file)
@@ -38,6 +38,8 @@ enum tpm_addr {
        TPM_ADDR = 0x4E,
 };
 
+#define TPM_WARN_DOING_SELFTEST 0x802
+#define TPM_HEADER_SIZE                10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
                                char *);
 extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
@@ -279,9 +281,9 @@ struct tpm_cmd_t {
 
 ssize_t        tpm_getcap(struct device *, __be32, cap_t *, const char *);
 
-extern void tpm_get_timeouts(struct tpm_chip *);
+extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
-extern void tpm_continue_selftest(struct tpm_chip *);
+extern int tpm_do_selftest(struct tpm_chip *);
 extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
 extern struct tpm_chip* tpm_register_hardware(struct device *,
                                 const struct tpm_vendor_specific *);
@@ -294,7 +296,8 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
 extern void tpm_remove_hardware(struct device *);
 extern int tpm_pm_suspend(struct device *, pm_message_t);
 extern int tpm_pm_resume(struct device *);
-
+extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
+                            wait_queue_head_t *);
 #ifdef CONFIG_ACPI
 extern struct dentry ** tpm_bios_log_setup(char *);
 extern void tpm_bios_log_teardown(struct dentry **);
index 3f4051a7c5a770440d8d0b32893c1885fa796480..10cc44ceb5d1259dc1c91a90168702f5a048ad9b 100644 (file)
@@ -29,8 +29,6 @@
 #include <linux/freezer.h>
 #include "tpm.h"
 
-#define TPM_HEADER_SIZE 10
-
 enum tis_access {
        TPM_ACCESS_VALID = 0x80,
        TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
@@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip)
        return -EBUSY;
 }
 
-static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
-                        wait_queue_head_t *queue)
-{
-       unsigned long stop;
-       long rc;
-       u8 status;
-
-       /* check current status */
-       status = tpm_tis_status(chip);
-       if ((status & mask) == mask)
-               return 0;
-
-       stop = jiffies + timeout;
-
-       if (chip->vendor.irq) {
-again:
-               timeout = stop - jiffies;
-               if ((long)timeout <= 0)
-                       return -ETIME;
-               rc = wait_event_interruptible_timeout(*queue,
-                                                     ((tpm_tis_status
-                                                       (chip) & mask) ==
-                                                      mask), timeout);
-               if (rc > 0)
-                       return 0;
-               if (rc == -ERESTARTSYS && freezing(current)) {
-                       clear_thread_flag(TIF_SIGPENDING);
-                       goto again;
-               }
-       } else {
-               do {
-                       msleep(TPM_TIMEOUT);
-                       status = tpm_tis_status(chip);
-                       if ((status & mask) == mask)
-                               return 0;
-               } while (time_before(jiffies, stop));
-       }
-       return -ETIME;
-}
-
 static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        int size = 0, burstcnt;
        while (size < count &&
-              wait_for_stat(chip,
-                            TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-                            chip->vendor.timeout_c,
-                            &chip->vendor.read_queue)
+              wait_for_tpm_stat(chip,
+                                TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+                                chip->vendor.timeout_c,
+                                &chip->vendor.read_queue)
               == 0) {
                burstcnt = get_burstcount(chip);
                for (; burstcnt > 0 && size < count; burstcnt--)
@@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
                goto out;
        }
 
-       wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
-                     &chip->vendor.int_queue);
+       wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+                         &chip->vendor.int_queue);
        status = tpm_tis_status(chip);
        if (status & TPM_STS_DATA_AVAIL) {      /* retry? */
                dev_err(chip->dev, "Error left over data\n");
@@ -317,7 +275,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
        status = tpm_tis_status(chip);
        if ((status & TPM_STS_COMMAND_READY) == 0) {
                tpm_tis_ready(chip);
-               if (wait_for_stat
+               if (wait_for_tpm_stat
                    (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
                     &chip->vendor.int_queue) < 0) {
                        rc = -ETIME;
@@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
                        count++;
                }
 
-               wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
-                             &chip->vendor.int_queue);
+               wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+                                 &chip->vendor.int_queue);
                status = tpm_tis_status(chip);
                if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
                        rc = -EIO;
@@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
        /* write last byte */
        iowrite8(buf[count],
                 chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
-       wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
-                     &chip->vendor.int_queue);
+       wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
+                         &chip->vendor.int_queue);
        status = tpm_tis_status(chip);
        if ((status & TPM_STS_DATA_EXPECT) != 0) {
                rc = -EIO;
@@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
 
        if (chip->vendor.irq) {
                ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
-               if (wait_for_stat
+               if (wait_for_tpm_stat
                    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
                     tpm_calc_ordinal_duration(chip, ordinal),
                     &chip->vendor.read_queue) < 0) {
@@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip)
 out:
        itpm = rem_itpm;
        tpm_tis_ready(chip);
+       /* some TPMs need a break here otherwise they will not work
+        * correctly on the immediately subsequent command */
+       msleep(chip->vendor.timeout_b);
        release_locality(chip, chip->vendor.locality, 0);
 
        return rc;
@@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                dev_dbg(dev, "\tData Avail Int Support\n");
 
        /* get the timeouts before testing for irqs */
-       tpm_get_timeouts(chip);
+       if (tpm_get_timeouts(chip)) {
+               dev_err(dev, "Could not get TPM timeouts and durations\n");
+               rc = -ENODEV;
+               goto out_err;
+       }
+
+       if (tpm_do_selftest(chip)) {
+               dev_err(dev, "TPM self test failed\n");
+               rc = -ENODEV;
+               goto out_err;
+       }
 
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
@@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
        list_add(&chip->vendor.list, &tis_chips);
        spin_unlock(&tis_lock);
 
-       tpm_continue_selftest(chip);
 
        return 0;
 out_err:
@@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
 
        ret = tpm_pm_resume(&dev->dev);
        if (!ret)
-               tpm_continue_selftest(chip);
+               tpm_do_selftest(chip);
 
        return ret;
 }
index 8e3c46d67cb3d9f1f636ca0e38fb175e02a18cdb..b58b5618706588936ebcf7a028bde7dba8f616c1 100644 (file)
@@ -392,7 +392,7 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 
        sg_init_one(sg, buf->buf, buf->size);
 
-       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
+       ret = virtqueue_add_buf(vq, sg, 0, 1, buf, GFP_ATOMIC);
        virtqueue_kick(vq);
        return ret;
 }
@@ -457,7 +457,7 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
        vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) >= 0) {
                virtqueue_kick(vq);
                while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
@@ -506,7 +506,7 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
        reclaim_consumed_buffers(port);
 
        sg_init_one(sg, in_buf, in_count);
-       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
+       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf, GFP_ATOMIC);
 
        /* Tell Host to go! */
        virtqueue_kick(out_vq);
@@ -1271,6 +1271,20 @@ static void remove_port(struct kref *kref)
        kfree(port);
 }
 
+static void remove_port_data(struct port *port)
+{
+       struct port_buffer *buf;
+
+       /* Remove unused data this port might have received. */
+       discard_port_data(port);
+
+       reclaim_consumed_buffers(port);
+
+       /* Remove buffers we queued up for the Host to send us data in. */
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+}
+
 /*
  * Port got unplugged.  Remove port from portdev's list and drop the
  * kref reference.  If no userspace has this port opened, it will
@@ -1278,8 +1292,6 @@ static void remove_port(struct kref *kref)
  */
 static void unplug_port(struct port *port)
 {
-       struct port_buffer *buf;
-
        spin_lock_irq(&port->portdev->ports_lock);
        list_del(&port->list);
        spin_unlock_irq(&port->portdev->ports_lock);
@@ -1300,14 +1312,7 @@ static void unplug_port(struct port *port)
                hvc_remove(port->cons.hvc);
        }
 
-       /* Remove unused data this port might have received. */
-       discard_port_data(port);
-
-       reclaim_consumed_buffers(port);
-
-       /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
+       remove_port_data(port);
 
        /*
         * We should just assume the device itself has gone off --
@@ -1659,6 +1664,28 @@ static const struct file_operations portdev_fops = {
        .owner = THIS_MODULE,
 };
 
+static void remove_vqs(struct ports_device *portdev)
+{
+       portdev->vdev->config->del_vqs(portdev->vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+}
+
+static void remove_controlq_data(struct ports_device *portdev)
+{
+       struct port_buffer *buf;
+       unsigned int len;
+
+       if (!use_multiport(portdev))
+               return;
+
+       while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+               free_buf(buf);
+
+       while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+               free_buf(buf);
+}
+
 /*
  * Once we're further in boot, we get probed like any other virtio
  * device.
@@ -1764,9 +1791,7 @@ free_vqs:
        /* The host might want to notify mgmt sw about device add failure */
        __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
                           VIRTIO_CONSOLE_DEVICE_READY, 0);
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
+       remove_vqs(portdev);
 free_chrdev:
        unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 free:
@@ -1804,21 +1829,8 @@ static void virtcons_remove(struct virtio_device *vdev)
         * have to just stop using the port, as the vqs are going
         * away.
         */
-       if (use_multiport(portdev)) {
-               struct port_buffer *buf;
-               unsigned int len;
-
-               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-                       free_buf(buf);
-
-               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-                       free_buf(buf);
-       }
-
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-
+       remove_controlq_data(portdev);
+       remove_vqs(portdev);
        kfree(portdev);
 }
 
@@ -1832,6 +1844,68 @@ static unsigned int features[] = {
        VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
+#ifdef CONFIG_PM
+static int virtcons_freeze(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+
+       portdev = vdev->priv;
+
+       vdev->config->reset(vdev);
+
+       virtqueue_disable_cb(portdev->c_ivq);
+       cancel_work_sync(&portdev->control_work);
+       /*
+        * Once more: if control_work_handler() was running, it would
+        * enable the cb as the last step.
+        */
+       virtqueue_disable_cb(portdev->c_ivq);
+       remove_controlq_data(portdev);
+
+       list_for_each_entry(port, &portdev->ports, list) {
+               virtqueue_disable_cb(port->in_vq);
+               virtqueue_disable_cb(port->out_vq);
+               /*
+                * We'll ask the host later if the new invocation has
+                * the port opened or closed.
+                */
+               port->host_connected = false;
+               remove_port_data(port);
+       }
+       remove_vqs(portdev);
+
+       return 0;
+}
+
+static int virtcons_restore(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+       int ret;
+
+       portdev = vdev->priv;
+
+       ret = init_vqs(portdev);
+       if (ret)
+               return ret;
+
+       if (use_multiport(portdev))
+               fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+
+       list_for_each_entry(port, &portdev->ports, list) {
+               port->in_vq = portdev->in_vqs[port->id];
+               port->out_vq = portdev->out_vqs[port->id];
+
+               fill_queue(port->in_vq, &port->inbuf_lock);
+
+               /* Get port open/close status on the host */
+               send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+       }
+       return 0;
+}
+#endif
+
 static struct virtio_driver virtio_console = {
        .feature_table = features,
        .feature_table_size = ARRAY_SIZE(features),
@@ -1841,6 +1915,10 @@ static struct virtio_driver virtio_console = {
        .probe =        virtcons_probe,
        .remove =       virtcons_remove,
        .config_changed = config_intr,
+#ifdef CONFIG_PM
+       .freeze =       virtcons_freeze,
+       .restore =      virtcons_restore,
+#endif
 };
 
 static int __init init(void)
index 72a0044c1baa8a688e267420b0f4985e912f0a6b..e0664fed018afc28ef8fd54c49630562a052366d 100644 (file)
@@ -21,12 +21,19 @@ config ARM_S5PV210_CPUFREQ
 
          If in doubt, say N.
 
+config ARM_EXYNOS_CPUFREQ
+       bool "SAMSUNG EXYNOS SoCs"
+       depends on ARCH_EXYNOS
+       select ARM_EXYNOS4210_CPUFREQ if CPU_EXYNOS4210
+       default y
+       help
+         This adds the CPUFreq driver common part for Samsung
+         EXYNOS SoCs.
+
+         If in doubt, say N.
+
 config ARM_EXYNOS4210_CPUFREQ
        bool "Samsung EXYNOS4210"
-       depends on CPU_EXYNOS4210
-       default y
        help
          This adds the CPUFreq driver for Samsung EXYNOS4210
          SoC (S5PV310 or S5PC210).
-
-         If in doubt, say N.
index a48bc02cd76539219f90ab9b4da5d4a1f7a9bfdf..ac000fa76bbb6b2fd068df07c1edf650798be88c 100644 (file)
@@ -42,7 +42,9 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2)     += cpufreq-nforce2.o
 obj-$(CONFIG_UX500_SOC_DB8500)         += db8500-cpufreq.o
 obj-$(CONFIG_ARM_S3C64XX_CPUFREQ)      += s3c64xx-cpufreq.o
 obj-$(CONFIG_ARM_S5PV210_CPUFREQ)      += s5pv210-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS_CPUFREQ)       += exynos-cpufreq.o
 obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ)   += exynos4210-cpufreq.o
+obj-$(CONFIG_ARCH_OMAP2PLUS)            += omap-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
index 8c2df3499da7b11beedf6535e125d1286cf3f17d..622013fb7890e465f6c62ecb4595c70534f4bc6b 100644 (file)
@@ -204,8 +204,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
                pr_debug("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
-       if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
-           (val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
+       if ((val == CPUFREQ_POSTCHANGE  && ci->old != ci->new) ||
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
index 3d679eee70a137266df009c1d91ae20535409a33..c3e0652520a1ff624a5f60fbfbfd027f67f3b8f8 100644 (file)
@@ -713,11 +713,10 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       cputime64_t wall;
        u64 idle_time;
        int cpu = get_cpu();
 
-       idle_time = get_cpu_idle_time_us(cpu, &wall);
+       idle_time = get_cpu_idle_time_us(cpu, NULL);
        put_cpu();
        if (idle_time != -1ULL) {
                /* Idle micro accounting is supported. Use finer thresholds */
index f231015904c0a6584ed0fb4c57d78de4636746b4..bedac1aa9be31919f74ea6e3788d47e64f1e3342 100644 (file)
@@ -47,9 +47,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
        if (!per_cpu(cpu_is_managed, freq->cpu))
                return 0;
 
-       pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
-                       freq->cpu, freq->new);
-       per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
+       if (val == CPUFREQ_POSTCHANGE) {
+               pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
+                               freq->cpu, freq->new);
+               per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
+       }
 
        return 0;
 }
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
new file mode 100644 (file)
index 0000000..5467879
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * EXYNOS - CPU frequency scaling support for EXYNOS series
+ *
+ * This program is free software; you can 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/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/cpufreq.h>
+#include <linux/suspend.h>
+
+#include <mach/cpufreq.h>
+
+#include <plat/cpu.h>
+
+static struct exynos_dvfs_info *exynos_info;
+
+static struct regulator *arm_regulator;
+static struct cpufreq_freqs freqs;
+
+static unsigned int locking_frequency;
+static bool frequency_locked;
+static DEFINE_MUTEX(cpufreq_lock);
+
+int exynos_verify_speed(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy,
+                                             exynos_info->freq_table);
+}
+
+unsigned int exynos_getspeed(unsigned int cpu)
+{
+       return clk_get_rate(exynos_info->cpu_clk) / 1000;
+}
+
+static int exynos_target(struct cpufreq_policy *policy,
+                         unsigned int target_freq,
+                         unsigned int relation)
+{
+       unsigned int index, old_index;
+       unsigned int arm_volt, safe_arm_volt = 0;
+       int ret = 0;
+       struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+       unsigned int *volt_table = exynos_info->volt_table;
+       unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
+
+       mutex_lock(&cpufreq_lock);
+
+       freqs.old = policy->cur;
+
+       if (frequency_locked && target_freq != locking_frequency) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       if (cpufreq_frequency_table_target(policy, freq_table,
+                                          freqs.old, relation, &old_index)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (cpufreq_frequency_table_target(policy, freq_table,
+                                          target_freq, relation, &index)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       freqs.new = freq_table[index].frequency;
+       freqs.cpu = policy->cpu;
+
+       /*
+        * ARM clock source will be changed APLL to MPLL temporary
+        * To support this level, need to control regulator for
+        * required voltage level
+        */
+       if (exynos_info->need_apll_change != NULL) {
+               if (exynos_info->need_apll_change(old_index, index) &&
+                  (freq_table[index].frequency < mpll_freq_khz) &&
+                  (freq_table[old_index].frequency < mpll_freq_khz))
+                       safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
+       }
+       arm_volt = volt_table[index];
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       /* When the new frequency is higher than current frequency */
+       if ((freqs.new > freqs.old) && !safe_arm_volt) {
+               /* Firstly, voltage up to increase frequency */
+               regulator_set_voltage(arm_regulator, arm_volt,
+                               arm_volt);
+       }
+
+       if (safe_arm_volt)
+               regulator_set_voltage(arm_regulator, safe_arm_volt,
+                                     safe_arm_volt);
+       if (freqs.new != freqs.old)
+               exynos_info->set_freq(old_index, index);
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       /* When the new frequency is lower than current frequency */
+       if ((freqs.new < freqs.old) ||
+          ((freqs.new > freqs.old) && safe_arm_volt)) {
+               /* down the voltage after frequency change */
+               regulator_set_voltage(arm_regulator, arm_volt,
+                               arm_volt);
+       }
+
+out:
+       mutex_unlock(&cpufreq_lock);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
+{
+       return 0;
+}
+
+static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
+{
+       return 0;
+}
+#endif
+
+/**
+ * exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
+ *                     context
+ * @notifier
+ * @pm_event
+ * @v
+ *
+ * While frequency_locked == true, target() ignores every frequency but
+ * locking_frequency. The locking_frequency value is the initial frequency,
+ * which is set by the bootloader. In order to eliminate possible
+ * inconsistency in clock values, we save and restore frequencies during
+ * suspend and resume and block CPUFREQ activities. Note that the standard
+ * suspend/resume cannot be used as they are too deep (syscore_ops) for
+ * regulator actions.
+ */
+static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
+                                      unsigned long pm_event, void *v)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
+       static unsigned int saved_frequency;
+       unsigned int temp;
+
+       mutex_lock(&cpufreq_lock);
+       switch (pm_event) {
+       case PM_SUSPEND_PREPARE:
+               if (frequency_locked)
+                       goto out;
+
+               frequency_locked = true;
+
+               if (locking_frequency) {
+                       saved_frequency = exynos_getspeed(0);
+
+                       mutex_unlock(&cpufreq_lock);
+                       exynos_target(policy, locking_frequency,
+                                     CPUFREQ_RELATION_H);
+                       mutex_lock(&cpufreq_lock);
+               }
+               break;
+
+       case PM_POST_SUSPEND:
+               if (saved_frequency) {
+                       /*
+                        * While frequency_locked, only locking_frequency
+                        * is valid for target(). In order to use
+                        * saved_frequency while keeping frequency_locked,
+                        * we temporarly overwrite locking_frequency.
+                        */
+                       temp = locking_frequency;
+                       locking_frequency = saved_frequency;
+
+                       mutex_unlock(&cpufreq_lock);
+                       exynos_target(policy, locking_frequency,
+                                     CPUFREQ_RELATION_H);
+                       mutex_lock(&cpufreq_lock);
+
+                       locking_frequency = temp;
+               }
+               frequency_locked = false;
+               break;
+       }
+out:
+       mutex_unlock(&cpufreq_lock);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block exynos_cpufreq_nb = {
+       .notifier_call = exynos_cpufreq_pm_notifier,
+};
+
+static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu);
+
+       cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
+
+       /* set the transition latency value */
+       policy->cpuinfo.transition_latency = 100000;
+
+       /*
+        * EXYNOS4 multi-core processors has 2 cores
+        * that the frequency cannot be set independently.
+        * Each cpu is bound to the same speed.
+        * So the affected cpu is all of the cpus.
+        */
+       if (num_online_cpus() == 1) {
+               cpumask_copy(policy->related_cpus, cpu_possible_mask);
+               cpumask_copy(policy->cpus, cpu_online_mask);
+       } else {
+               cpumask_setall(policy->cpus);
+       }
+
+       return cpufreq_frequency_table_cpuinfo(policy, exynos_info->freq_table);
+}
+
+static struct cpufreq_driver exynos_driver = {
+       .flags          = CPUFREQ_STICKY,
+       .verify         = exynos_verify_speed,
+       .target         = exynos_target,
+       .get            = exynos_getspeed,
+       .init           = exynos_cpufreq_cpu_init,
+       .name           = "exynos_cpufreq",
+#ifdef CONFIG_PM
+       .suspend        = exynos_cpufreq_suspend,
+       .resume         = exynos_cpufreq_resume,
+#endif
+};
+
+static int __init exynos_cpufreq_init(void)
+{
+       int ret = -EINVAL;
+
+       exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
+       if (!exynos_info)
+               return -ENOMEM;
+
+       if (soc_is_exynos4210())
+               ret = exynos4210_cpufreq_init(exynos_info);
+       else
+               pr_err("%s: CPU type not found\n", __func__);
+
+       if (ret)
+               goto err_vdd_arm;
+
+       if (exynos_info->set_freq == NULL) {
+               pr_err("%s: No set_freq function (ERR)\n", __func__);
+               goto err_vdd_arm;
+       }
+
+       arm_regulator = regulator_get(NULL, "vdd_arm");
+       if (IS_ERR(arm_regulator)) {
+               pr_err("%s: failed to get resource vdd_arm\n", __func__);
+               goto err_vdd_arm;
+       }
+
+       register_pm_notifier(&exynos_cpufreq_nb);
+
+       if (cpufreq_register_driver(&exynos_driver)) {
+               pr_err("%s: failed to register cpufreq driver\n", __func__);
+               goto err_cpufreq;
+       }
+
+       return 0;
+err_cpufreq:
+       unregister_pm_notifier(&exynos_cpufreq_nb);
+
+       if (!IS_ERR(arm_regulator))
+               regulator_put(arm_regulator);
+err_vdd_arm:
+       kfree(exynos_info);
+       pr_debug("%s: failed initialization\n", __func__);
+       return -EINVAL;
+}
+late_initcall(exynos_cpufreq_init);
index ab9741fab92e2341af91ca7a30d664851894666e..065da5b702f148c43b122be7784457f4d563a2c2 100644 (file)
@@ -2,61 +2,52 @@
  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
- * EXYNOS4 - CPU frequency scaling support
+ * EXYNOS4210 - CPU frequency scaling support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 */
 
-#include <linux/types.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 #include <linux/cpufreq.h>
-#include <linux/notifier.h>
-#include <linux/suspend.h>
 
-#include <mach/map.h>
 #include <mach/regs-clock.h>
-#include <mach/regs-mem.h>
+#include <mach/cpufreq.h>
 
-#include <plat/clock.h>
-#include <plat/pm.h>
+#define CPUFREQ_LEVEL_END      L5
+
+static int max_support_idx = L0;
+static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
 
 static struct clk *cpu_clk;
 static struct clk *moutcore;
 static struct clk *mout_mpll;
 static struct clk *mout_apll;
 
-static struct regulator *arm_regulator;
-static struct regulator *int_regulator;
-
-static struct cpufreq_freqs freqs;
-static unsigned int memtype;
-
-static unsigned int locking_frequency;
-static bool frequency_locked;
-static DEFINE_MUTEX(cpufreq_lock);
-
-enum exynos4_memory_type {
-       DDR2 = 4,
-       LPDDR2,
-       DDR3,
+struct cpufreq_clkdiv {
+       unsigned int index;
+       unsigned int clkdiv;
 };
 
-enum cpufreq_level_index {
-       L0, L1, L2, L3, CPUFREQ_LEVEL_END,
+static unsigned int exynos4210_volt_table[CPUFREQ_LEVEL_END] = {
+       1250000, 1150000, 1050000, 975000, 950000,
 };
 
-static struct cpufreq_frequency_table exynos4_freq_table[] = {
-       {L0, 1000*1000},
-       {L1, 800*1000},
-       {L2, 400*1000},
-       {L3, 100*1000},
+
+static struct cpufreq_clkdiv exynos4210_clkdiv_table[CPUFREQ_LEVEL_END];
+
+static struct cpufreq_frequency_table exynos4210_freq_table[] = {
+       {L0, 1200*1000},
+       {L1, 1000*1000},
+       {L2, 800*1000},
+       {L3, 500*1000},
+       {L4, 200*1000},
        {0, CPUFREQ_TABLE_END},
 };
 
@@ -67,17 +58,20 @@ static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
         *              DIVATB, DIVPCLK_DBG, DIVAPLL }
         */
 
-       /* ARM L0: 1000MHz */
-       { 0, 3, 7, 3, 3, 0, 1 },
+       /* ARM L0: 1200MHz */
+       { 0, 3, 7, 3, 4, 1, 7 },
 
-       /* ARM L1: 800MHz */
-       { 0, 3, 7, 3, 3, 0, 1 },
+       /* ARM L1: 1000MHz */
+       { 0, 3, 7, 3, 4, 1, 7 },
 
-       /* ARM L2: 400MHz */
-       { 0, 1, 3, 1, 3, 0, 1 },
+       /* ARM L2: 800MHz */
+       { 0, 3, 7, 3, 3, 1, 7 },
 
-       /* ARM L3: 100MHz */
-       { 0, 0, 1, 0, 3, 1, 1 },
+       /* ARM L3: 500MHz */
+       { 0, 3, 7, 3, 3, 1, 7 },
+
+       /* ARM L4: 200MHz */
+       { 0, 1, 3, 1, 3, 1, 0 },
 };
 
 static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
@@ -86,147 +80,46 @@ static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
         * { DIVCOPY, DIVHPM }
         */
 
-        /* ARM L0: 1000MHz */
-       { 3, 0 },
+       /* ARM L0: 1200MHz */
+       { 5, 0 },
 
-       /* ARM L1: 800MHz */
-       { 3, 0 },
+       /* ARM L1: 1000MHz */
+       { 4, 0 },
 
-       /* ARM L2: 400MHz */
+       /* ARM L2: 800MHz */
        { 3, 0 },
 
-       /* ARM L3: 100MHz */
+       /* ARM L3: 500MHz */
        { 3, 0 },
-};
-
-static unsigned int clkdiv_dmc0[CPUFREQ_LEVEL_END][8] = {
-       /*
-        * Clock divider value for following
-        * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
-        *              DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
-        */
-
-       /* DMC L0: 400MHz */
-       { 3, 1, 1, 1, 1, 1, 3, 1 },
-
-       /* DMC L1: 400MHz */
-       { 3, 1, 1, 1, 1, 1, 3, 1 },
-
-       /* DMC L2: 266.7MHz */
-       { 7, 1, 1, 2, 1, 1, 3, 1 },
-
-       /* DMC L3: 200MHz */
-       { 7, 1, 1, 3, 1, 1, 3, 1 },
-};
-
-static unsigned int clkdiv_top[CPUFREQ_LEVEL_END][5] = {
-       /*
-        * Clock divider value for following
-        * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
-        */
 
-       /* ACLK200 L0: 200MHz */
-       { 3, 7, 4, 5, 1 },
-
-       /* ACLK200 L1: 200MHz */
-       { 3, 7, 4, 5, 1 },
-
-       /* ACLK200 L2: 160MHz */
-       { 4, 7, 5, 7, 1 },
-
-       /* ACLK200 L3: 133.3MHz */
-       { 5, 7, 7, 7, 1 },
-};
-
-static unsigned int clkdiv_lr_bus[CPUFREQ_LEVEL_END][2] = {
-       /*
-        * Clock divider value for following
-        * { DIVGDL/R, DIVGPL/R }
-        */
-
-       /* ACLK_GDL/R L0: 200MHz */
-       { 3, 1 },
-
-       /* ACLK_GDL/R L1: 200MHz */
-       { 3, 1 },
-
-       /* ACLK_GDL/R L2: 160MHz */
-       { 4, 1 },
-
-       /* ACLK_GDL/R L3: 133.3MHz */
-       { 5, 1 },
-};
-
-struct cpufreq_voltage_table {
-       unsigned int    index;          /* any */
-       unsigned int    arm_volt;       /* uV */
-       unsigned int    int_volt;
+       /* ARM L4: 200MHz */
+       { 3, 0 },
 };
 
-static struct cpufreq_voltage_table exynos4_volt_table[CPUFREQ_LEVEL_END] = {
-       {
-               .index          = L0,
-               .arm_volt       = 1200000,
-               .int_volt       = 1100000,
-       }, {
-               .index          = L1,
-               .arm_volt       = 1100000,
-               .int_volt       = 1100000,
-       }, {
-               .index          = L2,
-               .arm_volt       = 1000000,
-               .int_volt       = 1000000,
-       }, {
-               .index          = L3,
-               .arm_volt       = 900000,
-               .int_volt       = 1000000,
-       },
-};
+static unsigned int exynos4210_apll_pms_table[CPUFREQ_LEVEL_END] = {
+       /* APLL FOUT L0: 1200MHz */
+       ((150 << 16) | (3 << 8) | 1),
 
-static unsigned int exynos4_apll_pms_table[CPUFREQ_LEVEL_END] = {
-       /* APLL FOUT L0: 1000MHz */
+       /* APLL FOUT L1: 1000MHz */
        ((250 << 16) | (6 << 8) | 1),
 
-       /* APLL FOUT L1: 800MHz */
+       /* APLL FOUT L2: 800MHz */
        ((200 << 16) | (6 << 8) | 1),
 
-       /* APLL FOUT L2 : 400MHz */
-       ((200 << 16) | (6 << 8) | 2),
+       /* APLL FOUT L3: 500MHz */
+       ((250 << 16) | (6 << 8) | 2),
 
-       /* APLL FOUT L3: 100MHz */
-       ((200 << 16) | (6 << 8) | 4),
+       /* APLL FOUT L4: 200MHz */
+       ((200 << 16) | (6 << 8) | 3),
 };
 
-static int exynos4_verify_speed(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, exynos4_freq_table);
-}
-
-static unsigned int exynos4_getspeed(unsigned int cpu)
-{
-       return clk_get_rate(cpu_clk) / 1000;
-}
-
-static void exynos4_set_clkdiv(unsigned int div_index)
+static void exynos4210_set_clkdiv(unsigned int div_index)
 {
        unsigned int tmp;
 
        /* Change Divider - CPU0 */
 
-       tmp = __raw_readl(S5P_CLKDIV_CPU);
-
-       tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK | S5P_CLKDIV_CPU0_COREM0_MASK |
-               S5P_CLKDIV_CPU0_COREM1_MASK | S5P_CLKDIV_CPU0_PERIPH_MASK |
-               S5P_CLKDIV_CPU0_ATB_MASK | S5P_CLKDIV_CPU0_PCLKDBG_MASK |
-               S5P_CLKDIV_CPU0_APLL_MASK);
-
-       tmp |= ((clkdiv_cpu0[div_index][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
-               (clkdiv_cpu0[div_index][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
-               (clkdiv_cpu0[div_index][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
-               (clkdiv_cpu0[div_index][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
-               (clkdiv_cpu0[div_index][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
-               (clkdiv_cpu0[div_index][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
-               (clkdiv_cpu0[div_index][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
+       tmp = exynos4210_clkdiv_table[div_index].clkdiv;
 
        __raw_writel(tmp, S5P_CLKDIV_CPU);
 
@@ -248,83 +141,9 @@ static void exynos4_set_clkdiv(unsigned int div_index)
        do {
                tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
        } while (tmp & 0x11);
-
-       /* Change Divider - DMC0 */
-
-       tmp = __raw_readl(S5P_CLKDIV_DMC0);
-
-       tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK | S5P_CLKDIV_DMC0_ACPPCLK_MASK |
-               S5P_CLKDIV_DMC0_DPHY_MASK | S5P_CLKDIV_DMC0_DMC_MASK |
-               S5P_CLKDIV_DMC0_DMCD_MASK | S5P_CLKDIV_DMC0_DMCP_MASK |
-               S5P_CLKDIV_DMC0_COPY2_MASK | S5P_CLKDIV_DMC0_CORETI_MASK);
-
-       tmp |= ((clkdiv_dmc0[div_index][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) |
-               (clkdiv_dmc0[div_index][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
-               (clkdiv_dmc0[div_index][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) |
-               (clkdiv_dmc0[div_index][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) |
-               (clkdiv_dmc0[div_index][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) |
-               (clkdiv_dmc0[div_index][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) |
-               (clkdiv_dmc0[div_index][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) |
-               (clkdiv_dmc0[div_index][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT));
-
-       __raw_writel(tmp, S5P_CLKDIV_DMC0);
-
-       do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
-       } while (tmp & 0x11111111);
-
-       /* Change Divider - TOP */
-
-       tmp = __raw_readl(S5P_CLKDIV_TOP);
-
-       tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK | S5P_CLKDIV_TOP_ACLK100_MASK |
-               S5P_CLKDIV_TOP_ACLK160_MASK | S5P_CLKDIV_TOP_ACLK133_MASK |
-               S5P_CLKDIV_TOP_ONENAND_MASK);
-
-       tmp |= ((clkdiv_top[div_index][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) |
-               (clkdiv_top[div_index][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) |
-               (clkdiv_top[div_index][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) |
-               (clkdiv_top[div_index][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) |
-               (clkdiv_top[div_index][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT));
-
-       __raw_writel(tmp, S5P_CLKDIV_TOP);
-
-       do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
-       } while (tmp & 0x11111);
-
-       /* Change Divider - LEFTBUS */
-
-       tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
-
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
-               (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
-
-       do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
-       } while (tmp & 0x11);
-
-       /* Change Divider - RIGHTBUS */
-
-       tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
-
-       tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
-               (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
-
-       do {
-               tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
-       } while (tmp & 0x11);
 }
 
-static void exynos4_set_apll(unsigned int index)
+static void exynos4210_set_apll(unsigned int index)
 {
        unsigned int tmp;
 
@@ -343,7 +162,7 @@ static void exynos4_set_apll(unsigned int index)
        /* 3. Change PLL PMS values */
        tmp = __raw_readl(S5P_APLL_CON0);
        tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
-       tmp |= exynos4_apll_pms_table[index];
+       tmp |= exynos4210_apll_pms_table[index];
        __raw_writel(tmp, S5P_APLL_CON0);
 
        /* 4. wait_lock_time */
@@ -360,328 +179,126 @@ static void exynos4_set_apll(unsigned int index)
        } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
 }
 
-static void exynos4_set_frequency(unsigned int old_index, unsigned int new_index)
+bool exynos4210_pms_change(unsigned int old_index, unsigned int new_index)
+{
+       unsigned int old_pm = (exynos4210_apll_pms_table[old_index] >> 8);
+       unsigned int new_pm = (exynos4210_apll_pms_table[new_index] >> 8);
+
+       return (old_pm == new_pm) ? 0 : 1;
+}
+
+static void exynos4210_set_frequency(unsigned int old_index,
+                                    unsigned int new_index)
 {
        unsigned int tmp;
 
        if (old_index > new_index) {
-               /* The frequency changing to L0 needs to change apll */
-               if (freqs.new == exynos4_freq_table[L0].frequency) {
-                       /* 1. Change the system clock divider values */
-                       exynos4_set_clkdiv(new_index);
-
-                       /* 2. Change the apll m,p,s value */
-                       exynos4_set_apll(new_index);
-               } else {
+               if (!exynos4210_pms_change(old_index, new_index)) {
                        /* 1. Change the system clock divider values */
-                       exynos4_set_clkdiv(new_index);
+                       exynos4210_set_clkdiv(new_index);
 
                        /* 2. Change just s value in apll m,p,s value */
                        tmp = __raw_readl(S5P_APLL_CON0);
                        tmp &= ~(0x7 << 0);
-                       tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
+                       tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
                        __raw_writel(tmp, S5P_APLL_CON0);
-               }
-       }
-
-       else if (old_index < new_index) {
-               /* The frequency changing from L0 needs to change apll */
-               if (freqs.old == exynos4_freq_table[L0].frequency) {
-                       /* 1. Change the apll m,p,s value */
-                       exynos4_set_apll(new_index);
-
-                       /* 2. Change the system clock divider values */
-                       exynos4_set_clkdiv(new_index);
                } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the system clock divider values */
+                       exynos4210_set_clkdiv(new_index);
+                       /* 2. Change the apll m,p,s value */
+                       exynos4210_set_apll(new_index);
+               }
+       } else if (old_index < new_index) {
+               if (!exynos4210_pms_change(old_index, new_index)) {
                        /* 1. Change just s value in apll m,p,s value */
                        tmp = __raw_readl(S5P_APLL_CON0);
                        tmp &= ~(0x7 << 0);
-                       tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
+                       tmp |= (exynos4210_apll_pms_table[new_index] & 0x7);
                        __raw_writel(tmp, S5P_APLL_CON0);
 
                        /* 2. Change the system clock divider values */
-                       exynos4_set_clkdiv(new_index);
+                       exynos4210_set_clkdiv(new_index);
+               } else {
+                       /* Clock Configuration Procedure */
+                       /* 1. Change the apll m,p,s value */
+                       exynos4210_set_apll(new_index);
+                       /* 2. Change the system clock divider values */
+                       exynos4210_set_clkdiv(new_index);
                }
        }
 }
 
-static int exynos4_target(struct cpufreq_policy *policy,
-                         unsigned int target_freq,
-                         unsigned int relation)
-{
-       unsigned int index, old_index;
-       unsigned int arm_volt, int_volt;
-       int err = -EINVAL;
-
-       freqs.old = exynos4_getspeed(policy->cpu);
-
-       mutex_lock(&cpufreq_lock);
-
-       if (frequency_locked && target_freq != locking_frequency) {
-               err = -EAGAIN;
-               goto out;
-       }
-
-       if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
-                                          freqs.old, relation, &old_index))
-               goto out;
-
-       if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
-                                          target_freq, relation, &index))
-               goto out;
-
-       err = 0;
-
-       freqs.new = exynos4_freq_table[index].frequency;
-       freqs.cpu = policy->cpu;
-
-       if (freqs.new == freqs.old)
-               goto out;
-
-       /* get the voltage value */
-       arm_volt = exynos4_volt_table[index].arm_volt;
-       int_volt = exynos4_volt_table[index].int_volt;
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-       /* control regulator */
-       if (freqs.new > freqs.old) {
-               /* Voltage up */
-               regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
-               regulator_set_voltage(int_regulator, int_volt, int_volt);
-       }
-
-       /* Clock Configuration Procedure */
-       exynos4_set_frequency(old_index, index);
-
-       /* control regulator */
-       if (freqs.new < freqs.old) {
-               /* Voltage down */
-               regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
-               regulator_set_voltage(int_regulator, int_volt, int_volt);
-       }
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-out:
-       mutex_unlock(&cpufreq_lock);
-       return err;
-}
-
-#ifdef CONFIG_PM
-/*
- * These suspend/resume are used as syscore_ops, it is already too
- * late to set regulator voltages at this stage.
- */
-static int exynos4_cpufreq_suspend(struct cpufreq_policy *policy)
-{
-       return 0;
-}
-
-static int exynos4_cpufreq_resume(struct cpufreq_policy *policy)
+int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
 {
-       return 0;
-}
-#endif
-
-/**
- * exynos4_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
- *                     context
- * @notifier
- * @pm_event
- * @v
- *
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
- * which is set by the bootloader. In order to eliminate possible
- * inconsistency in clock values, we save and restore frequencies during
- * suspend and resume and block CPUFREQ activities. Note that the standard
- * suspend/resume cannot be used as they are too deep (syscore_ops) for
- * regulator actions.
- */
-static int exynos4_cpufreq_pm_notifier(struct notifier_block *notifier,
-                                      unsigned long pm_event, void *v)
-{
-       struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
-       static unsigned int saved_frequency;
-       unsigned int temp;
-
-       mutex_lock(&cpufreq_lock);
-       switch (pm_event) {
-       case PM_SUSPEND_PREPARE:
-               if (frequency_locked)
-                       goto out;
-               frequency_locked = true;
-
-               if (locking_frequency) {
-                       saved_frequency = exynos4_getspeed(0);
-
-                       mutex_unlock(&cpufreq_lock);
-                       exynos4_target(policy, locking_frequency,
-                                      CPUFREQ_RELATION_H);
-                       mutex_lock(&cpufreq_lock);
-               }
-
-               break;
-       case PM_POST_SUSPEND:
-
-               if (saved_frequency) {
-                       /*
-                        * While frequency_locked, only locking_frequency
-                        * is valid for target(). In order to use
-                        * saved_frequency while keeping frequency_locked,
-                        * we temporarly overwrite locking_frequency.
-                        */
-                       temp = locking_frequency;
-                       locking_frequency = saved_frequency;
-
-                       mutex_unlock(&cpufreq_lock);
-                       exynos4_target(policy, locking_frequency,
-                                      CPUFREQ_RELATION_H);
-                       mutex_lock(&cpufreq_lock);
-
-                       locking_frequency = temp;
-               }
-
-               frequency_locked = false;
-               break;
-       }
-out:
-       mutex_unlock(&cpufreq_lock);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block exynos4_cpufreq_nb = {
-       .notifier_call = exynos4_cpufreq_pm_notifier,
-};
-
-static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
-{
-       int ret;
-
-       policy->cur = policy->min = policy->max = exynos4_getspeed(policy->cpu);
-
-       cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
-
-       /* set the transition latency value */
-       policy->cpuinfo.transition_latency = 100000;
-
-       /*
-        * EXYNOS4 multi-core processors has 2 cores
-        * that the frequency cannot be set independently.
-        * Each cpu is bound to the same speed.
-        * So the affected cpu is all of the cpus.
-        */
-       cpumask_setall(policy->cpus);
-
-       ret = cpufreq_frequency_table_cpuinfo(policy, exynos4_freq_table);
-       if (ret)
-               return ret;
-
-       cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
-
-       return 0;
-}
-
-static int exynos4_cpufreq_cpu_exit(struct cpufreq_policy *policy)
-{
-       cpufreq_frequency_table_put_attr(policy->cpu);
-       return 0;
-}
-
-static struct freq_attr *exynos4_cpufreq_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-
-static struct cpufreq_driver exynos4_driver = {
-       .flags          = CPUFREQ_STICKY,
-       .verify         = exynos4_verify_speed,
-       .target         = exynos4_target,
-       .get            = exynos4_getspeed,
-       .init           = exynos4_cpufreq_cpu_init,
-       .exit           = exynos4_cpufreq_cpu_exit,
-       .name           = "exynos4_cpufreq",
-       .attr           = exynos4_cpufreq_attr,
-#ifdef CONFIG_PM
-       .suspend        = exynos4_cpufreq_suspend,
-       .resume         = exynos4_cpufreq_resume,
-#endif
-};
+       int i;
+       unsigned int tmp;
+       unsigned long rate;
 
-static int __init exynos4_cpufreq_init(void)
-{
        cpu_clk = clk_get(NULL, "armclk");
        if (IS_ERR(cpu_clk))
                return PTR_ERR(cpu_clk);
 
-       locking_frequency = exynos4_getspeed(0);
-
        moutcore = clk_get(NULL, "moutcore");
        if (IS_ERR(moutcore))
-               goto out;
+               goto err_moutcore;
 
        mout_mpll = clk_get(NULL, "mout_mpll");
        if (IS_ERR(mout_mpll))
-               goto out;
+               goto err_mout_mpll;
+
+       rate = clk_get_rate(mout_mpll) / 1000;
 
        mout_apll = clk_get(NULL, "mout_apll");
        if (IS_ERR(mout_apll))
-               goto out;
+               goto err_mout_apll;
 
-       arm_regulator = regulator_get(NULL, "vdd_arm");
-       if (IS_ERR(arm_regulator)) {
-               printk(KERN_ERR "failed to get resource %s\n", "vdd_arm");
-               goto out;
-       }
+       tmp = __raw_readl(S5P_CLKDIV_CPU);
 
-       int_regulator = regulator_get(NULL, "vdd_int");
-       if (IS_ERR(int_regulator)) {
-               printk(KERN_ERR "failed to get resource %s\n", "vdd_int");
-               goto out;
+       for (i = L0; i <  CPUFREQ_LEVEL_END; i++) {
+               tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK |
+                       S5P_CLKDIV_CPU0_COREM0_MASK |
+                       S5P_CLKDIV_CPU0_COREM1_MASK |
+                       S5P_CLKDIV_CPU0_PERIPH_MASK |
+                       S5P_CLKDIV_CPU0_ATB_MASK |
+                       S5P_CLKDIV_CPU0_PCLKDBG_MASK |
+                       S5P_CLKDIV_CPU0_APLL_MASK);
+
+               tmp |= ((clkdiv_cpu0[i][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
+                       (clkdiv_cpu0[i][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
+                       (clkdiv_cpu0[i][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
+                       (clkdiv_cpu0[i][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
+                       (clkdiv_cpu0[i][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
+                       (clkdiv_cpu0[i][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+                       (clkdiv_cpu0[i][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
+
+               exynos4210_clkdiv_table[i].clkdiv = tmp;
        }
 
-       /*
-        * Check DRAM type.
-        * Because DVFS level is different according to DRAM type.
-        */
-       memtype = __raw_readl(S5P_VA_DMC0 + S5P_DMC0_MEMCON_OFFSET);
-       memtype = (memtype >> S5P_DMC0_MEMTYPE_SHIFT);
-       memtype &= S5P_DMC0_MEMTYPE_MASK;
-
-       if ((memtype < DDR2) && (memtype > DDR3)) {
-               printk(KERN_ERR "%s: wrong memtype= 0x%x\n", __func__, memtype);
-               goto out;
-       } else {
-               printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
-       }
-
-       register_pm_notifier(&exynos4_cpufreq_nb);
-
-       return cpufreq_register_driver(&exynos4_driver);
-
-out:
-       if (!IS_ERR(cpu_clk))
-               clk_put(cpu_clk);
+       info->mpll_freq_khz = rate;
+       info->pm_lock_idx = L2;
+       info->pll_safe_idx = L2;
+       info->max_support_idx = max_support_idx;
+       info->min_support_idx = min_support_idx;
+       info->cpu_clk = cpu_clk;
+       info->volt_table = exynos4210_volt_table;
+       info->freq_table = exynos4210_freq_table;
+       info->set_freq = exynos4210_set_frequency;
+       info->need_apll_change = exynos4210_pms_change;
 
-       if (!IS_ERR(moutcore))
-               clk_put(moutcore);
+       return 0;
 
+err_mout_apll:
        if (!IS_ERR(mout_mpll))
                clk_put(mout_mpll);
+err_mout_mpll:
+       if (!IS_ERR(moutcore))
+               clk_put(moutcore);
+err_moutcore:
+       if (!IS_ERR(cpu_clk))
+               clk_put(cpu_clk);
 
-       if (!IS_ERR(mout_apll))
-               clk_put(mout_apll);
-
-       if (!IS_ERR(arm_regulator))
-               regulator_put(arm_regulator);
-
-       if (!IS_ERR(int_regulator))
-               regulator_put(int_regulator);
-
-       printk(KERN_ERR "%s: failed initialization\n", __func__);
-
+       pr_debug("%s: failed initialization\n", __func__);
        return -EINVAL;
 }
-late_initcall(exynos4_cpufreq_init);
+EXPORT_SYMBOL(exynos4210_cpufreq_init);
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
new file mode 100644 (file)
index 0000000..5d04c57
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ *  CPU frequency scaling for OMAP using OPP information
+ *
+ *  Copyright (C) 2005 Nokia Corporation
+ *  Written by Tony Lindgren <tony@atomide.com>
+ *
+ *  Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * Copyright (C) 2007-2011 Texas Instruments, Inc.
+ * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/opp.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/smp_plat.h>
+#include <asm/cpu.h>
+
+#include <plat/clock.h>
+#include <plat/omap-pm.h>
+#include <plat/common.h>
+#include <plat/omap_device.h>
+
+#include <mach/hardware.h>
+
+#ifdef CONFIG_SMP
+struct lpj_info {
+       unsigned long   ref;
+       unsigned int    freq;
+};
+
+static DEFINE_PER_CPU(struct lpj_info, lpj_ref);
+static struct lpj_info global_lpj_ref;
+#endif
+
+static struct cpufreq_frequency_table *freq_table;
+static atomic_t freq_table_users = ATOMIC_INIT(0);
+static struct clk *mpu_clk;
+static char *mpu_clk_name;
+static struct device *mpu_dev;
+
+static int omap_verify_speed(struct cpufreq_policy *policy)
+{
+       if (!freq_table)
+               return -EINVAL;
+       return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int omap_getspeed(unsigned int cpu)
+{
+       unsigned long rate;
+
+       if (cpu >= NR_CPUS)
+               return 0;
+
+       rate = clk_get_rate(mpu_clk) / 1000;
+       return rate;
+}
+
+static int omap_target(struct cpufreq_policy *policy,
+                      unsigned int target_freq,
+                      unsigned int relation)
+{
+       unsigned int i;
+       int ret = 0;
+       struct cpufreq_freqs freqs;
+
+       if (!freq_table) {
+               dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
+                               policy->cpu);
+               return -EINVAL;
+       }
+
+       ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+                       relation, &i);
+       if (ret) {
+               dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
+                       __func__, policy->cpu, target_freq, ret);
+               return ret;
+       }
+       freqs.new = freq_table[i].frequency;
+       if (!freqs.new) {
+               dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
+                       policy->cpu, target_freq);
+               return -EINVAL;
+       }
+
+       freqs.old = omap_getspeed(policy->cpu);
+       freqs.cpu = policy->cpu;
+
+       if (freqs.old == freqs.new && policy->cur == freqs.new)
+               return ret;
+
+       /* notifiers */
+       for_each_cpu(i, policy->cpus) {
+               freqs.cpu = i;
+               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       }
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+       pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
+#endif
+
+       ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+       freqs.new = omap_getspeed(policy->cpu);
+
+#ifdef CONFIG_SMP
+       /*
+        * Note that loops_per_jiffy is not updated on SMP systems in
+        * cpufreq driver. So, update the per-CPU loops_per_jiffy value
+        * on frequency transition. We need to update all dependent CPUs.
+        */
+       for_each_cpu(i, policy->cpus) {
+               struct lpj_info *lpj = &per_cpu(lpj_ref, i);
+               if (!lpj->freq) {
+                       lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy;
+                       lpj->freq = freqs.old;
+               }
+
+               per_cpu(cpu_data, i).loops_per_jiffy =
+                       cpufreq_scale(lpj->ref, lpj->freq, freqs.new);
+       }
+
+       /* And don't forget to adjust the global one */
+       if (!global_lpj_ref.freq) {
+               global_lpj_ref.ref = loops_per_jiffy;
+               global_lpj_ref.freq = freqs.old;
+       }
+       loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
+                                       freqs.new);
+#endif
+
+       /* notifiers */
+       for_each_cpu(i, policy->cpus) {
+               freqs.cpu = i;
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       }
+
+       return ret;
+}
+
+static inline void freq_table_free(void)
+{
+       if (atomic_dec_and_test(&freq_table_users))
+               opp_free_cpufreq_table(mpu_dev, &freq_table);
+}
+
+static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
+{
+       int result = 0;
+
+       mpu_clk = clk_get(NULL, mpu_clk_name);
+       if (IS_ERR(mpu_clk))
+               return PTR_ERR(mpu_clk);
+
+       if (policy->cpu >= NR_CPUS) {
+               result = -EINVAL;
+               goto fail_ck;
+       }
+
+       policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
+
+       if (atomic_inc_return(&freq_table_users) == 1)
+               result = opp_init_cpufreq_table(mpu_dev, &freq_table);
+
+       if (result) {
+               dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
+                               __func__, policy->cpu, result);
+               goto fail_ck;
+       }
+
+       result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       if (result)
+               goto fail_table;
+
+       cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->cur = omap_getspeed(policy->cpu);
+
+       /*
+        * On OMAP SMP configuartion, both processors share the voltage
+        * and clock. So both CPUs needs to be scaled together and hence
+        * needs software co-ordination. Use cpufreq affected_cpus
+        * interface to handle this scenario. Additional is_smp() check
+        * is to keep SMP_ON_UP build working.
+        */
+       if (is_smp()) {
+               policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+               cpumask_setall(policy->cpus);
+       }
+
+       /* FIXME: what's the actual transition time? */
+       policy->cpuinfo.transition_latency = 300 * 1000;
+
+       return 0;
+
+fail_table:
+       freq_table_free();
+fail_ck:
+       clk_put(mpu_clk);
+       return result;
+}
+
+static int omap_cpu_exit(struct cpufreq_policy *policy)
+{
+       freq_table_free();
+       clk_put(mpu_clk);
+       return 0;
+}
+
+static struct freq_attr *omap_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static struct cpufreq_driver omap_driver = {
+       .flags          = CPUFREQ_STICKY,
+       .verify         = omap_verify_speed,
+       .target         = omap_target,
+       .get            = omap_getspeed,
+       .init           = omap_cpu_init,
+       .exit           = omap_cpu_exit,
+       .name           = "omap",
+       .attr           = omap_cpufreq_attr,
+};
+
+static int __init omap_cpufreq_init(void)
+{
+       if (cpu_is_omap24xx())
+               mpu_clk_name = "virt_prcm_set";
+       else if (cpu_is_omap34xx())
+               mpu_clk_name = "dpll1_ck";
+       else if (cpu_is_omap44xx())
+               mpu_clk_name = "dpll_mpu_ck";
+
+       if (!mpu_clk_name) {
+               pr_err("%s: unsupported Silicon?\n", __func__);
+               return -EINVAL;
+       }
+
+       mpu_dev = omap_device_get_by_hwmod_name("mpu");
+       if (!mpu_dev) {
+               pr_warning("%s: unable to get the mpu device\n", __func__);
+               return -EINVAL;
+       }
+
+       return cpufreq_register_driver(&omap_driver);
+}
+
+static void __exit omap_cpufreq_exit(void)
+{
+       cpufreq_unregister_driver(&omap_driver);
+}
+
+MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
+MODULE_LICENSE("GPL");
+module_init(omap_cpufreq_init);
+module_exit(omap_cpufreq_exit);
index bce576d7478ed41f9b69ac727cc5d143d850bb83..8f9b2ceeec850305feae1b8fefef0f7a166cc265 100644 (file)
@@ -1,10 +1,11 @@
 /*
- *   (c) 2003-2010 Advanced Micro Devices, Inc.
+ *   (c) 2003-2012 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
  *
- *  Support : mark.langsdorf@amd.com
+ *  Maintainer:
+ *  Andreas Herrmann <andreas.herrmann3@amd.com>
  *
  *  Based on the powernow-k7.c module written by Dave Jones.
  *  (C) 2003 Dave Jones on behalf of SuSE Labs
  *  Valuable input gratefully received from Dave Jones, Pavel Machek,
  *  Dominik Brodowski, Jacob Shin, and others.
  *  Originally developed by Paul Devriendt.
- *  Processor information obtained from Chapter 9 (Power and Thermal Management)
- *  of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
- *  Opteron Processors" available for download from www.amd.com
  *
- *  Tables for specific CPUs can be inferred from
- *     http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
+ *  Processor information obtained from Chapter 9 (Power and Thermal
+ *  Management) of the "BIOS and Kernel Developer's Guide (BKDG) for
+ *  the AMD Athlon 64 and AMD Opteron Processors" and section "2.x
+ *  Power Management" in BKDGs for newer AMD CPU families.
+ *
+ *  Tables for specific CPUs can be inferred from AMD's processor
+ *  power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf)
  */
 
 #include <linux/kernel.h>
@@ -54,6 +57,9 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
 
 static int cpu_family = CPU_OPTERON;
 
+/* array to map SW pstate number to acpi state */
+static u32 ps_to_as[8];
+
 /* core performance boost */
 static bool cpb_capable, cpb_enabled;
 static struct msr __percpu *msrs;
@@ -80,9 +86,9 @@ static u32 find_khz_freq_from_fid(u32 fid)
 }
 
 static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
-               u32 pstate)
+                                    u32 pstate)
 {
-       return data[pstate].frequency;
+       return data[ps_to_as[pstate]].frequency;
 }
 
 /* Return the vco fid for an input fid
@@ -926,23 +932,27 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data,
                        invalidate_entry(powernow_table, i);
                        continue;
                }
-               rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
-               if (!(hi & HW_PSTATE_VALID_MASK)) {
-                       pr_debug("invalid pstate %d, ignoring\n", index);
-                       invalidate_entry(powernow_table, i);
-                       continue;
-               }
 
-               powernow_table[i].index = index;
+               ps_to_as[index] = i;
 
                /* Frequency may be rounded for these */
                if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
                                 || boot_cpu_data.x86 == 0x11) {
+
+                       rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
+                       if (!(hi & HW_PSTATE_VALID_MASK)) {
+                               pr_debug("invalid pstate %d, ignoring\n", index);
+                               invalidate_entry(powernow_table, i);
+                               continue;
+                       }
+
                        powernow_table[i].frequency =
                                freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7);
                } else
                        powernow_table[i].frequency =
                                data->acpi_data.states[i].core_frequency * 1000;
+
+               powernow_table[i].index = index;
        }
        return 0;
 }
@@ -1189,7 +1199,8 @@ static int powernowk8_target(struct cpufreq_policy *pol,
        powernow_k8_acpi_pst_values(data, newstate);
 
        if (cpu_family == CPU_HW_PSTATE)
-               ret = transition_frequency_pstate(data, newstate);
+               ret = transition_frequency_pstate(data,
+                       data->powernow_table[newstate].index);
        else
                ret = transition_frequency_fidvid(data, newstate);
        if (ret) {
@@ -1202,7 +1213,7 @@ static int powernowk8_target(struct cpufreq_policy *pol,
 
        if (cpu_family == CPU_HW_PSTATE)
                pol->cur = find_khz_freq_from_pstate(data->powernow_table,
-                               newstate);
+                               data->powernow_table[newstate].index);
        else
                pol->cur = find_khz_freq_from_fid(data->currfid);
        ret = 0;
index 3475f65aeec692c4f7102492f028a3cf05e2d06c..a5e72cb5f53cf708706a99b1d98ed983e629a81c 100644 (file)
@@ -8,6 +8,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) "cpufreq: " fmt
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -91,7 +93,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
        if (freqs.old == freqs.new)
                return 0;
 
-       pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
+       pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new);
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
@@ -101,7 +103,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
                                            dvfs->vddarm_min,
                                            dvfs->vddarm_max);
                if (ret != 0) {
-                       pr_err("cpufreq: Failed to set VDDARM for %dkHz: %d\n",
+                       pr_err("Failed to set VDDARM for %dkHz: %d\n",
                               freqs.new, ret);
                        goto err;
                }
@@ -110,7 +112,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
 
        ret = clk_set_rate(armclk, freqs.new * 1000);
        if (ret < 0) {
-               pr_err("cpufreq: Failed to set rate %dkHz: %d\n",
+               pr_err("Failed to set rate %dkHz: %d\n",
                       freqs.new, ret);
                goto err;
        }
@@ -123,14 +125,14 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
                                            dvfs->vddarm_min,
                                            dvfs->vddarm_max);
                if (ret != 0) {
-                       pr_err("cpufreq: Failed to set VDDARM for %dkHz: %d\n",
+                       pr_err("Failed to set VDDARM for %dkHz: %d\n",
                               freqs.new, ret);
                        goto err_clk;
                }
        }
 #endif
 
-       pr_debug("cpufreq: Set actual frequency %lukHz\n",
+       pr_debug("Set actual frequency %lukHz\n",
                 clk_get_rate(armclk) / 1000);
 
        return 0;
@@ -153,7 +155,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
 
        count = regulator_count_voltages(vddarm);
        if (count < 0) {
-               pr_err("cpufreq: Unable to check supported voltages\n");
+               pr_err("Unable to check supported voltages\n");
        }
 
        freq = s3c64xx_freq_table;
@@ -171,7 +173,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
                }
 
                if (!found) {
-                       pr_debug("cpufreq: %dkHz unsupported by regulator\n",
+                       pr_debug("%dkHz unsupported by regulator\n",
                                 freq->frequency);
                        freq->frequency = CPUFREQ_ENTRY_INVALID;
                }
@@ -194,13 +196,13 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
                return -EINVAL;
 
        if (s3c64xx_freq_table == NULL) {
-               pr_err("cpufreq: No frequency information for this CPU\n");
+               pr_err("No frequency information for this CPU\n");
                return -ENODEV;
        }
 
        armclk = clk_get(NULL, "armclk");
        if (IS_ERR(armclk)) {
-               pr_err("cpufreq: Unable to obtain ARMCLK: %ld\n",
+               pr_err("Unable to obtain ARMCLK: %ld\n",
                       PTR_ERR(armclk));
                return PTR_ERR(armclk);
        }
@@ -209,12 +211,19 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
        vddarm = regulator_get(NULL, "vddarm");
        if (IS_ERR(vddarm)) {
                ret = PTR_ERR(vddarm);
-               pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
-               pr_err("cpufreq: Only frequency scaling available\n");
+               pr_err("Failed to obtain VDDARM: %d\n", ret);
+               pr_err("Only frequency scaling available\n");
                vddarm = NULL;
        } else {
                s3c64xx_cpufreq_config_regulator();
        }
+
+       vddint = regulator_get(NULL, "vddint");
+       if (IS_ERR(vddint)) {
+               ret = PTR_ERR(vddint);
+               pr_err("Failed to obtain VDDINT: %d\n", ret);
+               vddint = NULL;
+       }
 #endif
 
        freq = s3c64xx_freq_table;
@@ -225,7 +234,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
                r = clk_round_rate(armclk, freq->frequency * 1000);
                r /= 1000;
                if (r != freq->frequency) {
-                       pr_debug("cpufreq: %dkHz unsupported by clock\n",
+                       pr_debug("%dkHz unsupported by clock\n",
                                 freq->frequency);
                        freq->frequency = CPUFREQ_ENTRY_INVALID;
                }
@@ -248,7 +257,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
 
        ret = cpufreq_frequency_table_cpuinfo(policy, s3c64xx_freq_table);
        if (ret != 0) {
-               pr_err("cpufreq: Failed to configure frequency table: %d\n",
+               pr_err("Failed to configure frequency table: %d\n",
                       ret);
                regulator_put(vddarm);
                clk_put(armclk);
index 1d103f997dc21b7c175e4b4d2eae4199974b279c..13f8e1a149889076aa41f95b785702c0a6fd02a5 100644 (file)
@@ -1292,18 +1292,7 @@ static struct platform_driver crypto4xx_driver = {
        .remove         = crypto4xx_remove,
 };
 
-static int __init crypto4xx_init(void)
-{
-       return platform_driver_register(&crypto4xx_driver);
-}
-
-static void __exit crypto4xx_exit(void)
-{
-       platform_driver_unregister(&crypto4xx_driver);
-}
-
-module_init(crypto4xx_init);
-module_exit(crypto4xx_exit);
+module_platform_driver(crypto4xx_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("James Hsiao <jhsiao@amcc.com>");
index 4159265b453b1449d3247dd7977ca540cae7f329..e73cf2e8110ae944302608ce864bd7b9d71a8422 100644 (file)
@@ -113,7 +113,7 @@ static inline void append_dec_shr_done(u32 *desc)
 
        jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TEST_ALL);
        set_jump_tgt_here(desc, jump_cmd);
-       append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD);
+       append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
 }
 
 /*
@@ -213,7 +213,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx,
        set_jump_tgt_here(desc, key_jump_cmd);
 
        /* Propagate errors from shared to job descriptor */
-       append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD);
+       append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
 }
 
 static int aead_set_sh_desc(struct crypto_aead *aead)
@@ -310,7 +310,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
        /* Only propagate error immediately if shared */
        jump_cmd = append_jump(desc, JUMP_TEST_ALL);
        set_jump_tgt_here(desc, key_jump_cmd);
-       append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD);
+       append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
        set_jump_tgt_here(desc, jump_cmd);
 
        /* Class 2 operation */
@@ -683,7 +683,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
        set_jump_tgt_here(desc, key_jump_cmd);
 
        /* Propagate errors from shared to job descriptor */
-       append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD);
+       append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
 
        /* Load iv */
        append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
@@ -724,7 +724,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
        /* For aead, only propagate error immediately if shared */
        jump_cmd = append_jump(desc, JUMP_TEST_ALL);
        set_jump_tgt_here(desc, key_jump_cmd);
-       append_cmd(desc, SET_OK_PROP_ERRORS | CMD_LOAD);
+       append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
        set_jump_tgt_here(desc, jump_cmd);
 
        /* load IV */
@@ -1805,6 +1805,25 @@ struct caam_alg_template {
 
 static struct caam_alg_template driver_algs[] = {
        /* single-pass ipsec_esp descriptor */
+       {
+               .name = "authenc(hmac(md5),cbc(aes))",
+               .driver_name = "authenc-hmac-md5-cbc-aes-caam",
+               .blocksize = AES_BLOCK_SIZE,
+               .type = CRYPTO_ALG_TYPE_AEAD,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = AES_BLOCK_SIZE,
+                       .maxauthsize = MD5_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha1),cbc(aes))",
                .driver_name = "authenc-hmac-sha1-cbc-aes-caam",
@@ -1864,6 +1883,25 @@ static struct caam_alg_template driver_algs[] = {
                                   OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(md5),cbc(des3_ede))",
+               .driver_name = "authenc-hmac-md5-cbc-des3_ede-caam",
+               .blocksize = DES3_EDE_BLOCK_SIZE,
+               .type = CRYPTO_ALG_TYPE_AEAD,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES3_EDE_BLOCK_SIZE,
+                       .maxauthsize = MD5_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha1),cbc(des3_ede))",
                .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam",
@@ -1923,6 +1961,25 @@ static struct caam_alg_template driver_algs[] = {
                                   OP_ALG_AAI_HMAC_PRECOMP,
                .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
        },
+       {
+               .name = "authenc(hmac(md5),cbc(des))",
+               .driver_name = "authenc-hmac-md5-cbc-des-caam",
+               .blocksize = DES_BLOCK_SIZE,
+               .type = CRYPTO_ALG_TYPE_AEAD,
+               .template_aead = {
+                       .setkey = aead_setkey,
+                       .setauthsize = aead_setauthsize,
+                       .encrypt = aead_encrypt,
+                       .decrypt = aead_decrypt,
+                       .givencrypt = aead_givencrypt,
+                       .geniv = "<built-in>",
+                       .ivsize = DES_BLOCK_SIZE,
+                       .maxauthsize = MD5_DIGEST_SIZE,
+                       },
+               .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+               .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP,
+               .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC,
+       },
        {
                .name = "authenc(hmac(sha1),cbc(des))",
                .driver_name = "authenc-hmac-sha1-cbc-des-caam",
index d38f2afaa9660010c3df5bc645046891ae3bae5a..a63bc65fae862e1e8eb6c3aafce736afc02926a5 100644 (file)
@@ -28,6 +28,7 @@
 #include <crypto/aes.h>
 #include <crypto/des.h>
 #include <crypto/sha.h>
+#include <crypto/md5.h>
 #include <crypto/aead.h>
 #include <crypto/authenc.h>
 #include <crypto/scatterwalk.h>
index 73988bb7322abde6822094851801a0beb97b9169..8ae3ba2a160d5e1e08269a5d960b15d3dd0c732d 100644 (file)
@@ -52,8 +52,6 @@ static int caam_probe(struct platform_device *pdev)
        struct caam_ctrl __iomem *ctrl;
        struct caam_full __iomem *topregs;
        struct caam_drv_private *ctrlpriv;
-       struct caam_deco **deco;
-       u32 deconum;
 #ifdef CONFIG_DEBUG_FS
        struct caam_perfmon *perfmon;
 #endif
@@ -92,17 +90,6 @@ static int caam_probe(struct platform_device *pdev)
        if (sizeof(dma_addr_t) == sizeof(u64))
                dma_set_mask(dev, DMA_BIT_MASK(36));
 
-       /* Find out how many DECOs are present */
-       deconum = (rd_reg64(&topregs->ctrl.perfmon.cha_num) &
-                  CHA_NUM_DECONUM_MASK) >> CHA_NUM_DECONUM_SHIFT;
-
-       ctrlpriv->deco = kmalloc(deconum * sizeof(struct caam_deco *),
-                                GFP_KERNEL);
-
-       deco = (struct caam_deco __force **)&topregs->deco;
-       for (d = 0; d < deconum; d++)
-               ctrlpriv->deco[d] = deco[d];
-
        /*
         * Detect and enable JobRs
         * First, find out how many ring spec'ed, allocate references
@@ -253,18 +240,7 @@ static struct platform_driver caam_driver = {
        .remove      = __devexit_p(caam_remove),
 };
 
-static int __init caam_base_init(void)
-{
-       return platform_driver_register(&caam_driver);
-}
-
-static void __exit caam_base_exit(void)
-{
-       return platform_driver_unregister(&caam_driver);
-}
-
-module_init(caam_base_init);
-module_exit(caam_base_exit);
+module_platform_driver(caam_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("FSL CAAM request backend");
index 974a75842da926deb106acc6b6fd4f2e212c2607..a17c2958dab1eed5c2cd3d7a5a715085ce39f398 100644 (file)
@@ -9,7 +9,7 @@
 #define DESC_H
 
 /* Max size of any CAAM descriptor in 32-bit words, inclusive of header */
-#define MAX_CAAM_DESCSIZE       64
+#define MAX_CAAM_DESCSIZE      64
 
 /* Block size of any entity covered/uncovered with a KEK/TKEK */
 #define KEK_BLOCKSIZE          16
  * Supported descriptor command types as they show up
  * inside a descriptor command word.
  */
-#define CMD_SHIFT               27
-#define CMD_MASK                0xf8000000
-
-#define CMD_KEY                 (0x00 << CMD_SHIFT)
-#define CMD_SEQ_KEY             (0x01 << CMD_SHIFT)
-#define CMD_LOAD                (0x02 << CMD_SHIFT)
-#define CMD_SEQ_LOAD            (0x03 << CMD_SHIFT)
-#define CMD_FIFO_LOAD           (0x04 << CMD_SHIFT)
-#define CMD_SEQ_FIFO_LOAD       (0x05 << CMD_SHIFT)
-#define CMD_STORE               (0x0a << CMD_SHIFT)
-#define CMD_SEQ_STORE           (0x0b << CMD_SHIFT)
-#define CMD_FIFO_STORE          (0x0c << CMD_SHIFT)
-#define CMD_SEQ_FIFO_STORE      (0x0d << CMD_SHIFT)
-#define CMD_MOVE_LEN            (0x0e << CMD_SHIFT)
-#define CMD_MOVE                (0x0f << CMD_SHIFT)
-#define CMD_OPERATION           (0x10 << CMD_SHIFT)
-#define CMD_SIGNATURE           (0x12 << CMD_SHIFT)
-#define CMD_JUMP                (0x14 << CMD_SHIFT)
-#define CMD_MATH                (0x15 << CMD_SHIFT)
-#define CMD_DESC_HDR            (0x16 << CMD_SHIFT)
-#define CMD_SHARED_DESC_HDR     (0x17 << CMD_SHIFT)
-#define CMD_SEQ_IN_PTR          (0x1e << CMD_SHIFT)
-#define CMD_SEQ_OUT_PTR         (0x1f << CMD_SHIFT)
+#define CMD_SHIFT              27
+#define CMD_MASK               0xf8000000
+
+#define CMD_KEY                        (0x00 << CMD_SHIFT)
+#define CMD_SEQ_KEY            (0x01 << CMD_SHIFT)
+#define CMD_LOAD               (0x02 << CMD_SHIFT)
+#define CMD_SEQ_LOAD           (0x03 << CMD_SHIFT)
+#define CMD_FIFO_LOAD          (0x04 << CMD_SHIFT)
+#define CMD_SEQ_FIFO_LOAD      (0x05 << CMD_SHIFT)
+#define CMD_STORE              (0x0a << CMD_SHIFT)
+#define CMD_SEQ_STORE          (0x0b << CMD_SHIFT)
+#define CMD_FIFO_STORE         (0x0c << CMD_SHIFT)
+#define CMD_SEQ_FIFO_STORE     (0x0d << CMD_SHIFT)
+#define CMD_MOVE_LEN           (0x0e << CMD_SHIFT)
+#define CMD_MOVE               (0x0f << CMD_SHIFT)
+#define CMD_OPERATION          (0x10 << CMD_SHIFT)
+#define CMD_SIGNATURE          (0x12 << CMD_SHIFT)
+#define CMD_JUMP               (0x14 << CMD_SHIFT)
+#define CMD_MATH               (0x15 << CMD_SHIFT)
+#define CMD_DESC_HDR           (0x16 << CMD_SHIFT)
+#define CMD_SHARED_DESC_HDR    (0x17 << CMD_SHIFT)
+#define CMD_SEQ_IN_PTR         (0x1e << CMD_SHIFT)
+#define CMD_SEQ_OUT_PTR                (0x1f << CMD_SHIFT)
 
 /* General-purpose class selector for all commands */
-#define CLASS_SHIFT             25
-#define CLASS_MASK              (0x03 << CLASS_SHIFT)
+#define CLASS_SHIFT            25
+#define CLASS_MASK             (0x03 << CLASS_SHIFT)
 
-#define CLASS_NONE              (0x00 << CLASS_SHIFT)
-#define CLASS_1                 (0x01 << CLASS_SHIFT)
-#define CLASS_2                 (0x02 << CLASS_SHIFT)
-#define CLASS_BOTH              (0x03 << CLASS_SHIFT)
+#define CLASS_NONE             (0x00 << CLASS_SHIFT)
+#define CLASS_1                        (0x01 << CLASS_SHIFT)
+#define CLASS_2                        (0x02 << CLASS_SHIFT)
+#define CLASS_BOTH             (0x03 << CLASS_SHIFT)
 
 /*
  * Descriptor header command constructs
  * Do Not Run - marks a descriptor inexecutable if there was
  * a preceding error somewhere
  */
-#define HDR_DNR                 0x01000000
+#define HDR_DNR                        0x01000000
 
 /*
  * ONE - should always be set. Combination of ONE (always
  * set) and ZRO (always clear) forms an endianness sanity check
  */
-#define HDR_ONE                 0x00800000
-#define HDR_ZRO                 0x00008000
+#define HDR_ONE                        0x00800000
+#define HDR_ZRO                        0x00008000
 
 /* Start Index or SharedDesc Length */
-#define HDR_START_IDX_MASK      0x3f
-#define HDR_START_IDX_SHIFT     16
+#define HDR_START_IDX_MASK     0x3f
+#define HDR_START_IDX_SHIFT    16
 
 /* If shared descriptor header, 6-bit length */
-#define HDR_DESCLEN_SHR_MASK  0x3f
+#define HDR_DESCLEN_SHR_MASK   0x3f
 
 /* If non-shared header, 7-bit length */
-#define HDR_DESCLEN_MASK      0x7f
+#define HDR_DESCLEN_MASK       0x7f
 
 /* This is a TrustedDesc (if not SharedDesc) */
-#define HDR_TRUSTED             0x00004000
+#define HDR_TRUSTED            0x00004000
 
 /* Make into TrustedDesc (if not SharedDesc) */
-#define HDR_MAKE_TRUSTED        0x00002000
+#define HDR_MAKE_TRUSTED       0x00002000
 
 /* Save context if self-shared (if SharedDesc) */
-#define HDR_SAVECTX             0x00001000
+#define HDR_SAVECTX            0x00001000
 
 /* Next item points to SharedDesc */
-#define HDR_SHARED              0x00001000
+#define HDR_SHARED             0x00001000
 
 /*
  * Reverse Execution Order - execute JobDesc first, then
  * execute SharedDesc (normally SharedDesc goes first).
  */
-#define HDR_REVERSE             0x00000800
+#define HDR_REVERSE            0x00000800
 
 /* Propogate DNR property to SharedDesc */
-#define HDR_PROP_DNR            0x00000800
+#define HDR_PROP_DNR           0x00000800
 
 /* JobDesc/SharedDesc share property */
-#define HDR_SD_SHARE_MASK       0x03
-#define HDR_SD_SHARE_SHIFT      8
-#define HDR_JD_SHARE_MASK       0x07
-#define HDR_JD_SHARE_SHIFT      8
+#define HDR_SD_SHARE_MASK      0x03
+#define HDR_SD_SHARE_SHIFT     8
+#define HDR_JD_SHARE_MASK      0x07
+#define HDR_JD_SHARE_SHIFT     8
 
-#define HDR_SHARE_NEVER         (0x00 << HDR_SD_SHARE_SHIFT)
-#define HDR_SHARE_WAIT          (0x01 << HDR_SD_SHARE_SHIFT)
-#define HDR_SHARE_SERIAL        (0x02 << HDR_SD_SHARE_SHIFT)
-#define HDR_SHARE_ALWAYS        (0x03 << HDR_SD_SHARE_SHIFT)
-#define HDR_SHARE_DEFER         (0x04 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_NEVER                (0x00 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_WAIT         (0x01 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_SERIAL       (0x02 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_ALWAYS       (0x03 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_DEFER                (0x04 << HDR_SD_SHARE_SHIFT)
 
 /* JobDesc/SharedDesc descriptor length */
-#define HDR_JD_LENGTH_MASK      0x7f
-#define HDR_SD_LENGTH_MASK      0x3f
+#define HDR_JD_LENGTH_MASK     0x7f
+#define HDR_SD_LENGTH_MASK     0x3f
 
 /*
  * KEY/SEQ_KEY Command Constructs
  */
 
-/* Key Destination Class: 01 = Class 1, 02 - Class 2  */
-#define KEY_DEST_CLASS_SHIFT    25  /* use CLASS_1 or CLASS_2 */
-#define KEY_DEST_CLASS_MASK     (0x03 << KEY_DEST_CLASS_SHIFT)
+/* Key Destination Class: 01 = Class 1, 02 - Class 2 */
+#define KEY_DEST_CLASS_SHIFT   25      /* use CLASS_1 or CLASS_2 */
+#define KEY_DEST_CLASS_MASK    (0x03 << KEY_DEST_CLASS_SHIFT)
 
 /* Scatter-Gather Table/Variable Length Field */
-#define KEY_SGF                 0x01000000
-#define KEY_VLF                 0x01000000
+#define KEY_SGF                        0x01000000
+#define KEY_VLF                        0x01000000
 
 /* Immediate - Key follows command in the descriptor */
-#define KEY_IMM                 0x00800000
+#define KEY_IMM                        0x00800000
 
 /*
  * Encrypted - Key is encrypted either with the KEK, or
  * with the TDKEK if TK is set
  */
-#define KEY_ENC                 0x00400000
+#define KEY_ENC                        0x00400000
 
 /*
  * No Write Back - Do not allow key to be FIFO STOREd
  * KDEST - Key Destination: 0 - class key register,
  * 1 - PKHA 'e', 2 - AFHA Sbox, 3 - MDHA split-key
  */
-#define KEY_DEST_SHIFT          16
-#define KEY_DEST_MASK           (0x03 << KEY_DEST_SHIFT)
+#define KEY_DEST_SHIFT         16
+#define KEY_DEST_MASK          (0x03 << KEY_DEST_SHIFT)
 
-#define KEY_DEST_CLASS_REG      (0x00 << KEY_DEST_SHIFT)
-#define KEY_DEST_PKHA_E         (0x01 << KEY_DEST_SHIFT)
-#define KEY_DEST_AFHA_SBOX      (0x02 << KEY_DEST_SHIFT)
-#define KEY_DEST_MDHA_SPLIT     (0x03 << KEY_DEST_SHIFT)
+#define KEY_DEST_CLASS_REG     (0x00 << KEY_DEST_SHIFT)
+#define KEY_DEST_PKHA_E                (0x01 << KEY_DEST_SHIFT)
+#define KEY_DEST_AFHA_SBOX     (0x02 << KEY_DEST_SHIFT)
+#define KEY_DEST_MDHA_SPLIT    (0x03 << KEY_DEST_SHIFT)
 
 /* Length in bytes */
-#define KEY_LENGTH_MASK         0x000003ff
+#define KEY_LENGTH_MASK                0x000003ff
 
 /*
  * LOAD/SEQ_LOAD/STORE/SEQ_STORE Command Constructs
  * Load/Store Destination: 0 = class independent CCB,
  * 1 = class 1 CCB, 2 = class 2 CCB, 3 = DECO
  */
-#define LDST_CLASS_SHIFT        25
-#define LDST_CLASS_MASK         (0x03 << LDST_CLASS_SHIFT)
-#define LDST_CLASS_IND_CCB      (0x00 << LDST_CLASS_SHIFT)
-#define LDST_CLASS_1_CCB        (0x01 << LDST_CLASS_SHIFT)
-#define LDST_CLASS_2_CCB        (0x02 << LDST_CLASS_SHIFT)
-#define LDST_CLASS_DECO         (0x03 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_SHIFT       25
+#define LDST_CLASS_MASK                (0x03 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_IND_CCB     (0x00 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_1_CCB       (0x01 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_2_CCB       (0x02 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_DECO                (0x03 << LDST_CLASS_SHIFT)
 
 /* Scatter-Gather Table/Variable Length Field */
-#define LDST_SGF                0x01000000
+#define LDST_SGF               0x01000000
 #define LDST_VLF               LDST_SGF
 
-/* Immediate - Key follows this command in descriptor    */
-#define LDST_IMM_MASK           1
-#define LDST_IMM_SHIFT          23
-#define LDST_IMM                (LDST_IMM_MASK << LDST_IMM_SHIFT)
+/* Immediate - Key follows this command in descriptor */
+#define LDST_IMM_MASK          1
+#define LDST_IMM_SHIFT         23
+#define LDST_IMM               (LDST_IMM_MASK << LDST_IMM_SHIFT)
 
-/* SRC/DST - Destination for LOAD, Source for STORE   */
-#define LDST_SRCDST_SHIFT       16
-#define LDST_SRCDST_MASK        (0x7f << LDST_SRCDST_SHIFT)
+/* SRC/DST - Destination for LOAD, Source for STORE */
+#define LDST_SRCDST_SHIFT      16
+#define LDST_SRCDST_MASK       (0x7f << LDST_SRCDST_SHIFT)
 
 #define LDST_SRCDST_BYTE_CONTEXT       (0x20 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_BYTE_KEY           (0x40 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_DATASZ_REG    (0x02 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_ICVSZ_REG     (0x03 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_CHACTRL       (0x06 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECOCTRL       (0x06 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECOCTRL      (0x06 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_IRQCTRL       (0x07 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_PCLOVRD   (0x07 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_PCLOVRD  (0x07 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_CLRW          (0x08 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_MATH0     (0x08 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH0    (0x08 << LDST_SRCDST_SHIFT)
 #define LDST_SRCDST_WORD_STAT          (0x09 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_MATH1     (0x09 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_MATH2     (0x0a << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_AAD_SZ    (0x0b << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DECO_MATH3     (0x0b << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_CLASS1_ICV_SZ  (0x0c << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_ALTDS_CLASS1   (0x0f << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_PKHA_A_SZ      (0x10 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_PKHA_B_SZ      (0x11 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_PKHA_N_SZ      (0x12 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_PKHA_E_SZ      (0x13 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_DESCBUF        (0x40 << LDST_SRCDST_SHIFT)
-#define LDST_SRCDST_WORD_INFO_FIFO      (0x7a << LDST_SRCDST_SHIFT)
-
-/* Offset in source/destination                        */
-#define LDST_OFFSET_SHIFT       8
-#define LDST_OFFSET_MASK        (0xff << LDST_OFFSET_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH1    (0x09 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH2    (0x0a << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_AAD_SZ   (0x0b << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH3    (0x0b << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_ALTDS_CLASS1  (0x0f << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_A_SZ     (0x10 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_B_SZ     (0x11 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_N_SZ     (0x12 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_E_SZ     (0x13 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF       (0x40 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_INFO_FIFO     (0x7a << LDST_SRCDST_SHIFT)
+
+/* Offset in source/destination */
+#define LDST_OFFSET_SHIFT      8
+#define LDST_OFFSET_MASK       (0xff << LDST_OFFSET_SHIFT)
 
 /* LDOFF definitions used when DST = LDST_SRCDST_WORD_DECOCTRL */
 /* These could also be shifted by LDST_OFFSET_SHIFT - this reads better */
-#define LDOFF_CHG_SHARE_SHIFT        0
-#define LDOFF_CHG_SHARE_MASK         (0x3 << LDOFF_CHG_SHARE_SHIFT)
-#define LDOFF_CHG_SHARE_NEVER        (0x1 << LDOFF_CHG_SHARE_SHIFT)
-#define LDOFF_CHG_SHARE_OK_NO_PROP   (0x2 << LDOFF_CHG_SHARE_SHIFT)
-#define LDOFF_CHG_SHARE_OK_PROP      (0x3 << LDOFF_CHG_SHARE_SHIFT)
-
-#define LDOFF_ENABLE_AUTO_NFIFO         (1 << 2)
-#define LDOFF_DISABLE_AUTO_NFIFO        (1 << 3)
-
-#define LDOFF_CHG_NONSEQLIODN_SHIFT     4
-#define LDOFF_CHG_NONSEQLIODN_MASK      (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
-#define LDOFF_CHG_NONSEQLIODN_SEQ       (0x1 << LDOFF_CHG_NONSEQLIODN_SHIFT)
-#define LDOFF_CHG_NONSEQLIODN_NON_SEQ   (0x2 << LDOFF_CHG_NONSEQLIODN_SHIFT)
-#define LDOFF_CHG_NONSEQLIODN_TRUSTED   (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
-
-#define LDOFF_CHG_SEQLIODN_SHIFT     6
-#define LDOFF_CHG_SEQLIODN_MASK      (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
-#define LDOFF_CHG_SEQLIODN_SEQ       (0x1 << LDOFF_CHG_SEQLIODN_SHIFT)
-#define LDOFF_CHG_SEQLIODN_NON_SEQ   (0x2 << LDOFF_CHG_SEQLIODN_SHIFT)
-#define LDOFF_CHG_SEQLIODN_TRUSTED   (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
-
-/* Data length in bytes                                 */
-#define LDST_LEN_SHIFT          0
-#define LDST_LEN_MASK           (0xff << LDST_LEN_SHIFT)
+#define LDOFF_CHG_SHARE_SHIFT          0
+#define LDOFF_CHG_SHARE_MASK           (0x3 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_NEVER          (0x1 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_OK_PROP                (0x2 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_OK_NO_PROP     (0x3 << LDOFF_CHG_SHARE_SHIFT)
+
+#define LDOFF_ENABLE_AUTO_NFIFO                (1 << 2)
+#define LDOFF_DISABLE_AUTO_NFIFO       (1 << 3)
+
+#define LDOFF_CHG_NONSEQLIODN_SHIFT    4
+#define LDOFF_CHG_NONSEQLIODN_MASK     (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_SEQ      (0x1 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_NON_SEQ  (0x2 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_TRUSTED  (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+
+#define LDOFF_CHG_SEQLIODN_SHIFT       6
+#define LDOFF_CHG_SEQLIODN_MASK                (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_SEQ         (0x1 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_NON_SEQ     (0x2 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_TRUSTED     (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
+
+/* Data length in bytes        */
+#define LDST_LEN_SHIFT         0
+#define LDST_LEN_MASK          (0xff << LDST_LEN_SHIFT)
 
 /* Special Length definitions when dst=deco-ctrl */
-#define LDLEN_ENABLE_OSL_COUNT      (1 << 7)
-#define LDLEN_RST_CHA_OFIFO_PTR     (1 << 6)
-#define LDLEN_RST_OFIFO             (1 << 5)
-#define LDLEN_SET_OFIFO_OFF_VALID   (1 << 4)
-#define LDLEN_SET_OFIFO_OFF_RSVD    (1 << 3)
-#define LDLEN_SET_OFIFO_OFFSET_SHIFT 0
-#define LDLEN_SET_OFIFO_OFFSET_MASK (3 << LDLEN_SET_OFIFO_OFFSET_SHIFT)
+#define LDLEN_ENABLE_OSL_COUNT         (1 << 7)
+#define LDLEN_RST_CHA_OFIFO_PTR                (1 << 6)
+#define LDLEN_RST_OFIFO                        (1 << 5)
+#define LDLEN_SET_OFIFO_OFF_VALID      (1 << 4)
+#define LDLEN_SET_OFIFO_OFF_RSVD       (1 << 3)
+#define LDLEN_SET_OFIFO_OFFSET_SHIFT   0
+#define LDLEN_SET_OFIFO_OFFSET_MASK    (3 << LDLEN_SET_OFIFO_OFFSET_SHIFT)
 
 /*
  * FIFO_LOAD/FIFO_STORE/SEQ_FIFO_LOAD/SEQ_FIFO_STORE
  * 1 = Load for Class1, 2 = Load for Class2, 3 = Load both
  * Store Source: 0 = normal, 1 = Class1key, 2 = Class2key
  */
-#define FIFOLD_CLASS_SHIFT      25
-#define FIFOLD_CLASS_MASK       (0x03 << FIFOLD_CLASS_SHIFT)
-#define FIFOLD_CLASS_SKIP       (0x00 << FIFOLD_CLASS_SHIFT)
-#define FIFOLD_CLASS_CLASS1     (0x01 << FIFOLD_CLASS_SHIFT)
-#define FIFOLD_CLASS_CLASS2     (0x02 << FIFOLD_CLASS_SHIFT)
-#define FIFOLD_CLASS_BOTH       (0x03 << FIFOLD_CLASS_SHIFT)
-
-#define FIFOST_CLASS_SHIFT      25
-#define FIFOST_CLASS_MASK       (0x03 << FIFOST_CLASS_SHIFT)
-#define FIFOST_CLASS_NORMAL     (0x00 << FIFOST_CLASS_SHIFT)
-#define FIFOST_CLASS_CLASS1KEY  (0x01 << FIFOST_CLASS_SHIFT)
-#define FIFOST_CLASS_CLASS2KEY  (0x02 << FIFOST_CLASS_SHIFT)
+#define FIFOLD_CLASS_SHIFT     25
+#define FIFOLD_CLASS_MASK      (0x03 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_SKIP      (0x00 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_CLASS1    (0x01 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_CLASS2    (0x02 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_BOTH      (0x03 << FIFOLD_CLASS_SHIFT)
+
+#define FIFOST_CLASS_SHIFT     25
+#define FIFOST_CLASS_MASK      (0x03 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_NORMAL    (0x00 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_CLASS1KEY (0x01 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_CLASS2KEY (0x02 << FIFOST_CLASS_SHIFT)
 
 /*
  * Scatter-Gather Table/Variable Length Field
  * If set for FIFO_LOAD, refers to a SG table. Within
  * SEQ_FIFO_LOAD, is variable input sequence
  */
-#define FIFOLDST_SGF_SHIFT      24
-#define FIFOLDST_SGF_MASK       (1 << FIFOLDST_SGF_SHIFT)
-#define FIFOLDST_VLF_MASK       (1 << FIFOLDST_SGF_SHIFT)
-#define FIFOLDST_SGF            (1 << FIFOLDST_SGF_SHIFT)
-#define FIFOLDST_VLF            (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_SGF_SHIFT     24
+#define FIFOLDST_SGF_MASK      (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_VLF_MASK      (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_SGF           (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_VLF           (1 << FIFOLDST_SGF_SHIFT)
 
 /* Immediate - Data follows command in descriptor */
-#define FIFOLD_IMM_SHIFT      23
-#define FIFOLD_IMM_MASK       (1 << FIFOLD_IMM_SHIFT)
-#define FIFOLD_IMM            (1 << FIFOLD_IMM_SHIFT)
+#define FIFOLD_IMM_SHIFT       23
+#define FIFOLD_IMM_MASK                (1 << FIFOLD_IMM_SHIFT)
+#define FIFOLD_IMM             (1 << FIFOLD_IMM_SHIFT)
 
 /* Continue - Not the last FIFO store to come */
-#define FIFOST_CONT_SHIFT     23
-#define FIFOST_CONT_MASK      (1 << FIFOST_CONT_SHIFT)
-#define FIFOST_CONT_MASK      (1 << FIFOST_CONT_SHIFT)
+#define FIFOST_CONT_SHIFT      23
+#define FIFOST_CONT_MASK       (1 << FIFOST_CONT_SHIFT)
+#define FIFOST_CONT_MASK       (1 << FIFOST_CONT_SHIFT)
 
 /*
  * Extended Length - use 32-bit extended length that
  * follows the pointer field. Illegal with IMM set
  */
-#define FIFOLDST_EXT_SHIFT      22
-#define FIFOLDST_EXT_MASK       (1 << FIFOLDST_EXT_SHIFT)
-#define FIFOLDST_EXT            (1 << FIFOLDST_EXT_SHIFT)
+#define FIFOLDST_EXT_SHIFT     22
+#define FIFOLDST_EXT_MASK      (1 << FIFOLDST_EXT_SHIFT)
+#define FIFOLDST_EXT           (1 << FIFOLDST_EXT_SHIFT)
 
 /* Input data type.*/
-#define FIFOLD_TYPE_SHIFT       16
-#define FIFOLD_CONT_TYPE_SHIFT  19 /* shift past last-flush bits */
-#define FIFOLD_TYPE_MASK        (0x3f << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_SHIFT      16
+#define FIFOLD_CONT_TYPE_SHIFT 19 /* shift past last-flush bits */
+#define FIFOLD_TYPE_MASK       (0x3f << FIFOLD_TYPE_SHIFT)
 
 /* PK types */
-#define FIFOLD_TYPE_PK          (0x00 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_MASK     (0x30 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK         (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_MASK    (0x30 << FIFOLD_TYPE_SHIFT)
 #define FIFOLD_TYPE_PK_TYPEMASK (0x0f << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_A0       (0x00 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_A1       (0x01 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_A2       (0x02 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_A3       (0x03 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_B0       (0x04 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_B1       (0x05 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_B2       (0x06 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_B3       (0x07 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_N        (0x08 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_A        (0x0c << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_PK_B        (0x0d << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A0      (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A1      (0x01 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A2      (0x02 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A3      (0x03 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B0      (0x04 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B1      (0x05 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B2      (0x06 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B3      (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_N       (0x08 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A       (0x0c << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B       (0x0d << FIFOLD_TYPE_SHIFT)
 
 /* Other types. Need to OR in last/flush bits as desired */
-#define FIFOLD_TYPE_MSG_MASK    (0x38 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_MSG         (0x10 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_MSG1OUT2    (0x18 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_IV          (0x20 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_BITDATA     (0x28 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_AAD         (0x30 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_ICV         (0x38 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_MSG_MASK   (0x38 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_MSG                (0x10 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_MSG1OUT2   (0x18 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_IV         (0x20 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_BITDATA    (0x28 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_AAD                (0x30 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_ICV                (0x38 << FIFOLD_TYPE_SHIFT)
 
 /* Last/Flush bits for use with "other" types above */
-#define FIFOLD_TYPE_ACT_MASK    (0x07 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_NOACTION    (0x00 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_FLUSH1      (0x01 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_LAST1       (0x02 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_LAST2FLUSH  (0x03 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_LAST2       (0x04 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_ACT_MASK   (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_NOACTION   (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_FLUSH1     (0x01 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST1      (0x02 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST2FLUSH (0x03 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST2      (0x04 << FIFOLD_TYPE_SHIFT)
 #define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_LASTBOTH    (0x06 << FIFOLD_TYPE_SHIFT)
-#define FIFOLD_TYPE_LASTBOTHFL  (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LASTBOTH   (0x06 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT)
 
-#define FIFOLDST_LEN_MASK       0xffff
-#define FIFOLDST_EXT_LEN_MASK   0xffffffff
+#define FIFOLDST_LEN_MASK      0xffff
+#define FIFOLDST_EXT_LEN_MASK  0xffffffff
 
 /* Output data types */
-#define FIFOST_TYPE_SHIFT       16
-#define FIFOST_TYPE_MASK        (0x3f << FIFOST_TYPE_SHIFT)
-
-#define FIFOST_TYPE_PKHA_A0      (0x00 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_A1      (0x01 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_A2      (0x02 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_A3      (0x03 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_B0      (0x04 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_B1      (0x05 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_B2      (0x06 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_B3      (0x07 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_N       (0x08 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_A       (0x0c << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_B       (0x0d << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SHIFT      16
+#define FIFOST_TYPE_MASK       (0x3f << FIFOST_TYPE_SHIFT)
+
+#define FIFOST_TYPE_PKHA_A0     (0x00 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A1     (0x01 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A2     (0x02 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A3     (0x03 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B0     (0x04 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B1     (0x05 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B2     (0x06 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B3     (0x07 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_N      (0x08 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A      (0x0c << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B      (0x0d << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_E_JKEK  (0x22 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_PKHA_E_TKEK  (0x23 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_KEY_KEK      (0x24 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_KEY_TKEK     (0x25 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_SPLIT_KEK    (0x26 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_SPLIT_TKEK   (0x27 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_OUTFIFO_KEK  (0x28 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_E_JKEK         (0x22 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_E_TKEK         (0x23 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_KEK     (0x24 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_TKEK    (0x25 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SPLIT_KEK   (0x26 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SPLIT_TKEK  (0x27 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_OUTFIFO_KEK         (0x28 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_OUTFIFO_TKEK (0x29 << FIFOST_TYPE_SHIFT)
 #define FIFOST_TYPE_MESSAGE_DATA (0x30 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_RNGSTORE     (0x34 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_RNGFIFO      (0x35 << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_SKIP         (0x3f << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_RNGSTORE    (0x34 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_RNGFIFO     (0x35 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SKIP        (0x3f << FIFOST_TYPE_SHIFT)
 
 /*
  * OPERATION Command Constructs
  */
 
 /* Operation type selectors - OP TYPE */
-#define OP_TYPE_SHIFT           24
-#define OP_TYPE_MASK            (0x07 << OP_TYPE_SHIFT)
+#define OP_TYPE_SHIFT          24
+#define OP_TYPE_MASK           (0x07 << OP_TYPE_SHIFT)
 
-#define OP_TYPE_UNI_PROTOCOL    (0x00 << OP_TYPE_SHIFT)
-#define OP_TYPE_PK              (0x01 << OP_TYPE_SHIFT)
-#define OP_TYPE_CLASS1_ALG      (0x02 << OP_TYPE_SHIFT)
-#define OP_TYPE_CLASS2_ALG      (0x04 << OP_TYPE_SHIFT)
-#define OP_TYPE_DECAP_PROTOCOL  (0x06 << OP_TYPE_SHIFT)
-#define OP_TYPE_ENCAP_PROTOCOL  (0x07 << OP_TYPE_SHIFT)
+#define OP_TYPE_UNI_PROTOCOL   (0x00 << OP_TYPE_SHIFT)
+#define OP_TYPE_PK             (0x01 << OP_TYPE_SHIFT)
+#define OP_TYPE_CLASS1_ALG     (0x02 << OP_TYPE_SHIFT)
+#define OP_TYPE_CLASS2_ALG     (0x04 << OP_TYPE_SHIFT)
+#define OP_TYPE_DECAP_PROTOCOL (0x06 << OP_TYPE_SHIFT)
+#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT)
 
 /* ProtocolID selectors - PROTID */
-#define OP_PCLID_SHIFT          16
-#define OP_PCLID_MASK           (0xff << 16)
+#define OP_PCLID_SHIFT         16
+#define OP_PCLID_MASK          (0xff << 16)
 
 /* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */
-#define OP_PCLID_IKEV1_PRF      (0x01 << OP_PCLID_SHIFT)
-#define OP_PCLID_IKEV2_PRF      (0x02 << OP_PCLID_SHIFT)
-#define OP_PCLID_SSL30_PRF      (0x08 << OP_PCLID_SHIFT)
-#define OP_PCLID_TLS10_PRF      (0x09 << OP_PCLID_SHIFT)
-#define OP_PCLID_TLS11_PRF      (0x0a << OP_PCLID_SHIFT)
-#define OP_PCLID_DTLS10_PRF     (0x0c << OP_PCLID_SHIFT)
-#define OP_PCLID_PRF            (0x06 << OP_PCLID_SHIFT)
-#define OP_PCLID_BLOB           (0x0d << OP_PCLID_SHIFT)
-#define OP_PCLID_SECRETKEY      (0x11 << OP_PCLID_SHIFT)
-#define OP_PCLID_PUBLICKEYPAIR  (0x14 << OP_PCLID_SHIFT)
-#define OP_PCLID_DSASIGN        (0x15 << OP_PCLID_SHIFT)
-#define OP_PCLID_DSAVERIFY      (0x16 << OP_PCLID_SHIFT)
+#define OP_PCLID_IKEV1_PRF     (0x01 << OP_PCLID_SHIFT)
+#define OP_PCLID_IKEV2_PRF     (0x02 << OP_PCLID_SHIFT)
+#define OP_PCLID_SSL30_PRF     (0x08 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS10_PRF     (0x09 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS11_PRF     (0x0a << OP_PCLID_SHIFT)
+#define OP_PCLID_DTLS10_PRF    (0x0c << OP_PCLID_SHIFT)
+#define OP_PCLID_PRF           (0x06 << OP_PCLID_SHIFT)
+#define OP_PCLID_BLOB          (0x0d << OP_PCLID_SHIFT)
+#define OP_PCLID_SECRETKEY     (0x11 << OP_PCLID_SHIFT)
+#define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT)
+#define OP_PCLID_DSASIGN       (0x15 << OP_PCLID_SHIFT)
+#define OP_PCLID_DSAVERIFY     (0x16 << OP_PCLID_SHIFT)
 
 /* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */
-#define OP_PCLID_IPSEC          (0x01 << OP_PCLID_SHIFT)
-#define OP_PCLID_SRTP           (0x02 << OP_PCLID_SHIFT)
-#define OP_PCLID_MACSEC         (0x03 << OP_PCLID_SHIFT)
-#define OP_PCLID_WIFI           (0x04 << OP_PCLID_SHIFT)
-#define OP_PCLID_WIMAX          (0x05 << OP_PCLID_SHIFT)
-#define OP_PCLID_SSL30          (0x08 << OP_PCLID_SHIFT)
-#define OP_PCLID_TLS10          (0x09 << OP_PCLID_SHIFT)
-#define OP_PCLID_TLS11          (0x0a << OP_PCLID_SHIFT)
-#define OP_PCLID_TLS12          (0x0b << OP_PCLID_SHIFT)
-#define OP_PCLID_DTLS           (0x0c << OP_PCLID_SHIFT)
+#define OP_PCLID_IPSEC         (0x01 << OP_PCLID_SHIFT)
+#define OP_PCLID_SRTP          (0x02 << OP_PCLID_SHIFT)
+#define OP_PCLID_MACSEC                (0x03 << OP_PCLID_SHIFT)
+#define OP_PCLID_WIFI          (0x04 << OP_PCLID_SHIFT)
+#define OP_PCLID_WIMAX         (0x05 << OP_PCLID_SHIFT)
+#define OP_PCLID_SSL30         (0x08 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS10         (0x09 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS11         (0x0a << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS12         (0x0b << OP_PCLID_SHIFT)
+#define OP_PCLID_DTLS          (0x0c << OP_PCLID_SHIFT)
 
 /*
  * ProtocolInfo selectors
  */
-#define OP_PCLINFO_MASK                          0xffff
+#define OP_PCLINFO_MASK                                 0xffff
 
 /* for OP_PCLID_IPSEC */
-#define OP_PCL_IPSEC_CIPHER_MASK                 0xff00
-#define OP_PCL_IPSEC_AUTH_MASK                   0x00ff
-
-#define OP_PCL_IPSEC_DES_IV64                    0x0100
-#define OP_PCL_IPSEC_DES                         0x0200
-#define OP_PCL_IPSEC_3DES                        0x0300
-#define OP_PCL_IPSEC_AES_CBC                     0x0c00
-#define OP_PCL_IPSEC_AES_CTR                     0x0d00
-#define OP_PCL_IPSEC_AES_XTS                     0x1600
-#define OP_PCL_IPSEC_AES_CCM8                    0x0e00
-#define OP_PCL_IPSEC_AES_CCM12                   0x0f00
-#define OP_PCL_IPSEC_AES_CCM16                   0x1000
-#define OP_PCL_IPSEC_AES_GCM8                    0x1200
-#define OP_PCL_IPSEC_AES_GCM12                   0x1300
-#define OP_PCL_IPSEC_AES_GCM16                   0x1400
-
-#define OP_PCL_IPSEC_HMAC_NULL                   0x0000
-#define OP_PCL_IPSEC_HMAC_MD5_96                 0x0001
-#define OP_PCL_IPSEC_HMAC_SHA1_96                0x0002
-#define OP_PCL_IPSEC_AES_XCBC_MAC_96             0x0005
-#define OP_PCL_IPSEC_HMAC_MD5_128                0x0006
-#define OP_PCL_IPSEC_HMAC_SHA1_160               0x0007
-#define OP_PCL_IPSEC_HMAC_SHA2_256_128           0x000c
-#define OP_PCL_IPSEC_HMAC_SHA2_384_192           0x000d
-#define OP_PCL_IPSEC_HMAC_SHA2_512_256           0x000e
+#define OP_PCL_IPSEC_CIPHER_MASK                0xff00
+#define OP_PCL_IPSEC_AUTH_MASK                  0x00ff
+
+#define OP_PCL_IPSEC_DES_IV64                   0x0100
+#define OP_PCL_IPSEC_DES                        0x0200
+#define OP_PCL_IPSEC_3DES                       0x0300
+#define OP_PCL_IPSEC_AES_CBC                    0x0c00
+#define OP_PCL_IPSEC_AES_CTR                    0x0d00
+#define OP_PCL_IPSEC_AES_XTS                    0x1600
+#define OP_PCL_IPSEC_AES_CCM8                   0x0e00
+#define OP_PCL_IPSEC_AES_CCM12                  0x0f00
+#define OP_PCL_IPSEC_AES_CCM16                  0x1000
+#define OP_PCL_IPSEC_AES_GCM8                   0x1200
+#define OP_PCL_IPSEC_AES_GCM12                  0x1300
+#define OP_PCL_IPSEC_AES_GCM16                  0x1400
+
+#define OP_PCL_IPSEC_HMAC_NULL                  0x0000
+#define OP_PCL_IPSEC_HMAC_MD5_96                0x0001
+#define OP_PCL_IPSEC_HMAC_SHA1_96               0x0002
+#define OP_PCL_IPSEC_AES_XCBC_MAC_96            0x0005
+#define OP_PCL_IPSEC_HMAC_MD5_128               0x0006
+#define OP_PCL_IPSEC_HMAC_SHA1_160              0x0007
+#define OP_PCL_IPSEC_HMAC_SHA2_256_128          0x000c
+#define OP_PCL_IPSEC_HMAC_SHA2_384_192          0x000d
+#define OP_PCL_IPSEC_HMAC_SHA2_512_256          0x000e
 
 /* For SRTP - OP_PCLID_SRTP */
-#define OP_PCL_SRTP_CIPHER_MASK                  0xff00
-#define OP_PCL_SRTP_AUTH_MASK                    0x00ff
+#define OP_PCL_SRTP_CIPHER_MASK                         0xff00
+#define OP_PCL_SRTP_AUTH_MASK                   0x00ff
 
-#define OP_PCL_SRTP_AES_CTR                      0x0d00
+#define OP_PCL_SRTP_AES_CTR                     0x0d00
 
-#define OP_PCL_SRTP_HMAC_SHA1_160                0x0007
+#define OP_PCL_SRTP_HMAC_SHA1_160               0x0007
 
 /* For SSL 3.0 - OP_PCLID_SSL30 */
-#define OP_PCL_SSL30_AES_128_CBC_SHA             0x002f
-#define OP_PCL_SSL30_AES_128_CBC_SHA_2           0x0030
-#define OP_PCL_SSL30_AES_128_CBC_SHA_3           0x0031
-#define OP_PCL_SSL30_AES_128_CBC_SHA_4           0x0032
-#define OP_PCL_SSL30_AES_128_CBC_SHA_5           0x0033
-#define OP_PCL_SSL30_AES_128_CBC_SHA_6           0x0034
-#define OP_PCL_SSL30_AES_128_CBC_SHA_7           0x008c
-#define OP_PCL_SSL30_AES_128_CBC_SHA_8           0x0090
-#define OP_PCL_SSL30_AES_128_CBC_SHA_9           0x0094
-#define OP_PCL_SSL30_AES_128_CBC_SHA_10          0xc004
-#define OP_PCL_SSL30_AES_128_CBC_SHA_11          0xc009
-#define OP_PCL_SSL30_AES_128_CBC_SHA_12          0xc00e
-#define OP_PCL_SSL30_AES_128_CBC_SHA_13          0xc013
-#define OP_PCL_SSL30_AES_128_CBC_SHA_14          0xc018
-#define OP_PCL_SSL30_AES_128_CBC_SHA_15          0xc01d
-#define OP_PCL_SSL30_AES_128_CBC_SHA_16          0xc01e
-#define OP_PCL_SSL30_AES_128_CBC_SHA_17          0xc01f
-
-#define OP_PCL_SSL30_AES_256_CBC_SHA             0x0035
-#define OP_PCL_SSL30_AES_256_CBC_SHA_2           0x0036
-#define OP_PCL_SSL30_AES_256_CBC_SHA_3           0x0037
-#define OP_PCL_SSL30_AES_256_CBC_SHA_4           0x0038
-#define OP_PCL_SSL30_AES_256_CBC_SHA_5           0x0039
-#define OP_PCL_SSL30_AES_256_CBC_SHA_6           0x003a
-#define OP_PCL_SSL30_AES_256_CBC_SHA_7           0x008d
-#define OP_PCL_SSL30_AES_256_CBC_SHA_8           0x0091
-#define OP_PCL_SSL30_AES_256_CBC_SHA_9           0x0095
-#define OP_PCL_SSL30_AES_256_CBC_SHA_10          0xc005
-#define OP_PCL_SSL30_AES_256_CBC_SHA_11          0xc00a
-#define OP_PCL_SSL30_AES_256_CBC_SHA_12          0xc00f
-#define OP_PCL_SSL30_AES_256_CBC_SHA_13          0xc014
-#define OP_PCL_SSL30_AES_256_CBC_SHA_14          0xc019
-#define OP_PCL_SSL30_AES_256_CBC_SHA_15          0xc020
-#define OP_PCL_SSL30_AES_256_CBC_SHA_16          0xc021
-#define OP_PCL_SSL30_AES_256_CBC_SHA_17          0xc022
-
-#define OP_PCL_SSL30_3DES_EDE_CBC_MD5            0x0023
-
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA            0x001f
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_2          0x008b
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_3          0x008f
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_4          0x0093
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_5          0x000a
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_6          0x000d
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_7          0x0010
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_8          0x0013
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_9          0x0016
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_10         0x001b
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_11         0xc003
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_12         0xc008
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_13         0xc00d
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_14         0xc012
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_15         0xc017
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_16         0xc01a
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_17         0xc01b
-#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_18         0xc01c
-
-#define OP_PCL_SSL30_DES40_CBC_MD5               0x0029
-
-#define OP_PCL_SSL30_DES_CBC_MD5                 0x0022
-
-#define OP_PCL_SSL30_DES40_CBC_SHA               0x0008
-#define OP_PCL_SSL30_DES40_CBC_SHA_2             0x000b
-#define OP_PCL_SSL30_DES40_CBC_SHA_3             0x000e
-#define OP_PCL_SSL30_DES40_CBC_SHA_4             0x0011
-#define OP_PCL_SSL30_DES40_CBC_SHA_5             0x0014
-#define OP_PCL_SSL30_DES40_CBC_SHA_6             0x0019
-#define OP_PCL_SSL30_DES40_CBC_SHA_7             0x0026
-
-#define OP_PCL_SSL30_DES_CBC_SHA                 0x001e
-#define OP_PCL_SSL30_DES_CBC_SHA_2               0x0009
-#define OP_PCL_SSL30_DES_CBC_SHA_3               0x000c
-#define OP_PCL_SSL30_DES_CBC_SHA_4               0x000f
-#define OP_PCL_SSL30_DES_CBC_SHA_5               0x0012
-#define OP_PCL_SSL30_DES_CBC_SHA_6               0x0015
-#define OP_PCL_SSL30_DES_CBC_SHA_7               0x001a
-
-#define OP_PCL_SSL30_RC4_128_MD5                 0x0024
-#define OP_PCL_SSL30_RC4_128_MD5_2               0x0004
-#define OP_PCL_SSL30_RC4_128_MD5_3               0x0018
-
-#define OP_PCL_SSL30_RC4_40_MD5                  0x002b
-#define OP_PCL_SSL30_RC4_40_MD5_2                0x0003
-#define OP_PCL_SSL30_RC4_40_MD5_3                0x0017
-
-#define OP_PCL_SSL30_RC4_128_SHA                 0x0020
-#define OP_PCL_SSL30_RC4_128_SHA_2               0x008a
-#define OP_PCL_SSL30_RC4_128_SHA_3               0x008e
-#define OP_PCL_SSL30_RC4_128_SHA_4               0x0092
-#define OP_PCL_SSL30_RC4_128_SHA_5               0x0005
-#define OP_PCL_SSL30_RC4_128_SHA_6               0xc002
-#define OP_PCL_SSL30_RC4_128_SHA_7               0xc007
-#define OP_PCL_SSL30_RC4_128_SHA_8               0xc00c
-#define OP_PCL_SSL30_RC4_128_SHA_9               0xc011
-#define OP_PCL_SSL30_RC4_128_SHA_10              0xc016
-
-#define OP_PCL_SSL30_RC4_40_SHA                  0x0028
+#define OP_PCL_SSL30_AES_128_CBC_SHA            0x002f
+#define OP_PCL_SSL30_AES_128_CBC_SHA_2          0x0030
+#define OP_PCL_SSL30_AES_128_CBC_SHA_3          0x0031
+#define OP_PCL_SSL30_AES_128_CBC_SHA_4          0x0032
+#define OP_PCL_SSL30_AES_128_CBC_SHA_5          0x0033
+#define OP_PCL_SSL30_AES_128_CBC_SHA_6          0x0034
+#define OP_PCL_SSL30_AES_128_CBC_SHA_7          0x008c
+#define OP_PCL_SSL30_AES_128_CBC_SHA_8          0x0090
+#define OP_PCL_SSL30_AES_128_CBC_SHA_9          0x0094
+#define OP_PCL_SSL30_AES_128_CBC_SHA_10                 0xc004
+#define OP_PCL_SSL30_AES_128_CBC_SHA_11                 0xc009
+#define OP_PCL_SSL30_AES_128_CBC_SHA_12                 0xc00e
+#define OP_PCL_SSL30_AES_128_CBC_SHA_13                 0xc013
+#define OP_PCL_SSL30_AES_128_CBC_SHA_14                 0xc018
+#define OP_PCL_SSL30_AES_128_CBC_SHA_15                 0xc01d
+#define OP_PCL_SSL30_AES_128_CBC_SHA_16                 0xc01e
+#define OP_PCL_SSL30_AES_128_CBC_SHA_17                 0xc01f
+
+#define OP_PCL_SSL30_AES_256_CBC_SHA            0x0035
+#define OP_PCL_SSL30_AES_256_CBC_SHA_2          0x0036
+#define OP_PCL_SSL30_AES_256_CBC_SHA_3          0x0037
+#define OP_PCL_SSL30_AES_256_CBC_SHA_4          0x0038
+#define OP_PCL_SSL30_AES_256_CBC_SHA_5          0x0039
+#define OP_PCL_SSL30_AES_256_CBC_SHA_6          0x003a
+#define OP_PCL_SSL30_AES_256_CBC_SHA_7          0x008d
+#define OP_PCL_SSL30_AES_256_CBC_SHA_8          0x0091
+#define OP_PCL_SSL30_AES_256_CBC_SHA_9          0x0095
+#define OP_PCL_SSL30_AES_256_CBC_SHA_10                 0xc005
+#define OP_PCL_SSL30_AES_256_CBC_SHA_11                 0xc00a
+#define OP_PCL_SSL30_AES_256_CBC_SHA_12                 0xc00f
+#define OP_PCL_SSL30_AES_256_CBC_SHA_13                 0xc014
+#define OP_PCL_SSL30_AES_256_CBC_SHA_14                 0xc019
+#define OP_PCL_SSL30_AES_256_CBC_SHA_15                 0xc020
+#define OP_PCL_SSL30_AES_256_CBC_SHA_16                 0xc021
+#define OP_PCL_SSL30_AES_256_CBC_SHA_17                 0xc022
+
+#define OP_PCL_SSL30_3DES_EDE_CBC_MD5           0x0023
+
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA           0x001f
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_2                 0x008b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_3                 0x008f
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_4                 0x0093
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_5                 0x000a
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_6                 0x000d
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_7                 0x0010
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_8                 0x0013
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_9                 0x0016
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_10        0x001b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_11        0xc003
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_12        0xc008
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_13        0xc00d
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_14        0xc012
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_15        0xc017
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_16        0xc01a
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_17        0xc01b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_18        0xc01c
+
+#define OP_PCL_SSL30_DES40_CBC_MD5              0x0029
+
+#define OP_PCL_SSL30_DES_CBC_MD5                0x0022
+
+#define OP_PCL_SSL30_DES40_CBC_SHA              0x0008
+#define OP_PCL_SSL30_DES40_CBC_SHA_2            0x000b
+#define OP_PCL_SSL30_DES40_CBC_SHA_3            0x000e
+#define OP_PCL_SSL30_DES40_CBC_SHA_4            0x0011
+#define OP_PCL_SSL30_DES40_CBC_SHA_5            0x0014
+#define OP_PCL_SSL30_DES40_CBC_SHA_6            0x0019
+#define OP_PCL_SSL30_DES40_CBC_SHA_7            0x0026
+
+#define OP_PCL_SSL30_DES_CBC_SHA                0x001e
+#define OP_PCL_SSL30_DES_CBC_SHA_2              0x0009
+#define OP_PCL_SSL30_DES_CBC_SHA_3              0x000c
+#define OP_PCL_SSL30_DES_CBC_SHA_4              0x000f
+#define OP_PCL_SSL30_DES_CBC_SHA_5              0x0012
+#define OP_PCL_SSL30_DES_CBC_SHA_6              0x0015
+#define OP_PCL_SSL30_DES_CBC_SHA_7              0x001a
+
+#define OP_PCL_SSL30_RC4_128_MD5                0x0024
+#define OP_PCL_SSL30_RC4_128_MD5_2              0x0004
+#define OP_PCL_SSL30_RC4_128_MD5_3              0x0018
+
+#define OP_PCL_SSL30_RC4_40_MD5                         0x002b
+#define OP_PCL_SSL30_RC4_40_MD5_2               0x0003
+#define OP_PCL_SSL30_RC4_40_MD5_3               0x0017
+
+#define OP_PCL_SSL30_RC4_128_SHA                0x0020
+#define OP_PCL_SSL30_RC4_128_SHA_2              0x008a
+#define OP_PCL_SSL30_RC4_128_SHA_3              0x008e
+#define OP_PCL_SSL30_RC4_128_SHA_4              0x0092
+#define OP_PCL_SSL30_RC4_128_SHA_5              0x0005
+#define OP_PCL_SSL30_RC4_128_SHA_6              0xc002
+#define OP_PCL_SSL30_RC4_128_SHA_7              0xc007
+#define OP_PCL_SSL30_RC4_128_SHA_8              0xc00c
+#define OP_PCL_SSL30_RC4_128_SHA_9              0xc011
+#define OP_PCL_SSL30_RC4_128_SHA_10             0xc016
+
+#define OP_PCL_SSL30_RC4_40_SHA                         0x0028
 
 
 /* For TLS 1.0 - OP_PCLID_TLS10 */
-#define OP_PCL_TLS10_AES_128_CBC_SHA             0x002f
-#define OP_PCL_TLS10_AES_128_CBC_SHA_2           0x0030
-#define OP_PCL_TLS10_AES_128_CBC_SHA_3           0x0031
-#define OP_PCL_TLS10_AES_128_CBC_SHA_4           0x0032
-#define OP_PCL_TLS10_AES_128_CBC_SHA_5           0x0033
-#define OP_PCL_TLS10_AES_128_CBC_SHA_6           0x0034
-#define OP_PCL_TLS10_AES_128_CBC_SHA_7           0x008c
-#define OP_PCL_TLS10_AES_128_CBC_SHA_8           0x0090
-#define OP_PCL_TLS10_AES_128_CBC_SHA_9           0x0094
-#define OP_PCL_TLS10_AES_128_CBC_SHA_10          0xc004
-#define OP_PCL_TLS10_AES_128_CBC_SHA_11          0xc009
-#define OP_PCL_TLS10_AES_128_CBC_SHA_12          0xc00e
-#define OP_PCL_TLS10_AES_128_CBC_SHA_13          0xc013
-#define OP_PCL_TLS10_AES_128_CBC_SHA_14          0xc018
-#define OP_PCL_TLS10_AES_128_CBC_SHA_15          0xc01d
-#define OP_PCL_TLS10_AES_128_CBC_SHA_16          0xc01e
-#define OP_PCL_TLS10_AES_128_CBC_SHA_17          0xc01f
-
-#define OP_PCL_TLS10_AES_256_CBC_SHA             0x0035
-#define OP_PCL_TLS10_AES_256_CBC_SHA_2           0x0036
-#define OP_PCL_TLS10_AES_256_CBC_SHA_3           0x0037
-#define OP_PCL_TLS10_AES_256_CBC_SHA_4           0x0038
-#define OP_PCL_TLS10_AES_256_CBC_SHA_5           0x0039
-#define OP_PCL_TLS10_AES_256_CBC_SHA_6           0x003a
-#define OP_PCL_TLS10_AES_256_CBC_SHA_7           0x008d
-#define OP_PCL_TLS10_AES_256_CBC_SHA_8           0x0091
-#define OP_PCL_TLS10_AES_256_CBC_SHA_9           0x0095
-#define OP_PCL_TLS10_AES_256_CBC_SHA_10          0xc005
-#define OP_PCL_TLS10_AES_256_CBC_SHA_11          0xc00a
-#define OP_PCL_TLS10_AES_256_CBC_SHA_12          0xc00f
-#define OP_PCL_TLS10_AES_256_CBC_SHA_13          0xc014
-#define OP_PCL_TLS10_AES_256_CBC_SHA_14          0xc019
-#define OP_PCL_TLS10_AES_256_CBC_SHA_15          0xc020
-#define OP_PCL_TLS10_AES_256_CBC_SHA_16          0xc021
-#define OP_PCL_TLS10_AES_256_CBC_SHA_17          0xc022
-
-/* #define OP_PCL_TLS10_3DES_EDE_CBC_MD5            0x0023 */
-
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA            0x001f
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_2          0x008b
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_3          0x008f
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_4          0x0093
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_5          0x000a
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_6          0x000d
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_7          0x0010
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_8          0x0013
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_9          0x0016
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_10         0x001b
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_11         0xc003
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_12         0xc008
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_13         0xc00d
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_14         0xc012
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_15         0xc017
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_16         0xc01a
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_17         0xc01b
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_18         0xc01c
-
-#define OP_PCL_TLS10_DES40_CBC_MD5               0x0029
-
-#define OP_PCL_TLS10_DES_CBC_MD5                 0x0022
-
-#define OP_PCL_TLS10_DES40_CBC_SHA               0x0008
-#define OP_PCL_TLS10_DES40_CBC_SHA_2             0x000b
-#define OP_PCL_TLS10_DES40_CBC_SHA_3             0x000e
-#define OP_PCL_TLS10_DES40_CBC_SHA_4             0x0011
-#define OP_PCL_TLS10_DES40_CBC_SHA_5             0x0014
-#define OP_PCL_TLS10_DES40_CBC_SHA_6             0x0019
-#define OP_PCL_TLS10_DES40_CBC_SHA_7             0x0026
-
-
-#define OP_PCL_TLS10_DES_CBC_SHA                 0x001e
-#define OP_PCL_TLS10_DES_CBC_SHA_2               0x0009
-#define OP_PCL_TLS10_DES_CBC_SHA_3               0x000c
-#define OP_PCL_TLS10_DES_CBC_SHA_4               0x000f
-#define OP_PCL_TLS10_DES_CBC_SHA_5               0x0012
-#define OP_PCL_TLS10_DES_CBC_SHA_6               0x0015
-#define OP_PCL_TLS10_DES_CBC_SHA_7               0x001a
-
-#define OP_PCL_TLS10_RC4_128_MD5                 0x0024
-#define OP_PCL_TLS10_RC4_128_MD5_2               0x0004
-#define OP_PCL_TLS10_RC4_128_MD5_3               0x0018
-
-#define OP_PCL_TLS10_RC4_40_MD5                  0x002b
-#define OP_PCL_TLS10_RC4_40_MD5_2                0x0003
-#define OP_PCL_TLS10_RC4_40_MD5_3                0x0017
-
-#define OP_PCL_TLS10_RC4_128_SHA                 0x0020
-#define OP_PCL_TLS10_RC4_128_SHA_2               0x008a
-#define OP_PCL_TLS10_RC4_128_SHA_3               0x008e
-#define OP_PCL_TLS10_RC4_128_SHA_4               0x0092
-#define OP_PCL_TLS10_RC4_128_SHA_5               0x0005
-#define OP_PCL_TLS10_RC4_128_SHA_6               0xc002
-#define OP_PCL_TLS10_RC4_128_SHA_7               0xc007
-#define OP_PCL_TLS10_RC4_128_SHA_8               0xc00c
-#define OP_PCL_TLS10_RC4_128_SHA_9               0xc011
-#define OP_PCL_TLS10_RC4_128_SHA_10              0xc016
-
-#define OP_PCL_TLS10_RC4_40_SHA                  0x0028
-
-#define OP_PCL_TLS10_3DES_EDE_CBC_MD5            0xff23
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA160         0xff30
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA224         0xff34
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA256         0xff36
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA384         0xff33
-#define OP_PCL_TLS10_3DES_EDE_CBC_SHA512         0xff35
-#define OP_PCL_TLS10_AES_128_CBC_SHA160          0xff80
-#define OP_PCL_TLS10_AES_128_CBC_SHA224          0xff84
-#define OP_PCL_TLS10_AES_128_CBC_SHA256          0xff86
-#define OP_PCL_TLS10_AES_128_CBC_SHA384          0xff83
-#define OP_PCL_TLS10_AES_128_CBC_SHA512          0xff85
-#define OP_PCL_TLS10_AES_192_CBC_SHA160          0xff20
-#define OP_PCL_TLS10_AES_192_CBC_SHA224          0xff24
-#define OP_PCL_TLS10_AES_192_CBC_SHA256          0xff26
-#define OP_PCL_TLS10_AES_192_CBC_SHA384          0xff23
-#define OP_PCL_TLS10_AES_192_CBC_SHA512          0xff25
-#define OP_PCL_TLS10_AES_256_CBC_SHA160          0xff60
-#define OP_PCL_TLS10_AES_256_CBC_SHA224          0xff64
-#define OP_PCL_TLS10_AES_256_CBC_SHA256          0xff66
-#define OP_PCL_TLS10_AES_256_CBC_SHA384          0xff63
-#define OP_PCL_TLS10_AES_256_CBC_SHA512          0xff65
+#define OP_PCL_TLS10_AES_128_CBC_SHA            0x002f
+#define OP_PCL_TLS10_AES_128_CBC_SHA_2          0x0030
+#define OP_PCL_TLS10_AES_128_CBC_SHA_3          0x0031
+#define OP_PCL_TLS10_AES_128_CBC_SHA_4          0x0032
+#define OP_PCL_TLS10_AES_128_CBC_SHA_5          0x0033
+#define OP_PCL_TLS10_AES_128_CBC_SHA_6          0x0034
+#define OP_PCL_TLS10_AES_128_CBC_SHA_7          0x008c
+#define OP_PCL_TLS10_AES_128_CBC_SHA_8          0x0090
+#define OP_PCL_TLS10_AES_128_CBC_SHA_9          0x0094
+#define OP_PCL_TLS10_AES_128_CBC_SHA_10                 0xc004
+#define OP_PCL_TLS10_AES_128_CBC_SHA_11                 0xc009
+#define OP_PCL_TLS10_AES_128_CBC_SHA_12                 0xc00e
+#define OP_PCL_TLS10_AES_128_CBC_SHA_13                 0xc013
+#define OP_PCL_TLS10_AES_128_CBC_SHA_14                 0xc018
+#define OP_PCL_TLS10_AES_128_CBC_SHA_15                 0xc01d
+#define OP_PCL_TLS10_AES_128_CBC_SHA_16                 0xc01e
+#define OP_PCL_TLS10_AES_128_CBC_SHA_17                 0xc01f
+
+#define OP_PCL_TLS10_AES_256_CBC_SHA            0x0035
+#define OP_PCL_TLS10_AES_256_CBC_SHA_2          0x0036
+#define OP_PCL_TLS10_AES_256_CBC_SHA_3          0x0037
+#define OP_PCL_TLS10_AES_256_CBC_SHA_4          0x0038
+#define OP_PCL_TLS10_AES_256_CBC_SHA_5          0x0039
+#define OP_PCL_TLS10_AES_256_CBC_SHA_6          0x003a
+#define OP_PCL_TLS10_AES_256_CBC_SHA_7          0x008d
+#define OP_PCL_TLS10_AES_256_CBC_SHA_8          0x0091
+#define OP_PCL_TLS10_AES_256_CBC_SHA_9          0x0095
+#define OP_PCL_TLS10_AES_256_CBC_SHA_10                 0xc005
+#define OP_PCL_TLS10_AES_256_CBC_SHA_11                 0xc00a
+#define OP_PCL_TLS10_AES_256_CBC_SHA_12                 0xc00f
+#define OP_PCL_TLS10_AES_256_CBC_SHA_13                 0xc014
+#define OP_PCL_TLS10_AES_256_CBC_SHA_14                 0xc019
+#define OP_PCL_TLS10_AES_256_CBC_SHA_15                 0xc020
+#define OP_PCL_TLS10_AES_256_CBC_SHA_16                 0xc021
+#define OP_PCL_TLS10_AES_256_CBC_SHA_17                 0xc022
+
+/* #define OP_PCL_TLS10_3DES_EDE_CBC_MD5       0x0023 */
+
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA           0x001f
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_2                 0x008b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_3                 0x008f
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_4                 0x0093
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_5                 0x000a
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_6                 0x000d
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_7                 0x0010
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_8                 0x0013
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_9                 0x0016
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_10        0x001b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_11        0xc003
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_12        0xc008
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_13        0xc00d
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_14        0xc012
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_15        0xc017
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_16        0xc01a
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_17        0xc01b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_18        0xc01c
+
+#define OP_PCL_TLS10_DES40_CBC_MD5              0x0029
+
+#define OP_PCL_TLS10_DES_CBC_MD5                0x0022
+
+#define OP_PCL_TLS10_DES40_CBC_SHA              0x0008
+#define OP_PCL_TLS10_DES40_CBC_SHA_2            0x000b
+#define OP_PCL_TLS10_DES40_CBC_SHA_3            0x000e
+#define OP_PCL_TLS10_DES40_CBC_SHA_4            0x0011
+#define OP_PCL_TLS10_DES40_CBC_SHA_5            0x0014
+#define OP_PCL_TLS10_DES40_CBC_SHA_6            0x0019
+#define OP_PCL_TLS10_DES40_CBC_SHA_7            0x0026
+
+
+#define OP_PCL_TLS10_DES_CBC_SHA                0x001e
+#define OP_PCL_TLS10_DES_CBC_SHA_2              0x0009
+#define OP_PCL_TLS10_DES_CBC_SHA_3              0x000c
+#define OP_PCL_TLS10_DES_CBC_SHA_4              0x000f
+#define OP_PCL_TLS10_DES_CBC_SHA_5              0x0012
+#define OP_PCL_TLS10_DES_CBC_SHA_6              0x0015
+#define OP_PCL_TLS10_DES_CBC_SHA_7              0x001a
+
+#define OP_PCL_TLS10_RC4_128_MD5                0x0024
+#define OP_PCL_TLS10_RC4_128_MD5_2              0x0004
+#define OP_PCL_TLS10_RC4_128_MD5_3              0x0018
+
+#define OP_PCL_TLS10_RC4_40_MD5                         0x002b
+#define OP_PCL_TLS10_RC4_40_MD5_2               0x0003
+#define OP_PCL_TLS10_RC4_40_MD5_3               0x0017
+
+#define OP_PCL_TLS10_RC4_128_SHA                0x0020
+#define OP_PCL_TLS10_RC4_128_SHA_2              0x008a
+#define OP_PCL_TLS10_RC4_128_SHA_3              0x008e
+#define OP_PCL_TLS10_RC4_128_SHA_4              0x0092
+#define OP_PCL_TLS10_RC4_128_SHA_5              0x0005
+#define OP_PCL_TLS10_RC4_128_SHA_6              0xc002
+#define OP_PCL_TLS10_RC4_128_SHA_7              0xc007
+#define OP_PCL_TLS10_RC4_128_SHA_8              0xc00c
+#define OP_PCL_TLS10_RC4_128_SHA_9              0xc011
+#define OP_PCL_TLS10_RC4_128_SHA_10             0xc016
+
+#define OP_PCL_TLS10_RC4_40_SHA                         0x0028
+
+#define OP_PCL_TLS10_3DES_EDE_CBC_MD5           0xff23
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA160        0xff30
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA224        0xff34
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA256        0xff36
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA384        0xff33
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA512        0xff35
+#define OP_PCL_TLS10_AES_128_CBC_SHA160                 0xff80
+#define OP_PCL_TLS10_AES_128_CBC_SHA224                 0xff84
+#define OP_PCL_TLS10_AES_128_CBC_SHA256                 0xff86
+#define OP_PCL_TLS10_AES_128_CBC_SHA384                 0xff83
+#define OP_PCL_TLS10_AES_128_CBC_SHA512                 0xff85
+#define OP_PCL_TLS10_AES_192_CBC_SHA160                 0xff20
+#define OP_PCL_TLS10_AES_192_CBC_SHA224                 0xff24
+#define OP_PCL_TLS10_AES_192_CBC_SHA256                 0xff26
+#define OP_PCL_TLS10_AES_192_CBC_SHA384                 0xff23
+#define OP_PCL_TLS10_AES_192_CBC_SHA512                 0xff25
+#define OP_PCL_TLS10_AES_256_CBC_SHA160                 0xff60
+#define OP_PCL_TLS10_AES_256_CBC_SHA224                 0xff64
+#define OP_PCL_TLS10_AES_256_CBC_SHA256                 0xff66
+#define OP_PCL_TLS10_AES_256_CBC_SHA384                 0xff63
+#define OP_PCL_TLS10_AES_256_CBC_SHA512                 0xff65
 
 
 
 /* For TLS 1.1 - OP_PCLID_TLS11 */
-#define OP_PCL_TLS11_AES_128_CBC_SHA             0x002f
-#define OP_PCL_TLS11_AES_128_CBC_SHA_2           0x0030
-#define OP_PCL_TLS11_AES_128_CBC_SHA_3           0x0031
-#define OP_PCL_TLS11_AES_128_CBC_SHA_4           0x0032
-#define OP_PCL_TLS11_AES_128_CBC_SHA_5           0x0033
-#define OP_PCL_TLS11_AES_128_CBC_SHA_6           0x0034
-#define OP_PCL_TLS11_AES_128_CBC_SHA_7           0x008c
-#define OP_PCL_TLS11_AES_128_CBC_SHA_8           0x0090
-#define OP_PCL_TLS11_AES_128_CBC_SHA_9           0x0094
-#define OP_PCL_TLS11_AES_128_CBC_SHA_10          0xc004
-#define OP_PCL_TLS11_AES_128_CBC_SHA_11          0xc009
-#define OP_PCL_TLS11_AES_128_CBC_SHA_12          0xc00e
-#define OP_PCL_TLS11_AES_128_CBC_SHA_13          0xc013
-#define OP_PCL_TLS11_AES_128_CBC_SHA_14          0xc018
-#define OP_PCL_TLS11_AES_128_CBC_SHA_15          0xc01d
-#define OP_PCL_TLS11_AES_128_CBC_SHA_16          0xc01e
-#define OP_PCL_TLS11_AES_128_CBC_SHA_17          0xc01f
-
-#define OP_PCL_TLS11_AES_256_CBC_SHA             0x0035
-#define OP_PCL_TLS11_AES_256_CBC_SHA_2           0x0036
-#define OP_PCL_TLS11_AES_256_CBC_SHA_3           0x0037
-#define OP_PCL_TLS11_AES_256_CBC_SHA_4           0x0038
-#define OP_PCL_TLS11_AES_256_CBC_SHA_5           0x0039
-#define OP_PCL_TLS11_AES_256_CBC_SHA_6           0x003a
-#define OP_PCL_TLS11_AES_256_CBC_SHA_7           0x008d
-#define OP_PCL_TLS11_AES_256_CBC_SHA_8           0x0091
-#define OP_PCL_TLS11_AES_256_CBC_SHA_9           0x0095
-#define OP_PCL_TLS11_AES_256_CBC_SHA_10          0xc005
-#define OP_PCL_TLS11_AES_256_CBC_SHA_11          0xc00a
-#define OP_PCL_TLS11_AES_256_CBC_SHA_12          0xc00f
-#define OP_PCL_TLS11_AES_256_CBC_SHA_13          0xc014
-#define OP_PCL_TLS11_AES_256_CBC_SHA_14          0xc019
-#define OP_PCL_TLS11_AES_256_CBC_SHA_15          0xc020
-#define OP_PCL_TLS11_AES_256_CBC_SHA_16          0xc021
-#define OP_PCL_TLS11_AES_256_CBC_SHA_17          0xc022
-
-/* #define OP_PCL_TLS11_3DES_EDE_CBC_MD5            0x0023 */
-
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA            0x001f
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_2          0x008b
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_3          0x008f
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_4          0x0093
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_5          0x000a
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_6          0x000d
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_7          0x0010
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_8          0x0013
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_9          0x0016
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_10         0x001b
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_11         0xc003
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_12         0xc008
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_13         0xc00d
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_14         0xc012
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_15         0xc017
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_16         0xc01a
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_17         0xc01b
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_18         0xc01c
-
-#define OP_PCL_TLS11_DES40_CBC_MD5               0x0029
-
-#define OP_PCL_TLS11_DES_CBC_MD5                 0x0022
-
-#define OP_PCL_TLS11_DES40_CBC_SHA               0x0008
-#define OP_PCL_TLS11_DES40_CBC_SHA_2             0x000b
-#define OP_PCL_TLS11_DES40_CBC_SHA_3             0x000e
-#define OP_PCL_TLS11_DES40_CBC_SHA_4             0x0011
-#define OP_PCL_TLS11_DES40_CBC_SHA_5             0x0014
-#define OP_PCL_TLS11_DES40_CBC_SHA_6             0x0019
-#define OP_PCL_TLS11_DES40_CBC_SHA_7             0x0026
-
-#define OP_PCL_TLS11_DES_CBC_SHA                 0x001e
-#define OP_PCL_TLS11_DES_CBC_SHA_2               0x0009
-#define OP_PCL_TLS11_DES_CBC_SHA_3               0x000c
-#define OP_PCL_TLS11_DES_CBC_SHA_4               0x000f
-#define OP_PCL_TLS11_DES_CBC_SHA_5               0x0012
-#define OP_PCL_TLS11_DES_CBC_SHA_6               0x0015
-#define OP_PCL_TLS11_DES_CBC_SHA_7               0x001a
-
-#define OP_PCL_TLS11_RC4_128_MD5                 0x0024
-#define OP_PCL_TLS11_RC4_128_MD5_2               0x0004
-#define OP_PCL_TLS11_RC4_128_MD5_3               0x0018
-
-#define OP_PCL_TLS11_RC4_40_MD5                  0x002b
-#define OP_PCL_TLS11_RC4_40_MD5_2                0x0003
-#define OP_PCL_TLS11_RC4_40_MD5_3                0x0017
-
-#define OP_PCL_TLS11_RC4_128_SHA                 0x0020
-#define OP_PCL_TLS11_RC4_128_SHA_2               0x008a
-#define OP_PCL_TLS11_RC4_128_SHA_3               0x008e
-#define OP_PCL_TLS11_RC4_128_SHA_4               0x0092
-#define OP_PCL_TLS11_RC4_128_SHA_5               0x0005
-#define OP_PCL_TLS11_RC4_128_SHA_6               0xc002
-#define OP_PCL_TLS11_RC4_128_SHA_7               0xc007
-#define OP_PCL_TLS11_RC4_128_SHA_8               0xc00c
-#define OP_PCL_TLS11_RC4_128_SHA_9               0xc011
-#define OP_PCL_TLS11_RC4_128_SHA_10              0xc016
-
-#define OP_PCL_TLS11_RC4_40_SHA                  0x0028
-
-#define OP_PCL_TLS11_3DES_EDE_CBC_MD5            0xff23
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA160         0xff30
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA224         0xff34
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA256         0xff36
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA384         0xff33
-#define OP_PCL_TLS11_3DES_EDE_CBC_SHA512         0xff35
-#define OP_PCL_TLS11_AES_128_CBC_SHA160          0xff80
-#define OP_PCL_TLS11_AES_128_CBC_SHA224          0xff84
-#define OP_PCL_TLS11_AES_128_CBC_SHA256          0xff86
-#define OP_PCL_TLS11_AES_128_CBC_SHA384          0xff83
-#define OP_PCL_TLS11_AES_128_CBC_SHA512          0xff85
-#define OP_PCL_TLS11_AES_192_CBC_SHA160          0xff20
-#define OP_PCL_TLS11_AES_192_CBC_SHA224          0xff24
-#define OP_PCL_TLS11_AES_192_CBC_SHA256          0xff26
-#define OP_PCL_TLS11_AES_192_CBC_SHA384          0xff23
-#define OP_PCL_TLS11_AES_192_CBC_SHA512          0xff25
-#define OP_PCL_TLS11_AES_256_CBC_SHA160          0xff60
-#define OP_PCL_TLS11_AES_256_CBC_SHA224          0xff64
-#define OP_PCL_TLS11_AES_256_CBC_SHA256          0xff66
-#define OP_PCL_TLS11_AES_256_CBC_SHA384          0xff63
-#define OP_PCL_TLS11_AES_256_CBC_SHA512          0xff65
+#define OP_PCL_TLS11_AES_128_CBC_SHA            0x002f
+#define OP_PCL_TLS11_AES_128_CBC_SHA_2          0x0030
+#define OP_PCL_TLS11_AES_128_CBC_SHA_3          0x0031
+#define OP_PCL_TLS11_AES_128_CBC_SHA_4          0x0032
+#define OP_PCL_TLS11_AES_128_CBC_SHA_5          0x0033
+#define OP_PCL_TLS11_AES_128_CBC_SHA_6          0x0034
+#define OP_PCL_TLS11_AES_128_CBC_SHA_7          0x008c
+#define OP_PCL_TLS11_AES_128_CBC_SHA_8          0x0090
+#define OP_PCL_TLS11_AES_128_CBC_SHA_9          0x0094
+#define OP_PCL_TLS11_AES_128_CBC_SHA_10                 0xc004
+#define OP_PCL_TLS11_AES_128_CBC_SHA_11                 0xc009
+#define OP_PCL_TLS11_AES_128_CBC_SHA_12                 0xc00e
+#define OP_PCL_TLS11_AES_128_CBC_SHA_13                 0xc013
+#define OP_PCL_TLS11_AES_128_CBC_SHA_14                 0xc018
+#define OP_PCL_TLS11_AES_128_CBC_SHA_15                 0xc01d
+#define OP_PCL_TLS11_AES_128_CBC_SHA_16                 0xc01e
+#define OP_PCL_TLS11_AES_128_CBC_SHA_17                 0xc01f
+
+#define OP_PCL_TLS11_AES_256_CBC_SHA            0x0035
+#define OP_PCL_TLS11_AES_256_CBC_SHA_2          0x0036
+#define OP_PCL_TLS11_AES_256_CBC_SHA_3          0x0037
+#define OP_PCL_TLS11_AES_256_CBC_SHA_4          0x0038
+#define OP_PCL_TLS11_AES_256_CBC_SHA_5          0x0039
+#define OP_PCL_TLS11_AES_256_CBC_SHA_6          0x003a
+#define OP_PCL_TLS11_AES_256_CBC_SHA_7          0x008d
+#define OP_PCL_TLS11_AES_256_CBC_SHA_8          0x0091
+#define OP_PCL_TLS11_AES_256_CBC_SHA_9          0x0095
+#define OP_PCL_TLS11_AES_256_CBC_SHA_10                 0xc005
+#define OP_PCL_TLS11_AES_256_CBC_SHA_11                 0xc00a
+#define OP_PCL_TLS11_AES_256_CBC_SHA_12                 0xc00f
+#define OP_PCL_TLS11_AES_256_CBC_SHA_13                 0xc014
+#define OP_PCL_TLS11_AES_256_CBC_SHA_14                 0xc019
+#define OP_PCL_TLS11_AES_256_CBC_SHA_15                 0xc020
+#define OP_PCL_TLS11_AES_256_CBC_SHA_16                 0xc021
+#define OP_PCL_TLS11_AES_256_CBC_SHA_17                 0xc022
+
+/* #define OP_PCL_TLS11_3DES_EDE_CBC_MD5       0x0023 */
+
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA           0x001f
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_2                 0x008b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_3                 0x008f
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_4                 0x0093
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_5                 0x000a
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_6                 0x000d
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_7                 0x0010
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_8                 0x0013
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_9                 0x0016
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_10        0x001b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_11        0xc003
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_12        0xc008
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_13        0xc00d
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_14        0xc012
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_15        0xc017
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_16        0xc01a
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_17        0xc01b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_18        0xc01c
+
+#define OP_PCL_TLS11_DES40_CBC_MD5              0x0029
+
+#define OP_PCL_TLS11_DES_CBC_MD5                0x0022
+
+#define OP_PCL_TLS11_DES40_CBC_SHA              0x0008
+#define OP_PCL_TLS11_DES40_CBC_SHA_2            0x000b
+#define OP_PCL_TLS11_DES40_CBC_SHA_3            0x000e
+#define OP_PCL_TLS11_DES40_CBC_SHA_4            0x0011
+#define OP_PCL_TLS11_DES40_CBC_SHA_5            0x0014
+#define OP_PCL_TLS11_DES40_CBC_SHA_6            0x0019
+#define OP_PCL_TLS11_DES40_CBC_SHA_7            0x0026
+
+#define OP_PCL_TLS11_DES_CBC_SHA                0x001e
+#define OP_PCL_TLS11_DES_CBC_SHA_2              0x0009
+#define OP_PCL_TLS11_DES_CBC_SHA_3              0x000c
+#define OP_PCL_TLS11_DES_CBC_SHA_4              0x000f
+#define OP_PCL_TLS11_DES_CBC_SHA_5              0x0012
+#define OP_PCL_TLS11_DES_CBC_SHA_6              0x0015
+#define OP_PCL_TLS11_DES_CBC_SHA_7              0x001a
+
+#define OP_PCL_TLS11_RC4_128_MD5                0x0024
+#define OP_PCL_TLS11_RC4_128_MD5_2              0x0004
+#define OP_PCL_TLS11_RC4_128_MD5_3              0x0018
+
+#define OP_PCL_TLS11_RC4_40_MD5                         0x002b
+#define OP_PCL_TLS11_RC4_40_MD5_2               0x0003
+#define OP_PCL_TLS11_RC4_40_MD5_3               0x0017
+
+#define OP_PCL_TLS11_RC4_128_SHA                0x0020
+#define OP_PCL_TLS11_RC4_128_SHA_2              0x008a
+#define OP_PCL_TLS11_RC4_128_SHA_3              0x008e
+#define OP_PCL_TLS11_RC4_128_SHA_4              0x0092
+#define OP_PCL_TLS11_RC4_128_SHA_5              0x0005
+#define OP_PCL_TLS11_RC4_128_SHA_6              0xc002
+#define OP_PCL_TLS11_RC4_128_SHA_7              0xc007
+#define OP_PCL_TLS11_RC4_128_SHA_8              0xc00c
+#define OP_PCL_TLS11_RC4_128_SHA_9              0xc011
+#define OP_PCL_TLS11_RC4_128_SHA_10             0xc016
+
+#define OP_PCL_TLS11_RC4_40_SHA                         0x0028
+
+#define OP_PCL_TLS11_3DES_EDE_CBC_MD5           0xff23
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA160        0xff30
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA224        0xff34
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA256        0xff36
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA384        0xff33
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA512        0xff35
+#define OP_PCL_TLS11_AES_128_CBC_SHA160                 0xff80
+#define OP_PCL_TLS11_AES_128_CBC_SHA224                 0xff84
+#define OP_PCL_TLS11_AES_128_CBC_SHA256                 0xff86
+#define OP_PCL_TLS11_AES_128_CBC_SHA384                 0xff83
+#define OP_PCL_TLS11_AES_128_CBC_SHA512                 0xff85
+#define OP_PCL_TLS11_AES_192_CBC_SHA160                 0xff20
+#define OP_PCL_TLS11_AES_192_CBC_SHA224                 0xff24
+#define OP_PCL_TLS11_AES_192_CBC_SHA256                 0xff26
+#define OP_PCL_TLS11_AES_192_CBC_SHA384                 0xff23
+#define OP_PCL_TLS11_AES_192_CBC_SHA512                 0xff25
+#define OP_PCL_TLS11_AES_256_CBC_SHA160                 0xff60
+#define OP_PCL_TLS11_AES_256_CBC_SHA224                 0xff64
+#define OP_PCL_TLS11_AES_256_CBC_SHA256                 0xff66
+#define OP_PCL_TLS11_AES_256_CBC_SHA384                 0xff63
+#define OP_PCL_TLS11_AES_256_CBC_SHA512                 0xff65
 
 
 /* For TLS 1.2 - OP_PCLID_TLS12 */
-#define OP_PCL_TLS12_AES_128_CBC_SHA             0x002f
-#define OP_PCL_TLS12_AES_128_CBC_SHA_2           0x0030
-#define OP_PCL_TLS12_AES_128_CBC_SHA_3           0x0031
-#define OP_PCL_TLS12_AES_128_CBC_SHA_4           0x0032
-#define OP_PCL_TLS12_AES_128_CBC_SHA_5           0x0033
-#define OP_PCL_TLS12_AES_128_CBC_SHA_6           0x0034
-#define OP_PCL_TLS12_AES_128_CBC_SHA_7           0x008c
-#define OP_PCL_TLS12_AES_128_CBC_SHA_8           0x0090
-#define OP_PCL_TLS12_AES_128_CBC_SHA_9           0x0094
-#define OP_PCL_TLS12_AES_128_CBC_SHA_10          0xc004
-#define OP_PCL_TLS12_AES_128_CBC_SHA_11          0xc009
-#define OP_PCL_TLS12_AES_128_CBC_SHA_12          0xc00e
-#define OP_PCL_TLS12_AES_128_CBC_SHA_13          0xc013
-#define OP_PCL_TLS12_AES_128_CBC_SHA_14          0xc018
-#define OP_PCL_TLS12_AES_128_CBC_SHA_15          0xc01d
-#define OP_PCL_TLS12_AES_128_CBC_SHA_16          0xc01e
-#define OP_PCL_TLS12_AES_128_CBC_SHA_17          0xc01f
-
-#define OP_PCL_TLS12_AES_256_CBC_SHA             0x0035
-#define OP_PCL_TLS12_AES_256_CBC_SHA_2           0x0036
-#define OP_PCL_TLS12_AES_256_CBC_SHA_3           0x0037
-#define OP_PCL_TLS12_AES_256_CBC_SHA_4           0x0038
-#define OP_PCL_TLS12_AES_256_CBC_SHA_5           0x0039
-#define OP_PCL_TLS12_AES_256_CBC_SHA_6           0x003a
-#define OP_PCL_TLS12_AES_256_CBC_SHA_7           0x008d
-#define OP_PCL_TLS12_AES_256_CBC_SHA_8           0x0091
-#define OP_PCL_TLS12_AES_256_CBC_SHA_9           0x0095
-#define OP_PCL_TLS12_AES_256_CBC_SHA_10          0xc005
-#define OP_PCL_TLS12_AES_256_CBC_SHA_11          0xc00a
-#define OP_PCL_TLS12_AES_256_CBC_SHA_12          0xc00f
-#define OP_PCL_TLS12_AES_256_CBC_SHA_13          0xc014
-#define OP_PCL_TLS12_AES_256_CBC_SHA_14          0xc019
-#define OP_PCL_TLS12_AES_256_CBC_SHA_15          0xc020
-#define OP_PCL_TLS12_AES_256_CBC_SHA_16          0xc021
-#define OP_PCL_TLS12_AES_256_CBC_SHA_17          0xc022
-
-/* #define OP_PCL_TLS12_3DES_EDE_CBC_MD5            0x0023 */
-
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA            0x001f
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_2          0x008b
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_3          0x008f
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_4          0x0093
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_5          0x000a
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_6          0x000d
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_7          0x0010
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_8          0x0013
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_9          0x0016
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_10         0x001b
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_11         0xc003
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_12         0xc008
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_13         0xc00d
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_14         0xc012
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_15         0xc017
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_16         0xc01a
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_17         0xc01b
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_18         0xc01c
-
-#define OP_PCL_TLS12_DES40_CBC_MD5               0x0029
-
-#define OP_PCL_TLS12_DES_CBC_MD5                 0x0022
-
-#define OP_PCL_TLS12_DES40_CBC_SHA               0x0008
-#define OP_PCL_TLS12_DES40_CBC_SHA_2             0x000b
-#define OP_PCL_TLS12_DES40_CBC_SHA_3             0x000e
-#define OP_PCL_TLS12_DES40_CBC_SHA_4             0x0011
-#define OP_PCL_TLS12_DES40_CBC_SHA_5             0x0014
-#define OP_PCL_TLS12_DES40_CBC_SHA_6             0x0019
-#define OP_PCL_TLS12_DES40_CBC_SHA_7             0x0026
-
-#define OP_PCL_TLS12_DES_CBC_SHA                 0x001e
-#define OP_PCL_TLS12_DES_CBC_SHA_2               0x0009
-#define OP_PCL_TLS12_DES_CBC_SHA_3               0x000c
-#define OP_PCL_TLS12_DES_CBC_SHA_4               0x000f
-#define OP_PCL_TLS12_DES_CBC_SHA_5               0x0012
-#define OP_PCL_TLS12_DES_CBC_SHA_6               0x0015
-#define OP_PCL_TLS12_DES_CBC_SHA_7               0x001a
-
-#define OP_PCL_TLS12_RC4_128_MD5                 0x0024
-#define OP_PCL_TLS12_RC4_128_MD5_2               0x0004
-#define OP_PCL_TLS12_RC4_128_MD5_3               0x0018
-
-#define OP_PCL_TLS12_RC4_40_MD5                  0x002b
-#define OP_PCL_TLS12_RC4_40_MD5_2                0x0003
-#define OP_PCL_TLS12_RC4_40_MD5_3                0x0017
-
-#define OP_PCL_TLS12_RC4_128_SHA                 0x0020
-#define OP_PCL_TLS12_RC4_128_SHA_2               0x008a
-#define OP_PCL_TLS12_RC4_128_SHA_3               0x008e
-#define OP_PCL_TLS12_RC4_128_SHA_4               0x0092
-#define OP_PCL_TLS12_RC4_128_SHA_5               0x0005
-#define OP_PCL_TLS12_RC4_128_SHA_6               0xc002
-#define OP_PCL_TLS12_RC4_128_SHA_7               0xc007
-#define OP_PCL_TLS12_RC4_128_SHA_8               0xc00c
-#define OP_PCL_TLS12_RC4_128_SHA_9               0xc011
-#define OP_PCL_TLS12_RC4_128_SHA_10              0xc016
-
-#define OP_PCL_TLS12_RC4_40_SHA                  0x0028
-
-/* #define OP_PCL_TLS12_AES_128_CBC_SHA256          0x003c */
-#define OP_PCL_TLS12_AES_128_CBC_SHA256_2        0x003e
-#define OP_PCL_TLS12_AES_128_CBC_SHA256_3        0x003f
-#define OP_PCL_TLS12_AES_128_CBC_SHA256_4        0x0040
-#define OP_PCL_TLS12_AES_128_CBC_SHA256_5        0x0067
-#define OP_PCL_TLS12_AES_128_CBC_SHA256_6        0x006c
-
-/* #define OP_PCL_TLS12_AES_256_CBC_SHA256          0x003d */
-#define OP_PCL_TLS12_AES_256_CBC_SHA256_2        0x0068
-#define OP_PCL_TLS12_AES_256_CBC_SHA256_3        0x0069
-#define OP_PCL_TLS12_AES_256_CBC_SHA256_4        0x006a
-#define OP_PCL_TLS12_AES_256_CBC_SHA256_5        0x006b
-#define OP_PCL_TLS12_AES_256_CBC_SHA256_6        0x006d
+#define OP_PCL_TLS12_AES_128_CBC_SHA            0x002f
+#define OP_PCL_TLS12_AES_128_CBC_SHA_2          0x0030
+#define OP_PCL_TLS12_AES_128_CBC_SHA_3          0x0031
+#define OP_PCL_TLS12_AES_128_CBC_SHA_4          0x0032
+#define OP_PCL_TLS12_AES_128_CBC_SHA_5          0x0033
+#define OP_PCL_TLS12_AES_128_CBC_SHA_6          0x0034
+#define OP_PCL_TLS12_AES_128_CBC_SHA_7          0x008c
+#define OP_PCL_TLS12_AES_128_CBC_SHA_8          0x0090
+#define OP_PCL_TLS12_AES_128_CBC_SHA_9          0x0094
+#define OP_PCL_TLS12_AES_128_CBC_SHA_10                 0xc004
+#define OP_PCL_TLS12_AES_128_CBC_SHA_11                 0xc009
+#define OP_PCL_TLS12_AES_128_CBC_SHA_12                 0xc00e
+#define OP_PCL_TLS12_AES_128_CBC_SHA_13                 0xc013
+#define OP_PCL_TLS12_AES_128_CBC_SHA_14                 0xc018
+#define OP_PCL_TLS12_AES_128_CBC_SHA_15                 0xc01d
+#define OP_PCL_TLS12_AES_128_CBC_SHA_16                 0xc01e
+#define OP_PCL_TLS12_AES_128_CBC_SHA_17                 0xc01f
+
+#define OP_PCL_TLS12_AES_256_CBC_SHA            0x0035
+#define OP_PCL_TLS12_AES_256_CBC_SHA_2          0x0036
+#define OP_PCL_TLS12_AES_256_CBC_SHA_3          0x0037
+#define OP_PCL_TLS12_AES_256_CBC_SHA_4          0x0038
+#define OP_PCL_TLS12_AES_256_CBC_SHA_5          0x0039
+#define OP_PCL_TLS12_AES_256_CBC_SHA_6          0x003a
+#define OP_PCL_TLS12_AES_256_CBC_SHA_7          0x008d
+#define OP_PCL_TLS12_AES_256_CBC_SHA_8          0x0091
+#define OP_PCL_TLS12_AES_256_CBC_SHA_9          0x0095
+#define OP_PCL_TLS12_AES_256_CBC_SHA_10                 0xc005
+#define OP_PCL_TLS12_AES_256_CBC_SHA_11                 0xc00a
+#define OP_PCL_TLS12_AES_256_CBC_SHA_12                 0xc00f
+#define OP_PCL_TLS12_AES_256_CBC_SHA_13                 0xc014
+#define OP_PCL_TLS12_AES_256_CBC_SHA_14                 0xc019
+#define OP_PCL_TLS12_AES_256_CBC_SHA_15                 0xc020
+#define OP_PCL_TLS12_AES_256_CBC_SHA_16                 0xc021
+#define OP_PCL_TLS12_AES_256_CBC_SHA_17                 0xc022
+
+/* #define OP_PCL_TLS12_3DES_EDE_CBC_MD5       0x0023 */
+
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA           0x001f
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_2                 0x008b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_3                 0x008f
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_4                 0x0093
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_5                 0x000a
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_6                 0x000d
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_7                 0x0010
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_8                 0x0013
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_9                 0x0016
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_10        0x001b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_11        0xc003
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_12        0xc008
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_13        0xc00d
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_14        0xc012
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_15        0xc017
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_16        0xc01a
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_17        0xc01b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_18        0xc01c
+
+#define OP_PCL_TLS12_DES40_CBC_MD5              0x0029
+
+#define OP_PCL_TLS12_DES_CBC_MD5                0x0022
+
+#define OP_PCL_TLS12_DES40_CBC_SHA              0x0008
+#define OP_PCL_TLS12_DES40_CBC_SHA_2            0x000b
+#define OP_PCL_TLS12_DES40_CBC_SHA_3            0x000e
+#define OP_PCL_TLS12_DES40_CBC_SHA_4            0x0011
+#define OP_PCL_TLS12_DES40_CBC_SHA_5            0x0014
+#define OP_PCL_TLS12_DES40_CBC_SHA_6            0x0019
+#define OP_PCL_TLS12_DES40_CBC_SHA_7            0x0026
+
+#define OP_PCL_TLS12_DES_CBC_SHA                0x001e
+#define OP_PCL_TLS12_DES_CBC_SHA_2              0x0009
+#define OP_PCL_TLS12_DES_CBC_SHA_3              0x000c
+#define OP_PCL_TLS12_DES_CBC_SHA_4              0x000f
+#define OP_PCL_TLS12_DES_CBC_SHA_5              0x0012
+#define OP_PCL_TLS12_DES_CBC_SHA_6              0x0015
+#define OP_PCL_TLS12_DES_CBC_SHA_7              0x001a
+
+#define OP_PCL_TLS12_RC4_128_MD5                0x0024
+#define OP_PCL_TLS12_RC4_128_MD5_2              0x0004
+#define OP_PCL_TLS12_RC4_128_MD5_3              0x0018
+
+#define OP_PCL_TLS12_RC4_40_MD5                         0x002b
+#define OP_PCL_TLS12_RC4_40_MD5_2               0x0003
+#define OP_PCL_TLS12_RC4_40_MD5_3               0x0017
+
+#define OP_PCL_TLS12_RC4_128_SHA                0x0020
+#define OP_PCL_TLS12_RC4_128_SHA_2              0x008a
+#define OP_PCL_TLS12_RC4_128_SHA_3              0x008e
+#define OP_PCL_TLS12_RC4_128_SHA_4              0x0092
+#define OP_PCL_TLS12_RC4_128_SHA_5              0x0005
+#define OP_PCL_TLS12_RC4_128_SHA_6              0xc002
+#define OP_PCL_TLS12_RC4_128_SHA_7              0xc007
+#define OP_PCL_TLS12_RC4_128_SHA_8              0xc00c
+#define OP_PCL_TLS12_RC4_128_SHA_9              0xc011
+#define OP_PCL_TLS12_RC4_128_SHA_10             0xc016
+
+#define OP_PCL_TLS12_RC4_40_SHA                         0x0028
+
+/* #define OP_PCL_TLS12_AES_128_CBC_SHA256     0x003c */
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_2       0x003e
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_3       0x003f
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_4       0x0040
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_5       0x0067
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_6       0x006c
+
+/* #define OP_PCL_TLS12_AES_256_CBC_SHA256     0x003d */
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_2       0x0068
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_3       0x0069
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_4       0x006a
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_5       0x006b
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_6       0x006d
 
 /* AEAD_AES_xxx_CCM/GCM remain to be defined... */
 
-#define OP_PCL_TLS12_3DES_EDE_CBC_MD5            0xff23
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA160         0xff30
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA224         0xff34
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA256         0xff36
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA384         0xff33
-#define OP_PCL_TLS12_3DES_EDE_CBC_SHA512         0xff35
-#define OP_PCL_TLS12_AES_128_CBC_SHA160          0xff80
-#define OP_PCL_TLS12_AES_128_CBC_SHA224          0xff84
-#define OP_PCL_TLS12_AES_128_CBC_SHA256          0xff86
-#define OP_PCL_TLS12_AES_128_CBC_SHA384          0xff83
-#define OP_PCL_TLS12_AES_128_CBC_SHA512          0xff85
-#define OP_PCL_TLS12_AES_192_CBC_SHA160          0xff20
-#define OP_PCL_TLS12_AES_192_CBC_SHA224          0xff24
-#define OP_PCL_TLS12_AES_192_CBC_SHA256          0xff26
-#define OP_PCL_TLS12_AES_192_CBC_SHA384          0xff23
-#define OP_PCL_TLS12_AES_192_CBC_SHA512          0xff25
-#define OP_PCL_TLS12_AES_256_CBC_SHA160          0xff60
-#define OP_PCL_TLS12_AES_256_CBC_SHA224          0xff64
-#define OP_PCL_TLS12_AES_256_CBC_SHA256          0xff66
-#define OP_PCL_TLS12_AES_256_CBC_SHA384          0xff63
-#define OP_PCL_TLS12_AES_256_CBC_SHA512          0xff65
+#define OP_PCL_TLS12_3DES_EDE_CBC_MD5           0xff23
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA160        0xff30
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA224        0xff34
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA256        0xff36
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA384        0xff33
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA512        0xff35
+#define OP_PCL_TLS12_AES_128_CBC_SHA160                 0xff80
+#define OP_PCL_TLS12_AES_128_CBC_SHA224                 0xff84
+#define OP_PCL_TLS12_AES_128_CBC_SHA256                 0xff86
+#define OP_PCL_TLS12_AES_128_CBC_SHA384                 0xff83
+#define OP_PCL_TLS12_AES_128_CBC_SHA512                 0xff85
+#define OP_PCL_TLS12_AES_192_CBC_SHA160                 0xff20
+#define OP_PCL_TLS12_AES_192_CBC_SHA224                 0xff24
+#define OP_PCL_TLS12_AES_192_CBC_SHA256                 0xff26
+#define OP_PCL_TLS12_AES_192_CBC_SHA384                 0xff23
+#define OP_PCL_TLS12_AES_192_CBC_SHA512                 0xff25
+#define OP_PCL_TLS12_AES_256_CBC_SHA160                 0xff60
+#define OP_PCL_TLS12_AES_256_CBC_SHA224                 0xff64
+#define OP_PCL_TLS12_AES_256_CBC_SHA256                 0xff66
+#define OP_PCL_TLS12_AES_256_CBC_SHA384                 0xff63
+#define OP_PCL_TLS12_AES_256_CBC_SHA512                 0xff65
 
 /* For DTLS - OP_PCLID_DTLS */
 
-#define OP_PCL_DTLS_AES_128_CBC_SHA              0x002f
-#define OP_PCL_DTLS_AES_128_CBC_SHA_2            0x0030
-#define OP_PCL_DTLS_AES_128_CBC_SHA_3            0x0031
-#define OP_PCL_DTLS_AES_128_CBC_SHA_4            0x0032
-#define OP_PCL_DTLS_AES_128_CBC_SHA_5            0x0033
-#define OP_PCL_DTLS_AES_128_CBC_SHA_6            0x0034
-#define OP_PCL_DTLS_AES_128_CBC_SHA_7            0x008c
-#define OP_PCL_DTLS_AES_128_CBC_SHA_8            0x0090
-#define OP_PCL_DTLS_AES_128_CBC_SHA_9            0x0094
-#define OP_PCL_DTLS_AES_128_CBC_SHA_10           0xc004
-#define OP_PCL_DTLS_AES_128_CBC_SHA_11           0xc009
-#define OP_PCL_DTLS_AES_128_CBC_SHA_12           0xc00e
-#define OP_PCL_DTLS_AES_128_CBC_SHA_13           0xc013
-#define OP_PCL_DTLS_AES_128_CBC_SHA_14           0xc018
-#define OP_PCL_DTLS_AES_128_CBC_SHA_15           0xc01d
-#define OP_PCL_DTLS_AES_128_CBC_SHA_16           0xc01e
-#define OP_PCL_DTLS_AES_128_CBC_SHA_17           0xc01f
-
-#define OP_PCL_DTLS_AES_256_CBC_SHA              0x0035
-#define OP_PCL_DTLS_AES_256_CBC_SHA_2            0x0036
-#define OP_PCL_DTLS_AES_256_CBC_SHA_3            0x0037
-#define OP_PCL_DTLS_AES_256_CBC_SHA_4            0x0038
-#define OP_PCL_DTLS_AES_256_CBC_SHA_5            0x0039
-#define OP_PCL_DTLS_AES_256_CBC_SHA_6            0x003a
-#define OP_PCL_DTLS_AES_256_CBC_SHA_7            0x008d
-#define OP_PCL_DTLS_AES_256_CBC_SHA_8            0x0091
-#define OP_PCL_DTLS_AES_256_CBC_SHA_9            0x0095
-#define OP_PCL_DTLS_AES_256_CBC_SHA_10           0xc005
-#define OP_PCL_DTLS_AES_256_CBC_SHA_11           0xc00a
-#define OP_PCL_DTLS_AES_256_CBC_SHA_12           0xc00f
-#define OP_PCL_DTLS_AES_256_CBC_SHA_13           0xc014
-#define OP_PCL_DTLS_AES_256_CBC_SHA_14           0xc019
-#define OP_PCL_DTLS_AES_256_CBC_SHA_15           0xc020
-#define OP_PCL_DTLS_AES_256_CBC_SHA_16           0xc021
-#define OP_PCL_DTLS_AES_256_CBC_SHA_17           0xc022
-
-/* #define OP_PCL_DTLS_3DES_EDE_CBC_MD5             0x0023 */
-
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA             0x001f
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_2           0x008b
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_3           0x008f
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_4           0x0093
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_5           0x000a
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_6           0x000d
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_7           0x0010
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_8           0x0013
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_9           0x0016
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_10          0x001b
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_11          0xc003
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_12          0xc008
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_13          0xc00d
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_14          0xc012
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_15          0xc017
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_16          0xc01a
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_17          0xc01b
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_18          0xc01c
-
-#define OP_PCL_DTLS_DES40_CBC_MD5                0x0029
-
-#define OP_PCL_DTLS_DES_CBC_MD5                  0x0022
-
-#define OP_PCL_DTLS_DES40_CBC_SHA                0x0008
-#define OP_PCL_DTLS_DES40_CBC_SHA_2              0x000b
-#define OP_PCL_DTLS_DES40_CBC_SHA_3              0x000e
-#define OP_PCL_DTLS_DES40_CBC_SHA_4              0x0011
-#define OP_PCL_DTLS_DES40_CBC_SHA_5              0x0014
-#define OP_PCL_DTLS_DES40_CBC_SHA_6              0x0019
-#define OP_PCL_DTLS_DES40_CBC_SHA_7              0x0026
-
-
-#define OP_PCL_DTLS_DES_CBC_SHA                  0x001e
-#define OP_PCL_DTLS_DES_CBC_SHA_2                0x0009
-#define OP_PCL_DTLS_DES_CBC_SHA_3                0x000c
-#define OP_PCL_DTLS_DES_CBC_SHA_4                0x000f
-#define OP_PCL_DTLS_DES_CBC_SHA_5                0x0012
-#define OP_PCL_DTLS_DES_CBC_SHA_6                0x0015
-#define OP_PCL_DTLS_DES_CBC_SHA_7                0x001a
-
-
-#define OP_PCL_DTLS_3DES_EDE_CBC_MD5             0xff23
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA160          0xff30
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA224          0xff34
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA256          0xff36
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA384          0xff33
-#define OP_PCL_DTLS_3DES_EDE_CBC_SHA512          0xff35
-#define OP_PCL_DTLS_AES_128_CBC_SHA160           0xff80
-#define OP_PCL_DTLS_AES_128_CBC_SHA224           0xff84
-#define OP_PCL_DTLS_AES_128_CBC_SHA256           0xff86
-#define OP_PCL_DTLS_AES_128_CBC_SHA384           0xff83
-#define OP_PCL_DTLS_AES_128_CBC_SHA512           0xff85
-#define OP_PCL_DTLS_AES_192_CBC_SHA160           0xff20
-#define OP_PCL_DTLS_AES_192_CBC_SHA224           0xff24
-#define OP_PCL_DTLS_AES_192_CBC_SHA256           0xff26
-#define OP_PCL_DTLS_AES_192_CBC_SHA384           0xff23
-#define OP_PCL_DTLS_AES_192_CBC_SHA512           0xff25
-#define OP_PCL_DTLS_AES_256_CBC_SHA160           0xff60
-#define OP_PCL_DTLS_AES_256_CBC_SHA224           0xff64
-#define OP_PCL_DTLS_AES_256_CBC_SHA256           0xff66
-#define OP_PCL_DTLS_AES_256_CBC_SHA384           0xff63
-#define OP_PCL_DTLS_AES_256_CBC_SHA512           0xff65
+#define OP_PCL_DTLS_AES_128_CBC_SHA             0x002f
+#define OP_PCL_DTLS_AES_128_CBC_SHA_2           0x0030
+#define OP_PCL_DTLS_AES_128_CBC_SHA_3           0x0031
+#define OP_PCL_DTLS_AES_128_CBC_SHA_4           0x0032
+#define OP_PCL_DTLS_AES_128_CBC_SHA_5           0x0033
+#define OP_PCL_DTLS_AES_128_CBC_SHA_6           0x0034
+#define OP_PCL_DTLS_AES_128_CBC_SHA_7           0x008c
+#define OP_PCL_DTLS_AES_128_CBC_SHA_8           0x0090
+#define OP_PCL_DTLS_AES_128_CBC_SHA_9           0x0094
+#define OP_PCL_DTLS_AES_128_CBC_SHA_10          0xc004
+#define OP_PCL_DTLS_AES_128_CBC_SHA_11          0xc009
+#define OP_PCL_DTLS_AES_128_CBC_SHA_12          0xc00e
+#define OP_PCL_DTLS_AES_128_CBC_SHA_13          0xc013
+#define OP_PCL_DTLS_AES_128_CBC_SHA_14          0xc018
+#define OP_PCL_DTLS_AES_128_CBC_SHA_15          0xc01d
+#define OP_PCL_DTLS_AES_128_CBC_SHA_16          0xc01e
+#define OP_PCL_DTLS_AES_128_CBC_SHA_17          0xc01f
+
+#define OP_PCL_DTLS_AES_256_CBC_SHA             0x0035
+#define OP_PCL_DTLS_AES_256_CBC_SHA_2           0x0036
+#define OP_PCL_DTLS_AES_256_CBC_SHA_3           0x0037
+#define OP_PCL_DTLS_AES_256_CBC_SHA_4           0x0038
+#define OP_PCL_DTLS_AES_256_CBC_SHA_5           0x0039
+#define OP_PCL_DTLS_AES_256_CBC_SHA_6           0x003a
+#define OP_PCL_DTLS_AES_256_CBC_SHA_7           0x008d
+#define OP_PCL_DTLS_AES_256_CBC_SHA_8           0x0091
+#define OP_PCL_DTLS_AES_256_CBC_SHA_9           0x0095
+#define OP_PCL_DTLS_AES_256_CBC_SHA_10          0xc005
+#define OP_PCL_DTLS_AES_256_CBC_SHA_11          0xc00a
+#define OP_PCL_DTLS_AES_256_CBC_SHA_12          0xc00f
+#define OP_PCL_DTLS_AES_256_CBC_SHA_13          0xc014
+#define OP_PCL_DTLS_AES_256_CBC_SHA_14          0xc019
+#define OP_PCL_DTLS_AES_256_CBC_SHA_15          0xc020
+#define OP_PCL_DTLS_AES_256_CBC_SHA_16          0xc021
+#define OP_PCL_DTLS_AES_256_CBC_SHA_17          0xc022
+
+/* #define OP_PCL_DTLS_3DES_EDE_CBC_MD5                0x0023 */
+
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA            0x001f
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_2          0x008b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_3          0x008f
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_4          0x0093
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_5          0x000a
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_6          0x000d
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_7          0x0010
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_8          0x0013
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_9          0x0016
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_10                 0x001b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_11                 0xc003
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_12                 0xc008
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_13                 0xc00d
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_14                 0xc012
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_15                 0xc017
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_16                 0xc01a
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_17                 0xc01b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_18                 0xc01c
+
+#define OP_PCL_DTLS_DES40_CBC_MD5               0x0029
+
+#define OP_PCL_DTLS_DES_CBC_MD5                         0x0022
+
+#define OP_PCL_DTLS_DES40_CBC_SHA               0x0008
+#define OP_PCL_DTLS_DES40_CBC_SHA_2             0x000b
+#define OP_PCL_DTLS_DES40_CBC_SHA_3             0x000e
+#define OP_PCL_DTLS_DES40_CBC_SHA_4             0x0011
+#define OP_PCL_DTLS_DES40_CBC_SHA_5             0x0014
+#define OP_PCL_DTLS_DES40_CBC_SHA_6             0x0019
+#define OP_PCL_DTLS_DES40_CBC_SHA_7             0x0026
+
+
+#define OP_PCL_DTLS_DES_CBC_SHA                         0x001e
+#define OP_PCL_DTLS_DES_CBC_SHA_2               0x0009
+#define OP_PCL_DTLS_DES_CBC_SHA_3               0x000c
+#define OP_PCL_DTLS_DES_CBC_SHA_4               0x000f
+#define OP_PCL_DTLS_DES_CBC_SHA_5               0x0012
+#define OP_PCL_DTLS_DES_CBC_SHA_6               0x0015
+#define OP_PCL_DTLS_DES_CBC_SHA_7               0x001a
+
+
+#define OP_PCL_DTLS_3DES_EDE_CBC_MD5            0xff23
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA160                 0xff30
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA224                 0xff34
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA256                 0xff36
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA384                 0xff33
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA512                 0xff35
+#define OP_PCL_DTLS_AES_128_CBC_SHA160          0xff80
+#define OP_PCL_DTLS_AES_128_CBC_SHA224          0xff84
+#define OP_PCL_DTLS_AES_128_CBC_SHA256          0xff86
+#define OP_PCL_DTLS_AES_128_CBC_SHA384          0xff83
+#define OP_PCL_DTLS_AES_128_CBC_SHA512          0xff85
+#define OP_PCL_DTLS_AES_192_CBC_SHA160          0xff20
+#define OP_PCL_DTLS_AES_192_CBC_SHA224          0xff24
+#define OP_PCL_DTLS_AES_192_CBC_SHA256          0xff26
+#define OP_PCL_DTLS_AES_192_CBC_SHA384          0xff23
+#define OP_PCL_DTLS_AES_192_CBC_SHA512          0xff25
+#define OP_PCL_DTLS_AES_256_CBC_SHA160          0xff60
+#define OP_PCL_DTLS_AES_256_CBC_SHA224          0xff64
+#define OP_PCL_DTLS_AES_256_CBC_SHA256          0xff66
+#define OP_PCL_DTLS_AES_256_CBC_SHA384          0xff63
+#define OP_PCL_DTLS_AES_256_CBC_SHA512          0xff65
 
 /* 802.16 WiMAX protinfos */
-#define OP_PCL_WIMAX_OFDM                        0x0201
-#define OP_PCL_WIMAX_OFDMA                       0x0231
+#define OP_PCL_WIMAX_OFDM                       0x0201
+#define OP_PCL_WIMAX_OFDMA                      0x0231
 
 /* 802.11 WiFi protinfos */
-#define OP_PCL_WIFI                              0xac04
+#define OP_PCL_WIFI                             0xac04
 
 /* MacSec protinfos */
-#define OP_PCL_MACSEC                            0x0001
+#define OP_PCL_MACSEC                           0x0001
 
 /* PKI unidirectional protocol protinfo bits */
-#define OP_PCL_PKPROT_TEST                       0x0008
-#define OP_PCL_PKPROT_DECRYPT                    0x0004
-#define OP_PCL_PKPROT_ECC                        0x0002
-#define OP_PCL_PKPROT_F2M                        0x0001
+#define OP_PCL_PKPROT_TEST                      0x0008
+#define OP_PCL_PKPROT_DECRYPT                   0x0004
+#define OP_PCL_PKPROT_ECC                       0x0002
+#define OP_PCL_PKPROT_F2M                       0x0001
 
 /* For non-protocol/alg-only op commands */
 #define OP_ALG_TYPE_SHIFT      24
 #define OP_ALG_ENCRYPT         1
 
 /* PKHA algorithm type set */
-#define OP_ALG_PK                    0x00800000
-#define OP_ALG_PK_FUN_MASK           0x3f /* clrmem, modmath, or cpymem */
+#define OP_ALG_PK              0x00800000
+#define OP_ALG_PK_FUN_MASK     0x3f /* clrmem, modmath, or cpymem */
 
 /* PKHA mode clear memory functions */
-#define OP_ALG_PKMODE_A_RAM          0x80000
-#define OP_ALG_PKMODE_B_RAM          0x40000
-#define OP_ALG_PKMODE_E_RAM          0x20000
-#define OP_ALG_PKMODE_N_RAM          0x10000
-#define OP_ALG_PKMODE_CLEARMEM       0x00001
+#define OP_ALG_PKMODE_A_RAM    0x80000
+#define OP_ALG_PKMODE_B_RAM    0x40000
+#define OP_ALG_PKMODE_E_RAM    0x20000
+#define OP_ALG_PKMODE_N_RAM    0x10000
+#define OP_ALG_PKMODE_CLEARMEM 0x00001
 
 /* PKHA mode modular-arithmetic functions */
-#define OP_ALG_PKMODE_MOD_IN_MONTY   0x80000
-#define OP_ALG_PKMODE_MOD_OUT_MONTY  0x40000
-#define OP_ALG_PKMODE_MOD_F2M        0x20000
-#define OP_ALG_PKMODE_MOD_R2_IN      0x10000
-#define OP_ALG_PKMODE_PRJECTV        0x00800
-#define OP_ALG_PKMODE_TIME_EQ        0x400
-#define OP_ALG_PKMODE_OUT_B          0x000
-#define OP_ALG_PKMODE_OUT_A          0x100
-#define OP_ALG_PKMODE_MOD_ADD        0x002
-#define OP_ALG_PKMODE_MOD_SUB_AB     0x003
-#define OP_ALG_PKMODE_MOD_SUB_BA     0x004
-#define OP_ALG_PKMODE_MOD_MULT       0x005
-#define OP_ALG_PKMODE_MOD_EXPO       0x006
-#define OP_ALG_PKMODE_MOD_REDUCT     0x007
-#define OP_ALG_PKMODE_MOD_INV        0x008
-#define OP_ALG_PKMODE_MOD_ECC_ADD    0x009
-#define OP_ALG_PKMODE_MOD_ECC_DBL    0x00a
-#define OP_ALG_PKMODE_MOD_ECC_MULT   0x00b
-#define OP_ALG_PKMODE_MOD_MONT_CNST  0x00c
-#define OP_ALG_PKMODE_MOD_CRT_CNST   0x00d
-#define OP_ALG_PKMODE_MOD_GCD        0x00e
-#define OP_ALG_PKMODE_MOD_PRIMALITY  0x00f
+#define OP_ALG_PKMODE_MOD_IN_MONTY     0x80000
+#define OP_ALG_PKMODE_MOD_OUT_MONTY    0x40000
+#define OP_ALG_PKMODE_MOD_F2M          0x20000
+#define OP_ALG_PKMODE_MOD_R2_IN                0x10000
+#define OP_ALG_PKMODE_PRJECTV          0x00800
+#define OP_ALG_PKMODE_TIME_EQ          0x400
+#define OP_ALG_PKMODE_OUT_B            0x000
+#define OP_ALG_PKMODE_OUT_A            0x100
+#define OP_ALG_PKMODE_MOD_ADD          0x002
+#define OP_ALG_PKMODE_MOD_SUB_AB       0x003
+#define OP_ALG_PKMODE_MOD_SUB_BA       0x004
+#define OP_ALG_PKMODE_MOD_MULT         0x005
+#define OP_ALG_PKMODE_MOD_EXPO         0x006
+#define OP_ALG_PKMODE_MOD_REDUCT       0x007
+#define OP_ALG_PKMODE_MOD_INV          0x008
+#define OP_ALG_PKMODE_MOD_ECC_ADD      0x009
+#define OP_ALG_PKMODE_MOD_ECC_DBL      0x00a
+#define OP_ALG_PKMODE_MOD_ECC_MULT     0x00b
+#define OP_ALG_PKMODE_MOD_MONT_CNST    0x00c
+#define OP_ALG_PKMODE_MOD_CRT_CNST     0x00d
+#define OP_ALG_PKMODE_MOD_GCD          0x00e
+#define OP_ALG_PKMODE_MOD_PRIMALITY    0x00f
 
 /* PKHA mode copy-memory functions */
-#define OP_ALG_PKMODE_SRC_REG_SHIFT  13
-#define OP_ALG_PKMODE_SRC_REG_MASK   (7 << OP_ALG_PKMODE_SRC_REG_SHIFT)
-#define OP_ALG_PKMODE_DST_REG_SHIFT  10
-#define OP_ALG_PKMODE_DST_REG_MASK   (7 << OP_ALG_PKMODE_DST_REG_SHIFT)
-#define OP_ALG_PKMODE_SRC_SEG_SHIFT  8
-#define OP_ALG_PKMODE_SRC_SEG_MASK   (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
-#define OP_ALG_PKMODE_DST_SEG_SHIFT  6
-#define OP_ALG_PKMODE_DST_SEG_MASK   (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
-
-#define OP_ALG_PKMODE_SRC_REG_A      (0 << OP_ALG_PKMODE_SRC_REG_SHIFT)
-#define OP_ALG_PKMODE_SRC_REG_B      (1 << OP_ALG_PKMODE_SRC_REG_SHIFT)
-#define OP_ALG_PKMODE_SRC_REG_N      (3 << OP_ALG_PKMODE_SRC_REG_SHIFT)
-#define OP_ALG_PKMODE_DST_REG_A      (0 << OP_ALG_PKMODE_DST_REG_SHIFT)
-#define OP_ALG_PKMODE_DST_REG_B      (1 << OP_ALG_PKMODE_DST_REG_SHIFT)
-#define OP_ALG_PKMODE_DST_REG_E      (2 << OP_ALG_PKMODE_DST_REG_SHIFT)
-#define OP_ALG_PKMODE_DST_REG_N      (3 << OP_ALG_PKMODE_DST_REG_SHIFT)
-#define OP_ALG_PKMODE_SRC_SEG_0      (0 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
-#define OP_ALG_PKMODE_SRC_SEG_1      (1 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
-#define OP_ALG_PKMODE_SRC_SEG_2      (2 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
-#define OP_ALG_PKMODE_SRC_SEG_3      (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
-#define OP_ALG_PKMODE_DST_SEG_0      (0 << OP_ALG_PKMODE_DST_SEG_SHIFT)
-#define OP_ALG_PKMODE_DST_SEG_1      (1 << OP_ALG_PKMODE_DST_SEG_SHIFT)
-#define OP_ALG_PKMODE_DST_SEG_2      (2 << OP_ALG_PKMODE_DST_SEG_SHIFT)
-#define OP_ALG_PKMODE_DST_SEG_3      (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
-#define OP_ALG_PKMODE_CPYMEM_N_SZ    0x80
-#define OP_ALG_PKMODE_CPYMEM_SRC_SZ  0x81
+#define OP_ALG_PKMODE_SRC_REG_SHIFT    13
+#define OP_ALG_PKMODE_SRC_REG_MASK     (7 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_SHIFT    10
+#define OP_ALG_PKMODE_DST_REG_MASK     (7 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_SHIFT    8
+#define OP_ALG_PKMODE_SRC_SEG_MASK     (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_SHIFT    6
+#define OP_ALG_PKMODE_DST_SEG_MASK     (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+
+#define OP_ALG_PKMODE_SRC_REG_A                (0 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_REG_B                (1 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_REG_N                (3 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_A                (0 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_B                (1 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_E                (2 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_N                (3 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_0                (0 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_1                (1 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_2                (2 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_3                (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_0                (0 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_1                (1 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_2                (2 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_3                (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_CPYMEM_N_SZ      0x80
+#define OP_ALG_PKMODE_CPYMEM_SRC_SZ    0x81
 
 /*
  * SEQ_IN_PTR Command Constructs
  */
 
 /* Release Buffers */
-#define SQIN_RBS               0x04000000
+#define SQIN_RBS       0x04000000
 
 /* Sequence pointer is really a descriptor */
-#define SQIN_INL               0x02000000
+#define SQIN_INL       0x02000000
 
 /* Sequence pointer is a scatter-gather table */
-#define SQIN_SGF               0x01000000
+#define SQIN_SGF       0x01000000
 
 /* Appends to a previous pointer */
-#define SQIN_PRE               0x00800000
+#define SQIN_PRE       0x00800000
 
 /* Use extended length following pointer */
-#define SQIN_EXT               0x00400000
+#define SQIN_EXT       0x00400000
 
 /* Restore sequence with pointer/length */
-#define SQIN_RTO               0x00200000
+#define SQIN_RTO       0x00200000
 
 /* Replace job descriptor */
-#define SQIN_RJD               0x00100000
+#define SQIN_RJD       0x00100000
 
-#define SQIN_LEN_SHIFT           0
-#define SQIN_LEN_MASK           (0xffff << SQIN_LEN_SHIFT)
+#define SQIN_LEN_SHIFT          0
+#define SQIN_LEN_MASK          (0xffff << SQIN_LEN_SHIFT)
 
 /*
  * SEQ_OUT_PTR Command Constructs
  */
 
 /* Sequence pointer is a scatter-gather table */
-#define SQOUT_SGF              0x01000000
+#define SQOUT_SGF      0x01000000
 
 /* Appends to a previous pointer */
-#define SQOUT_PRE              0x00800000
+#define SQOUT_PRE      0x00800000
 
 /* Restore sequence with pointer/length */
-#define SQOUT_RTO              0x00200000
+#define SQOUT_RTO      0x00200000
 
 /* Use extended length following pointer */
-#define SQOUT_EXT              0x00400000
+#define SQOUT_EXT      0x00400000
 
-#define SQOUT_LEN_SHIFT           0
-#define SQOUT_LEN_MASK           (0xffff << SQOUT_LEN_SHIFT)
+#define SQOUT_LEN_SHIFT                0
+#define SQOUT_LEN_MASK         (0xffff << SQOUT_LEN_SHIFT)
 
 
 /*
  */
 
 /* TYPE field is all that's relevant */
-#define SIGN_TYPE_SHIFT         16
-#define SIGN_TYPE_MASK          (0x0f << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_SHIFT                16
+#define SIGN_TYPE_MASK         (0x0f << SIGN_TYPE_SHIFT)
 
-#define SIGN_TYPE_FINAL         (0x00 << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_FINAL                (0x00 << SIGN_TYPE_SHIFT)
 #define SIGN_TYPE_FINAL_RESTORE (0x01 << SIGN_TYPE_SHIFT)
 #define SIGN_TYPE_FINAL_NONZERO (0x02 << SIGN_TYPE_SHIFT)
-#define SIGN_TYPE_IMM_2         (0x0a << SIGN_TYPE_SHIFT)
-#define SIGN_TYPE_IMM_3         (0x0b << SIGN_TYPE_SHIFT)
-#define SIGN_TYPE_IMM_4         (0x0c << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_2                (0x0a << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_3                (0x0b << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_4                (0x0c << SIGN_TYPE_SHIFT)
 
 /*
  * MOVE Command Constructs
  */
 
-#define MOVE_AUX_SHIFT          25
-#define MOVE_AUX_MASK           (3 << MOVE_AUX_SHIFT)
-#define MOVE_AUX_MS             (2 << MOVE_AUX_SHIFT)
-#define MOVE_AUX_LS             (1 << MOVE_AUX_SHIFT)
-
-#define MOVE_WAITCOMP_SHIFT     24
-#define MOVE_WAITCOMP_MASK      (1 << MOVE_WAITCOMP_SHIFT)
-#define MOVE_WAITCOMP           (1 << MOVE_WAITCOMP_SHIFT)
-
-#define MOVE_SRC_SHIFT          20
-#define MOVE_SRC_MASK           (0x0f << MOVE_SRC_SHIFT)
-#define MOVE_SRC_CLASS1CTX      (0x00 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_CLASS2CTX      (0x01 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_OUTFIFO        (0x02 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_DESCBUF        (0x03 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_MATH0          (0x04 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_MATH1          (0x05 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_MATH2          (0x06 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_MATH3          (0x07 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_INFIFO         (0x08 << MOVE_SRC_SHIFT)
-#define MOVE_SRC_INFIFO_CL      (0x09 << MOVE_SRC_SHIFT)
-
-#define MOVE_DEST_SHIFT         16
-#define MOVE_DEST_MASK          (0x0f << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS1CTX     (0x00 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS2CTX     (0x01 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_OUTFIFO       (0x02 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_DESCBUF       (0x03 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_MATH0         (0x04 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_MATH1         (0x05 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_MATH2         (0x06 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_MATH3         (0x07 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS1INFIFO  (0x08 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS2INFIFO  (0x09 << MOVE_DEST_SHIFT)
-#define MOVE_DEST_PK_A          (0x0c << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS1KEY     (0x0d << MOVE_DEST_SHIFT)
-#define MOVE_DEST_CLASS2KEY     (0x0e << MOVE_DEST_SHIFT)
-
-#define MOVE_OFFSET_SHIFT       8
-#define MOVE_OFFSET_MASK        (0xff << MOVE_OFFSET_SHIFT)
-
-#define MOVE_LEN_SHIFT          0
-#define MOVE_LEN_MASK           (0xff << MOVE_LEN_SHIFT)
-
-#define MOVELEN_MRSEL_SHIFT     0
-#define MOVELEN_MRSEL_MASK      (0x3 << MOVE_LEN_SHIFT)
+#define MOVE_AUX_SHIFT         25
+#define MOVE_AUX_MASK          (3 << MOVE_AUX_SHIFT)
+#define MOVE_AUX_MS            (2 << MOVE_AUX_SHIFT)
+#define MOVE_AUX_LS            (1 << MOVE_AUX_SHIFT)
+
+#define MOVE_WAITCOMP_SHIFT    24
+#define MOVE_WAITCOMP_MASK     (1 << MOVE_WAITCOMP_SHIFT)
+#define MOVE_WAITCOMP          (1 << MOVE_WAITCOMP_SHIFT)
+
+#define MOVE_SRC_SHIFT         20
+#define MOVE_SRC_MASK          (0x0f << MOVE_SRC_SHIFT)
+#define MOVE_SRC_CLASS1CTX     (0x00 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_CLASS2CTX     (0x01 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_OUTFIFO       (0x02 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_DESCBUF       (0x03 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH0         (0x04 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH1         (0x05 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH2         (0x06 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH3         (0x07 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_INFIFO                (0x08 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_INFIFO_CL     (0x09 << MOVE_SRC_SHIFT)
+
+#define MOVE_DEST_SHIFT                16
+#define MOVE_DEST_MASK         (0x0f << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1CTX    (0x00 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2CTX    (0x01 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_OUTFIFO      (0x02 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_DESCBUF      (0x03 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH0                (0x04 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH1                (0x05 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH2                (0x06 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH3                (0x07 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_PK_A         (0x0c << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1KEY    (0x0d << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2KEY    (0x0e << MOVE_DEST_SHIFT)
+
+#define MOVE_OFFSET_SHIFT      8
+#define MOVE_OFFSET_MASK       (0xff << MOVE_OFFSET_SHIFT)
+
+#define MOVE_LEN_SHIFT         0
+#define MOVE_LEN_MASK          (0xff << MOVE_LEN_SHIFT)
+
+#define MOVELEN_MRSEL_SHIFT    0
+#define MOVELEN_MRSEL_MASK     (0x3 << MOVE_LEN_SHIFT)
 
 /*
  * MATH Command Constructs
  */
 
-#define MATH_IFB_SHIFT          26
-#define MATH_IFB_MASK           (1 << MATH_IFB_SHIFT)
-#define MATH_IFB                (1 << MATH_IFB_SHIFT)
+#define MATH_IFB_SHIFT         26
+#define MATH_IFB_MASK          (1 << MATH_IFB_SHIFT)
+#define MATH_IFB               (1 << MATH_IFB_SHIFT)
 
-#define MATH_NFU_SHIFT          25
-#define MATH_NFU_MASK           (1 << MATH_NFU_SHIFT)
-#define MATH_NFU                (1 << MATH_NFU_SHIFT)
+#define MATH_NFU_SHIFT         25
+#define MATH_NFU_MASK          (1 << MATH_NFU_SHIFT)
+#define MATH_NFU               (1 << MATH_NFU_SHIFT)
 
-#define MATH_STL_SHIFT          24
-#define MATH_STL_MASK           (1 << MATH_STL_SHIFT)
-#define MATH_STL                (1 << MATH_STL_SHIFT)
+#define MATH_STL_SHIFT         24
+#define MATH_STL_MASK          (1 << MATH_STL_SHIFT)
+#define MATH_STL               (1 << MATH_STL_SHIFT)
 
 /* Function selectors */
-#define MATH_FUN_SHIFT          20
-#define MATH_FUN_MASK           (0x0f << MATH_FUN_SHIFT)
-#define MATH_FUN_ADD            (0x00 << MATH_FUN_SHIFT)
-#define MATH_FUN_ADDC           (0x01 << MATH_FUN_SHIFT)
-#define MATH_FUN_SUB            (0x02 << MATH_FUN_SHIFT)
-#define MATH_FUN_SUBB           (0x03 << MATH_FUN_SHIFT)
-#define MATH_FUN_OR             (0x04 << MATH_FUN_SHIFT)
-#define MATH_FUN_AND            (0x05 << MATH_FUN_SHIFT)
-#define MATH_FUN_XOR            (0x06 << MATH_FUN_SHIFT)
-#define MATH_FUN_LSHIFT         (0x07 << MATH_FUN_SHIFT)
-#define MATH_FUN_RSHIFT         (0x08 << MATH_FUN_SHIFT)
-#define MATH_FUN_SHLD           (0x09 << MATH_FUN_SHIFT)
-#define MATH_FUN_ZBYT           (0x0a << MATH_FUN_SHIFT)
+#define MATH_FUN_SHIFT         20
+#define MATH_FUN_MASK          (0x0f << MATH_FUN_SHIFT)
+#define MATH_FUN_ADD           (0x00 << MATH_FUN_SHIFT)
+#define MATH_FUN_ADDC          (0x01 << MATH_FUN_SHIFT)
+#define MATH_FUN_SUB           (0x02 << MATH_FUN_SHIFT)
+#define MATH_FUN_SUBB          (0x03 << MATH_FUN_SHIFT)
+#define MATH_FUN_OR            (0x04 << MATH_FUN_SHIFT)
+#define MATH_FUN_AND           (0x05 << MATH_FUN_SHIFT)
+#define MATH_FUN_XOR           (0x06 << MATH_FUN_SHIFT)
+#define MATH_FUN_LSHIFT                (0x07 << MATH_FUN_SHIFT)
+#define MATH_FUN_RSHIFT                (0x08 << MATH_FUN_SHIFT)
+#define MATH_FUN_SHLD          (0x09 << MATH_FUN_SHIFT)
+#define MATH_FUN_ZBYT          (0x0a << MATH_FUN_SHIFT)
 
 /* Source 0 selectors */
-#define MATH_SRC0_SHIFT         16
-#define MATH_SRC0_MASK          (0x0f << MATH_SRC0_SHIFT)
-#define MATH_SRC0_REG0          (0x00 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_REG1          (0x01 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_REG2          (0x02 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_REG3          (0x03 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_IMM           (0x04 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_SEQINLEN      (0x08 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_SEQOUTLEN     (0x09 << MATH_SRC0_SHIFT)
-#define MATH_SRC0_VARSEQINLEN   (0x0a << MATH_SRC0_SHIFT)
-#define MATH_SRC0_VARSEQOUTLEN  (0x0b << MATH_SRC0_SHIFT)
-#define MATH_SRC0_ZERO          (0x0c << MATH_SRC0_SHIFT)
+#define MATH_SRC0_SHIFT                16
+#define MATH_SRC0_MASK         (0x0f << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG0         (0x00 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG1         (0x01 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG2         (0x02 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG3         (0x03 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_IMM          (0x04 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_SEQINLEN     (0x08 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_SEQOUTLEN    (0x09 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_VARSEQINLEN  (0x0a << MATH_SRC0_SHIFT)
+#define MATH_SRC0_VARSEQOUTLEN (0x0b << MATH_SRC0_SHIFT)
+#define MATH_SRC0_ZERO         (0x0c << MATH_SRC0_SHIFT)
 
 /* Source 1 selectors */
-#define MATH_SRC1_SHIFT         12
-#define MATH_SRC1_MASK          (0x0f << MATH_SRC1_SHIFT)
-#define MATH_SRC1_REG0          (0x00 << MATH_SRC1_SHIFT)
-#define MATH_SRC1_REG1          (0x01 << MATH_SRC1_SHIFT)
-#define MATH_SRC1_REG2          (0x02 << MATH_SRC1_SHIFT)
-#define MATH_SRC1_REG3          (0x03 << MATH_SRC1_SHIFT)
-#define MATH_SRC1_IMM           (0x04 << MATH_SRC1_SHIFT)
-#define MATH_SRC1_INFIFO        (0x0a << MATH_SRC1_SHIFT)
-#define MATH_SRC1_OUTFIFO       (0x0b << MATH_SRC1_SHIFT)
-#define MATH_SRC1_ONE           (0x0c << MATH_SRC1_SHIFT)
+#define MATH_SRC1_SHIFT                12
+#define MATH_SRC1_MASK         (0x0f << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG0         (0x00 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG1         (0x01 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG2         (0x02 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG3         (0x03 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_IMM          (0x04 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_INFIFO       (0x0a << MATH_SRC1_SHIFT)
+#define MATH_SRC1_OUTFIFO      (0x0b << MATH_SRC1_SHIFT)
+#define MATH_SRC1_ONE          (0x0c << MATH_SRC1_SHIFT)
 
 /* Destination selectors */
-#define MATH_DEST_SHIFT         8
-#define MATH_DEST_MASK          (0x0f << MATH_DEST_SHIFT)
-#define MATH_DEST_REG0          (0x00 << MATH_DEST_SHIFT)
-#define MATH_DEST_REG1          (0x01 << MATH_DEST_SHIFT)
-#define MATH_DEST_REG2          (0x02 << MATH_DEST_SHIFT)
-#define MATH_DEST_REG3          (0x03 << MATH_DEST_SHIFT)
-#define MATH_DEST_SEQINLEN      (0x08 << MATH_DEST_SHIFT)
-#define MATH_DEST_SEQOUTLEN     (0x09 << MATH_DEST_SHIFT)
-#define MATH_DEST_VARSEQINLEN   (0x0a << MATH_DEST_SHIFT)
-#define MATH_DEST_VARSEQOUTLEN  (0x0b << MATH_DEST_SHIFT)
-#define MATH_DEST_NONE          (0x0f << MATH_DEST_SHIFT)
+#define MATH_DEST_SHIFT                8
+#define MATH_DEST_MASK         (0x0f << MATH_DEST_SHIFT)
+#define MATH_DEST_REG0         (0x00 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG1         (0x01 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG2         (0x02 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG3         (0x03 << MATH_DEST_SHIFT)
+#define MATH_DEST_SEQINLEN     (0x08 << MATH_DEST_SHIFT)
+#define MATH_DEST_SEQOUTLEN    (0x09 << MATH_DEST_SHIFT)
+#define MATH_DEST_VARSEQINLEN  (0x0a << MATH_DEST_SHIFT)
+#define MATH_DEST_VARSEQOUTLEN (0x0b << MATH_DEST_SHIFT)
+#define MATH_DEST_NONE         (0x0f << MATH_DEST_SHIFT)
 
 /* Length selectors */
-#define MATH_LEN_SHIFT          0
-#define MATH_LEN_MASK           (0x0f << MATH_LEN_SHIFT)
-#define MATH_LEN_1BYTE          0x01
-#define MATH_LEN_2BYTE          0x02
-#define MATH_LEN_4BYTE          0x04
-#define MATH_LEN_8BYTE          0x08
+#define MATH_LEN_SHIFT         0
+#define MATH_LEN_MASK          (0x0f << MATH_LEN_SHIFT)
+#define MATH_LEN_1BYTE         0x01
+#define MATH_LEN_2BYTE         0x02
+#define MATH_LEN_4BYTE         0x04
+#define MATH_LEN_8BYTE         0x08
 
 /*
  * JUMP Command Constructs
  */
 
-#define JUMP_CLASS_SHIFT        25
+#define JUMP_CLASS_SHIFT       25
 #define JUMP_CLASS_MASK                (3 << JUMP_CLASS_SHIFT)
 #define JUMP_CLASS_NONE                0
 #define JUMP_CLASS_CLASS1      (1 << JUMP_CLASS_SHIFT)
 #define JUMP_CLASS_CLASS2      (2 << JUMP_CLASS_SHIFT)
 #define JUMP_CLASS_BOTH                (3 << JUMP_CLASS_SHIFT)
 
-#define JUMP_JSL_SHIFT          24
-#define JUMP_JSL_MASK           (1 << JUMP_JSL_SHIFT)
-#define JUMP_JSL                (1 << JUMP_JSL_SHIFT)
+#define JUMP_JSL_SHIFT         24
+#define JUMP_JSL_MASK          (1 << JUMP_JSL_SHIFT)
+#define JUMP_JSL               (1 << JUMP_JSL_SHIFT)
 
-#define JUMP_TYPE_SHIFT         22
-#define JUMP_TYPE_MASK          (0x03 << JUMP_TYPE_SHIFT)
-#define JUMP_TYPE_LOCAL         (0x00 << JUMP_TYPE_SHIFT)
-#define JUMP_TYPE_NONLOCAL      (0x01 << JUMP_TYPE_SHIFT)
-#define JUMP_TYPE_HALT          (0x02 << JUMP_TYPE_SHIFT)
-#define JUMP_TYPE_HALT_USER     (0x03 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_SHIFT                22
+#define JUMP_TYPE_MASK         (0x03 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_LOCAL                (0x00 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_NONLOCAL     (0x01 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_HALT         (0x02 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_HALT_USER    (0x03 << JUMP_TYPE_SHIFT)
 
-#define JUMP_TEST_SHIFT         16
-#define JUMP_TEST_MASK          (0x03 << JUMP_TEST_SHIFT)
-#define JUMP_TEST_ALL           (0x00 << JUMP_TEST_SHIFT)
-#define JUMP_TEST_INVALL        (0x01 << JUMP_TEST_SHIFT)
-#define JUMP_TEST_ANY           (0x02 << JUMP_TEST_SHIFT)
-#define JUMP_TEST_INVANY        (0x03 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_SHIFT                16
+#define JUMP_TEST_MASK         (0x03 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_ALL          (0x00 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_INVALL       (0x01 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_ANY          (0x02 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_INVANY       (0x03 << JUMP_TEST_SHIFT)
 
 /* Condition codes. JSL bit is factored in */
-#define JUMP_COND_SHIFT         8
-#define JUMP_COND_MASK          (0x100ff << JUMP_COND_SHIFT)
-#define JUMP_COND_PK_0          (0x80 << JUMP_COND_SHIFT)
-#define JUMP_COND_PK_GCD_1      (0x40 << JUMP_COND_SHIFT)
-#define JUMP_COND_PK_PRIME      (0x20 << JUMP_COND_SHIFT)
-#define JUMP_COND_MATH_N        (0x08 << JUMP_COND_SHIFT)
-#define JUMP_COND_MATH_Z        (0x04 << JUMP_COND_SHIFT)
-#define JUMP_COND_MATH_C        (0x02 << JUMP_COND_SHIFT)
-#define JUMP_COND_MATH_NV       (0x01 << JUMP_COND_SHIFT)
-
-#define JUMP_COND_JRP           ((0x80 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_SHRD          ((0x40 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_SELF          ((0x20 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_CALM          ((0x10 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_NIP           ((0x08 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_NIFP          ((0x04 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_NOP           ((0x02 << JUMP_COND_SHIFT) | JUMP_JSL)
-#define JUMP_COND_NCP           ((0x01 << JUMP_COND_SHIFT) | JUMP_JSL)
-
-#define JUMP_OFFSET_SHIFT       0
-#define JUMP_OFFSET_MASK        (0xff << JUMP_OFFSET_SHIFT)
+#define JUMP_COND_SHIFT                8
+#define JUMP_COND_MASK         (0x100ff << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_0         (0x80 << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_GCD_1     (0x40 << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_PRIME     (0x20 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_N       (0x08 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_Z       (0x04 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_C       (0x02 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_NV      (0x01 << JUMP_COND_SHIFT)
+
+#define JUMP_COND_JRP          ((0x80 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_SHRD         ((0x40 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_SELF         ((0x20 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_CALM         ((0x10 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NIP          ((0x08 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NIFP         ((0x04 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NOP          ((0x02 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NCP          ((0x01 << JUMP_COND_SHIFT) | JUMP_JSL)
+
+#define JUMP_OFFSET_SHIFT      0
+#define JUMP_OFFSET_MASK       (0xff << JUMP_OFFSET_SHIFT)
 
 /*
  * NFIFO ENTRY
 #define NFIFOENTRY_DEST_BOTH   (3 << NFIFOENTRY_DEST_SHIFT)
 
 #define NFIFOENTRY_LC2_SHIFT   29
-#define NFIFOENTRY_LC2_MASK            (1 << NFIFOENTRY_LC2_SHIFT)
-#define NFIFOENTRY_LC2                 (1 << NFIFOENTRY_LC2_SHIFT)
+#define NFIFOENTRY_LC2_MASK    (1 << NFIFOENTRY_LC2_SHIFT)
+#define NFIFOENTRY_LC2         (1 << NFIFOENTRY_LC2_SHIFT)
 
 #define NFIFOENTRY_LC1_SHIFT   28
-#define NFIFOENTRY_LC1_MASK            (1 << NFIFOENTRY_LC1_SHIFT)
-#define NFIFOENTRY_LC1                 (1 << NFIFOENTRY_LC1_SHIFT)
+#define NFIFOENTRY_LC1_MASK    (1 << NFIFOENTRY_LC1_SHIFT)
+#define NFIFOENTRY_LC1         (1 << NFIFOENTRY_LC1_SHIFT)
 
 #define NFIFOENTRY_FC2_SHIFT   27
-#define NFIFOENTRY_FC2_MASK            (1 << NFIFOENTRY_FC2_SHIFT)
-#define NFIFOENTRY_FC2                 (1 << NFIFOENTRY_FC2_SHIFT)
+#define NFIFOENTRY_FC2_MASK    (1 << NFIFOENTRY_FC2_SHIFT)
+#define NFIFOENTRY_FC2         (1 << NFIFOENTRY_FC2_SHIFT)
 
 #define NFIFOENTRY_FC1_SHIFT   26
-#define NFIFOENTRY_FC1_MASK            (1 << NFIFOENTRY_FC1_SHIFT)
-#define NFIFOENTRY_FC1                 (1 << NFIFOENTRY_FC1_SHIFT)
+#define NFIFOENTRY_FC1_MASK    (1 << NFIFOENTRY_FC1_SHIFT)
+#define NFIFOENTRY_FC1         (1 << NFIFOENTRY_FC1_SHIFT)
 
 #define NFIFOENTRY_STYPE_SHIFT 24
 #define NFIFOENTRY_STYPE_MASK  (3 << NFIFOENTRY_STYPE_SHIFT)
 #define NFIFOENTRY_DTYPE_SHIFT 20
 #define NFIFOENTRY_DTYPE_MASK  (0xF << NFIFOENTRY_DTYPE_SHIFT)
 
-#define NFIFOENTRY_DTYPE_SBOX      (0x0  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_AAD       (0x1  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_IV        (0x2  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_SAD       (0x3  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_ICV       (0xA  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_SKIP      (0xE  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_MSG       (0xF  << NFIFOENTRY_DTYPE_SHIFT)
-
-#define NFIFOENTRY_DTYPE_PK_A0     (0x0  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_A1     (0x1  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_A2     (0x2  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_A3     (0x3  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_B0     (0x4  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_B1     (0x5  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_B2     (0x6  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_B3     (0x7  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_N      (0x8  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_E      (0x9  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_A      (0xC  << NFIFOENTRY_DTYPE_SHIFT)
-#define NFIFOENTRY_DTYPE_PK_B      (0xD  << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_SBOX  (0x0 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_AAD   (0x1 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_IV    (0x2 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_SAD   (0x3 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_ICV   (0xA << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_SKIP  (0xE << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_MSG   (0xF << NFIFOENTRY_DTYPE_SHIFT)
+
+#define NFIFOENTRY_DTYPE_PK_A0 (0x0 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A1 (0x1 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A2 (0x2 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A3 (0x3 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B0 (0x4 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B1 (0x5 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B2 (0x6 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B3 (0x7 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_N  (0x8 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_E  (0x9 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A  (0xC << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B  (0xD << NFIFOENTRY_DTYPE_SHIFT)
 
 
 #define NFIFOENTRY_BND_SHIFT   19
-#define NFIFOENTRY_BND_MASK            (1 << NFIFOENTRY_BND_SHIFT)
-#define NFIFOENTRY_BND                 (1 << NFIFOENTRY_BND_SHIFT)
+#define NFIFOENTRY_BND_MASK    (1 << NFIFOENTRY_BND_SHIFT)
+#define NFIFOENTRY_BND         (1 << NFIFOENTRY_BND_SHIFT)
 
 #define NFIFOENTRY_PTYPE_SHIFT 16
 #define NFIFOENTRY_PTYPE_MASK  (0x7 << NFIFOENTRY_PTYPE_SHIFT)
 
-#define NFIFOENTRY_PTYPE_ZEROS         (0x0  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_RND_NOZEROS   (0x1  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_INCREMENT     (0x2  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_RND           (0x3  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_ZEROS_NZ      (0x4  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_RND_NZ_LZ     (0x5  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_N             (0x6  << NFIFOENTRY_PTYPE_SHIFT)
-#define NFIFOENTRY_PTYPE_RND_NZ_N      (0x7  << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_ZEROS         (0x0 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NOZEROS   (0x1 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_INCREMENT     (0x2 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND           (0x3 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_ZEROS_NZ      (0x4 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NZ_LZ     (0x5 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_N             (0x6 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NZ_N      (0x7 << NFIFOENTRY_PTYPE_SHIFT)
 
-#define NFIFOENTRY_OC_SHIFT            15
-#define NFIFOENTRY_OC_MASK             (1 << NFIFOENTRY_OC_SHIFT)
-#define NFIFOENTRY_OC                  (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_OC_SHIFT    15
+#define NFIFOENTRY_OC_MASK     (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_OC          (1 << NFIFOENTRY_OC_SHIFT)
 
 #define NFIFOENTRY_AST_SHIFT   14
-#define NFIFOENTRY_AST_MASK            (1 << NFIFOENTRY_OC_SHIFT)
-#define NFIFOENTRY_AST                 (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_AST_MASK    (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_AST         (1 << NFIFOENTRY_OC_SHIFT)
 
-#define NFIFOENTRY_BM_SHIFT            11
-#define NFIFOENTRY_BM_MASK             (1 << NFIFOENTRY_BM_SHIFT)
-#define NFIFOENTRY_BM                  (1 << NFIFOENTRY_BM_SHIFT)
-
-#define NFIFOENTRY_PS_SHIFT            10
-#define NFIFOENTRY_PS_MASK             (1 << NFIFOENTRY_PS_SHIFT)
-#define NFIFOENTRY_PS                  (1 << NFIFOENTRY_PS_SHIFT)
+#define NFIFOENTRY_BM_SHIFT    11
+#define NFIFOENTRY_BM_MASK     (1 << NFIFOENTRY_BM_SHIFT)
+#define NFIFOENTRY_BM          (1 << NFIFOENTRY_BM_SHIFT)
 
+#define NFIFOENTRY_PS_SHIFT    10
+#define NFIFOENTRY_PS_MASK     (1 << NFIFOENTRY_PS_SHIFT)
+#define NFIFOENTRY_PS          (1 << NFIFOENTRY_PS_SHIFT)
 
 #define NFIFOENTRY_DLEN_SHIFT  0
 #define NFIFOENTRY_DLEN_MASK   (0xFFF << NFIFOENTRY_DLEN_SHIFT)
  */
 
 /* IPSec ESP CBC Encap/Decap Options */
-#define PDBOPTS_ESPCBC_ARSNONE  0x00   /* no antireplay window              */
-#define PDBOPTS_ESPCBC_ARS32    0x40   /* 32-entry antireplay window        */
-#define PDBOPTS_ESPCBC_ARS64    0xc0   /* 64-entry antireplay window        */
-#define PDBOPTS_ESPCBC_IVSRC    0x20   /* IV comes from internal random gen */
-#define PDBOPTS_ESPCBC_ESN      0x10   /* extended sequence included        */
-#define PDBOPTS_ESPCBC_OUTFMT   0x08   /* output only decapsulation (decap) */
-#define PDBOPTS_ESPCBC_IPHDRSRC 0x08   /* IP header comes from PDB (encap)  */
-#define PDBOPTS_ESPCBC_INCIPHDR 0x04   /* Prepend IP header to output frame */
-#define PDBOPTS_ESPCBC_IPVSN    0x02   /* process IPv6 header               */
-#define PDBOPTS_ESPCBC_TUNNEL   0x01   /* tunnel mode next-header byte      */
+#define PDBOPTS_ESPCBC_ARSNONE 0x00    /* no antireplay window */
+#define PDBOPTS_ESPCBC_ARS32   0x40    /* 32-entry antireplay window */
+#define PDBOPTS_ESPCBC_ARS64   0xc0    /* 64-entry antireplay window */
+#define PDBOPTS_ESPCBC_IVSRC   0x20    /* IV comes from internal random gen */
+#define PDBOPTS_ESPCBC_ESN     0x10    /* extended sequence included */
+#define PDBOPTS_ESPCBC_OUTFMT  0x08    /* output only decapsulation (decap) */
+#define PDBOPTS_ESPCBC_IPHDRSRC 0x08   /* IP header comes from PDB (encap) */
+#define PDBOPTS_ESPCBC_INCIPHDR 0x04   /* Prepend IP header to output frame */
+#define PDBOPTS_ESPCBC_IPVSN   0x02    /* process IPv6 header */
+#define PDBOPTS_ESPCBC_TUNNEL  0x01    /* tunnel mode next-header byte */
 
 #endif /* DESC_H */
index 0991323cf3fd40bd7e9f09f2e9c522aa78be3dfb..348b882275f059ede78df5d3ecf82b447c8e847e 100644 (file)
 #define PRINT_POS
 #endif
 
-#define SET_OK_PROP_ERRORS (IMMEDIATE | LDST_CLASS_DECO | \
-                           LDST_SRCDST_WORD_DECOCTRL | \
-                           (LDOFF_CHG_SHARE_OK_PROP << LDST_OFFSET_SHIFT))
+#define SET_OK_NO_PROP_ERRORS (IMMEDIATE | LDST_CLASS_DECO | \
+                              LDST_SRCDST_WORD_DECOCTRL | \
+                              (LDOFF_CHG_SHARE_OK_NO_PROP << \
+                               LDST_OFFSET_SHIFT))
 #define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \
                                LDST_SRCDST_WORD_DECOCTRL | \
                                (LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
index aee394e3905643dc02a9ef81cb7fb72984bdb174..e9f7a70cdd5efa443a9bd4d3d928d0a562002a0d 100644 (file)
@@ -657,7 +657,6 @@ struct caam_full {
        u64 rsvd[512];
        struct caam_assurance assure;
        struct caam_queue_if qi;
-       struct caam_deco *deco;
 };
 
 #endif /* REGS_H */
index dcd8babae9eb36fe864bae433558e5e1b4c77d83..597235a2f8f908bbc69fffc596ffc20d71a16c5b 100644 (file)
@@ -1128,17 +1128,7 @@ static struct platform_driver marvell_crypto = {
 };
 MODULE_ALIAS("platform:mv_crypto");
 
-static int __init mv_crypto_init(void)
-{
-       return platform_driver_register(&marvell_crypto);
-}
-module_init(mv_crypto_init);
-
-static void __exit mv_crypto_exit(void)
-{
-       platform_driver_unregister(&marvell_crypto);
-}
-module_exit(mv_crypto_exit);
+module_platform_driver(marvell_crypto);
 
 MODULE_AUTHOR("Sebastian Andrzej Siewior <sebastian@breakpoint.cc>");
 MODULE_DESCRIPTION("Support for Marvell's cryptographic engine");
index a2b553eabbdb6db38839ba1f14cc26a61edb31d2..58480d009324d603c9e78ba081793f4938c087c7 100644 (file)
@@ -873,7 +873,7 @@ static int spacc_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
         * request for any other size (192 bits) then we need to do a software
         * fallback.
         */
-       if ((len != AES_KEYSIZE_128 || len != AES_KEYSIZE_256) &&
+       if (len != AES_KEYSIZE_128 && len != AES_KEYSIZE_256 &&
            ctx->sw_cipher) {
                /*
                 * Set the fallback transform to use the same request flags as
@@ -886,7 +886,7 @@ static int spacc_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
                err = crypto_ablkcipher_setkey(ctx->sw_cipher, key, len);
                if (err)
                        goto sw_setkey_failed;
-       } else if ((len != AES_KEYSIZE_128 || len != AES_KEYSIZE_256) &&
+       } else if (len != AES_KEYSIZE_128 && len != AES_KEYSIZE_256 &&
                   !ctx->sw_cipher)
                err = -EINVAL;
 
@@ -1854,17 +1854,7 @@ static struct platform_driver spacc_driver = {
        .id_table       = spacc_id_table,
 };
 
-static int __init spacc_init(void)
-{
-       return platform_driver_register(&spacc_driver);
-}
-module_init(spacc_init);
-
-static void __exit spacc_exit(void)
-{
-       platform_driver_unregister(&spacc_driver);
-}
-module_exit(spacc_exit);
+module_platform_driver(spacc_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jamie Iles");
index 8115417a1c93af7d3155964de863add26183e44e..3376bca200fc86c33f1472864b28299906d7a5ab 100644 (file)
@@ -683,18 +683,7 @@ static struct platform_driver s5p_aes_crypto = {
        },
 };
 
-static int __init s5p_aes_mod_init(void)
-{
-       return  platform_driver_register(&s5p_aes_crypto);
-}
-
-static void __exit s5p_aes_mod_exit(void)
-{
-       platform_driver_unregister(&s5p_aes_crypto);
-}
-
-module_init(s5p_aes_mod_init);
-module_exit(s5p_aes_mod_exit);
+module_platform_driver(s5p_aes_crypto);
 
 MODULE_DESCRIPTION("S5PV210 AES hw acceleration support.");
 MODULE_LICENSE("GPL v2");
index dbe76b5df9cf2550b2e2621e2b051cf490396f76..2d8c7890168664778be01834c8911bb2f52c97bc 100644 (file)
@@ -99,6 +99,8 @@ struct talitos_request {
 
 /* per-channel fifo management */
 struct talitos_channel {
+       void __iomem *reg;
+
        /* request fifo */
        struct talitos_request *fifo;
 
@@ -120,7 +122,7 @@ struct talitos_private {
        struct device *dev;
        struct platform_device *ofdev;
        void __iomem *reg;
-       int irq;
+       int irq[2];
 
        /* SEC version geometry (from device tree node) */
        unsigned int num_channels;
@@ -144,7 +146,7 @@ struct talitos_private {
        atomic_t last_chan ____cacheline_aligned;
 
        /* request callback tasklet */
-       struct tasklet_struct done_task;
+       struct tasklet_struct done_task[2];
 
        /* list of registered algorithms */
        struct list_head alg_list;
@@ -157,6 +159,7 @@ struct talitos_private {
 #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
 #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
 #define TALITOS_FTR_SHA224_HWINIT 0x00000004
+#define TALITOS_FTR_HMAC_OK 0x00000008
 
 static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr)
 {
@@ -196,9 +199,9 @@ static int reset_channel(struct device *dev, int ch)
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
 
-       setbits32(priv->reg + TALITOS_CCCR(ch), TALITOS_CCCR_RESET);
+       setbits32(priv->chan[ch].reg + TALITOS_CCCR, TALITOS_CCCR_RESET);
 
-       while ((in_be32(priv->reg + TALITOS_CCCR(ch)) & TALITOS_CCCR_RESET)
+       while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) & TALITOS_CCCR_RESET)
               && --timeout)
                cpu_relax();
 
@@ -208,12 +211,12 @@ static int reset_channel(struct device *dev, int ch)
        }
 
        /* set 36-bit addressing, done writeback enable and done IRQ enable */
-       setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_EAE |
+       setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, TALITOS_CCCR_LO_EAE |
                  TALITOS_CCCR_LO_CDWE | TALITOS_CCCR_LO_CDIE);
 
        /* and ICCR writeback, if available */
        if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
-               setbits32(priv->reg + TALITOS_CCCR_LO(ch),
+               setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO,
                          TALITOS_CCCR_LO_IWSE);
 
        return 0;
@@ -223,13 +226,19 @@ static int reset_device(struct device *dev)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
+       u32 mcr = TALITOS_MCR_SWR;
 
-       setbits32(priv->reg + TALITOS_MCR, TALITOS_MCR_SWR);
+       setbits32(priv->reg + TALITOS_MCR, mcr);
 
        while ((in_be32(priv->reg + TALITOS_MCR) & TALITOS_MCR_SWR)
               && --timeout)
                cpu_relax();
 
+       if (priv->irq[1]) {
+               mcr = TALITOS_MCR_RCA1 | TALITOS_MCR_RCA3;
+               setbits32(priv->reg + TALITOS_MCR, mcr);
+       }
+
        if (timeout == 0) {
                dev_err(dev, "failed to reset device\n");
                return -EIO;
@@ -327,8 +336,9 @@ static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
 
        /* GO! */
        wmb();
-       out_be32(priv->reg + TALITOS_FF(ch), upper_32_bits(request->dma_desc));
-       out_be32(priv->reg + TALITOS_FF_LO(ch),
+       out_be32(priv->chan[ch].reg + TALITOS_FF,
+                upper_32_bits(request->dma_desc));
+       out_be32(priv->chan[ch].reg + TALITOS_FF_LO,
                 lower_32_bits(request->dma_desc));
 
        spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
@@ -397,21 +407,32 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
 /*
  * process completed requests for channels that have done status
  */
-static void talitos_done(unsigned long data)
-{
-       struct device *dev = (struct device *)data;
-       struct talitos_private *priv = dev_get_drvdata(dev);
-       int ch;
-
-       for (ch = 0; ch < priv->num_channels; ch++)
-               flush_channel(dev, ch, 0, 0);
-
-       /* At this point, all completed channels have been processed.
-        * Unmask done interrupts for channels completed later on.
-        */
-       setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
-       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
+#define DEF_TALITOS_DONE(name, ch_done_mask)                           \
+static void talitos_done_##name(unsigned long data)                    \
+{                                                                      \
+       struct device *dev = (struct device *)data;                     \
+       struct talitos_private *priv = dev_get_drvdata(dev);            \
+                                                                       \
+       if (ch_done_mask & 1)                                           \
+               flush_channel(dev, 0, 0, 0);                            \
+       if (priv->num_channels == 1)                                    \
+               goto out;                                               \
+       if (ch_done_mask & (1 << 2))                                    \
+               flush_channel(dev, 1, 0, 0);                            \
+       if (ch_done_mask & (1 << 4))                                    \
+               flush_channel(dev, 2, 0, 0);                            \
+       if (ch_done_mask & (1 << 6))                                    \
+               flush_channel(dev, 3, 0, 0);                            \
+                                                                       \
+out:                                                                   \
+       /* At this point, all completed channels have been processed */ \
+       /* Unmask done interrupts for channels completed later on. */   \
+       setbits32(priv->reg + TALITOS_IMR, ch_done_mask);               \
+       setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);     \
 }
+DEF_TALITOS_DONE(4ch, TALITOS_ISR_4CHDONE)
+DEF_TALITOS_DONE(ch0_2, TALITOS_ISR_CH_0_2_DONE)
+DEF_TALITOS_DONE(ch1_3, TALITOS_ISR_CH_1_3_DONE)
 
 /*
  * locate current (offending) descriptor
@@ -422,7 +443,7 @@ static u32 current_desc_hdr(struct device *dev, int ch)
        int tail = priv->chan[ch].tail;
        dma_addr_t cur_desc;
 
-       cur_desc = in_be32(priv->reg + TALITOS_CDPR_LO(ch));
+       cur_desc = in_be32(priv->chan[ch].reg + TALITOS_CDPR_LO);
 
        while (priv->chan[ch].fifo[tail].dma_desc != cur_desc) {
                tail = (tail + 1) & (priv->fifo_len - 1);
@@ -444,7 +465,7 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
        int i;
 
        if (!desc_hdr)
-               desc_hdr = in_be32(priv->reg + TALITOS_DESCBUF(ch));
+               desc_hdr = in_be32(priv->chan[ch].reg + TALITOS_DESCBUF);
 
        switch (desc_hdr & DESC_HDR_SEL0_MASK) {
        case DESC_HDR_SEL0_AFEU:
@@ -506,16 +527,15 @@ static void report_eu_error(struct device *dev, int ch, u32 desc_hdr)
 
        for (i = 0; i < 8; i++)
                dev_err(dev, "DESCBUF 0x%08x_%08x\n",
-                       in_be32(priv->reg + TALITOS_DESCBUF(ch) + 8*i),
-                       in_be32(priv->reg + TALITOS_DESCBUF_LO(ch) + 8*i));
+                       in_be32(priv->chan[ch].reg + TALITOS_DESCBUF + 8*i),
+                       in_be32(priv->chan[ch].reg + TALITOS_DESCBUF_LO + 8*i));
 }
 
 /*
  * recover from error interrupts
  */
-static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
+static void talitos_error(struct device *dev, u32 isr, u32 isr_lo)
 {
-       struct device *dev = (struct device *)data;
        struct talitos_private *priv = dev_get_drvdata(dev);
        unsigned int timeout = TALITOS_TIMEOUT;
        int ch, error, reset_dev = 0, reset_ch = 0;
@@ -528,8 +548,8 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
 
                error = -EINVAL;
 
-               v = in_be32(priv->reg + TALITOS_CCPSR(ch));
-               v_lo = in_be32(priv->reg + TALITOS_CCPSR_LO(ch));
+               v = in_be32(priv->chan[ch].reg + TALITOS_CCPSR);
+               v_lo = in_be32(priv->chan[ch].reg + TALITOS_CCPSR_LO);
 
                if (v_lo & TALITOS_CCPSR_LO_DOF) {
                        dev_err(dev, "double fetch fifo overflow error\n");
@@ -567,10 +587,10 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
                if (reset_ch) {
                        reset_channel(dev, ch);
                } else {
-                       setbits32(priv->reg + TALITOS_CCCR(ch),
+                       setbits32(priv->chan[ch].reg + TALITOS_CCCR,
                                  TALITOS_CCCR_CONT);
-                       setbits32(priv->reg + TALITOS_CCCR_LO(ch), 0);
-                       while ((in_be32(priv->reg + TALITOS_CCCR(ch)) &
+                       setbits32(priv->chan[ch].reg + TALITOS_CCCR_LO, 0);
+                       while ((in_be32(priv->chan[ch].reg + TALITOS_CCCR) &
                               TALITOS_CCCR_CONT) && --timeout)
                                cpu_relax();
                        if (timeout == 0) {
@@ -580,7 +600,7 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
                        }
                }
        }
-       if (reset_dev || isr & ~TALITOS_ISR_CHERR || isr_lo) {
+       if (reset_dev || isr & ~TALITOS_ISR_4CHERR || isr_lo) {
                dev_err(dev, "done overflow, internal time out, or rngu error: "
                        "ISR 0x%08x_%08x\n", isr, isr_lo);
 
@@ -593,30 +613,35 @@ static void talitos_error(unsigned long data, u32 isr, u32 isr_lo)
        }
 }
 
-static irqreturn_t talitos_interrupt(int irq, void *data)
-{
-       struct device *dev = data;
-       struct talitos_private *priv = dev_get_drvdata(dev);
-       u32 isr, isr_lo;
-
-       isr = in_be32(priv->reg + TALITOS_ISR);
-       isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);
-       /* Acknowledge interrupt */
-       out_be32(priv->reg + TALITOS_ICR, isr);
-       out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);
-
-       if (unlikely((isr & ~TALITOS_ISR_CHDONE) || isr_lo))
-               talitos_error((unsigned long)data, isr, isr_lo);
-       else
-               if (likely(isr & TALITOS_ISR_CHDONE)) {
-                       /* mask further done interrupts. */
-                       clrbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE);
-                       /* done_task will unmask done interrupts at exit */
-                       tasklet_schedule(&priv->done_task);
-               }
-
-       return (isr || isr_lo) ? IRQ_HANDLED : IRQ_NONE;
+#define DEF_TALITOS_INTERRUPT(name, ch_done_mask, ch_err_mask, tlet)          \
+static irqreturn_t talitos_interrupt_##name(int irq, void *data)              \
+{                                                                             \
+       struct device *dev = data;                                             \
+       struct talitos_private *priv = dev_get_drvdata(dev);                   \
+       u32 isr, isr_lo;                                                       \
+                                                                              \
+       isr = in_be32(priv->reg + TALITOS_ISR);                                \
+       isr_lo = in_be32(priv->reg + TALITOS_ISR_LO);                          \
+       /* Acknowledge interrupt */                                            \
+       out_be32(priv->reg + TALITOS_ICR, isr & (ch_done_mask | ch_err_mask)); \
+       out_be32(priv->reg + TALITOS_ICR_LO, isr_lo);                          \
+                                                                              \
+       if (unlikely((isr & ~TALITOS_ISR_4CHDONE) & ch_err_mask || isr_lo))    \
+               talitos_error(dev, isr, isr_lo);                               \
+       else                                                                   \
+               if (likely(isr & ch_done_mask)) {                              \
+                       /* mask further done interrupts. */                    \
+                       clrbits32(priv->reg + TALITOS_IMR, ch_done_mask);      \
+                       /* done_task will unmask done interrupts at exit */    \
+                       tasklet_schedule(&priv->done_task[tlet]);              \
+               }                                                              \
+                                                                              \
+       return (isr & (ch_done_mask | ch_err_mask) || isr_lo) ? IRQ_HANDLED :  \
+                                                               IRQ_NONE;      \
 }
+DEF_TALITOS_INTERRUPT(4ch, TALITOS_ISR_4CHDONE, TALITOS_ISR_4CHERR, 0)
+DEF_TALITOS_INTERRUPT(ch0_2, TALITOS_ISR_CH_0_2_DONE, TALITOS_ISR_CH_0_2_ERR, 0)
+DEF_TALITOS_INTERRUPT(ch1_3, TALITOS_ISR_CH_1_3_DONE, TALITOS_ISR_CH_1_3_ERR, 1)
 
 /*
  * hwrng
@@ -1874,6 +1899,97 @@ static int ahash_digest(struct ahash_request *areq)
        return ahash_process_req(areq, areq->nbytes);
 }
 
+struct keyhash_result {
+       struct completion completion;
+       int err;
+};
+
+static void keyhash_complete(struct crypto_async_request *req, int err)
+{
+       struct keyhash_result *res = req->data;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       res->err = err;
+       complete(&res->completion);
+}
+
+static int keyhash(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen,
+                  u8 *hash)
+{
+       struct talitos_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+
+       struct scatterlist sg[1];
+       struct ahash_request *req;
+       struct keyhash_result hresult;
+       int ret;
+
+       init_completion(&hresult.completion);
+
+       req = ahash_request_alloc(tfm, GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       /* Keep tfm keylen == 0 during hash of the long key */
+       ctx->keylen = 0;
+       ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                  keyhash_complete, &hresult);
+
+       sg_init_one(&sg[0], key, keylen);
+
+       ahash_request_set_crypt(req, sg, hash, keylen);
+       ret = crypto_ahash_digest(req);
+       switch (ret) {
+       case 0:
+               break;
+       case -EINPROGRESS:
+       case -EBUSY:
+               ret = wait_for_completion_interruptible(
+                       &hresult.completion);
+               if (!ret)
+                       ret = hresult.err;
+               break;
+       default:
+               break;
+       }
+       ahash_request_free(req);
+
+       return ret;
+}
+
+static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+                       unsigned int keylen)
+{
+       struct talitos_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm));
+       unsigned int blocksize =
+                       crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
+       unsigned int digestsize = crypto_ahash_digestsize(tfm);
+       unsigned int keysize = keylen;
+       u8 hash[SHA512_DIGEST_SIZE];
+       int ret;
+
+       if (keylen <= blocksize)
+               memcpy(ctx->key, key, keysize);
+       else {
+               /* Must get the hash of the long key */
+               ret = keyhash(tfm, key, keylen, hash);
+
+               if (ret) {
+                       crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+                       return -EINVAL;
+               }
+
+               keysize = digestsize;
+               memcpy(ctx->key, hash, digestsize);
+       }
+
+       ctx->keylen = keysize;
+
+       return 0;
+}
+
+
 struct talitos_alg_template {
        u32 type;
        union {
@@ -2217,6 +2333,138 @@ static struct talitos_alg_template driver_algs[] = {
                                     DESC_HDR_SEL0_MDEUB |
                                     DESC_HDR_MODE0_MDEUB_SHA512,
        },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = MD5_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(md5)",
+                               .cra_driver_name = "hmac-md5-talitos",
+                               .cra_blocksize = MD5_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUA |
+                                    DESC_HDR_MODE0_MDEU_MD5,
+       },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = SHA1_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(sha1)",
+                               .cra_driver_name = "hmac-sha1-talitos",
+                               .cra_blocksize = SHA1_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUA |
+                                    DESC_HDR_MODE0_MDEU_SHA1,
+       },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = SHA224_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(sha224)",
+                               .cra_driver_name = "hmac-sha224-talitos",
+                               .cra_blocksize = SHA224_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUA |
+                                    DESC_HDR_MODE0_MDEU_SHA224,
+       },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = SHA256_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(sha256)",
+                               .cra_driver_name = "hmac-sha256-talitos",
+                               .cra_blocksize = SHA256_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUA |
+                                    DESC_HDR_MODE0_MDEU_SHA256,
+       },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = SHA384_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(sha384)",
+                               .cra_driver_name = "hmac-sha384-talitos",
+                               .cra_blocksize = SHA384_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUB |
+                                    DESC_HDR_MODE0_MDEUB_SHA384,
+       },
+       {       .type = CRYPTO_ALG_TYPE_AHASH,
+               .alg.hash = {
+                       .init = ahash_init,
+                       .update = ahash_update,
+                       .final = ahash_final,
+                       .finup = ahash_finup,
+                       .digest = ahash_digest,
+                       .setkey = ahash_setkey,
+                       .halg.digestsize = SHA512_DIGEST_SIZE,
+                       .halg.base = {
+                               .cra_name = "hmac(sha512)",
+                               .cra_driver_name = "hmac-sha512-talitos",
+                               .cra_blocksize = SHA512_BLOCK_SIZE,
+                               .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+                                            CRYPTO_ALG_ASYNC,
+                               .cra_type = &crypto_ahash_type
+                       }
+               },
+               .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                    DESC_HDR_SEL0_MDEUB |
+                                    DESC_HDR_MODE0_MDEUB_SHA512,
+       }
 };
 
 struct talitos_crypto_alg {
@@ -2331,12 +2579,15 @@ static int talitos_remove(struct platform_device *ofdev)
 
        kfree(priv->chan);
 
-       if (priv->irq != NO_IRQ) {
-               free_irq(priv->irq, dev);
-               irq_dispose_mapping(priv->irq);
-       }
+       for (i = 0; i < 2; i++)
+               if (priv->irq[i]) {
+                       free_irq(priv->irq[i], dev);
+                       irq_dispose_mapping(priv->irq[i]);
+               }
 
-       tasklet_kill(&priv->done_task);
+       tasklet_kill(&priv->done_task[0]);
+       if (priv->irq[1])
+               tasklet_kill(&priv->done_task[1]);
 
        iounmap(priv->reg);
 
@@ -2373,8 +2624,14 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
        case CRYPTO_ALG_TYPE_AHASH:
                alg = &t_alg->algt.alg.hash.halg.base;
                alg->cra_init = talitos_cra_init_ahash;
+               if (!(priv->features & TALITOS_FTR_HMAC_OK) &&
+                   !strncmp(alg->cra_name, "hmac", 4)) {
+                       kfree(t_alg);
+                       return ERR_PTR(-ENOTSUPP);
+               }
                if (!(priv->features & TALITOS_FTR_SHA224_HWINIT) &&
-                   !strcmp(alg->cra_name, "sha224")) {
+                   (!strcmp(alg->cra_name, "sha224") ||
+                    !strcmp(alg->cra_name, "hmac(sha224)"))) {
                        t_alg->algt.alg.hash.init = ahash_init_sha224_swinit;
                        t_alg->algt.desc_hdr_template =
                                        DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
@@ -2397,6 +2654,54 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
        return t_alg;
 }
 
+static int talitos_probe_irq(struct platform_device *ofdev)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->dev.of_node;
+       struct talitos_private *priv = dev_get_drvdata(dev);
+       int err;
+
+       priv->irq[0] = irq_of_parse_and_map(np, 0);
+       if (!priv->irq[0]) {
+               dev_err(dev, "failed to map irq\n");
+               return -EINVAL;
+       }
+
+       priv->irq[1] = irq_of_parse_and_map(np, 1);
+
+       /* get the primary irq line */
+       if (!priv->irq[1]) {
+               err = request_irq(priv->irq[0], talitos_interrupt_4ch, 0,
+                                 dev_driver_string(dev), dev);
+               goto primary_out;
+       }
+
+       err = request_irq(priv->irq[0], talitos_interrupt_ch0_2, 0,
+                         dev_driver_string(dev), dev);
+       if (err)
+               goto primary_out;
+
+       /* get the secondary irq line */
+       err = request_irq(priv->irq[1], talitos_interrupt_ch1_3, 0,
+                         dev_driver_string(dev), dev);
+       if (err) {
+               dev_err(dev, "failed to request secondary irq\n");
+               irq_dispose_mapping(priv->irq[1]);
+               priv->irq[1] = 0;
+       }
+
+       return err;
+
+primary_out:
+       if (err) {
+               dev_err(dev, "failed to request primary irq\n");
+               irq_dispose_mapping(priv->irq[0]);
+               priv->irq[0] = 0;
+       }
+
+       return err;
+}
+
 static int talitos_probe(struct platform_device *ofdev)
 {
        struct device *dev = &ofdev->dev;
@@ -2413,28 +2718,22 @@ static int talitos_probe(struct platform_device *ofdev)
 
        priv->ofdev = ofdev;
 
-       tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
-
-       INIT_LIST_HEAD(&priv->alg_list);
-
-       priv->irq = irq_of_parse_and_map(np, 0);
-
-       if (priv->irq == NO_IRQ) {
-               dev_err(dev, "failed to map irq\n");
-               err = -EINVAL;
+       err = talitos_probe_irq(ofdev);
+       if (err)
                goto err_out;
-       }
 
-       /* get the irq line */
-       err = request_irq(priv->irq, talitos_interrupt, 0,
-                         dev_driver_string(dev), dev);
-       if (err) {
-               dev_err(dev, "failed to request irq %d\n", priv->irq);
-               irq_dispose_mapping(priv->irq);
-               priv->irq = NO_IRQ;
-               goto err_out;
+       if (!priv->irq[1]) {
+               tasklet_init(&priv->done_task[0], talitos_done_4ch,
+                            (unsigned long)dev);
+       } else {
+               tasklet_init(&priv->done_task[0], talitos_done_ch0_2,
+                            (unsigned long)dev);
+               tasklet_init(&priv->done_task[1], talitos_done_ch1_3,
+                            (unsigned long)dev);
        }
 
+       INIT_LIST_HEAD(&priv->alg_list);
+
        priv->reg = of_iomap(np, 0);
        if (!priv->reg) {
                dev_err(dev, "failed to of_iomap\n");
@@ -2471,7 +2770,8 @@ static int talitos_probe(struct platform_device *ofdev)
 
        if (of_device_is_compatible(np, "fsl,sec2.1"))
                priv->features |= TALITOS_FTR_HW_AUTH_CHECK |
-                                 TALITOS_FTR_SHA224_HWINIT;
+                                 TALITOS_FTR_SHA224_HWINIT |
+                                 TALITOS_FTR_HMAC_OK;
 
        priv->chan = kzalloc(sizeof(struct talitos_channel) *
                             priv->num_channels, GFP_KERNEL);
@@ -2481,6 +2781,12 @@ static int talitos_probe(struct platform_device *ofdev)
                goto err_out;
        }
 
+       for (i = 0; i < priv->num_channels; i++) {
+               priv->chan[i].reg = priv->reg + TALITOS_CH_STRIDE * (i + 1);
+               if (!priv->irq[1] || !(i & 1))
+                       priv->chan[i].reg += TALITOS_CH_BASE_OFFSET;
+       }
+
        for (i = 0; i < priv->num_channels; i++) {
                spin_lock_init(&priv->chan[i].head_lock);
                spin_lock_init(&priv->chan[i].tail_lock);
@@ -2530,6 +2836,8 @@ static int talitos_probe(struct platform_device *ofdev)
                        t_alg = talitos_alg_alloc(dev, &driver_algs[i]);
                        if (IS_ERR(t_alg)) {
                                err = PTR_ERR(t_alg);
+                               if (err == -ENOTSUPP)
+                                       continue;
                                goto err_out;
                        }
 
@@ -2551,12 +2859,13 @@ static int talitos_probe(struct platform_device *ofdev)
                                dev_err(dev, "%s alg registration failed\n",
                                        name);
                                kfree(t_alg);
-                       } else {
+                       } else
                                list_add_tail(&t_alg->entry, &priv->alg_list);
-                               dev_info(dev, "%s\n", name);
-                       }
                }
        }
+       if (!list_empty(&priv->alg_list))
+               dev_info(dev, "%s algorithms registered in /proc/crypto\n",
+                        (char *)of_get_property(np, "compatible", NULL));
 
        return 0;
 
@@ -2584,17 +2893,7 @@ static struct platform_driver talitos_driver = {
        .remove = talitos_remove,
 };
 
-static int __init talitos_init(void)
-{
-       return platform_driver_register(&talitos_driver);
-}
-module_init(talitos_init);
-
-static void __exit talitos_exit(void)
-{
-       platform_driver_unregister(&talitos_driver);
-}
-module_exit(talitos_exit);
+module_platform_driver(talitos_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kim Phillips <kim.phillips@freescale.com>");
index 0b746aca4587e55b793592c59130a57136fe728c..3c173954ef295d618da2084e5082b940708536b5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale SEC (talitos) device register and descriptor header defines
  *
- * Copyright (c) 2006-2010 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 /* global register offset addresses */
 #define TALITOS_MCR                    0x1030  /* master control register */
-#define TALITOS_MCR_LO                 0x1038
+#define   TALITOS_MCR_RCA0             (1 << 15) /* remap channel 0 */
+#define   TALITOS_MCR_RCA1             (1 << 14) /* remap channel 1 */
+#define   TALITOS_MCR_RCA2             (1 << 13) /* remap channel 2 */
+#define   TALITOS_MCR_RCA3             (1 << 12) /* remap channel 3 */
 #define   TALITOS_MCR_SWR              0x1     /* s/w reset */
+#define TALITOS_MCR_LO                 0x1034
 #define TALITOS_IMR                    0x1008  /* interrupt mask register */
 #define   TALITOS_IMR_INIT             0x100ff /* enable channel IRQs */
 #define   TALITOS_IMR_DONE             0x00055 /* done IRQs */
 #define TALITOS_IMR_LO                 0x100C
 #define   TALITOS_IMR_LO_INIT          0x20000 /* allow RNGU error IRQs */
 #define TALITOS_ISR                    0x1010  /* interrupt status register */
-#define   TALITOS_ISR_CHERR            0xaa    /* channel errors mask */
-#define   TALITOS_ISR_CHDONE           0x55    /* channel done mask */
+#define   TALITOS_ISR_4CHERR           0xaa    /* 4 channel errors mask */
+#define   TALITOS_ISR_4CHDONE          0x55    /* 4 channel done mask */
+#define   TALITOS_ISR_CH_0_2_ERR       0x22    /* channels 0, 2 errors mask */
+#define   TALITOS_ISR_CH_0_2_DONE      0x11    /* channels 0, 2 done mask */
+#define   TALITOS_ISR_CH_1_3_ERR       0x88    /* channels 1, 3 errors mask */
+#define   TALITOS_ISR_CH_1_3_DONE      0x44    /* channels 1, 3 done mask */
 #define TALITOS_ISR_LO                 0x1014
 #define TALITOS_ICR                    0x1018  /* interrupt clear register */
 #define TALITOS_ICR_LO                 0x101C
 
 /* channel register address stride */
+#define TALITOS_CH_BASE_OFFSET         0x1000  /* default channel map base */
 #define TALITOS_CH_STRIDE              0x100
 
 /* channel configuration register  */
-#define TALITOS_CCCR(ch)               (ch * TALITOS_CH_STRIDE + 0x1108)
+#define TALITOS_CCCR                   0x8
 #define   TALITOS_CCCR_CONT            0x2    /* channel continue */
 #define   TALITOS_CCCR_RESET           0x1    /* channel reset */
-#define TALITOS_CCCR_LO(ch)            (ch * TALITOS_CH_STRIDE + 0x110c)
+#define TALITOS_CCCR_LO                        0xc
 #define   TALITOS_CCCR_LO_IWSE         0x80   /* chan. ICCR writeback enab. */
 #define   TALITOS_CCCR_LO_EAE          0x20   /* extended address enable */
 #define   TALITOS_CCCR_LO_CDWE         0x10   /* chan. done writeback enab. */
@@ -63,8 +72,8 @@
 #define   TALITOS_CCCR_LO_CDIE         0x2    /* channel done IRQ enable */
 
 /* CCPSR: channel pointer status register */
-#define TALITOS_CCPSR(ch)              (ch * TALITOS_CH_STRIDE + 0x1110)
-#define TALITOS_CCPSR_LO(ch)           (ch * TALITOS_CH_STRIDE + 0x1114)
+#define TALITOS_CCPSR                  0x10
+#define TALITOS_CCPSR_LO               0x14
 #define   TALITOS_CCPSR_LO_DOF         0x8000 /* double FF write oflow error */
 #define   TALITOS_CCPSR_LO_SOF         0x4000 /* single FF write oflow error */
 #define   TALITOS_CCPSR_LO_MDTE                0x2000 /* master data transfer error */
 #define   TALITOS_CCPSR_LO_SRL         0x0010 /* scatter return/length error */
 
 /* channel fetch fifo register */
-#define TALITOS_FF(ch)                 (ch * TALITOS_CH_STRIDE + 0x1148)
-#define TALITOS_FF_LO(ch)              (ch * TALITOS_CH_STRIDE + 0x114c)
+#define TALITOS_FF                     0x48
+#define TALITOS_FF_LO                  0x4c
 
 /* current descriptor pointer register */
-#define TALITOS_CDPR(ch)               (ch * TALITOS_CH_STRIDE + 0x1140)
-#define TALITOS_CDPR_LO(ch)            (ch * TALITOS_CH_STRIDE + 0x1144)
+#define TALITOS_CDPR                   0x40
+#define TALITOS_CDPR_LO                        0x44
 
 /* descriptor buffer register */
-#define TALITOS_DESCBUF(ch)            (ch * TALITOS_CH_STRIDE + 0x1180)
-#define TALITOS_DESCBUF_LO(ch)         (ch * TALITOS_CH_STRIDE + 0x1184)
+#define TALITOS_DESCBUF                        0x80
+#define TALITOS_DESCBUF_LO             0x84
 
 /* gather link table */
-#define TALITOS_GATHER(ch)             (ch * TALITOS_CH_STRIDE + 0x11c0)
-#define TALITOS_GATHER_LO(ch)          (ch * TALITOS_CH_STRIDE + 0x11c4)
+#define TALITOS_GATHER                 0xc0
+#define TALITOS_GATHER_LO              0xc4
 
 /* scatter link table */
-#define TALITOS_SCATTER(ch)            (ch * TALITOS_CH_STRIDE + 0x11e0)
-#define TALITOS_SCATTER_LO(ch)         (ch * TALITOS_CH_STRIDE + 0x11e4)
+#define TALITOS_SCATTER                        0xe0
+#define TALITOS_SCATTER_LO             0xe4
 
 /* execution unit interrupt status registers */
 #define TALITOS_DEUISR                 0x2030 /* DES unit */
index efba163595db1dd6a981f426d3581351a0fbd8b6..9b00072a020fb5141060c5ee89cfe31edbd651be 100644 (file)
@@ -145,18 +145,6 @@ config ISCSI_IBFT
          detect iSCSI boot parameters dynamically during system boot, say Y.
          Otherwise, say N.
 
-config SIGMA
-       tristate "SigmaStudio firmware loader"
-       depends on I2C
-       select CRC32
-       default n
-       help
-         Enable helper functions for working with Analog Devices SigmaDSP
-         parts and binary firmwares produced by Analog Devices SigmaStudio.
-
-         If unsure, say N here.  Drivers that need these helpers will select
-         this option automatically.
-
 source "drivers/firmware/google/Kconfig"
 
 endmenu
index 47338c9791263e849a9db97b34fb9f777afa2145..5a7e27399729789054c5069ca14ab4738786266f 100644 (file)
@@ -12,6 +12,5 @@ obj-$(CONFIG_DMIID)           += dmi-id.o
 obj-$(CONFIG_ISCSI_IBFT_FIND)  += iscsi_ibft_find.o
 obj-$(CONFIG_ISCSI_IBFT)       += iscsi_ibft.o
 obj-$(CONFIG_FIRMWARE_MEMMAP)  += memmap.o
-obj-$(CONFIG_SIGMA)            += sigma.o
 
 obj-$(CONFIG_GOOGLE_FIRMWARE)  += google/
diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c
deleted file mode 100644 (file)
index 1eedb6f..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Load Analog Devices SigmaStudio firmware files
- *
- * Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/sigma.h>
-
-static size_t sigma_action_size(struct sigma_action *sa)
-{
-       size_t payload = 0;
-
-       switch (sa->instr) {
-       case SIGMA_ACTION_WRITEXBYTES:
-       case SIGMA_ACTION_WRITESINGLE:
-       case SIGMA_ACTION_WRITESAFELOAD:
-               payload = sigma_action_len(sa);
-               break;
-       default:
-               break;
-       }
-
-       payload = ALIGN(payload, 2);
-
-       return payload + sizeof(struct sigma_action);
-}
-
-/*
- * Returns a negative error value in case of an error, 0 if processing of
- * the firmware should be stopped after this action, 1 otherwise.
- */
-static int
-process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
-{
-       size_t len = sigma_action_len(sa);
-       int ret;
-
-       pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
-               sa->instr, sa->addr, len);
-
-       switch (sa->instr) {
-       case SIGMA_ACTION_WRITEXBYTES:
-       case SIGMA_ACTION_WRITESINGLE:
-       case SIGMA_ACTION_WRITESAFELOAD:
-               ret = i2c_master_send(client, (void *)&sa->addr, len);
-               if (ret < 0)
-                       return -EINVAL;
-               break;
-       case SIGMA_ACTION_DELAY:
-               udelay(len);
-               len = 0;
-               break;
-       case SIGMA_ACTION_END:
-               return 0;
-       default:
-               return -EINVAL;
-       }
-
-       return 1;
-}
-
-static int
-process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
-{
-       struct sigma_action *sa;
-       size_t size;
-       int ret;
-
-       while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
-               sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
-
-               size = sigma_action_size(sa);
-               ssfw->pos += size;
-               if (ssfw->pos > ssfw->fw->size || size == 0)
-                       break;
-
-               ret = process_sigma_action(client, sa);
-
-               pr_debug("%s: action returned %i\n", __func__, ret);
-
-               if (ret <= 0)
-                       return ret;
-       }
-
-       if (ssfw->pos != ssfw->fw->size)
-               return -EINVAL;
-
-       return 0;
-}
-
-int process_sigma_firmware(struct i2c_client *client, const char *name)
-{
-       int ret;
-       struct sigma_firmware_header *ssfw_head;
-       struct sigma_firmware ssfw;
-       const struct firmware *fw;
-       u32 crc;
-
-       pr_debug("%s: loading firmware %s\n", __func__, name);
-
-       /* first load the blob */
-       ret = request_firmware(&fw, name, &client->dev);
-       if (ret) {
-               pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
-               return ret;
-       }
-       ssfw.fw = fw;
-
-       /* then verify the header */
-       ret = -EINVAL;
-
-       /*
-        * Reject too small or unreasonable large files. The upper limit has been
-        * chosen a bit arbitrarily, but it should be enough for all practical
-        * purposes and having the limit makes it easier to avoid integer
-        * overflows later in the loading process.
-        */
-       if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
-               goto done;
-
-       ssfw_head = (void *)fw->data;
-       if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
-               goto done;
-
-       crc = crc32(0, fw->data + sizeof(*ssfw_head),
-                       fw->size - sizeof(*ssfw_head));
-       pr_debug("%s: crc=%x\n", __func__, crc);
-       if (crc != le32_to_cpu(ssfw_head->crc))
-               goto done;
-
-       ssfw.pos = sizeof(*ssfw_head);
-
-       /* finally process all of the actions */
-       ret = process_sigma_actions(client, &ssfw);
-
- done:
-       release_firmware(fw);
-
-       pr_debug("%s: loaded %s\n", __func__, name);
-
-       return ret;
-}
-EXPORT_SYMBOL(process_sigma_firmware);
-
-MODULE_LICENSE("GPL");
index 4c980b573328eaeb4432504284ffe249fdb66a45..87a68a896abf7a0a010aa6395db5b0a53ba9ba41 100644 (file)
@@ -65,7 +65,14 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
        u8 reg = stmpe->regs[which] - (offset / 8);
        u8 mask = 1 << (offset % 8);
 
-       stmpe_reg_write(stmpe, reg, mask);
+       /*
+        * Some variants have single register for gpio set/clear functionality.
+        * For them we need to write 0 to clear and 1 to set.
+        */
+       if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB])
+               stmpe_set_bits(stmpe, reg, mask, val ? mask : 0);
+       else
+               stmpe_reg_write(stmpe, reg, mask);
 }
 
 static int stmpe_gpio_direction_output(struct gpio_chip *chip,
@@ -132,6 +139,10 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
                return -EINVAL;
 
+       /* STMPE801 doesn't have RE and FE registers */
+       if (stmpe_gpio->stmpe->partnum == STMPE801)
+               return 0;
+
        if (type == IRQ_TYPE_EDGE_RISING)
                stmpe_gpio->regs[REG_RE][regoffset] |= mask;
        else
@@ -165,6 +176,11 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
        int i, j;
 
        for (i = 0; i < CACHE_NR_REGS; i++) {
+               /* STMPE801 doesn't have RE and FE registers */
+               if ((stmpe->partnum == STMPE801) &&
+                               (i != REG_IE))
+                       continue;
+
                for (j = 0; j < num_banks; j++) {
                        u8 old = stmpe_gpio->oldregs[i][j];
                        u8 new = stmpe_gpio->regs[i][j];
@@ -241,8 +257,11 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
                }
 
                stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
-               stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
-                               status[i]);
+
+               /* Edge detect register is not present on 801 */
+               if (stmpe->partnum != STMPE801)
+                       stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
+                                       + i, status[i]);
        }
 
        return IRQ_HANDLED;
index 6d0f10b7569cd4842def5fc1d5ca68a713bf842c..c100f3e9c9207cbf38359a5df9fdf3d8a1bd0b3d 100644 (file)
@@ -66,6 +66,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
 static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        int max_clock = 0;
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
@@ -82,6 +83,11 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
        if (mode->hdisplay > 1680 || mode->vdisplay > 1050)
                return MODE_PANEL;
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 50d7cfb51662eba470c87704d6b37041f67f5a3c..de25560e629d19031848b0ec09c32ca19d7c2fe3 100644 (file)
@@ -241,6 +241,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector)
 static int cdv_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
 
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
@@ -255,14 +256,11 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                return MODE_NO_INTERLACE;
 
-       /*
-        * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it
-        * will go beyond the stolen memory size allocated to the framebuffer
-        */
-       if (mode->hdisplay > 1680)
-               return MODE_PANEL;
-       if (mode->vdisplay > 1050)
-               return MODE_PANEL;
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 36878a60080d8a59749dd838a2a4c762dd1046df..025d30970cc00e080b2140a5b2fe56540c57ee95 100644 (file)
@@ -506,6 +506,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc,
 static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
@@ -514,6 +515,11 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
                return MODE_NO_DBLESCAN;
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 4882b29119e09f0c5e753eb90289702b9976cf1d..88b42971c0fd07356155110581ea5c7e681a8408 100644 (file)
@@ -1141,6 +1141,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
+       struct drm_psb_private *dev_priv = connector->dev->dev_private;
        struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1160,6 +1161,11 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
                        return MODE_PANEL;
        }
 
+       /* We assume worst case scenario of 32 bpp here, since we don't know */
+       if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
+           dev_priv->vram_stolen_size)
+               return MODE_MEM;
+
        return MODE_OK;
 }
 
index 525744d593c1e981cc1039c79391f6aa38813b1d..7814a760c16439e8d6a0c74da474b4a978ce9793 100644 (file)
 
 #include <linux/vga_switcheroo.h>
 
-#define NOUVEAU_DSM_SUPPORTED 0x00
-#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
-
-#define NOUVEAU_DSM_ACTIVE 0x01
-#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
-
 #define NOUVEAU_DSM_LED 0x02
 #define NOUVEAU_DSM_LED_STATE 0x00
 #define NOUVEAU_DSM_LED_OFF 0x10
@@ -35,6 +29,9 @@
 #define NOUVEAU_DSM_POWER_SPEED 0x01
 #define NOUVEAU_DSM_POWER_STAMINA 0x02
 
+#define NOUVEAU_DSM_OPTIMUS_FN 0x1A
+#define NOUVEAU_DSM_OPTIMUS_ARGS 0x03000001
+
 static struct nouveau_dsm_priv {
        bool dsm_detected;
        bool optimus_detected;
@@ -61,7 +58,8 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        struct acpi_object_list input;
        union acpi_object params[4];
        union acpi_object *obj;
-       int err;
+       int i, err;
+       char args_buff[4];
 
        input.count = 4;
        input.pointer = params;
@@ -73,7 +71,11 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        params[2].type = ACPI_TYPE_INTEGER;
        params[2].integer.value = func;
        params[3].type = ACPI_TYPE_BUFFER;
-       params[3].buffer.length = 0;
+       params[3].buffer.length = 4;
+       /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
+       for (i = 0; i < 4; i++)
+               args_buff[i] = (arg >> i * 8) & 0xFF;
+       params[3].buffer.pointer = args_buff;
 
        err = acpi_evaluate_object(handle, "_DSM", &input, &output);
        if (err) {
@@ -148,6 +150,23 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
        return 0;
 }
 
+/* Returns 1 if a DSM function is usable and 0 otherwise */
+static int nouveau_test_dsm(acpi_handle test_handle,
+       int (*dsm_func)(acpi_handle, int, int, uint32_t *),
+       int sfnc)
+{
+       u32 result = 0;
+
+       /* Function 0 returns a Buffer containing available functions. The args
+        * parameter is ignored for function 0, so just put 0 in it */
+       if (dsm_func(test_handle, 0, 0, &result))
+               return 0;
+
+       /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If
+        * the n-th bit is enabled, function n is supported */
+       return result & 1 && result & (1 << sfnc);
+}
+
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
        mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
@@ -168,6 +187,10 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
 
 static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
 {
+       /* perhaps the _DSM functions are mutually exclusive, but prepare for
+        * the future */
+       if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+               return 0;
        if (id == VGA_SWITCHEROO_IGD)
                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
        else
@@ -180,6 +203,11 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
        if (id == VGA_SWITCHEROO_IGD)
                return 0;
 
+       /* Optimus laptops have the card already disabled in
+        * nouveau_switcheroo_set_state */
+       if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+               return 0;
+
        return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
@@ -212,8 +240,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
        acpi_handle dhandle, nvidia_handle;
        acpi_status status;
-       int ret, retval = 0;
-       uint32_t result;
+       int retval = 0;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
        if (!dhandle)
@@ -224,13 +251,11 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
                return false;
        }
 
-       ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
-                         NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-       if (ret == 0)
+       if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
                retval |= NOUVEAU_DSM_HAS_MUX;
 
-       ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
-       if (ret == 0)
+       if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm,
+               NOUVEAU_DSM_OPTIMUS_FN))
                retval |= NOUVEAU_DSM_HAS_OPT;
 
        if (retval)
@@ -269,15 +294,22 @@ static bool nouveau_dsm_detect(void)
        }
 
        if (vga_count == 2 && has_dsm && guid_valid) {
-               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+                       &buffer);
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
-                      acpi_method_name);
+                       acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
                ret = true;
        }
 
-       if (has_optimus == 1)
+       if (has_optimus == 1) {
+               acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+                       &buffer);
+               printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
+                       acpi_method_name);
                nouveau_dsm_priv.optimus_detected = true;
+               ret = true;
+       }
 
        return ret;
 }
@@ -293,6 +325,17 @@ void nouveau_register_dsm_handler(void)
        vga_switcheroo_register_handler(&nouveau_dsm_handler);
 }
 
+/* Must be called for Optimus models before the card can be turned off */
+void nouveau_switcheroo_optimus_dsm(void)
+{
+       u32 result = 0;
+       if (!nouveau_dsm_priv.optimus_detected)
+               return;
+
+       nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FN,
+               NOUVEAU_DSM_OPTIMUS_ARGS, &result);
+}
+
 void nouveau_unregister_dsm_handler(void)
 {
        vga_switcheroo_unregister_handler();
index 38134a9c75780a16ab4f646aa978f4d85719ecea..b827098289311bf94012f66b91d1d17c2159f333 100644 (file)
@@ -1055,12 +1055,14 @@ extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
 #if defined(CONFIG_ACPI)
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
+void nouveau_switcheroo_optimus_dsm(void);
 int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
 bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
 int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
 #else
 static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
+static inline void nouveau_switcheroo_optimus_dsm(void) {}
 static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
 static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
 static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; }
index f5e98910d17faf6b80bcd64f49d9c8909896b6a7..f80c5e0762ff90b4c29ec186ee1c5c4017f2fc7d 100644 (file)
@@ -525,6 +525,7 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
                printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
                drm_kms_helper_poll_disable(dev);
+               nouveau_switcheroo_optimus_dsm();
                nouveau_pci_suspend(pdev, pmm);
                dev->switch_power_state = DRM_SWITCH_POWER_OFF;
        }
index f7442e62c03f676c42afc518eba2be44400c43da..8e8cd85e5c0045926fb6f185744532eb2d588464 100644 (file)
@@ -1793,10 +1793,12 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                        ret = -EINVAL;
                        break;
                case PACKET_TYPE2:
+                       idx += 1;
                        break;
                case PACKET_TYPE3:
                        pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]);
                        ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt);
+                       idx += pkt.count + 2;
                        break;
                default:
                        dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type);
@@ -1805,7 +1807,6 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
                }
                if (ret)
                        break;
-               idx += pkt.count + 2;
        } while (idx < ib->length_dw);
 
        return ret;
index 3ec81c3d5108ce24163b00da4f42dbf4df83d7f6..bfd36ab643a68a5dea2b43d24283d08a0a2eb703 100644 (file)
@@ -2186,7 +2186,6 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 void r100_bm_disable(struct radeon_device *rdev)
 {
        u32 tmp;
-       u16 tmp16;
 
        /* disable bus mastering */
        tmp = RREG32(R_000030_BUS_CNTL);
@@ -2197,8 +2196,7 @@ void r100_bm_disable(struct radeon_device *rdev)
        WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040);
        tmp = RREG32(RADEON_BUS_CNTL);
        mdelay(1);
-       pci_read_config_word(rdev->pdev, 0x4, &tmp16);
-       pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB);
+       pci_clear_master(rdev->pdev);
        mdelay(1);
 }
 
index 31da622eef63c20e7dc66e821eff0cc5f43ec62d..8032f1fedb114005ae3b0e38c5c4073409cb2f93 100644 (file)
@@ -145,7 +145,7 @@ module_param_named(vramlimit, radeon_vram_limit, int, 0600);
 MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)");
 module_param_named(agpmode, radeon_agpmode, int, 0444);
 
-MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n");
+MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)");
 module_param_named(gartsize, radeon_gart_size, int, 0600);
 
 MODULE_PARM_DESC(benchmark, "Run benchmark");
index 803e0d3c177385ad31c4861c2647b28f721562d8..ec46eb45e34cd8b7534deb5f75353496424756f7 100644 (file)
@@ -322,16 +322,6 @@ void rs600_hpd_fini(struct radeon_device *rdev)
        }
 }
 
-void rs600_bm_disable(struct radeon_device *rdev)
-{
-       u16 tmp;
-
-       /* disable bus mastering */
-       pci_read_config_word(rdev->pdev, 0x4, &tmp);
-       pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB);
-       mdelay(1);
-}
-
 int rs600_asic_reset(struct radeon_device *rdev)
 {
        struct rv515_mc_save save;
@@ -355,7 +345,8 @@ int rs600_asic_reset(struct radeon_device *rdev)
        WREG32(RADEON_CP_RB_CNTL, tmp);
        pci_save_state(rdev->pdev);
        /* disable bus mastering */
-       rs600_bm_disable(rdev);
+       pci_clear_master(rdev->pdev);
+       mdelay(1);
        /* reset GA+VAP */
        WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) |
                                        S_0000F0_SOFT_RESET_GA(1));
index 37ead6995c872b64e1f2b4cef484365688364b71..0c46d8cdc6eadee9f7c712905c3f24239a0f6e52 100644 (file)
@@ -952,10 +952,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 
        type = ttm_to_type(ttm->page_flags, ttm->caching_state);
        pool = ttm_dma_find_pool(dev, type);
-       if (!pool) {
-               WARN_ON(!pool);
+       if (!pool)
                return;
-       }
+
        is_cached = (ttm_dma_find_pool(pool->dev,
                     ttm_to_type(ttm->page_flags, tt_cached)) == pool);
 
index f2183486a9b60882025d0eacc00070fa97253ce7..b47e58b52d9fbd1a28ef00d2d9392f8e44fe4d0f 100644 (file)
@@ -49,12 +49,14 @@ static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
 
 static enum power_supply_property wacom_battery_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_CAPACITY
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_SCOPE,
 };
 
 static enum power_supply_property wacom_ac_props[] = {
        POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_ONLINE
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_SCOPE,
 };
 
 static int wacom_battery_get_property(struct power_supply *psy,
@@ -70,6 +72,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = 1;
                break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+               break;
        case POWER_SUPPLY_PROP_CAPACITY:
                /* show 100% battery capacity when charging */
                if (power_state == 0)
@@ -101,6 +106,9 @@ static int wacom_ac_get_property(struct power_supply *psy,
                else
                        val->intval = 0;
                break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+               break;
        default:
                ret = -EINVAL;
                break;
@@ -523,6 +531,8 @@ static int wacom_probe(struct hid_device *hdev,
        wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
        wdata->battery.use_for_apm = 0;
 
+       power_supply_powers(&wdata->battery, &hdev->dev);
+
        ret = power_supply_register(&hdev->dev, &wdata->battery);
        if (ret) {
                hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
@@ -537,6 +547,8 @@ static int wacom_probe(struct hid_device *hdev,
        wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
        wdata->ac.use_for_apm = 0;
 
+       power_supply_powers(&wdata->battery, &hdev->dev);
+
        ret = power_supply_register(&hdev->dev, &wdata->ac);
        if (ret) {
                hid_warn(hdev,
index 61881b35c6702fa976b6e289cefb74ebbbe0ec4b..fc253b472f9d4033922693aa980d947210b1d4c2 100644 (file)
@@ -52,7 +52,8 @@ static __u16 wiiproto_keymap[] = {
 };
 
 static enum power_supply_property wiimote_battery_props[] = {
-       POWER_SUPPLY_PROP_CAPACITY
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_SCOPE,
 };
 
 static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
@@ -402,6 +403,11 @@ static int wiimote_battery_get_property(struct power_supply *psy,
        int ret = 0, state;
        unsigned long flags;
 
+       if (psp == POWER_SUPPLY_PROP_SCOPE) {
+               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+               return 0;
+       }
+
        ret = wiimote_cmd_acquire(wdata);
        if (ret)
                return ret;
@@ -1220,6 +1226,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
        wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
        wdata->battery.use_for_apm = 0;
 
+       power_supply_powers(&wdata->battery, &hdev->dev);
+
        ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
        if (ret) {
                hid_err(hdev, "Cannot register battery device\n");
index b6807db7b36f98f03ff00d15f6677906c4ddc8aa..e66d248fc126b8ffe4f9d85e45f82a76c5ee9bf7 100644 (file)
 #define        ALI1535_SMBIO_EN        0x04    /* SMB I/O Space enable         */
 
 static struct pci_driver ali1535_driver;
-static unsigned short ali1535_smba;
+static unsigned long ali1535_smba;
+static unsigned short ali1535_offset;
 
 /* Detect whether a ALI1535 can be found, and initialize it, where necessary.
    Note the differences between kernels with the old PCI BIOS interface and
@@ -140,7 +141,7 @@ static unsigned short ali1535_smba;
    defined to make the transition easier. */
 static int __devinit ali1535_setup(struct pci_dev *dev)
 {
-       int retval = -ENODEV;
+       int retval;
        unsigned char temp;
 
        /* Check the following things:
@@ -149,15 +150,28 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
                - We can use the addresses
        */
 
+       retval = pci_enable_device(dev);
+       if (retval) {
+               dev_err(&dev->dev, "ALI1535_smb can't enable device\n");
+               goto exit;
+       }
+
        /* Determine the address of the SMBus area */
-       pci_read_config_word(dev, SMBBA, &ali1535_smba);
-       ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
-       if (ali1535_smba == 0) {
+       pci_read_config_word(dev, SMBBA, &ali1535_offset);
+       dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset);
+       ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+       if (ali1535_offset == 0) {
                dev_warn(&dev->dev,
                        "ALI1535_smb region uninitialized - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit;
        }
 
+       if (pci_resource_flags(dev, 0) & IORESOURCE_IO)
+               ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset;
+       else
+               ali1535_smba = ali1535_offset;
+
        retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
                                   ali1535_driver.name);
        if (retval)
@@ -165,8 +179,9 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
 
        if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
                            ali1535_driver.name)) {
-               dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n",
+               dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n",
                        ali1535_smba);
+               retval = -EBUSY;
                goto exit;
        }
 
@@ -174,6 +189,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        pci_read_config_byte(dev, SMBCFG, &temp);
        if ((temp & ALI1535_SMBIO_EN) == 0) {
                dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit_free;
        }
 
@@ -181,6 +197,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        pci_read_config_byte(dev, SMBHSTCFG, &temp);
        if ((temp & 1) == 0) {
                dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+               retval = -ENODEV;
                goto exit_free;
        }
 
@@ -196,14 +213,13 @@ static int __devinit ali1535_setup(struct pci_dev *dev)
        */
        pci_read_config_byte(dev, SMBREV, &temp);
        dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
-       dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba);
+       dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba);
 
-       retval = 0;
-exit:
-       return retval;
+       return 0;
 
 exit_free:
        release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
        return retval;
 }
 
@@ -498,7 +514,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
        ali1535_adapter.dev.parent = &dev->dev;
 
        snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
-               "SMBus ALI1535 adapter at %04x", ali1535_smba);
+               "SMBus ALI1535 adapter at %04x", ali1535_offset);
        return i2c_add_adapter(&ali1535_adapter);
 }
 
index a409cfcf06291fdf568c6c2aed21e666da7b23bb..47ae0091e027dbab7b11e83b7924e7a2fc016027 100644 (file)
@@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev)
        ali1563_shutdown(dev);
 }
 
-static const struct pci_device_id ali1563_id_table[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
        {},
 };
index 83e8a60cdc86ba8cc87d4d0463d0d3cf859c35e7..087ea9caa74d3ac34b4ced643c0b8303aba6474e 100644 (file)
@@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id ali15x3_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { 0, }
 };
index 03bcd07c4697721b35810bf0b379465baffd23f2..eb778bf15c18539f579a6d435d4d0410fe1e4bce 100644 (file)
@@ -308,7 +308,7 @@ static const char* chipname[] = {
        "nVidia nForce", "AMD8111",
 };
 
-static const struct pci_device_id amd756_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
          .driver_data = AMD756 },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
index 6b6a6b1d70252539f6be0c0da874281d624d817e..e5ac53b99b0473703b8408bdde663ddd207f2b70 100644 (file)
@@ -415,7 +415,7 @@ static const struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static const struct pci_device_id amd8111_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
        { 0, }
 };
index 305c07504f7ebe055f2bfd5468e75a8e0ba31790..1679deef9c890131a951ee5cb8d50217ecb9bcf5 100644 (file)
@@ -295,9 +295,6 @@ static int at91_i2c_resume(struct platform_device *pdev)
 #define at91_i2c_resume                NULL
 #endif
 
-/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
-MODULE_ALIAS("platform:at91_i2c");
-
 static struct platform_driver at91_i2c_driver = {
        .probe          = at91_i2c_probe,
        .remove         = __devexit_p(at91_i2c_remove),
@@ -309,19 +306,9 @@ static struct platform_driver at91_i2c_driver = {
        },
 };
 
-static int __init at91_i2c_init(void)
-{
-       return platform_driver_register(&at91_i2c_driver);
-}
-
-static void __exit at91_i2c_exit(void)
-{
-       platform_driver_unregister(&at91_i2c_driver);
-}
-
-module_init(at91_i2c_init);
-module_exit(at91_i2c_exit);
+module_platform_driver(at91_i2c_driver);
 
 MODULE_AUTHOR("Rick Bronson");
 MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
index f314d7f433d321f4abd236cca1723443db778aa7..582d616db34615611c4783525cbfc46bccf37351 100644 (file)
@@ -426,20 +426,9 @@ static struct platform_driver au1xpsc_smbus_driver = {
        .remove         = __devexit_p(i2c_au1550_remove),
 };
 
-static int __init i2c_au1550_init(void)
-{
-       return platform_driver_register(&au1xpsc_smbus_driver);
-}
-
-static void __exit i2c_au1550_exit(void)
-{
-       platform_driver_unregister(&au1xpsc_smbus_driver);
-}
+module_platform_driver(au1xpsc_smbus_driver);
 
 MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
 MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:au1xpsc_smbus");
-
-module_init (i2c_au1550_init);
-module_exit (i2c_au1550_exit);
index b1d9cd28d8da9d92906a6cd5dc6b20c50ac3b48e..c1e1096ba06936a08cb60950123d67fdf59b3e96 100644 (file)
@@ -724,18 +724,7 @@ static struct platform_driver cpm_i2c_driver = {
        },
 };
 
-static int __init cpm_i2c_init(void)
-{
-       return platform_driver_register(&cpm_i2c_driver);
-}
-
-static void __exit cpm_i2c_exit(void)
-{
-       platform_driver_unregister(&cpm_i2c_driver);
-}
-
-module_init(cpm_i2c_init);
-module_exit(cpm_i2c_exit);
+module_platform_driver(cpm_i2c_driver);
 
 MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
 MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
index 9e89e7313d620437fcd892abb808a1181709f726..37f42113af31bc54da67d953938630c513955a4d 100644 (file)
@@ -349,7 +349,7 @@ static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
 /* work with hotplug and coldplug */
 MODULE_ALIAS("i2c_designware-pci");
 
-DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
        /* Moorestown */
        { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
        { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
index 18936ac9d51cd14af2221546fd062c3494ea18ec..3ef3557b6e32d5d03b1b048bdae39988d0524a4e 100644 (file)
@@ -185,7 +185,7 @@ static DEFINE_MUTEX(pch_mutex);
 #define PCI_DEVICE_ID_ML7213_I2C       0x802D
 #define PCI_DEVICE_ID_ML7223_I2C       0x8010
 
-static struct pci_device_id __devinitdata pch_pcidev_id[] = {
+static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
index 63bb1cc2a042125fe87e2bf9243a4bc40ffc5ab8..2294dea6b14584d1d757614da2a8870a2a7fc0da 100644 (file)
@@ -468,18 +468,7 @@ static struct platform_driver highlander_i2c_driver = {
        .remove         = __devexit_p(highlander_i2c_remove),
 };
 
-static int __init highlander_i2c_init(void)
-{
-       return platform_driver_register(&highlander_i2c_driver);
-}
-
-static void __exit highlander_i2c_exit(void)
-{
-       platform_driver_unregister(&highlander_i2c_driver);
-}
-
-module_init(highlander_i2c_init);
-module_exit(highlander_i2c_exit);
+module_platform_driver(highlander_i2c_driver);
 
 MODULE_AUTHOR("Paul Mundt");
 MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
index 9ff1695d845862ec77a4cf8ab1e5db7486ddc459..c527de17db4f25d8c539cefd2f3d2661b4e12fbf 100644 (file)
@@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = {
        .algo_data      = &hydra_bit_data,
 };
 
-static const struct pci_device_id hydra_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
        { 0, }
 };
index ab26840d0c7087073dbbba598953ebfca699b7b9..5d2e2816831f21dcd73912e8d33a9407f6df0b62 100644 (file)
@@ -609,7 +609,7 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = i801_func,
 };
 
-static const struct pci_device_id i801_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
index 3c110fbc409bb2c2ecd0cc2d7c6f9048914256cf..dacc5457a1be5c0eb23e8938bb06a7399dde1d88 100644 (file)
@@ -815,15 +815,4 @@ static struct platform_driver ibm_iic_driver = {
        .remove = __devexit_p(iic_remove),
 };
 
-static int __init iic_init(void)
-{
-       return platform_driver_register(&ibm_iic_driver);
-}
-
-static void __exit iic_exit(void)
-{
-       platform_driver_unregister(&ibm_iic_driver);
-}
-
-module_init(iic_init);
-module_exit(iic_exit);
+module_platform_driver(ibm_iic_driver);
index e828ac85cfa7298c68e1c5d6396ce13bc051aa14..365bad5b890b7ed6001ab48de51a17505056a789 100644 (file)
@@ -1093,7 +1093,7 @@ static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
        pci_release_region(dev, 0);
 }
 
-static struct pci_device_id intel_mid_i2c_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = {
        /* Moorestown */
        { PCI_VDEVICE(INTEL, 0x0802), 0 },
        { PCI_VDEVICE(INTEL, 0x0803), 1 },
index f09c9319a2babdecdb743a016995c0dd6554ad5a..93f147a96b6222253f367d4c6eb161922447a85a 100644 (file)
@@ -523,21 +523,7 @@ static struct platform_driver iop3xx_i2c_driver = {
        },
 };
 
-static int __init 
-i2c_iop3xx_init (void)
-{
-       return platform_driver_register(&iop3xx_i2c_driver);
-}
-
-static void __exit 
-i2c_iop3xx_exit (void)
-{
-       platform_driver_unregister(&iop3xx_i2c_driver);
-       return;
-}
-
-module_init (i2c_iop3xx_init);
-module_exit (i2c_iop3xx_exit);
+module_platform_driver(iop3xx_i2c_driver);
 
 MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
 MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
index 0682f8f277b013847b5545f597f68114920f408d..6561d275b8cf20fd9ed056c1963d66fd4c318899 100644 (file)
@@ -306,20 +306,9 @@ static struct platform_driver smbus_sch_driver = {
        .remove         = __devexit_p(smbus_sch_remove),
 };
 
-static int __init i2c_sch_init(void)
-{
-       return platform_driver_register(&smbus_sch_driver);
-}
-
-static void __exit i2c_sch_exit(void)
-{
-       platform_driver_unregister(&smbus_sch_driver);
-}
+module_platform_driver(smbus_sch_driver);
 
 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
 MODULE_DESCRIPTION("Intel SCH SMBus driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_sch_init);
-module_exit(i2c_sch_exit);
 MODULE_ALIAS("platform:isch_smbus");
index c01e9519f6c15ee5df4e8cb32ae44ae234f57482..5d263f9014d647a325373ce76fe26c4e7ba75177 100644 (file)
@@ -148,18 +148,7 @@ static struct platform_driver ixp2000_i2c_driver = {
        },
 };
 
-static int __init ixp2000_i2c_init(void)
-{
-       return platform_driver_register(&ixp2000_i2c_driver);
-}
-
-static void __exit ixp2000_i2c_exit(void)
-{
-       platform_driver_unregister(&ixp2000_i2c_driver);
-}
-
-module_init(ixp2000_i2c_init);
-module_exit(ixp2000_i2c_exit);
+module_platform_driver(ixp2000_i2c_driver);
 
 MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
 MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
index 107397a606b48957638a9569c2672ba363a5c57d..a8ebb84e23f9b179c80c2eb20c8266461b0265da 100644 (file)
@@ -715,18 +715,7 @@ static struct platform_driver mpc_i2c_driver = {
        },
 };
 
-static int __init fsl_i2c_init(void)
-{
-       return platform_driver_register(&mpc_i2c_driver);
-}
-
-static void __exit fsl_i2c_exit(void)
-{
-       platform_driver_unregister(&mpc_i2c_driver);
-}
-
-module_init(fsl_i2c_init);
-module_exit(fsl_i2c_exit);
+module_platform_driver(mpc_i2c_driver);
 
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
 MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
index a9941c65f226758d2992bb123fd0b5b2ead759dd..4f44a33017b061db314e051f9df882d4dee6a9e0 100644 (file)
@@ -611,20 +611,7 @@ static struct platform_driver mv64xxx_i2c_driver = {
        },
 };
 
-static int __init
-mv64xxx_i2c_init(void)
-{
-       return platform_driver_register(&mv64xxx_i2c_driver);
-}
-
-static void __exit
-mv64xxx_i2c_exit(void)
-{
-       platform_driver_unregister(&mv64xxx_i2c_driver);
-}
-
-module_init(mv64xxx_i2c_init);
-module_exit(mv64xxx_i2c_exit);
+module_platform_driver(mv64xxx_i2c_driver);
 
 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
 MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
index ff1e127dfea8e9b100c9fa1f6e2ebfd54c6992a6..43a96a123920c8d75773735b3070e7b4872ddd62 100644 (file)
@@ -309,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static const struct pci_device_id nforce2_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
@@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
        error = acpi_check_region(smbus->base, smbus->size,
                                  nforce2_driver.name);
        if (error)
-               return -1;
+               return error;
 
        if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
                dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
index 1b46a9d9f907336fb70526ca93881ce3b3934950..18068dee48f1aa11543413894485e4916bfc5811 100644 (file)
@@ -394,9 +394,6 @@ static struct of_device_id ocores_i2c_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:ocores-i2c");
-
 static struct platform_driver ocores_i2c_driver = {
        .probe   = ocores_i2c_probe,
        .remove  = __devexit_p(ocores_i2c_remove),
@@ -409,19 +406,9 @@ static struct platform_driver ocores_i2c_driver = {
        },
 };
 
-static int __init ocores_i2c_init(void)
-{
-       return platform_driver_register(&ocores_i2c_driver);
-}
-
-static void __exit ocores_i2c_exit(void)
-{
-       platform_driver_unregister(&ocores_i2c_driver);
-}
-
-module_init(ocores_i2c_init);
-module_exit(ocores_i2c_exit);
+module_platform_driver(ocores_i2c_driver);
 
 MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
 MODULE_DESCRIPTION("OpenCores I2C bus driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ocores-i2c");
index 56dbe54e88118a3fb7b112da16e11ccd5bdbc9fb..ee139a598814ea46da91fc494d6d2ded770ddef4 100644 (file)
@@ -629,24 +629,10 @@ static struct platform_driver octeon_i2c_driver = {
        },
 };
 
-static int __init octeon_i2c_init(void)
-{
-       int rv;
-
-       rv = platform_driver_register(&octeon_i2c_driver);
-       return rv;
-}
-
-static void __exit octeon_i2c_exit(void)
-{
-       platform_driver_unregister(&octeon_i2c_driver);
-}
+module_platform_driver(octeon_i2c_driver);
 
 MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
 MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:" DRV_NAME);
-
-module_init(octeon_i2c_init);
-module_exit(octeon_i2c_exit);
index 837b8c1aa02a494ef92899c46ccaf67cb709f9c1..eaaea73209c5ca5d81a0aec5b389d0520cba850d 100644 (file)
@@ -401,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev)
        kfree(smbus);
 }
 
-static const struct pci_device_id pasemi_smb_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = {
        { PCI_DEVICE(0x1959, 0xa003) },
        { 0, }
 };
index ace67995d7de85d6bd93920e0595f73b49bd9763..2adbf1a8fdea0019d8ca3acae29790ca18722552 100644 (file)
@@ -286,20 +286,8 @@ static struct platform_driver i2c_pca_pf_driver = {
        },
 };
 
-static int __init i2c_pca_pf_init(void)
-{
-       return platform_driver_register(&i2c_pca_pf_driver);
-}
-
-static void __exit i2c_pca_pf_exit(void)
-{
-       platform_driver_unregister(&i2c_pca_pf_driver);
-}
+module_platform_driver(i2c_pca_pf_driver);
 
 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
 MODULE_LICENSE("GPL");
-
-module_init(i2c_pca_pf_init);
-module_exit(i2c_pca_pf_exit);
-
index 6d14ac2e3c41b80982b1c5666cbca554d7c5facb..c14d48dd601a7d524ab97c8fff076867f21bae05 100644 (file)
@@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id piix4_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
index 127051b06921093f423b055f8b58cf364cc318e3..07b7447ecbc9102c7721e27727ab7d25223f35d8 100644 (file)
@@ -627,9 +627,6 @@ static struct i2c_adapter pmcmsptwi_adapter = {
        .name           = DRV_NAME,
 };
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:" DRV_NAME);
-
 static struct platform_driver pmcmsptwi_driver = {
        .probe  = pmcmsptwi_probe,
        .remove = __devexit_p(pmcmsptwi_remove),
@@ -639,18 +636,8 @@ static struct platform_driver pmcmsptwi_driver = {
        },
 };
 
-static int __init pmcmsptwi_init(void)
-{
-       return platform_driver_register(&pmcmsptwi_driver);
-}
-
-static void __exit pmcmsptwi_exit(void)
-{
-       platform_driver_unregister(&pmcmsptwi_driver);
-}
+module_platform_driver(pmcmsptwi_driver);
 
 MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
 MODULE_LICENSE("GPL");
-
-module_init(pmcmsptwi_init);
-module_exit(pmcmsptwi_exit);
+MODULE_ALIAS("platform:" DRV_NAME);
index b289ec99eeba087cd4be7e7da762a70a5de34889..7b397c6f607e46e4d52dd87f127d0208dde13839 100644 (file)
@@ -312,10 +312,6 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
        return rc;
 }
 
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:i2c-powermac");
-
 static struct platform_driver i2c_powermac_driver = {
        .probe = i2c_powermac_probe,
        .remove = __devexit_p(i2c_powermac_remove),
@@ -325,17 +321,6 @@ static struct platform_driver i2c_powermac_driver = {
        },
 };
 
-static int __init i2c_powermac_init(void)
-{
-       platform_driver_register(&i2c_powermac_driver);
-       return 0;
-}
+module_platform_driver(i2c_powermac_driver);
 
-
-static void __exit i2c_powermac_cleanup(void)
-{
-       platform_driver_unregister(&i2c_powermac_driver);
-}
-
-module_init(i2c_powermac_init);
-module_exit(i2c_powermac_cleanup);
+MODULE_ALIAS("platform:i2c-powermac");
index fac673940849742b60a7377a57b1cee367c2c22f..93709fbe30eb4c248527fa528bce2ae278807b8e 100644 (file)
@@ -276,8 +276,6 @@ static int puv3_i2c_resume(struct platform_device *dev)
 #define puv3_i2c_resume NULL
 #endif
 
-MODULE_ALIAS("platform:puv3_i2c");
-
 static struct platform_driver puv3_i2c_driver = {
        .probe          = puv3_i2c_probe,
        .remove         = __devexit_p(puv3_i2c_remove),
@@ -289,18 +287,8 @@ static struct platform_driver puv3_i2c_driver = {
        }
 };
 
-static int __init puv3_i2c_init(void)
-{
-       return platform_driver_register(&puv3_i2c_driver);
-}
-
-static void __exit puv3_i2c_exit(void)
-{
-       platform_driver_unregister(&puv3_i2c_driver);
-}
-
-module_init(puv3_i2c_init);
-module_exit(puv3_i2c_exit);
+module_platform_driver(puv3_i2c_driver);
 
 MODULE_DESCRIPTION("PKUnity v3 I2C driver");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:puv3_i2c");
index 632e088760a3fc006147f375bd97d15b453fe961..a05817980556542d77a9e4463060fb8e7fc6ab5d 100644 (file)
@@ -150,7 +150,7 @@ static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
        kfree(sds);
 }
 
-static struct pci_device_id ce4100_i2c_devices[] __devinitdata = {
+static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
        { },
 };
index a67132b2e0922b893c3920621524a014aabaf4c9..c0c9dffbdb12faa38fded2cfdae970dc941c91c5 100644 (file)
@@ -560,18 +560,7 @@ static struct platform_driver sh7760_i2c_drv = {
        .remove         = __devexit_p(sh7760_i2c_remove),
 };
 
-static int __init sh7760_i2c_init(void)
-{
-       return platform_driver_register(&sh7760_i2c_drv);
-}
-
-static void __exit sh7760_i2c_exit(void)
-{
-       platform_driver_unregister(&sh7760_i2c_drv);
-}
-
-module_init(sh7760_i2c_init);
-module_exit(sh7760_i2c_exit);
+module_platform_driver(sh7760_i2c_drv);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 I2C bus driver");
index 2fc08fbf67a223d6e7bfb26a0cf0d50ff40f821d..4fc87e7c94c9472b1df8b44f25e10dd605593805 100644 (file)
@@ -156,12 +156,8 @@ static int simtec_i2c_remove(struct platform_device *dev)
        return 0;
 }
 
-
 /* device driver */
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:simtec-i2c");
-
 static struct platform_driver simtec_i2c_driver = {
        .driver         = {
                .name           = "simtec-i2c",
@@ -171,19 +167,9 @@ static struct platform_driver simtec_i2c_driver = {
        .remove         = simtec_i2c_remove,
 };
 
-static int __init i2c_adap_simtec_init(void)
-{
-       return platform_driver_register(&simtec_i2c_driver);
-}
-
-static void __exit i2c_adap_simtec_exit(void)
-{
-       platform_driver_unregister(&simtec_i2c_driver);
-}
-
-module_init(i2c_adap_simtec_init);
-module_exit(i2c_adap_simtec_exit);
+module_platform_driver(simtec_i2c_driver);
 
 MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:simtec-i2c");
index 437586611d4a18819f110698d7618f7dde9471c3..87e5126d449ce4072eb263cb04b180e5c6d597f4 100644 (file)
@@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
        u16 a;
        u8 val;
        int *i;
-       int retval = -ENODEV;
+       int retval;
 
        /* Look for imposters */
        for (i = blacklist; *i != 0; i++) {
@@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
 
 error:
        release_region(sis5595_base + SMB_INDEX, 2);
-       return retval;
+       return -ENODEV;
 }
 
 static int sis5595_transaction(struct i2c_adapter *adap)
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis5595_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 
        { 0, }
 };
index e6f539e26f65fb97918e132164d45b80ce4a0113..e3df028bcf3b08946823253a281d30aea0afe660 100644 (file)
@@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
 {
        unsigned char b;
        struct pci_dev *dummy = NULL;
-       int retval = -ENODEV, i;
+       int retval, i;
 
        /* check for supported SiS devices */
        for (i=0; supported[i] > 0 ; i++) {
@@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
        */
        if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
                dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+               retval = -ENODEV;
                goto exit;
        }
        /* if ACPI already enabled , do nothing */
        if (!(b & 0x80) &&
            pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
                dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+               retval = -ENODEV;
                goto exit;
        }
 
        /* Determine the ACPI base address */
        if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
                dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
+               retval = -ENODEV;
                goto exit;
        }
 
@@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev)
                            sis630_driver.name)) {
                dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
                        "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
+               retval = -EBUSY;
                goto exit;
        }
 
@@ -468,7 +472,7 @@ static struct i2c_adapter sis630_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis630_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
        { 0, }
index 86837f0c4cb92efc4e1582dc2cfa2e89f68d936a..cc5d149413f7edb236ca48f57af155aaef5fefd9 100644 (file)
@@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static const struct pci_device_id sis96x_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
        { 0, }
 };
index 7799fe5bda885d3513a6e7b34f5686ae979d8456..713d31ade26b7ca8f77f2fa6be99757cb6af3299 100644 (file)
@@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = {
 };
 
 
-static const struct pci_device_id vt586b_ids[] __devinitconst = {
+static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
        { 0, }
 };
index 0b012f1f8ac5791ba9a4aa7926f75fbe97c57567..c3926c26d8cfa55f432dac0906bbd31c5701a675 100644 (file)
@@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
                                 const struct pci_device_id *id)
 {
        unsigned char temp;
-       int error = -ENODEV;
+       int error;
 
        /* Determine the address of the SMBus areas */
        if (force_addr) {
@@ -390,6 +390,7 @@ found:
                        dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
                                "controller not enabled! - upgrade BIOS or "
                                "use force=1\n");
+                       error = -ENODEV;
                        goto release_region;
                }
        }
@@ -422,9 +423,11 @@ found:
                 "SMBus Via Pro adapter at %04x", vt596_smba);
 
        vt596_pdev = pci_dev_get(pdev);
-       if (i2c_add_adapter(&vt596_adapter)) {
+       error = i2c_add_adapter(&vt596_adapter);
+       if (error) {
                pci_dev_put(vt596_pdev);
                vt596_pdev = NULL;
+               goto release_region;
        }
 
        /* Always return failure here.  This is to allow other drivers to bind
@@ -438,7 +441,7 @@ release_region:
        return error;
 }
 
-static const struct pci_device_id vt596_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
          .driver_data = SMBBA1 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
index ac083a28ae08e97f815632836638a7637d8732c1..2bded7647ef25b1a98f2211d1723de10568e3e7f 100644 (file)
@@ -795,10 +795,6 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev)
        return 0;
 }
 
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:"DRIVER_NAME);
-
 static struct platform_driver xiic_i2c_driver = {
        .probe   = xiic_i2c_probe,
        .remove  = __devexit_p(xiic_i2c_remove),
@@ -808,19 +804,9 @@ static struct platform_driver xiic_i2c_driver = {
        },
 };
 
-static int __init xiic_i2c_init(void)
-{
-       return platform_driver_register(&xiic_i2c_driver);
-}
-
-static void __exit xiic_i2c_exit(void)
-{
-       platform_driver_unregister(&xiic_i2c_driver);
-}
-
-module_init(xiic_i2c_init);
-module_exit(xiic_i2c_exit);
+module_platform_driver(xiic_i2c_driver);
 
 MODULE_AUTHOR("info@mocean-labs.com");
 MODULE_DESCRIPTION("Xilinx I2C bus driver");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
index 91e349c884c5c9ec73fc42b6fecd4964afc7ff12..2eacb7784d565edfeac64533ef48937c068220da 100644 (file)
@@ -559,7 +559,7 @@ static struct platform_driver scx200_pci_driver = {
        .remove = __devexit_p(scx200_remove),
 };
 
-static const struct pci_device_id scx200_isa[] __initconst = {
+static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
        { 0, }
index 57a45ce84b2d42f893cf45fb6e876bc1904bcfde..10e7f1e7658610b8e2b697cf6e355a999aa4f5b6 100644 (file)
@@ -251,15 +251,10 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
        if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
                return -EINVAL;
 
-       rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
-       if (!rdwr_pa)
-               return -ENOMEM;
-
-       if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
-                          rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
-               kfree(rdwr_pa);
-               return -EFAULT;
-       }
+       rdwr_pa = memdup_user(rdwr_arg.msgs,
+                             rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+       if (IS_ERR(rdwr_pa))
+               return PTR_ERR(rdwr_pa);
 
        data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
        if (data_ptrs == NULL) {
index 7b6ce624cd6e7e403b2cb7708b8581423298ef42..e5fa695eb0fa64673e1c26e82536b52a3a3388e8 100644 (file)
@@ -165,18 +165,7 @@ static struct platform_driver gpiomux_driver = {
        },
 };
 
-static int __init gpiomux_init(void)
-{
-       return platform_driver_register(&gpiomux_driver);
-}
-
-static void __exit gpiomux_exit(void)
-{
-       platform_driver_unregister(&gpiomux_driver);
-}
-
-module_init(gpiomux_init);
-module_exit(gpiomux_exit);
+module_platform_driver(gpiomux_driver);
 
 MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
 MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
index 6df5f6aa7908a9dbf649226cfb1bbc8dee6685cf..79172af164f25a5ccd913f32225dcd5e60c22760 100644 (file)
@@ -259,6 +259,19 @@ static struct platform_driver amikbd_driver = {
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(amikbd_driver);
+
+static int __init amikbd_init(void)
+{
+       return platform_driver_probe(&amikbd_driver, amikbd_probe);
+}
+
+module_init(amikbd_init);
+
+static void __exit amikbd_exit(void)
+{
+       platform_driver_unregister(&amikbd_driver);
+}
+
+module_exit(amikbd_exit);
 
 MODULE_ALIAS("platform:amiga-keyboard");
index 469825247552588e46615d04d5e4221006ab9186..9d82b3aeff5e5535b5f85d4a084a410523359564 100644 (file)
@@ -328,7 +328,18 @@ static struct platform_driver davinci_ks_driver = {
        },
        .remove = __devexit_p(davinci_ks_remove),
 };
-module_platform_driver(davinci_ks_driver);
+
+static int __init davinci_ks_init(void)
+{
+       return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
+}
+module_init(davinci_ks_init);
+
+static void __exit davinci_ks_exit(void)
+{
+       platform_driver_unregister(&davinci_ks_driver);
+}
+module_exit(davinci_ks_exit);
 
 MODULE_AUTHOR("Miguel Aguilar");
 MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
index 5a71e55c9c54e2c6f532ef70e0cc114b49eeeb67..e35566aa102fa2b4dde8c1f193d705b13fbbd1f3 100644 (file)
@@ -390,7 +390,18 @@ static struct platform_driver ske_keypad_driver = {
        .probe = ske_keypad_probe,
        .remove = __devexit_p(ske_keypad_remove),
 };
-module_platform_driver(ske_keypad_driver);
+
+static int __init ske_keypad_init(void)
+{
+       return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
+}
+module_init(ske_keypad_init);
+
+static void __exit ske_keypad_exit(void)
+{
+       platform_driver_unregister(&ske_keypad_driver);
+}
+module_exit(ske_keypad_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
index 79d9016336355a4885681ca68a2a0249b3b5894e..350fd0c385d2449115ea332fdf8f27601c46485c 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/slab.h>
 
 /**
index 19a68828cd865d0812ae57e2305dea1432bee912..38e4b507b94cc629ef330cf173b1b41d3765e904 100644 (file)
@@ -107,14 +107,25 @@ static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver twl4030_pwrbutton_driver = {
-       .probe          = twl4030_pwrbutton_probe,
        .remove         = __exit_p(twl4030_pwrbutton_remove),
        .driver         = {
                .name   = "twl4030_pwrbutton",
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(twl4030_pwrbutton_driver);
+
+static int __init twl4030_pwrbutton_init(void)
+{
+       return platform_driver_probe(&twl4030_pwrbutton_driver,
+                       twl4030_pwrbutton_probe);
+}
+module_init(twl4030_pwrbutton_init);
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+       platform_driver_unregister(&twl4030_pwrbutton_driver);
+}
+module_exit(twl4030_pwrbutton_exit);
 
 MODULE_ALIAS("platform:twl4030_pwrbutton");
 MODULE_DESCRIPTION("Triton2 Power Button");
index 39be7b82c046ac9b9129678631077aa5cf5e37e8..ff5f61a0fd3ad1eb071e600e5e37fb15fb4ca61a 100644 (file)
@@ -140,13 +140,25 @@ static int __exit amimouse_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver amimouse_driver = {
-       .probe = amimouse_probe,
        .remove = __exit_p(amimouse_remove),
        .driver   = {
                .name   = "amiga-mouse",
                .owner  = THIS_MODULE,
        },
 };
-module_platform_driver(amimouse_driver);
+
+static int __init amimouse_init(void)
+{
+       return platform_driver_probe(&amimouse_driver, amimouse_probe);
+}
+
+module_init(amimouse_init);
+
+static void __exit amimouse_exit(void)
+{
+       platform_driver_unregister(&amimouse_driver);
+}
+
+module_exit(amimouse_exit);
 
 MODULE_ALIAS("platform:amiga-mouse");
index cf87f8b18e34479c14bbfe49d1ca95495ecf4a5d..927e479c26494506df371e9cc4757d7b032ea3f4 100644 (file)
@@ -433,6 +433,9 @@ static void setup_events_to_report(struct input_dev *input_dev,
        __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
        __set_bit(BTN_LEFT, input_dev->keybit);
 
+       if (cfg->caps & HAS_INTEGRATED_BUTTON)
+               __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
+
        input_set_events_per_packet(input_dev, 60);
 }
 
index 421a7442e4641f92e73aa231cefe1de805a87fd2..95280f9207e14cf4d552aaa7cf8b7b3704fc123f 100644 (file)
@@ -358,7 +358,19 @@ static struct platform_driver psif_driver = {
        .suspend        = psif_suspend,
        .resume         = psif_resume,
 };
-module_platform_driver(psif_driver);
+
+static int __init psif_init(void)
+{
+       return platform_driver_probe(&psif_driver, psif_probe);
+}
+
+static void __exit psif_exit(void)
+{
+       platform_driver_unregister(&psif_driver);
+}
+
+module_init(psif_init);
+module_exit(psif_exit);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
index 4d4cd142bbbb126455e739b083750c547af4bfaa..8250299fd64ff37d78d97910a702f00710157532 100644 (file)
@@ -220,11 +220,11 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
                        goto out;
                }
                written++;
-       };
+       }
 
 out:
        mutex_unlock(&serio_raw_mutex);
-       return written;
+       return written ?: retval;
 }
 
 static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
@@ -237,9 +237,9 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
 
        mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM;
        if (serio_raw->head != serio_raw->tail)
-               return POLLIN | POLLRDNORM;
+               mask |= POLLIN | POLLRDNORM;
 
-       return 0;
+       return mask;
 }
 
 static const struct file_operations serio_raw_fops = {
index 127c391decedc319f00d014bf2967a0eb2ac6cd0..d96d4c2a76a94793270c6e4ce6dda247b2e08ebe 100644 (file)
@@ -253,7 +253,7 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
        }
 
        /* Get IRQ for the device */
-       if (of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq) == NO_IRQ) {
+       if (!of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq)) {
                dev_err(dev, "no IRQ found\n");
                return -ENODEV;
        }
index d016cb26d12523f6eb24214aa10a7e1f70a286ee..8034cbb20f74c8d8bcd426aa27b998e8bd8fcf20 100644 (file)
@@ -429,7 +429,18 @@ static struct platform_driver atmel_wm97xx_driver = {
        .suspend        = atmel_wm97xx_suspend,
        .resume         = atmel_wm97xx_resume,
 };
-module_platform_driver(atmel_wm97xx_driver);
+
+static int __init atmel_wm97xx_init(void)
+{
+       return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
+}
+module_init(atmel_wm97xx_init);
+
+static void __exit atmel_wm97xx_exit(void)
+{
+       platform_driver_unregister(&atmel_wm97xx_driver);
+}
+module_exit(atmel_wm97xx_exit);
 
 MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
index 68f86f7dabbce712f80ebe3c6322f008bf934ea2..ede02743eac1997b426a7970f96429a486ea4059 100644 (file)
@@ -240,7 +240,18 @@ static struct platform_driver mc13783_ts_driver = {
                .name   = MC13783_TS_NAME,
        },
 };
-module_platform_driver(mc13783_ts_driver);
+
+static int __init mc13783_ts_init(void)
+{
+       return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
+}
+module_init(mc13783_ts_init);
+
+static void __exit mc13783_ts_exit(void)
+{
+       platform_driver_unregister(&mc13783_ts_driver);
+}
+module_exit(mc13783_ts_exit);
 
 MODULE_DESCRIPTION("MC13783 input touchscreen driver");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
index 9c6650ea848ece07f2a369cbc0e7a17b26fc035b..2302fbe70ac62badd292a5e455a24042687f2b09 100644 (file)
@@ -6,7 +6,7 @@ if ISDN_I4L
 
 config ISDN_PPP
        bool "Support synchronous PPP"
-       depends on INET
+       depends on INET && NETDEVICES
        select SLHC
        help
          Over digital connections such as ISDN, there is no need to
index 1b75a56ebd08016cb517e62086ec62949e9aed0a..c957c344233f4ed283df710222492f1ee38d9bf0 100644 (file)
@@ -388,6 +388,21 @@ config LEDS_RENESAS_TPU
          pin function. The latter to support brightness control.
          Brightness control is supported but hardware blinking is not.
 
+config LEDS_TCA6507
+       tristate "LED Support for TCA6507 I2C chip"
+       depends on LEDS_CLASS && I2C
+       help
+         This option enables support for LEDs connected to TC6507
+         LED driver chips accessed via the I2C bus.
+         Driver support brightness control and hardware-assisted blinking.
+
+config LEDS_MAX8997
+       tristate "LED support for MAX8997 PMIC"
+       depends on LEDS_CLASS && MFD_MAX8997
+       help
+         This option enables support for on-chip LED drivers on
+         MAXIM MAX8997 PMIC.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        depends on LEDS_CLASS
index e4f6bf568880d284cc4743e4cb6231b450d57296..b8a9723477f0819b2fb07e2c19a61847888945e6 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_LEDS_GPIO)                       += leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
 obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
+obj-$(CONFIG_LEDS_TCA6507)             += leds-tca6507.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_LEDS_NS2)                        += leds-ns2.o
 obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)               += leds-asic3.o
 obj-$(CONFIG_LEDS_RENESAS_TPU)         += leds-renesas-tpu.o
+obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
index 0810604dc701307973f2967b8fd578f5a9bee997..4ca00624bd1860ed3b1f29e27ea79b59b47dc46d 100644 (file)
@@ -238,17 +238,7 @@ static struct platform_driver pm860x_led_driver = {
        .remove = pm860x_led_remove,
 };
 
-static int __devinit pm860x_led_init(void)
-{
-       return platform_driver_register(&pm860x_led_driver);
-}
-module_init(pm860x_led_init);
-
-static void __devexit pm860x_led_exit(void)
-{
-       platform_driver_unregister(&pm860x_led_driver);
-}
-module_exit(pm860x_led_exit);
+module_platform_driver(pm860x_led_driver);
 
 MODULE_DESCRIPTION("LED driver for Marvell PM860x");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index 7ba4c7b5b97e07ce6ff11d26895a154b25b5a956..b1400db3f839a2730b6dc29db302306fb3f627eb 100644 (file)
@@ -213,17 +213,7 @@ static struct platform_driver adp5520_led_driver = {
        .remove         = __devexit_p(adp5520_led_remove),
 };
 
-static int __init adp5520_led_init(void)
-{
-       return platform_driver_register(&adp5520_led_driver);
-}
-module_init(adp5520_led_init);
-
-static void __exit adp5520_led_exit(void)
-{
-       platform_driver_unregister(&adp5520_led_driver);
-}
-module_exit(adp5520_led_exit);
+module_platform_driver(adp5520_led_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("LEDS ADP5520(01) Driver");
index 8c00937bf7e74d02bc1759cbab01ca6eba1bc13e..07428357c83fd467ef2c524c65f4c4f4404f2fe1 100644 (file)
@@ -118,18 +118,7 @@ static struct platform_driver ams_delta_led_driver = {
        },
 };
 
-static int __init ams_delta_led_init(void)
-{
-       return platform_driver_register(&ams_delta_led_driver);
-}
-
-static void __exit ams_delta_led_exit(void)
-{
-       platform_driver_unregister(&ams_delta_led_driver);
-}
-
-module_init(ams_delta_led_init);
-module_exit(ams_delta_led_exit);
+module_platform_driver(ams_delta_led_driver);
 
 MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
 MODULE_DESCRIPTION("Amstrad Delta LED driver");
index 48d9fe61bdfcdc39e7bd6b1d942bb637f28c00ff..525a92492837bb892de5b4fb29050bf939a0a4fb 100644 (file)
@@ -179,21 +179,9 @@ static struct platform_driver asic3_led_driver = {
        },
 };
 
-MODULE_ALIAS("platform:leds-asic3");
-
-static int __init asic3_led_init(void)
-{
-       return platform_driver_register(&asic3_led_driver);
-}
-
-static void __exit asic3_led_exit(void)
-{
-       platform_driver_unregister(&asic3_led_driver);
-}
-
-module_init(asic3_led_init);
-module_exit(asic3_led_exit);
+module_platform_driver(asic3_led_driver);
 
 MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
 MODULE_DESCRIPTION("HTC ASIC3 LED driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-asic3");
index 109c875ea233486fc191a33b938f06f719ad1eaa..800243b6037ed9edc5b945b74d226a17be05f712 100644 (file)
@@ -134,29 +134,18 @@ static int __exit pwmled_remove(struct platform_device *pdev)
        return 0;
 }
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:leds-atmel-pwm");
-
 static struct platform_driver pwmled_driver = {
        .driver = {
                .name =         "leds-atmel-pwm",
                .owner =        THIS_MODULE,
        },
        /* REVISIT add suspend() and resume() methods */
+       .probe =        pwmled_probe,
        .remove =       __exit_p(pwmled_remove),
 };
 
-static int __init modinit(void)
-{
-       return platform_driver_probe(&pwmled_driver, pwmled_probe);
-}
-module_init(modinit);
-
-static void __exit modexit(void)
-{
-       platform_driver_unregister(&pwmled_driver);
-}
-module_exit(modexit);
+module_platform_driver(pwmled_driver);
 
 MODULE_DESCRIPTION("Driver for LEDs with PWM-controlled brightness");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-atmel-pwm");
index ea2185531f826e064d53437f956fbfb04e5e35f5..591cbdf5a0463e99ab91892bfc50b0beeb1c579c 100644 (file)
@@ -688,8 +688,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
        i2c_set_clientdata(client, led);
 
        /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
-       gpio_request(pdata->reset_gpio, "RGB_RESETB");
-       gpio_direction_output(pdata->reset_gpio, 1);
+       gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH, "RGB_RESETB");
 
        /* Tacss = min 0.1ms */
        udelay(100);
@@ -813,17 +812,7 @@ static struct i2c_driver bd2802_i2c_driver = {
        .id_table       = bd2802_id,
 };
 
-static int __init bd2802_init(void)
-{
-       return i2c_add_driver(&bd2802_i2c_driver);
-}
-module_init(bd2802_init);
-
-static void __exit bd2802_exit(void)
-{
-       i2c_del_driver(&bd2802_i2c_driver);
-}
-module_exit(bd2802_exit);
+module_i2c_driver(bd2802_i2c_driver);
 
 MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
 MODULE_DESCRIPTION("BD2802 LED driver");
index da5fb016b1a550fabfee5114bb11727a22c01749..6a8725cc7b4dfe119a2083e37e1290198bdbdd24 100644 (file)
@@ -75,9 +75,6 @@ static int __devexit cobalt_qube_led_remove(struct platform_device *pdev)
        return 0;
 }
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:cobalt-qube-leds");
-
 static struct platform_driver cobalt_qube_led_driver = {
        .probe  = cobalt_qube_led_probe,
        .remove = __devexit_p(cobalt_qube_led_remove),
@@ -87,19 +84,9 @@ static struct platform_driver cobalt_qube_led_driver = {
        },
 };
 
-static int __init cobalt_qube_led_init(void)
-{
-       return platform_driver_register(&cobalt_qube_led_driver);
-}
-
-static void __exit cobalt_qube_led_exit(void)
-{
-       platform_driver_unregister(&cobalt_qube_led_driver);
-}
-
-module_init(cobalt_qube_led_init);
-module_exit(cobalt_qube_led_exit);
+module_platform_driver(cobalt_qube_led_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Front LED support for Cobalt Server");
 MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_ALIAS("platform:cobalt-qube-leds");
index f28931cf6781049562018d0af5d59e014b2936d2..d9cd73ebd6c44c3e89ff032e2c2155eb036ad972 100644 (file)
@@ -158,17 +158,7 @@ static struct platform_driver da903x_led_driver = {
        .remove         = __devexit_p(da903x_led_remove),
 };
 
-static int __init da903x_led_init(void)
-{
-       return platform_driver_register(&da903x_led_driver);
-}
-module_init(da903x_led_init);
-
-static void __exit da903x_led_exit(void)
-{
-       platform_driver_unregister(&da903x_led_driver);
-}
-module_exit(da903x_led_exit);
+module_platform_driver(da903x_led_driver);
 
 MODULE_DESCRIPTION("LEDs driver for Dialog Semiconductor DA9030/DA9034");
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
index 31cf0d60a9a546052e782d5177b8461c9673d941..d56c14269ff0c7e9c5e40992f689919024cef7bd 100644 (file)
@@ -131,18 +131,7 @@ static struct spi_driver dac124s085_driver = {
        },
 };
 
-static int __init dac124s085_leds_init(void)
-{
-       return spi_register_driver(&dac124s085_driver);
-}
-
-static void __exit dac124s085_leds_exit(void)
-{
-       spi_unregister_driver(&dac124s085_driver);
-}
-
-module_init(dac124s085_leds_init);
-module_exit(dac124s085_leds_exit);
+module_spi_driver(dac124s085_driver);
 
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
 MODULE_DESCRIPTION("DAC124S085 LED driver");
index 49aceffaa5b6b76d0fb4b5fc8e14d6b90012f7fa..b9053fa6e2534312495217164c4a5f4e1eeb403d 100644 (file)
@@ -224,20 +224,7 @@ static struct platform_driver fsg_led_driver = {
        },
 };
 
-
-static int __init fsg_led_init(void)
-{
-       return platform_driver_register(&fsg_led_driver);
-}
-
-static void __exit fsg_led_exit(void)
-{
-       platform_driver_unregister(&fsg_led_driver);
-}
-
-
-module_init(fsg_led_init);
-module_exit(fsg_led_exit);
+module_platform_driver(fsg_led_driver);
 
 MODULE_AUTHOR("Rod Whitby <rod@whitby.id.au>");
 MODULE_DESCRIPTION("Freecom FSG-3 LED driver");
index 399a86f2013a145f1945f39077d23805bb40213d..7df74cb97e702e693935ab798598b9967b0d0ae7 100644 (file)
@@ -293,21 +293,9 @@ static struct platform_driver gpio_led_driver = {
        },
 };
 
-MODULE_ALIAS("platform:leds-gpio");
-
-static int __init gpio_led_init(void)
-{
-       return platform_driver_register(&gpio_led_driver);
-}
-
-static void __exit gpio_led_exit(void)
-{
-       platform_driver_unregister(&gpio_led_driver);
-}
-
-module_init(gpio_led_init);
-module_exit(gpio_led_exit);
+module_platform_driver(gpio_led_driver);
 
 MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
 MODULE_DESCRIPTION("GPIO LED driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-gpio");
index bcfbd3a60eab6b8ee4ae0ecb4cf14efce17a2ac3..366b6055e33063e5461d5fdc2bdac3ba23fff611 100644 (file)
@@ -79,9 +79,6 @@ static int hp6xxled_remove(struct platform_device *pdev)
        return 0;
 }
 
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:hp6xx-led");
-
 static struct platform_driver hp6xxled_driver = {
        .probe          = hp6xxled_probe,
        .remove         = hp6xxled_remove,
@@ -91,19 +88,9 @@ static struct platform_driver hp6xxled_driver = {
        },
 };
 
-static int __init hp6xxled_init(void)
-{
-       return platform_driver_register(&hp6xxled_driver);
-}
-
-static void __exit hp6xxled_exit(void)
-{
-       platform_driver_unregister(&hp6xxled_driver);
-}
-
-module_init(hp6xxled_init);
-module_exit(hp6xxled_exit);
+module_platform_driver(hp6xxled_driver);
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 6xx LED driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hp6xx-led");
index 0630e4f4b2866a8829a1731411dfa19afb7e0bae..45e6878d73741d8359db2069b68bbe1df2589f2e 100644 (file)
@@ -457,18 +457,7 @@ static struct i2c_driver lm3530_i2c_driver = {
        },
 };
 
-static int __init lm3530_init(void)
-{
-       return i2c_add_driver(&lm3530_i2c_driver);
-}
-
-static void __exit lm3530_exit(void)
-{
-       i2c_del_driver(&lm3530_i2c_driver);
-}
-
-module_init(lm3530_init);
-module_exit(lm3530_exit);
+module_i2c_driver(lm3530_i2c_driver);
 
 MODULE_DESCRIPTION("Back Light driver for LM3530");
 MODULE_LICENSE("GPL v2");
index 9010c054615e414fa5c236a8fe2cc4a700a00757..b8f9f0a5d4318d1291e377fe1fd4599d3bc15e13 100644 (file)
@@ -453,18 +453,7 @@ static struct i2c_driver lp3944_driver = {
        .id_table = lp3944_id,
 };
 
-static int __init lp3944_module_init(void)
-{
-       return i2c_add_driver(&lp3944_driver);
-}
-
-static void __exit lp3944_module_exit(void)
-{
-       i2c_del_driver(&lp3944_driver);
-}
-
-module_init(lp3944_module_init);
-module_exit(lp3944_module_exit);
+module_i2c_driver(lp3944_driver);
 
 MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
 MODULE_DESCRIPTION("LP3944 Fun Light Chip");
index cb641f1b33429ab2776cb300194b4e0fd00d3fdb..d62a7982a5e66ad25812e87c86773985c3ffc802 100644 (file)
@@ -797,25 +797,7 @@ static struct i2c_driver lp5521_driver = {
        .id_table       = lp5521_id,
 };
 
-static int __init lp5521_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&lp5521_driver);
-
-       if (ret < 0)
-               printk(KERN_ALERT "Adding lp5521 driver failed\n");
-
-       return ret;
-}
-
-static void __exit lp5521_exit(void)
-{
-       i2c_del_driver(&lp5521_driver);
-}
-
-module_init(lp5521_init);
-module_exit(lp5521_exit);
+module_i2c_driver(lp5521_driver);
 
 MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
 MODULE_DESCRIPTION("LP5521 LED engine");
index 5971e309b2342390a1988cd7f58d6e49d5a24301..73e791ae725993e1833f40cc8b0b059a0a55b53e 100644 (file)
@@ -870,8 +870,6 @@ static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev,
        return 0;
 }
 
-static struct i2c_driver lp5523_driver;
-
 static int __devinit lp5523_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -1021,25 +1019,7 @@ static struct i2c_driver lp5523_driver = {
        .id_table       = lp5523_id,
 };
 
-static int __init lp5523_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&lp5523_driver);
-
-       if (ret < 0)
-               printk(KERN_ALERT "Adding lp5523 driver failed\n");
-
-       return ret;
-}
-
-static void __exit lp5523_exit(void)
-{
-       i2c_del_driver(&lp5523_driver);
-}
-
-module_init(lp5523_init);
-module_exit(lp5523_exit);
+module_i2c_driver(lp5523_driver);
 
 MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
 MODULE_DESCRIPTION("LP5523 LED engine");
index 53f67b8ce55db505bd4ae5127423202e9141bca3..e311a96c4469759ae72eadabfc3f86c8c7795760 100644 (file)
@@ -199,21 +199,9 @@ static struct platform_driver lt3593_led_driver = {
        },
 };
 
-MODULE_ALIAS("platform:leds-lt3593");
-
-static int __init lt3593_led_init(void)
-{
-       return platform_driver_register(&lt3593_led_driver);
-}
-
-static void __exit lt3593_led_exit(void)
-{
-       platform_driver_unregister(&lt3593_led_driver);
-}
-
-module_init(lt3593_led_init);
-module_exit(lt3593_led_exit);
+module_platform_driver(lt3593_led_driver);
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 MODULE_DESCRIPTION("LED driver for LT3593 controllers");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-lt3593");
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
new file mode 100644 (file)
index 0000000..f4c0e37
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * leds-max8997.c - LED class driver for MAX8997 LEDs.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Donggeun Kim <dg77.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/leds.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/platform_device.h>
+
+#define MAX8997_LED_FLASH_SHIFT                        3
+#define MAX8997_LED_FLASH_CUR_MASK             0xf8
+#define MAX8997_LED_MOVIE_SHIFT                        4
+#define MAX8997_LED_MOVIE_CUR_MASK             0xf0
+
+#define MAX8997_LED_FLASH_MAX_BRIGHTNESS       0x1f
+#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS       0xf
+#define MAX8997_LED_NONE_MAX_BRIGHTNESS                0
+
+#define MAX8997_LED0_FLASH_MASK                        0x1
+#define MAX8997_LED0_FLASH_PIN_MASK            0x5
+#define MAX8997_LED0_MOVIE_MASK                        0x8
+#define MAX8997_LED0_MOVIE_PIN_MASK            0x28
+
+#define MAX8997_LED1_FLASH_MASK                        0x2
+#define MAX8997_LED1_FLASH_PIN_MASK            0x6
+#define MAX8997_LED1_MOVIE_MASK                        0x10
+#define MAX8997_LED1_MOVIE_PIN_MASK            0x30
+
+#define MAX8997_LED_BOOST_ENABLE_MASK          (1 << 6)
+
+struct max8997_led {
+       struct max8997_dev *iodev;
+       struct led_classdev cdev;
+       bool enabled;
+       int id;
+       enum max8997_led_mode led_mode;
+       struct mutex mutex;
+};
+
+static void max8997_led_clear_mode(struct max8997_led *led,
+                       enum max8997_led_mode mode)
+{
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = 0;
+       int ret;
+
+       switch (mode) {
+       case MAX8997_FLASH_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
+               break;
+       case MAX8997_MOVIE_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
+               break;
+       default:
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client,
+                               MAX8997_REG_LEN_CNTL, val, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+}
+
+static void max8997_led_set_mode(struct max8997_led *led,
+                       enum max8997_led_mode mode)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 mask = 0;
+
+       /* First, clear the previous mode */
+       max8997_led_clear_mode(led, led->led_mode);
+
+       switch (mode) {
+       case MAX8997_FLASH_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
+               led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_MOVIE_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
+               led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
+               led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               mask = led->id ?
+                     MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
+               led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
+               break;
+       default:
+               led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client,
+                               MAX8997_REG_LEN_CNTL, mask, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+
+       led->led_mode = mode;
+}
+
+static void max8997_led_enable(struct max8997_led *led, bool enable)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;
+
+       if (led->enabled == enable)
+               return;
+
+       val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;
+
+       ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);
+       if (ret)
+               dev_err(led->iodev->dev,
+                       "failed to update register(%d)\n", ret);
+
+       led->enabled = enable;
+}
+
+static void max8997_led_set_current(struct max8997_led *led,
+                               enum led_brightness value)
+{
+       int ret;
+       struct i2c_client *client = led->iodev->i2c;
+       u8 val = 0, mask = 0, reg = 0;
+
+       switch (led->led_mode) {
+       case MAX8997_FLASH_MODE:
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               val = value << MAX8997_LED_FLASH_SHIFT;
+               mask = MAX8997_LED_FLASH_CUR_MASK;
+               reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;
+               break;
+       case MAX8997_MOVIE_MODE:
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               val = value << MAX8997_LED_MOVIE_SHIFT;
+               mask = MAX8997_LED_MOVIE_CUR_MASK;
+               reg = MAX8997_REG_MOVIE_CUR;
+               break;
+       default:
+               break;
+       }
+
+       if (mask) {
+               ret = max8997_update_reg(client, reg, val, mask);
+               if (ret)
+                       dev_err(led->iodev->dev,
+                               "failed to update register(%d)\n", ret);
+       }
+}
+
+static void max8997_led_brightness_set(struct led_classdev *led_cdev,
+                               enum led_brightness value)
+{
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+
+       if (value) {
+               max8997_led_set_current(led, value);
+               max8997_led_enable(led, true);
+       } else {
+               max8997_led_set_current(led, value);
+               max8997_led_enable(led, false);
+       }
+}
+
+static ssize_t max8997_led_show_mode(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+       ssize_t ret = 0;
+
+       mutex_lock(&led->mutex);
+
+       switch (led->led_mode) {
+       case MAX8997_FLASH_MODE:
+               ret += sprintf(buf, "FLASH\n");
+               break;
+       case MAX8997_MOVIE_MODE:
+               ret += sprintf(buf, "MOVIE\n");
+               break;
+       case MAX8997_FLASH_PIN_CONTROL_MODE:
+               ret += sprintf(buf, "FLASH_PIN_CONTROL\n");
+               break;
+       case MAX8997_MOVIE_PIN_CONTROL_MODE:
+               ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");
+               break;
+       default:
+               ret += sprintf(buf, "NONE\n");
+               break;
+       }
+
+       mutex_unlock(&led->mutex);
+
+       return ret;
+}
+
+static ssize_t max8997_led_store_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct max8997_led *led =
+                       container_of(led_cdev, struct max8997_led, cdev);
+       enum max8997_led_mode mode;
+
+       mutex_lock(&led->mutex);
+
+       if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))
+               mode = MAX8997_FLASH_PIN_CONTROL_MODE;
+       else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))
+               mode = MAX8997_MOVIE_PIN_CONTROL_MODE;
+       else if (!strncmp(buf, "FLASH", 5))
+               mode = MAX8997_FLASH_MODE;
+       else if (!strncmp(buf, "MOVIE", 5))
+               mode = MAX8997_MOVIE_MODE;
+       else
+               mode = MAX8997_NONE;
+
+       max8997_led_set_mode(led, mode);
+
+       mutex_unlock(&led->mutex);
+
+       return size;
+}
+
+static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
+
+static int __devinit max8997_led_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8997_led *led;
+       char name[20];
+       int ret = 0;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -ENODEV;
+       }
+
+       led = kzalloc(sizeof(*led), GFP_KERNEL);
+       if (led == NULL) {
+               ret = -ENOMEM;
+               goto err_mem;
+       }
+
+       led->id = pdev->id;
+       snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
+
+       led->cdev.name = name;
+       led->cdev.brightness_set = max8997_led_brightness_set;
+       led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led->cdev.brightness = 0;
+       led->iodev = iodev;
+
+       /* initialize mode and brightness according to platform_data */
+       if (pdata->led_pdata) {
+               u8 mode = 0, brightness = 0;
+
+               mode = pdata->led_pdata->mode[led->id];
+               brightness = pdata->led_pdata->brightness[led->id];
+
+               max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]);
+
+               if (brightness > led->cdev.max_brightness)
+                       brightness = led->cdev.max_brightness;
+               max8997_led_set_current(led, brightness);
+               led->cdev.brightness = brightness;
+       } else {
+               max8997_led_set_mode(led, MAX8997_NONE);
+               max8997_led_set_current(led, 0);
+       }
+
+       mutex_init(&led->mutex);
+
+       platform_set_drvdata(pdev, led);
+
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0)
+               goto err_led;
+
+       ret = device_create_file(led->cdev.dev, &dev_attr_mode);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "failed to create file: %d\n", ret);
+               goto err_file;
+       }
+
+       return 0;
+
+err_file:
+       led_classdev_unregister(&led->cdev);
+err_led:
+       kfree(led);
+err_mem:
+       return ret;
+}
+
+static int __devexit max8997_led_remove(struct platform_device *pdev)
+{
+       struct max8997_led *led = platform_get_drvdata(pdev);
+
+       device_remove_file(led->cdev.dev, &dev_attr_mode);
+       led_classdev_unregister(&led->cdev);
+       kfree(led);
+
+       return 0;
+}
+
+static struct platform_driver max8997_led_driver = {
+       .driver = {
+               .name  = "max8997-led",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max8997_led_probe,
+       .remove = __devexit_p(max8997_led_remove),
+};
+
+static int __init max8997_led_init(void)
+{
+       return platform_driver_register(&max8997_led_driver);
+}
+module_init(max8997_led_init);
+
+static void __exit max8997_led_exit(void)
+{
+       platform_driver_unregister(&max8997_led_driver);
+}
+module_exit(max8997_led_exit);
+
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_DESCRIPTION("MAX8997 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8997-led");
index b3393a9f21398c119ad0440b68cf58953bc002a5..8bc4915415509d6e2456a0d4ea46446bf9188eca 100644 (file)
@@ -275,7 +275,7 @@ static int __devinit mc13783_led_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       if (pdata->num_leds < 1 || pdata->num_leds > MC13783_LED_MAX) {
+       if (pdata->num_leds < 1 || pdata->num_leds > (MC13783_LED_MAX + 1)) {
                dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
                return -EINVAL;
        }
@@ -385,17 +385,7 @@ static struct platform_driver mc13783_led_driver = {
        .remove         = __devexit_p(mc13783_led_remove),
 };
 
-static int __init mc13783_led_init(void)
-{
-       return platform_driver_register(&mc13783_led_driver);
-}
-module_init(mc13783_led_init);
-
-static void __exit mc13783_led_exit(void)
-{
-       platform_driver_unregister(&mc13783_led_driver);
-}
-module_exit(mc13783_led_exit);
+module_platform_driver(mc13783_led_driver);
 
 MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC");
 MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
index f2e51c13439962391626b682337e912ca2a83bfb..d8433f2d53bc712995b899db7a19e6d16bb091be 100644 (file)
@@ -81,35 +81,23 @@ static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
 
        /* Configure address GPIOs. */
        for (i = 0; i < gpio_ext->num_addr; i++) {
-               err = gpio_request(gpio_ext->addr[i], "GPIO extension addr");
+               err = gpio_request_one(gpio_ext->addr[i], GPIOF_OUT_INIT_LOW,
+                                      "GPIO extension addr");
                if (err)
                        goto err_free_addr;
-               err = gpio_direction_output(gpio_ext->addr[i], 0);
-               if (err) {
-                       gpio_free(gpio_ext->addr[i]);
-                       goto err_free_addr;
-               }
        }
        /* Configure data GPIOs. */
        for (i = 0; i < gpio_ext->num_data; i++) {
-               err = gpio_request(gpio_ext->data[i], "GPIO extension data");
+               err = gpio_request_one(gpio_ext->data[i], GPIOF_OUT_INIT_LOW,
+                                  "GPIO extension data");
                if (err)
                        goto err_free_data;
-               err = gpio_direction_output(gpio_ext->data[i], 0);
-               if (err) {
-                       gpio_free(gpio_ext->data[i]);
-                       goto err_free_data;
-               }
        }
        /* Configure "enable select" GPIO. */
-       err = gpio_request(gpio_ext->enable, "GPIO extension enable");
+       err = gpio_request_one(gpio_ext->enable, GPIOF_OUT_INIT_LOW,
+                              "GPIO extension enable");
        if (err)
                goto err_free_data;
-       err = gpio_direction_output(gpio_ext->enable, 0);
-       if (err) {
-               gpio_free(gpio_ext->enable);
-               goto err_free_data;
-       }
 
        return 0;
 
@@ -429,21 +417,10 @@ static struct platform_driver netxbig_led_driver = {
                .owner  = THIS_MODULE,
        },
 };
-MODULE_ALIAS("platform:leds-netxbig");
 
-static int __init netxbig_led_init(void)
-{
-       return platform_driver_register(&netxbig_led_driver);
-}
-
-static void __exit netxbig_led_exit(void)
-{
-       platform_driver_unregister(&netxbig_led_driver);
-}
-
-module_init(netxbig_led_init);
-module_exit(netxbig_led_exit);
+module_platform_driver(netxbig_led_driver);
 
 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
 MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-netxbig");
index 37b7d0cfe5867e91ed0c1aa94039dc4985dc79f7..2f0a14421a7344fa0505f27bea94b23857fba340 100644 (file)
@@ -323,21 +323,10 @@ static struct platform_driver ns2_led_driver = {
                .owner  = THIS_MODULE,
        },
 };
-MODULE_ALIAS("platform:leds-ns2");
-
-static int __init ns2_led_init(void)
-{
-       return platform_driver_register(&ns2_led_driver);
-}
 
-static void __exit ns2_led_exit(void)
-{
-       platform_driver_unregister(&ns2_led_driver);
-}
-
-module_init(ns2_led_init);
-module_exit(ns2_led_exit);
+module_platform_driver(ns2_led_driver);
 
 MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
 MODULE_DESCRIPTION("Network Space v2 LED driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:leds-ns2");
index a2c874623e3521550ab6917be4b56eb3e42b4aaa..ceccab44b5b818404da63b76f74cda552e7eb367 100644 (file)
@@ -489,20 +489,8 @@ static int pca9532_remove(struct i2c_client *client)
        return 0;
 }
 
-static int __init pca9532_init(void)
-{
-       return i2c_add_driver(&pca9532_driver);
-}
-
-static void __exit pca9532_exit(void)
-{
-       i2c_del_driver(&pca9532_driver);
-}
+module_i2c_driver(pca9532_driver);
 
 MODULE_AUTHOR("Riku Voipio");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("PCA 9532 LED dimmer");
-
-module_init(pca9532_init);
-module_exit(pca9532_exit);
-
index 66aa3e8e786f545c4db0e6bd4318a173a792fc1e..dcc3bc3d38db8cac7384c65009965967bc026f24 100644 (file)
@@ -371,18 +371,7 @@ static struct i2c_driver pca955x_driver = {
        .id_table = pca955x_id,
 };
 
-static int __init pca955x_leds_init(void)
-{
-       return i2c_add_driver(&pca955x_driver);
-}
-
-static void __exit pca955x_leds_exit(void)
-{
-       i2c_del_driver(&pca955x_driver);
-}
-
-module_init(pca955x_leds_init);
-module_exit(pca955x_leds_exit);
+module_i2c_driver(pca955x_driver);
 
 MODULE_AUTHOR("Nate Case <ncase@xes-inc.com>");
 MODULE_DESCRIPTION("PCA955x LED driver");
index 666daf77872e56239bbf59a002c180593996ae7a..3ed92f34bd4477108549499e7bbf4959af1a56cd 100644 (file)
@@ -135,18 +135,7 @@ static struct platform_driver led_pwm_driver = {
        },
 };
 
-static int __init led_pwm_init(void)
-{
-       return platform_driver_register(&led_pwm_driver);
-}
-
-static void __exit led_pwm_exit(void)
-{
-       platform_driver_unregister(&led_pwm_driver);
-}
-
-module_init(led_pwm_init);
-module_exit(led_pwm_exit);
+module_platform_driver(led_pwm_driver);
 
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 MODULE_DESCRIPTION("PWM LED driver for PXA");
index c3525f37f73d6895c5abfd619af06c7164cf119f..a7815b6cd8567d9dfd97ed9437f348d9cac4ebc8 100644 (file)
@@ -57,21 +57,9 @@ static struct platform_driver rb532_led_driver = {
        },
 };
 
-static int __init rb532_led_init(void)
-{
-       return platform_driver_register(&rb532_led_driver);
-}
-
-static void __exit rb532_led_exit(void)
-{
-       platform_driver_unregister(&rb532_led_driver);
-}
-
-module_init(rb532_led_init);
-module_exit(rb532_led_exit);
-
-MODULE_ALIAS("platform:rb532-led");
+module_platform_driver(rb532_led_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("User LED support for Routerboard532");
 MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
+MODULE_ALIAS("platform:rb532-led");
index 8497f56f8e461cf70d8d1b8692e04b11e353323c..df7e963bddd304f37bf507fe61ca317066111253 100644 (file)
@@ -229,17 +229,7 @@ static struct platform_driver regulator_led_driver = {
        .remove = __devexit_p(regulator_led_remove),
 };
 
-static int __init regulator_led_init(void)
-{
-       return platform_driver_register(&regulator_led_driver);
-}
-module_init(regulator_led_init);
-
-static void __exit regulator_led_exit(void)
-{
-       platform_driver_unregister(&regulator_led_driver);
-}
-module_exit(regulator_led_exit);
+module_platform_driver(regulator_led_driver);
 
 MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
 MODULE_DESCRIPTION("Regulator driven LED driver");
index 3ee540eb127e7ffadfd0d5c2e471dc14380fa307..32fe337d5c687fbb09c06bd778e70cdc3cc7a223 100644 (file)
@@ -339,18 +339,7 @@ static struct platform_driver r_tpu_device_driver = {
        }
 };
 
-static int __init r_tpu_init(void)
-{
-       return platform_driver_register(&r_tpu_device_driver);
-}
-
-static void __exit r_tpu_exit(void)
-{
-       platform_driver_unregister(&r_tpu_device_driver);
-}
-
-module_init(r_tpu_init);
-module_exit(r_tpu_exit);
+module_platform_driver(r_tpu_device_driver);
 
 MODULE_AUTHOR("Magnus Damm");
 MODULE_DESCRIPTION("Renesas TPU LED Driver");
index 29f8b0f0e2c6f880429aea67bcddee59f52f6b91..bd0a5ed49c42d9473bf1fa2e735500ee8c2f67ad 100644 (file)
@@ -121,18 +121,7 @@ static struct platform_driver s3c24xx_led_driver = {
        },
 };
 
-static int __init s3c24xx_led_init(void)
-{
-       return platform_driver_register(&s3c24xx_led_driver);
-}
-
-static void __exit s3c24xx_led_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_led_driver);
-}
-
-module_init(s3c24xx_led_init);
-module_exit(s3c24xx_led_exit);
+module_platform_driver(s3c24xx_led_driver);
 
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C24XX LED driver");
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
new file mode 100644 (file)
index 0000000..133f89f
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * leds-tca6507
+ *
+ * The TCA6507 is a programmable LED controller that can drive 7
+ * separate lines either by holding them low, or by pulsing them
+ * with modulated width.
+ * The modulation can be varied in a simple pattern to produce a blink or
+ * double-blink.
+ *
+ * This driver can configure each line either as a 'GPIO' which is out-only
+ * (no pull-up) or as an LED with variable brightness and hardware-assisted
+ * blinking.
+ *
+ * Apart from OFF and ON there are three programmable brightness levels which
+ * can be programmed from 0 to 15 and indicate how many 500usec intervals in
+ * each 8msec that the led is 'on'.  The levels are named MASTER, BANK0 and
+ * BANK1.
+ *
+ * There are two different blink rates that can be programmed, each with
+ * separate time for rise, on, fall, off and second-off.  Thus if 3 or more
+ * different non-trivial rates are required, software must be used for the extra
+ * rates. The two different blink rates must align with the two levels BANK0 and
+ * BANK1.
+ * This driver does not support double-blink so 'second-off' always matches
+ * 'off'.
+ *
+ * Only 16 different times can be programmed in a roughly logarithmic scale from
+ * 64ms to 16320ms.  To be precise the possible times are:
+ *    0, 64, 128, 192, 256, 384, 512, 768,
+ *    1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320
+ *
+ * Times that cannot be closely matched with these must be
+ * handled in software.  This driver allows 12.5% error in matching.
+ *
+ * This driver does not allow rise/fall rates to be set explicitly.  When trying
+ * to match a given 'on' or 'off' period, an appropriate pair of 'change' and
+ * 'hold' times are chosen to get a close match.  If the target delay is even,
+ * the 'change' number will be the smaller; if odd, the 'hold' number will be
+ * the smaller.
+
+ * Choosing pairs of delays with 12.5% errors allows us to match delays in the
+ * ranges: 56-72, 112-144, 168-216, 224-27504, 28560-36720.
+ * 26% of the achievable sums can be matched by multiple pairings. For example
+ * 1536 == 1536+0, 1024+512, or 768+768.  This driver will always choose the
+ * pairing with the least maximum - 768+768 in this case.  Other pairings are
+ * not available.
+ *
+ * Access to the 3 levels and 2 blinks are on a first-come, first-served basis.
+ * Access can be shared by multiple leds if they have the same level and
+ * either same blink rates, or some don't blink.
+ * When a led changes, it relinquishes access and tries again, so it might
+ * lose access to hardware blink.
+ * If a blink engine cannot be allocated, software blink is used.
+ * If the desired brightness cannot be allocated, the closest available non-zero
+ * brightness is used.  As 'full' is always available, the worst case would be
+ * to have two different blink rates at '1', with Max at '2', then other leds
+ * will have to choose between '2' and '16'.  Hopefully this is not likely.
+ *
+ * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the brightness
+ * and LEDs using the blink.  It can only be reprogrammed when the appropriate
+ * counter is zero.  The MASTER level has a single usage count.
+ *
+ * Each Led has programmable 'on' and 'off' time as milliseconds.  With each
+ * there is a flag saying if it was explicitly requested or defaulted.
+ * Similarly the banks know if each time was explicit or a default.  Defaults
+ * are permitted to be changed freely - they are not recognised when matching.
+ *
+ *
+ * An led-tca6507 device must be provided with platform data.  This data
+ * lists for each output: the name, default trigger, and whether the signal
+ * is being used as a GPiO rather than an led.  'struct led_plaform_data'
+ * is used for this.  If 'name' is NULL, the output isn't used.  If 'flags'
+ * is TCA6507_MAKE_CPIO, the output is a GPO.
+ * The "struct led_platform_data" can be embedded in a
+ * "struct tca6507_platform_data" which adds a 'gpio_base' for the GPiOs,
+ * and a 'setup' callback which is called once the GPiOs are available.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/leds-tca6507.h>
+
+/* LED select registers determine the source that drives LED outputs */
+#define TCA6507_LS_LED_OFF     0x0     /* Output HI-Z (off) */
+#define TCA6507_LS_LED_OFF1    0x1     /* Output HI-Z (off) - not used */
+#define TCA6507_LS_LED_PWM0    0x2     /* Output LOW with Bank0 rate */
+#define TCA6507_LS_LED_PWM1    0x3     /* Output LOW with Bank1 rate */
+#define TCA6507_LS_LED_ON      0x4     /* Output LOW (on) */
+#define TCA6507_LS_LED_MIR     0x5     /* Output LOW with Master Intensity */
+#define TCA6507_LS_BLINK0      0x6     /* Blink at Bank0 rate */
+#define TCA6507_LS_BLINK1      0x7     /* Blink at Bank1 rate */
+
+enum {
+       BANK0,
+       BANK1,
+       MASTER,
+};
+static int bank_source[3] = {
+       TCA6507_LS_LED_PWM0,
+       TCA6507_LS_LED_PWM1,
+       TCA6507_LS_LED_MIR,
+};
+static int blink_source[2] = {
+       TCA6507_LS_BLINK0,
+       TCA6507_LS_BLINK1,
+};
+
+/* PWM registers */
+#define        TCA6507_REG_CNT                 11
+
+/*
+ * 0x00, 0x01, 0x02 encode the TCA6507_LS_* values, each output
+ * owns one bit in each register
+ */
+#define        TCA6507_FADE_ON                 0x03
+#define        TCA6507_FULL_ON                 0x04
+#define        TCA6507_FADE_OFF                0x05
+#define        TCA6507_FIRST_OFF               0x06
+#define        TCA6507_SECOND_OFF              0x07
+#define        TCA6507_MAX_INTENSITY           0x08
+#define        TCA6507_MASTER_INTENSITY        0x09
+#define        TCA6507_INITIALIZE              0x0A
+
+#define        INIT_CODE                       0x8
+
+#define TIMECODES 16
+static int time_codes[TIMECODES] = {
+       0, 64, 128, 192, 256, 384, 512, 768,
+       1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320
+};
+
+/* Convert an led.brightness level (0..255) to a TCA6507 level (0..15) */
+static inline int TO_LEVEL(int brightness)
+{
+       return brightness >> 4;
+}
+
+/* ...and convert back */
+static inline int TO_BRIGHT(int level)
+{
+       if (level)
+               return (level << 4) | 0xf;
+       return 0;
+}
+
+#define NUM_LEDS 7
+struct tca6507_chip {
+       int                     reg_set;        /* One bit per register where
+                                                * a '1' means the register
+                                                * should be written */
+       u8                      reg_file[TCA6507_REG_CNT];
+       /* Bank 2 is Master Intensity and doesn't use times */
+       struct bank {
+               int level;
+               int ontime, offtime;
+               int on_dflt, off_dflt;
+               int time_use, level_use;
+       } bank[3];
+       struct i2c_client       *client;
+       struct work_struct      work;
+       spinlock_t              lock;
+
+       struct tca6507_led {
+               struct tca6507_chip     *chip;
+               struct led_classdev     led_cdev;
+               int                     num;
+               int                     ontime, offtime;
+               int                     on_dflt, off_dflt;
+               int                     bank;   /* Bank used, or -1 */
+               int                     blink;  /* Set if hardware-blinking */
+       } leds[NUM_LEDS];
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip                gpio;
+       const char                      *gpio_name[NUM_LEDS];
+       int                             gpio_map[NUM_LEDS];
+#endif
+};
+
+static const struct i2c_device_id tca6507_id[] = {
+       { "tca6507" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tca6507_id);
+
+static int choose_times(int msec, int *c1p, int *c2p)
+{
+       /*
+        * Choose two timecodes which add to 'msec' as near as possible.
+        * The first returned is the 'on' or 'off' time.  The second is to be
+        * used as a 'fade-on' or 'fade-off' time.  If 'msec' is even,
+        * the first will not be smaller than the second.  If 'msec' is odd,
+        * the first will not be larger than the second.
+        * If we cannot get a sum within 1/8 of 'msec' fail with -EINVAL,
+        * otherwise return the sum that was achieved, plus 1 if the first is
+        * smaller.
+        * If two possibilities are equally good (e.g. 512+0, 256+256), choose
+        * the first pair so there is more change-time visible (i.e. it is
+        * softer).
+        */
+       int c1, c2;
+       int tmax = msec * 9 / 8;
+       int tmin = msec * 7 / 8;
+       int diff = 65536;
+
+       /* We start at '1' to ensure we never even think of choosing a
+        * total time of '0'.
+        */
+       for (c1 = 1; c1 < TIMECODES; c1++) {
+               int t = time_codes[c1];
+               if (t*2 < tmin)
+                       continue;
+               if (t > tmax)
+                       break;
+               for (c2 = 0; c2 <= c1; c2++) {
+                       int tt = t + time_codes[c2];
+                       int d;
+                       if (tt < tmin)
+                               continue;
+                       if (tt > tmax)
+                               break;
+                       /* This works! */
+                       d = abs(msec - tt);
+                       if (d >= diff)
+                               continue;
+                       /* Best yet */
+                       *c1p = c1;
+                       *c2p = c2;
+                       diff = d;
+                       if (d == 0)
+                               return msec;
+               }
+       }
+       if (diff < 65536) {
+               int actual;
+               if (msec & 1) {
+                       c1 = *c2p;
+                       *c2p = *c1p;
+                       *c1p = c1;
+               }
+               actual = time_codes[*c1p] + time_codes[*c2p];
+               if (*c1p < *c2p)
+                       return actual + 1;
+               else
+                       return actual;
+       }
+       /* No close match */
+       return -EINVAL;
+}
+
+/*
+ * Update the register file with the appropriate 3-bit state for
+ * the given led.
+ */
+static void set_select(struct tca6507_chip *tca, int led, int val)
+{
+       int mask = (1 << led);
+       int bit;
+
+       for (bit = 0; bit < 3; bit++) {
+               int n = tca->reg_file[bit] & ~mask;
+               if (val & (1 << bit))
+                       n |= mask;
+               if (tca->reg_file[bit] != n) {
+                       tca->reg_file[bit] = n;
+                       tca->reg_set |= (1 << bit);
+               }
+       }
+}
+
+/* Update the register file with the appropriate 4-bit code for
+ * one bank or other.  This can be used for timers, for levels, or
+ * for initialisation.
+ */
+static void set_code(struct tca6507_chip *tca, int reg, int bank, int new)
+{
+       int mask = 0xF;
+       int n;
+       if (bank) {
+               mask <<= 4;
+               new <<= 4;
+       }
+       n = tca->reg_file[reg] & ~mask;
+       n |= new;
+       if (tca->reg_file[reg] != n) {
+               tca->reg_file[reg] = n;
+               tca->reg_set |= 1 << reg;
+       }
+}
+
+/* Update brightness level. */
+static void set_level(struct tca6507_chip *tca, int bank, int level)
+{
+       switch (bank) {
+       case BANK0:
+       case BANK1:
+               set_code(tca, TCA6507_MAX_INTENSITY, bank, level);
+               break;
+       case MASTER:
+               set_code(tca, TCA6507_MASTER_INTENSITY, 0, level);
+               break;
+       }
+       tca->bank[bank].level = level;
+}
+
+/* Record all relevant time code for a given bank */
+static void set_times(struct tca6507_chip *tca, int bank)
+{
+       int c1, c2;
+       int result;
+
+       result = choose_times(tca->bank[bank].ontime, &c1, &c2);
+       dev_dbg(&tca->client->dev,
+               "Chose on  times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
+               c2, time_codes[c2], tca->bank[bank].ontime);
+       set_code(tca, TCA6507_FADE_ON, bank, c2);
+       set_code(tca, TCA6507_FULL_ON, bank, c1);
+       tca->bank[bank].ontime = result;
+
+       result = choose_times(tca->bank[bank].offtime, &c1, &c2);
+       dev_dbg(&tca->client->dev,
+               "Chose off times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
+               c2, time_codes[c2], tca->bank[bank].offtime);
+       set_code(tca, TCA6507_FADE_OFF, bank, c2);
+       set_code(tca, TCA6507_FIRST_OFF, bank, c1);
+       set_code(tca, TCA6507_SECOND_OFF, bank, c1);
+       tca->bank[bank].offtime = result;
+
+       set_code(tca, TCA6507_INITIALIZE, bank, INIT_CODE);
+}
+
+/* Write all needed register of tca6507 */
+
+static void tca6507_work(struct work_struct *work)
+{
+       struct tca6507_chip *tca = container_of(work, struct tca6507_chip,
+                                               work);
+       struct i2c_client *cl = tca->client;
+       int set;
+       u8 file[TCA6507_REG_CNT];
+       int r;
+
+       spin_lock_irq(&tca->lock);
+       set = tca->reg_set;
+       memcpy(file, tca->reg_file, TCA6507_REG_CNT);
+       tca->reg_set = 0;
+       spin_unlock_irq(&tca->lock);
+
+       for (r = 0; r < TCA6507_REG_CNT; r++)
+               if (set & (1<<r))
+                       i2c_smbus_write_byte_data(cl, r, file[r]);
+}
+
+static void led_release(struct tca6507_led *led)
+{
+       /* If led owns any resource, release it. */
+       struct tca6507_chip *tca = led->chip;
+       if (led->bank >= 0) {
+               struct bank *b = tca->bank + led->bank;
+               if (led->blink)
+                       b->time_use--;
+               b->level_use--;
+       }
+       led->blink = 0;
+       led->bank = -1;
+}
+
+static int led_prepare(struct tca6507_led *led)
+{
+       /* Assign this led to a bank, configuring that bank if necessary. */
+       int level = TO_LEVEL(led->led_cdev.brightness);
+       struct tca6507_chip *tca = led->chip;
+       int c1, c2;
+       int i;
+       struct bank *b;
+       int need_init = 0;
+
+       led->led_cdev.brightness = TO_BRIGHT(level);
+       if (level == 0) {
+               set_select(tca, led->num, TCA6507_LS_LED_OFF);
+               return 0;
+       }
+
+       if (led->ontime == 0 || led->offtime == 0) {
+               /*
+                * Just set the brightness, choosing first usable bank.
+                * If none perfect, choose best.
+                * Count backwards so we check MASTER bank first
+                * to avoid wasting a timer.
+                */
+               int best = -1;/* full-on */
+               int diff = 15-level;
+
+               if (level == 15) {
+                       set_select(tca, led->num, TCA6507_LS_LED_ON);
+                       return 0;
+               }
+
+               for (i = MASTER; i >= BANK0; i--) {
+                       int d;
+                       if (tca->bank[i].level == level ||
+                           tca->bank[i].level_use == 0) {
+                               best = i;
+                               break;
+                       }
+                       d = abs(level - tca->bank[i].level);
+                       if (d < diff) {
+                               diff = d;
+                               best = i;
+                       }
+               }
+               if (best == -1) {
+                       /* Best brightness is full-on */
+                       set_select(tca, led->num, TCA6507_LS_LED_ON);
+                       led->led_cdev.brightness = LED_FULL;
+                       return 0;
+               }
+
+               if (!tca->bank[best].level_use)
+                       set_level(tca, best, level);
+
+               tca->bank[best].level_use++;
+               led->bank = best;
+               set_select(tca, led->num, bank_source[best]);
+               led->led_cdev.brightness = TO_BRIGHT(tca->bank[best].level);
+               return 0;
+       }
+
+       /*
+        * We have on/off time so we need to try to allocate a timing bank.
+        * First check if times are compatible with hardware and give up if
+        * not.
+        */
+       if (choose_times(led->ontime, &c1, &c2) < 0)
+               return -EINVAL;
+       if (choose_times(led->offtime, &c1, &c2) < 0)
+               return -EINVAL;
+
+       for (i = BANK0; i <= BANK1; i++) {
+               if (tca->bank[i].level_use == 0)
+                       /* not in use - it is ours! */
+                       break;
+               if (tca->bank[i].level != level)
+                       /* Incompatible level - skip */
+                       /* FIX: if timer matches we maybe should consider
+                        * this anyway...
+                        */
+                       continue;
+
+               if (tca->bank[i].time_use == 0)
+                       /* Timer not in use, and level matches - use it */
+                       break;
+
+               if (!(tca->bank[i].on_dflt ||
+                     led->on_dflt ||
+                     tca->bank[i].ontime == led->ontime))
+                       /* on time is incompatible */
+                       continue;
+
+               if (!(tca->bank[i].off_dflt ||
+                     led->off_dflt ||
+                     tca->bank[i].offtime == led->offtime))
+                       /* off time is incompatible */
+                       continue;
+
+               /* looks like a suitable match */
+               break;
+       }
+
+       if (i > BANK1)
+               /* Nothing matches - how sad */
+               return -EINVAL;
+
+       b = &tca->bank[i];
+       if (b->level_use == 0)
+               set_level(tca, i, level);
+       b->level_use++;
+       led->bank = i;
+
+       if (b->on_dflt ||
+           !led->on_dflt ||
+           b->time_use == 0) {
+               b->ontime = led->ontime;
+               b->on_dflt = led->on_dflt;
+               need_init = 1;
+       }
+
+       if (b->off_dflt ||
+           !led->off_dflt ||
+           b->time_use == 0) {
+               b->offtime = led->offtime;
+               b->off_dflt = led->off_dflt;
+               need_init = 1;
+       }
+
+       if (need_init)
+               set_times(tca, i);
+
+       led->ontime = b->ontime;
+       led->offtime = b->offtime;
+
+       b->time_use++;
+       led->blink = 1;
+       led->led_cdev.brightness = TO_BRIGHT(b->level);
+       set_select(tca, led->num, blink_source[i]);
+       return 0;
+}
+
+static int led_assign(struct tca6507_led *led)
+{
+       struct tca6507_chip *tca = led->chip;
+       int err;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tca->lock, flags);
+       led_release(led);
+       err = led_prepare(led);
+       if (err) {
+               /*
+                * Can only fail on timer setup.  In that case we need to
+                * re-establish as steady level.
+                */
+               led->ontime = 0;
+               led->offtime = 0;
+               led_prepare(led);
+       }
+       spin_unlock_irqrestore(&tca->lock, flags);
+
+       if (tca->reg_set)
+               schedule_work(&tca->work);
+       return err;
+}
+
+static void tca6507_brightness_set(struct led_classdev *led_cdev,
+                                  enum led_brightness brightness)
+{
+       struct tca6507_led *led = container_of(led_cdev, struct tca6507_led,
+                                              led_cdev);
+       led->led_cdev.brightness = brightness;
+       led->ontime = 0;
+       led->offtime = 0;
+       led_assign(led);
+}
+
+static int tca6507_blink_set(struct led_classdev *led_cdev,
+                            unsigned long *delay_on,
+                            unsigned long *delay_off)
+{
+       struct tca6507_led *led = container_of(led_cdev, struct tca6507_led,
+                                              led_cdev);
+
+       if (*delay_on == 0)
+               led->on_dflt = 1;
+       else if (delay_on != &led_cdev->blink_delay_on)
+               led->on_dflt = 0;
+       led->ontime = *delay_on;
+
+       if (*delay_off == 0)
+               led->off_dflt = 1;
+       else if (delay_off != &led_cdev->blink_delay_off)
+               led->off_dflt = 0;
+       led->offtime = *delay_off;
+
+       if (led->ontime == 0)
+               led->ontime = 512;
+       if (led->offtime == 0)
+               led->offtime = 512;
+
+       if (led->led_cdev.brightness == LED_OFF)
+               led->led_cdev.brightness = LED_FULL;
+       if (led_assign(led) < 0) {
+               led->ontime = 0;
+               led->offtime = 0;
+               led->led_cdev.brightness = LED_OFF;
+               return -EINVAL;
+       }
+       *delay_on = led->ontime;
+       *delay_off = led->offtime;
+       return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static void tca6507_gpio_set_value(struct gpio_chip *gc,
+                                  unsigned offset, int val)
+{
+       struct tca6507_chip *tca = container_of(gc, struct tca6507_chip, gpio);
+       unsigned long flags;
+
+       spin_lock_irqsave(&tca->lock, flags);
+       /*
+        * 'OFF' is floating high, and 'ON' is pulled down, so it has the
+        * inverse sense of 'val'.
+        */
+       set_select(tca, tca->gpio_map[offset],
+                  val ? TCA6507_LS_LED_OFF : TCA6507_LS_LED_ON);
+       spin_unlock_irqrestore(&tca->lock, flags);
+       if (tca->reg_set)
+               schedule_work(&tca->work);
+}
+
+static int tca6507_gpio_direction_output(struct gpio_chip *gc,
+                                         unsigned offset, int val)
+{
+       tca6507_gpio_set_value(gc, offset, val);
+       return 0;
+}
+
+static int tca6507_probe_gpios(struct i2c_client *client,
+                              struct tca6507_chip *tca,
+                              struct tca6507_platform_data *pdata)
+{
+       int err;
+       int i = 0;
+       int gpios = 0;
+
+       for (i = 0; i < NUM_LEDS; i++)
+               if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) {
+                       /* Configure as a gpio */
+                       tca->gpio_name[gpios] = pdata->leds.leds[i].name;
+                       tca->gpio_map[gpios] = i;
+                       gpios++;
+               }
+
+       if (!gpios)
+               return 0;
+
+       tca->gpio.label = "gpio-tca6507";
+       tca->gpio.names = tca->gpio_name;
+       tca->gpio.ngpio = gpios;
+       tca->gpio.base = pdata->gpio_base;
+       tca->gpio.owner = THIS_MODULE;
+       tca->gpio.direction_output = tca6507_gpio_direction_output;
+       tca->gpio.set = tca6507_gpio_set_value;
+       tca->gpio.dev = &client->dev;
+       err = gpiochip_add(&tca->gpio);
+       if (err) {
+               tca->gpio.ngpio = 0;
+               return err;
+       }
+       if (pdata->setup)
+               pdata->setup(tca->gpio.base, tca->gpio.ngpio);
+       return 0;
+}
+
+static void tca6507_remove_gpio(struct tca6507_chip *tca)
+{
+       if (tca->gpio.ngpio) {
+               int err = gpiochip_remove(&tca->gpio);
+               dev_err(&tca->client->dev, "%s failed, %d\n",
+                       "gpiochip_remove()", err);
+       }
+}
+#else /* CONFIG_GPIOLIB */
+static int tca6507_probe_gpios(struct i2c_client *client,
+                              struct tca6507_chip *tca,
+                              struct tca6507_platform_data *pdata)
+{
+       return 0;
+}
+static void tca6507_remove_gpio(struct tca6507_chip *tca)
+{
+}
+#endif /* CONFIG_GPIOLIB */
+
+static int __devinit tca6507_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
+{
+       struct tca6507_chip *tca;
+       struct i2c_adapter *adapter;
+       struct tca6507_platform_data *pdata;
+       int err;
+       int i = 0;
+
+       adapter = to_i2c_adapter(client->dev.parent);
+       pdata = client->dev.platform_data;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -EIO;
+
+       if (!pdata || pdata->leds.num_leds != NUM_LEDS) {
+               dev_err(&client->dev, "Need %d entries in platform-data list\n",
+                       NUM_LEDS);
+               return -ENODEV;
+       }
+       err = -ENOMEM;
+       tca = kzalloc(sizeof(*tca), GFP_KERNEL);
+       if (!tca)
+               goto exit;
+
+       tca->client = client;
+       INIT_WORK(&tca->work, tca6507_work);
+       spin_lock_init(&tca->lock);
+       i2c_set_clientdata(client, tca);
+
+       for (i = 0; i < NUM_LEDS; i++) {
+               struct tca6507_led *l = tca->leds + i;
+
+               l->chip = tca;
+               l->num = i;
+               if (pdata->leds.leds[i].name && !pdata->leds.leds[i].flags) {
+                       l->led_cdev.name = pdata->leds.leds[i].name;
+                       l->led_cdev.default_trigger
+                               = pdata->leds.leds[i].default_trigger;
+                       l->led_cdev.brightness_set = tca6507_brightness_set;
+                       l->led_cdev.blink_set = tca6507_blink_set;
+                       l->bank = -1;
+                       err = led_classdev_register(&client->dev,
+                                                   &l->led_cdev);
+                       if (err < 0)
+                               goto exit;
+               }
+       }
+       err = tca6507_probe_gpios(client, tca, pdata);
+       if (err)
+               goto exit;
+       /* set all registers to known state - zero */
+       tca->reg_set = 0x7f;
+       schedule_work(&tca->work);
+
+       return 0;
+exit:
+       while (i--)
+               if (tca->leds[i].led_cdev.name)
+                       led_classdev_unregister(&tca->leds[i].led_cdev);
+       cancel_work_sync(&tca->work);
+       i2c_set_clientdata(client, NULL);
+       kfree(tca);
+       return err;
+}
+
+static int __devexit tca6507_remove(struct i2c_client *client)
+{
+       int i;
+       struct tca6507_chip *tca = i2c_get_clientdata(client);
+       struct tca6507_led *tca_leds = tca->leds;
+
+       for (i = 0; i < NUM_LEDS; i++) {
+               if (tca_leds[i].led_cdev.name)
+                       led_classdev_unregister(&tca_leds[i].led_cdev);
+       }
+       tca6507_remove_gpio(tca);
+       cancel_work_sync(&tca->work);
+       i2c_set_clientdata(client, NULL);
+       kfree(tca);
+
+       return 0;
+}
+
+static struct i2c_driver tca6507_driver = {
+       .driver   = {
+               .name    = "leds-tca6507",
+               .owner   = THIS_MODULE,
+       },
+       .probe    = tca6507_probe,
+       .remove   = __devexit_p(tca6507_remove),
+       .id_table = tca6507_id,
+};
+
+static int __init tca6507_leds_init(void)
+{
+       return i2c_add_driver(&tca6507_driver);
+}
+
+static void __exit tca6507_leds_exit(void)
+{
+       i2c_del_driver(&tca6507_driver);
+}
+
+module_init(tca6507_leds_init);
+module_exit(tca6507_leds_exit);
+
+MODULE_AUTHOR("NeilBrown <neilb@suse.de>");
+MODULE_DESCRIPTION("TCA6507 LED/GPO driver");
+MODULE_LICENSE("GPL v2");
index b1eb34c3e81f41d5eafdd00ed112373a5f25c970..74a24cf897c386952f47bdb0a9df319808f2d5a6 100644 (file)
@@ -237,7 +237,8 @@ static int wm831x_status_probe(struct platform_device *pdev)
                goto err;
        }
 
-       drvdata = kzalloc(sizeof(struct wm831x_status), GFP_KERNEL);
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_status),
+                              GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
        dev_set_drvdata(&pdev->dev, drvdata);
@@ -300,7 +301,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
 
 err_led:
        led_classdev_unregister(&drvdata->cdev);
-       kfree(drvdata);
 err:
        return ret;
 }
@@ -311,7 +311,6 @@ static int wm831x_status_remove(struct platform_device *pdev)
 
        device_remove_file(drvdata->cdev.dev, &dev_attr_src);
        led_classdev_unregister(&drvdata->cdev);
-       kfree(drvdata);
 
        return 0;
 }
@@ -325,17 +324,7 @@ static struct platform_driver wm831x_status_driver = {
        .remove = wm831x_status_remove,
 };
 
-static int __devinit wm831x_status_init(void)
-{
-       return platform_driver_register(&wm831x_status_driver);
-}
-module_init(wm831x_status_init);
-
-static void wm831x_status_exit(void)
-{
-       platform_driver_unregister(&wm831x_status_driver);
-}
-module_exit(wm831x_status_exit);
+module_platform_driver(wm831x_status_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM831x status LED driver");
index 4a1276578352283544ceb6fda2ff176d0772d887..918d4baff1c7257c65276bfcf4cb05b73350553c 100644 (file)
@@ -227,7 +227,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
                goto err_isink;
        }
 
-       led = kzalloc(sizeof(*led), GFP_KERNEL);
+       led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
        if (led == NULL) {
                ret = -ENOMEM;
                goto err_dcdc;
@@ -259,12 +259,10 @@ static int wm8350_led_probe(struct platform_device *pdev)
 
        ret = led_classdev_register(&pdev->dev, &led->cdev);
        if (ret < 0)
-               goto err_led;
+               goto err_dcdc;
 
        return 0;
 
- err_led:
-       kfree(led);
  err_dcdc:
        regulator_put(dcdc);
  err_isink:
@@ -281,7 +279,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
        wm8350_led_disable(led);
        regulator_put(led->dcdc);
        regulator_put(led->isink);
-       kfree(led);
        return 0;
 }
 
@@ -295,17 +292,7 @@ static struct platform_driver wm8350_led_driver = {
        .shutdown = wm8350_led_shutdown,
 };
 
-static int __devinit wm8350_led_init(void)
-{
-       return platform_driver_register(&wm8350_led_driver);
-}
-module_init(wm8350_led_init);
-
-static void wm8350_led_exit(void)
-{
-       platform_driver_unregister(&wm8350_led_driver);
-}
-module_exit(wm8350_led_exit);
+module_platform_driver(wm8350_led_driver);
 
 MODULE_AUTHOR("Mark Brown");
 MODULE_DESCRIPTION("WM8350 LED driver");
index 8ac947c7e7c77e11cb08d8482221fb8e48087685..c4197503900ed3a1457e27d3a1c05207952036be 100644 (file)
@@ -18,7 +18,7 @@ Mastery: PREFIX=M
 Beer:
        @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
 Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
-       @sh ../../Documentation/virtual/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
+       @sh ../../tools/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
 Puppy:
        @clear
        @printf "      __  \n (___()'\`;\n /,    /\`\n \\\\\\\"--\\\\\\   \n"
index 595d7319701680d9360e9f252d9f0273e7de8726..9e8388efd88e2cffeb4c11fc8c432d2a5a7eb371 100644 (file)
@@ -241,7 +241,7 @@ static void lg_notify(struct virtqueue *vq)
 }
 
 /* An extern declaration inside a C file is bad form.  Don't do it. */
-extern void lguest_setup_irq(unsigned int irq);
+extern int lguest_setup_irq(unsigned int irq);
 
 /*
  * This routine finds the Nth virtqueue described in the configuration of
@@ -292,17 +292,21 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
 
        /*
         * OK, tell virtio_ring.c to set up a virtqueue now we know its size
-        * and we've got a pointer to its pages.
+        * and we've got a pointer to its pages.  Note that we set weak_barriers
+        * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu
+        * barriers.
         */
-       vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
-                                vdev, lvq->pages, lg_notify, callback, name);
+       vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev,
+                                true, lvq->pages, lg_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto unmap;
        }
 
        /* Make sure the interrupt is allocated. */
-       lguest_setup_irq(lvq->config.irq);
+       err = lguest_setup_irq(lvq->config.irq);
+       if (err)
+               goto destroy_vring;
 
        /*
         * Tell the interrupt for this virtqueue to go to the virtio_ring
@@ -315,7 +319,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
                          dev_name(&vdev->dev), vq);
        if (err)
-               goto destroy_vring;
+               goto free_desc;
 
        /*
         * Last of all we hook up our 'struct lguest_vq_info" to the
@@ -324,6 +328,8 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        vq->priv = lvq;
        return vq;
 
+free_desc:
+       irq_free_desc(lvq->config.irq);
 destroy_vring:
        vring_del_virtqueue(vq);
 unmap:
index ede46581351a04d9a635aee91bec38d69c67c76f..c4fb424dfddbac93d4a191f99dd93627136f5aa6 100644 (file)
@@ -81,8 +81,8 @@ static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
                 * sometimes careless and leaves this as 0, even though it's
                 * running at privilege level 1.  If so, we fix it here.
                 */
-               if ((cpu->arch.gdt[i].b & 0x00006000) == 0)
-                       cpu->arch.gdt[i].b |= (GUEST_PL << 13);
+               if (cpu->arch.gdt[i].dpl == 0)
+                       cpu->arch.gdt[i].dpl |= GUEST_PL;
 
                /*
                 * Each descriptor has an "accessed" bit.  If we don't set it
@@ -90,7 +90,7 @@ static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
                 * that entry into a segment register.  But the GDT isn't
                 * writable by the Guest, so bad things can happen.
                 */
-               cpu->arch.gdt[i].b |= 0x00000100;
+               cpu->arch.gdt[i].type |= 0x1;
        }
 }
 
@@ -114,13 +114,19 @@ void setup_default_gdt_entries(struct lguest_ro_state *state)
 
        /*
         * The TSS segment refers to the TSS entry for this particular CPU.
-        * Forgive the magic flags: the 0x8900 means the entry is Present, it's
-        * privilege level 0 Available 386 TSS system segment, and the 0x67
-        * means Saturn is eclipsed by Mercury in the twelfth house.
         */
-       gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
-       gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
-               | ((tss >> 16) & 0x000000FF);
+       gdt[GDT_ENTRY_TSS].a = 0;
+       gdt[GDT_ENTRY_TSS].b = 0;
+
+       gdt[GDT_ENTRY_TSS].limit0 = 0x67;
+       gdt[GDT_ENTRY_TSS].base0  = tss & 0xFFFF;
+       gdt[GDT_ENTRY_TSS].base1  = (tss >> 16) & 0xFF;
+       gdt[GDT_ENTRY_TSS].base2  = tss >> 24;
+       gdt[GDT_ENTRY_TSS].type   = 0x9; /* 32-bit TSS (available) */
+       gdt[GDT_ENTRY_TSS].p      = 0x1; /* Entry is present */
+       gdt[GDT_ENTRY_TSS].dpl    = 0x0; /* Privilege level 0 */
+       gdt[GDT_ENTRY_TSS].s      = 0x0; /* system segment */
+
 }
 
 /*
@@ -135,8 +141,8 @@ void setup_guest_gdt(struct lg_cpu *cpu)
         */
        cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
        cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
-       cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
-       cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+       cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].dpl |= GUEST_PL;
+       cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].dpl |= GUEST_PL;
 }
 
 /*H:650
index ca8527fe77ebe1a8ddfb5a7adc2d21ee79123319..da52acb60f520088fbb169de53769d5f81abc887 100644 (file)
@@ -7382,6 +7382,7 @@ static int remove_and_add_spares(struct mddev *mddev)
 {
        struct md_rdev *rdev;
        int spares = 0;
+       int removed = 0;
 
        mddev->curr_resync_completed = 0;
 
@@ -7395,8 +7396,13 @@ static int remove_and_add_spares(struct mddev *mddev)
                                    mddev, rdev) == 0) {
                                sysfs_unlink_rdev(mddev, rdev);
                                rdev->raid_disk = -1;
+                               removed++;
                        }
                }
+       if (removed)
+               sysfs_notify(&mddev->kobj, NULL,
+                            "degraded");
+
 
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                if (rdev->raid_disk >= 0 &&
index cc24f0cb7ee31ef420e4f8c86f6cb1b09733ec36..a368db2431a596020a98a3e64f67685ccef9c6cc 100644 (file)
@@ -531,8 +531,17 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                if (test_bit(WriteMostly, &rdev->flags)) {
                        /* Don't balance among write-mostly, just
                         * use the first as a last resort */
-                       if (best_disk < 0)
+                       if (best_disk < 0) {
+                               if (is_badblock(rdev, this_sector, sectors,
+                                               &first_bad, &bad_sectors)) {
+                                       if (first_bad < this_sector)
+                                               /* Cannot use this */
+                                               continue;
+                                       best_good_sectors = first_bad - this_sector;
+                               } else
+                                       best_good_sectors = sectors;
                                best_disk = disk;
+                       }
                        continue;
                }
                /* This is a reasonable device to use.  It might
index e017dc88622ada48f145457585e5fc376a6d155e..f93dd9571c3c81e8b44f26dc51d54b0901039cd6 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/slab.h>
 
-static inline int pm860x_read_device(struct i2c_client *i2c,
-                                    int reg, int bytes, void *dest)
-{
-       unsigned char data;
-       int ret;
-
-       data = (unsigned char)reg;
-       ret = i2c_master_send(i2c, &data, 1);
-       if (ret < 0)
-               return ret;
-
-       ret = i2c_master_recv(i2c, dest, bytes);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pm860x_write_device(struct i2c_client *i2c,
-                                     int reg, int bytes, void *src)
-{
-       unsigned char buf[bytes + 1];
-       int ret;
-
-       buf[0] = (unsigned char)reg;
-       memcpy(&buf[1], src, bytes);
-
-       ret = i2c_master_send(i2c, buf, bytes + 1);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
 int pm860x_reg_read(struct i2c_client *i2c, int reg)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
-       unsigned char data;
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
+       unsigned int data;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, 1, &data);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_read(map, reg, &data);
        if (ret < 0)
                return ret;
        else
@@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg,
                     unsigned char data)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_write_device(i2c, reg, 1, &data);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_write(map, reg, data);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_reg_write);
@@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg,
                     int count, unsigned char *buf)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, count, buf);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_raw_read(map, reg, buf, count);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_bulk_read);
@@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg,
                      int count, unsigned char *buf)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_write_device(i2c, reg, count, buf);
-       mutex_unlock(&chip->io_lock);
-
+       ret = regmap_raw_write(map, reg, buf, count);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_bulk_write);
@@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg,
                    unsigned char mask, unsigned char data)
 {
        struct pm860x_chip *chip = i2c_get_clientdata(i2c);
-       unsigned char value;
+       struct regmap *map = (i2c == chip->client) ? chip->regmap
+                               : chip->regmap_companion;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       ret = pm860x_read_device(i2c, reg, 1, &value);
-       if (ret < 0)
-               goto out;
-       value &= ~mask;
-       value |= data;
-       ret = pm860x_write_device(i2c, reg, 1, &value);
-out:
-       mutex_unlock(&chip->io_lock);
+       ret = regmap_update_bits(map, reg, mask, data);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_set_bits);
 
+static int read_device(struct i2c_client *i2c, int reg,
+                      int bytes, void *dest)
+{
+       unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
+       unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
+       struct i2c_adapter *adap = i2c->adapter;
+       struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
+                                {i2c->addr, I2C_M_RD, 0, msgbuf1},
+                               };
+       int num = 1, ret = 0;
+
+       if (dest == NULL)
+               return -EINVAL;
+       msgbuf0[0] = (unsigned char)reg;        /* command */
+       msg[1].len = bytes;
+
+       /* if data needs to read back, num should be 2 */
+       if (bytes > 0)
+               num = 2;
+       ret = adap->algo->master_xfer(adap, msg, num);
+       memcpy(dest, msgbuf1, bytes);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int write_device(struct i2c_client *i2c, int reg,
+                       int bytes, void *src)
+{
+       unsigned char buf[bytes + 1];
+       struct i2c_adapter *adap = i2c->adapter;
+       struct i2c_msg msg;
+       int ret;
+
+       buf[0] = (unsigned char)reg;
+       memcpy(&buf[1], src, bytes);
+       msg.addr = i2c->addr;
+       msg.flags = 0;
+       msg.len = bytes + 1;
+       msg.buf = buf;
+
+       ret = adap->algo->master_xfer(adap, &msg, 1);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
 int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        unsigned char data;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, 1, &data);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = read_device(i2c, reg, 1, &data);
        if (ret >= 0)
                ret = (int)data;
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_reg_read);
@@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read);
 int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
                          unsigned char data)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_write_device(i2c, reg, 1, &data);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = write_device(i2c, reg, 1, &data);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_reg_write);
@@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write);
 int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
                          int count, unsigned char *buf)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, count, buf);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xfa, 0, &zero);
+       read_device(i2c, 0xfb, 0, &zero);
+       read_device(i2c, 0xff, 0, &zero);
+       ret = read_device(i2c, reg, count, buf);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_bulk_read);
@@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read);
 int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
                           int count, unsigned char *buf)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero = 0;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_write_device(i2c, reg, count, buf);
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = write_device(i2c, reg, count, buf);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_bulk_write);
@@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write);
 int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
                         unsigned char mask, unsigned char data)
 {
-       struct pm860x_chip *chip = i2c_get_clientdata(i2c);
        unsigned char zero;
        unsigned char value;
        int ret;
 
-       mutex_lock(&chip->io_lock);
-       pm860x_write_device(i2c, 0xFA, 0, &zero);
-       pm860x_write_device(i2c, 0xFB, 0, &zero);
-       pm860x_write_device(i2c, 0xFF, 0, &zero);
-       ret = pm860x_read_device(i2c, reg, 1, &value);
+       i2c_lock_adapter(i2c->adapter);
+       read_device(i2c, 0xFA, 0, &zero);
+       read_device(i2c, 0xFB, 0, &zero);
+       read_device(i2c, 0xFF, 0, &zero);
+       ret = read_device(i2c, reg, 1, &value);
        if (ret < 0)
                goto out;
        value &= ~mask;
        value |= data;
-       ret = pm860x_write_device(i2c, reg, 1, &value);
+       ret = write_device(i2c, reg, 1, &value);
 out:
-       pm860x_write_device(i2c, 0xFE, 0, &zero);
-       pm860x_write_device(i2c, 0xFC, 0, &zero);
-       mutex_unlock(&chip->io_lock);
+       read_device(i2c, 0xFE, 0, &zero);
+       read_device(i2c, 0xFC, 0, &zero);
+       i2c_unlock_adapter(i2c->adapter);
        return ret;
 }
 EXPORT_SYMBOL(pm860x_page_set_bits);
@@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c)
        return 0;
 }
 
+static struct regmap_config pm860x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
 static int __devinit pm860x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        struct pm860x_platform_data *pdata = client->dev.platform_data;
        struct pm860x_chip *chip;
+       int ret;
 
        if (!pdata) {
                pr_info("No platform data in %s!\n", __func__);
@@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client,
                return -ENOMEM;
 
        chip->id = verify_addr(client);
+       chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
+       if (IS_ERR(chip->regmap)) {
+               ret = PTR_ERR(chip->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                               ret);
+               kfree(chip);
+               return ret;
+       }
        chip->client = client;
        i2c_set_clientdata(client, chip);
        chip->dev = &client->dev;
-       mutex_init(&chip->io_lock);
        dev_set_drvdata(chip->dev, chip);
 
        /*
@@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client,
                chip->companion_addr = pdata->companion_addr;
                chip->companion = i2c_new_dummy(chip->client->adapter,
                                                chip->companion_addr);
+               chip->regmap_companion = regmap_init_i2c(chip->companion,
+                                                       &pm860x_regmap_config);
+               if (IS_ERR(chip->regmap_companion)) {
+                       ret = PTR_ERR(chip->regmap_companion);
+                       dev_err(&chip->companion->dev,
+                               "Failed to allocate register map: %d\n", ret);
+                       return ret;
+               }
                i2c_set_clientdata(chip->companion, chip);
        }
 
@@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client)
        struct pm860x_chip *chip = i2c_get_clientdata(client);
 
        pm860x_device_exit(chip);
-       i2c_unregister_device(chip->companion);
+       if (chip->companion) {
+               regmap_exit(chip->regmap_companion);
+               i2c_unregister_device(chip->companion);
+       }
+       regmap_exit(chip->regmap);
        kfree(chip);
        return 0;
 }
index c8322eefc865a30340d4ee998b8c224b98bfbd43..cd13e9f2f5e668d14927b698b851b6d0f99dd7bb 100644 (file)
@@ -12,6 +12,7 @@ config MFD_CORE
 config MFD_88PM860X
        bool "Support Marvell 88PM8606/88PM8607"
        depends on I2C=y && GENERIC_HARDIRQS
+       select REGMAP_I2C
        select MFD_CORE
        help
          This supports for Marvell 88PM8606/88PM8607 Power Management IC.
@@ -199,7 +200,7 @@ config MENELAUS
 
 config TWL4030_CORE
        bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
        help
          Say yes here if you have TWL4030 / TWL6030 family chip on your board.
          This core driver provides register access and IRQ handling
@@ -257,7 +258,7 @@ config TWL6040_CORE
 
 config MFD_STMPE
        bool "Support STMicroelectronics STMPE"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
        select MFD_CORE
        help
          Support for the STMPE family of I/O Expanders from
@@ -278,6 +279,23 @@ config MFD_STMPE
                Keypad: stmpe-keypad
                Touchscreen: stmpe-ts
 
+menu "STMPE Interface Drivers"
+depends on MFD_STMPE
+
+config STMPE_I2C
+       bool "STMPE I2C Inteface"
+       depends on I2C=y
+       default y
+       help
+         This is used to enable I2C interface of STMPE
+
+config STMPE_SPI
+       bool "STMPE SPI Inteface"
+       depends on SPI_MASTER
+       help
+         This is used to enable SPI interface of STMPE
+endmenu
+
 config MFD_TC3589X
        bool "Support Toshiba TC35892 and variants"
        depends on I2C=y && GENERIC_HARDIRQS
@@ -311,7 +329,7 @@ config MFD_TC6387XB
 
 config MFD_TC6393XB
        bool "Support Toshiba TC6393XB"
-       depends on GPIOLIB && ARM
+       depends on GPIOLIB && ARM && HAVE_CLK
        select MFD_CORE
        select MFD_TMIO
        help
@@ -399,6 +417,17 @@ config MFD_MAX8998
          additional drivers must be enabled in order to use the functionality
          of the device.
 
+config MFD_S5M_CORE
+       bool "SAMSUNG S5M Series Support"
+       depends on I2C=y && GENERIC_HARDIRQS
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+        Support for the Samsung Electronics S5M MFD series.
+        This driver provies common support for accessing the device,
+        additional drivers must be enabled in order to use the functionality
+        of the device
+
 config MFD_WM8400
        tristate "Support Wolfson Microelectronics WM8400"
        select MFD_CORE
@@ -505,6 +534,7 @@ config MFD_WM8994
        bool "Support Wolfson Microelectronics WM8994"
        select MFD_CORE
        select REGMAP_I2C
+       select REGMAP_IRQ
        depends on I2C=y && GENERIC_HARDIRQS
        help
          The WM8994 is a highly integrated hi-fi CODEC designed for
index d5f574306c7ffc5ab4fe7a1ee5cf8233d0356af3..b953bab934f7f872a7f53307a865a7efa22312ac 100644 (file)
@@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP)        += dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_SSP)       += ti-ssp.o
 
 obj-$(CONFIG_MFD_STMPE)                += stmpe.o
+obj-$(CONFIG_STMPE_I2C)                += stmpe-i2c.o
+obj-$(CONFIG_STMPE_SPI)                += stmpe-spi.o
 obj-$(CONFIG_MFD_TC3589X)      += tc3589x.o
 obj-$(CONFIG_MFD_T7L66XB)      += t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o tmio_core.o
@@ -31,7 +33,7 @@ wm8350-objs                   := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
 wm8350-objs                    += wm8350-irq.o
 obj-$(CONFIG_MFD_WM8350)       += wm8350.o
 obj-$(CONFIG_MFD_WM8350_I2C)   += wm8350-i2c.o
-obj-$(CONFIG_MFD_WM8994)       += wm8994-core.o wm8994-irq.o
+obj-$(CONFIG_MFD_WM8994)       += wm8994-core.o wm8994-irq.o wm8994-regmap.o
 
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
@@ -109,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ)        += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
 obj-$(CONFIG_MFD_INTEL_MSIC)   += intel_msic.o
+obj-$(CONFIG_MFD_S5M_CORE)     += s5m-core.o s5m-irq.o
index 02c42015ba5108344c46cd29986d30e64e5cd304..3aa36eb5c79bcf769616013cd3176ed04af500bc 100644 (file)
@@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client,
                aat2870->init(aat2870);
 
        if (aat2870->en_pin >= 0) {
-               ret = gpio_request(aat2870->en_pin, "aat2870-en");
+               ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH,
+                                      "aat2870-en");
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Failed to request GPIO %d\n", aat2870->en_pin);
                        goto out_kfree;
                }
-               gpio_direction_output(aat2870->en_pin, 1);
        }
 
        aat2870_enable(aat2870);
@@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int aat2870_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct aat2870_data *aat2870 = i2c_get_clientdata(client);
 
        aat2870_disable(aat2870);
@@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
        return 0;
 }
 
-static int aat2870_i2c_resume(struct i2c_client *client)
+static int aat2870_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct aat2870_data *aat2870 = i2c_get_clientdata(client);
        struct aat2870_register *reg = NULL;
        int i;
@@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define aat2870_i2c_suspend    NULL
-#define aat2870_i2c_resume     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend,
+                        aat2870_i2c_resume);
 
-static struct i2c_device_id aat2870_i2c_id_table[] = {
+static const struct i2c_device_id aat2870_i2c_id_table[] = {
        { "aat2870", 0 },
        { }
 };
@@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = {
        .driver = {
                .name   = "aat2870",
                .owner  = THIS_MODULE,
+               .pm     = &aat2870_pm_ops,
        },
        .probe          = aat2870_i2c_probe,
        .remove         = aat2870_i2c_remove,
-       .suspend        = aat2870_i2c_suspend,
-       .resume         = aat2870_i2c_resume,
        .id_table       = aat2870_i2c_id_table,
 };
 
index ec10629a0b0b151b5235432dc08bb238f4783b22..bd56a764dea1f36cb522225e09ce4992e0733a56 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/random.h>
-#include <linux/mfd/ab5500/ab5500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
 #include <linux/list.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
index b7b2d3483fd4e1e1f8bb5b6a2feb6e7c349c57f3..72006940937ae54a1500ac66fd3461d2e6ca9b32 100644 (file)
@@ -7,8 +7,8 @@
 #include <linux/module.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
-#include <linux/mfd/ab5500/ab5500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
 #include <linux/uaccess.h>
 
 #include "ab5500-core.h"
index d3d572b2317b888be174bf52d3d17c65b391ef07..53e2a80f42facb931f56c4adcde9221f5b5c69e1 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/ab8500.h>
 
 /*
index dedb7f65cea600a205f83fc2e81e385649cf74ee..9a0211aa88971c0207b3caa18d30eab6cb57821a 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 static u32 debug_bank;
 static u32 debug_address;
index e985d1701a83df56a463cb47ff2a1169bc894ba6..c39fc716e1dcf520592bc866cba0be4e661d0e09 100644 (file)
@@ -18,9 +18,9 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpadc.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
 
 /*
  * GPADC register offsets
index 9be541c6b004c8adc9cf6cde3416c6bff31c9e31..087fecd71ce032b2ad459467c02aef47197f13ea 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/db8500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
index f20feefac19020969dc55a24bb8a8d162934adb5..c28d4eb1eff019517d166476c590652f2ac1b8b1 100644 (file)
@@ -7,9 +7,9 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/sysctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
 
 static struct device *sysctrl_dev;
 
index 155fa04078821d6fc8d5a5475225bba3a436ba06..315fef5d466ac3f2d380246ffa75a056d131cb52 100644 (file)
@@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
 
-static struct pci_driver cs5535_mfd_drv = {
+static struct pci_driver cs5535_mfd_driver = {
        .name = DRV_NAME,
        .id_table = cs5535_mfd_pci_tbl,
        .probe = cs5535_mfd_probe,
@@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = {
 
 static int __init cs5535_mfd_init(void)
 {
-       return pci_register_driver(&cs5535_mfd_drv);
+       return pci_register_driver(&cs5535_mfd_driver);
 }
 
 static void __exit cs5535_mfd_exit(void)
 {
-       pci_unregister_driver(&cs5535_mfd_drv);
+       pci_unregister_driver(&cs5535_mfd_driver);
 }
 
 module_init(cs5535_mfd_init);
index 8ad88da647b9abfd201c659eb92ec12072b03a60..7710227d284e82f3ea98bd6dcf307abd177f71e9 100644 (file)
@@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client)
        for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
                int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
 
-               gpio_request(gpio, config_inputs[i].label);
-               gpio_direction_input(gpio);
+               gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label);
 
                /* make it easy for userspace to see these */
                gpio_export(gpio, false);
index 97c27762174f1527af8c2b72c5438c4eebc12144..b76657eb0c51044503e3c71b7345c98596d33cbd 100644 (file)
@@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = {
        },
 };
 
-static int __init intel_msic_init(void)
-{
-       return platform_driver_register(&intel_msic_driver);
-}
-module_init(intel_msic_init);
-
-static void __exit intel_msic_exit(void)
-{
-       platform_driver_unregister(&intel_msic_driver);
-}
-module_exit(intel_msic_exit);
+module_platform_driver(intel_msic_driver);
 
 MODULE_DESCRIPTION("Driver for Intel MSIC");
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
index ef39528088f2298a47e7f62f69317b2a6af428ee..87662a17dec62d527a3af1b8b7fb8c782c85dd92 100644 (file)
@@ -181,7 +181,7 @@ static struct resource jz4740_battery_resources[] = {
        },
 };
 
-const struct mfd_cell jz4740_adc_cells[] = {
+static struct mfd_cell jz4740_adc_cells[] = {
        {
                .id = 0,
                .name = "jz4740-hwmon",
@@ -338,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = {
        },
 };
 
-static int __init jz4740_adc_init(void)
-{
-       return platform_driver_register(&jz4740_adc_driver);
-}
-module_init(jz4740_adc_init);
-
-static void __exit jz4740_adc_exit(void)
-{
-       platform_driver_unregister(&jz4740_adc_driver);
-}
-module_exit(jz4740_adc_exit);
+module_platform_driver(jz4740_adc_driver);
 
 MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index ea1169b04779597cb4bf8964b26d7f861ba75afa..abc421364a454f0f596f7e5be734e346838318cb 100644 (file)
@@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = {
        },
 };
 
-static struct pci_device_id lpc_sch_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
        { 0, }
index e1e59c92f7588592e141839f2af5c0c4298d53d5..ca881efedf75a43f7543e19d506702ab1518e0ec 100644 (file)
@@ -210,21 +210,6 @@ static struct max8925_irq_data max8925_irqs[] = {
                .mask_reg       = MAX8925_CHG_IRQ1_MASK,
                .offs           = 1 << 2,
        },
-       [MAX8925_IRQ_VCHG_USB_OVP] = {
-               .reg            = MAX8925_CHG_IRQ1,
-               .mask_reg       = MAX8925_CHG_IRQ1_MASK,
-               .offs           = 1 << 3,
-       },
-       [MAX8925_IRQ_VCHG_USB_F] =  {
-               .reg            = MAX8925_CHG_IRQ1,
-               .mask_reg       = MAX8925_CHG_IRQ1_MASK,
-               .offs           = 1 << 4,
-       },
-       [MAX8925_IRQ_VCHG_USB_R] = {
-               .reg            = MAX8925_CHG_IRQ1,
-               .mask_reg       = MAX8925_CHG_IRQ1_MASK,
-               .offs           = 1 << 5,
-       },
        [MAX8925_IRQ_VCHG_THM_OK_R] = {
                .reg            = MAX8925_CHG_IRQ2,
                .mask_reg       = MAX8925_CHG_IRQ2_MASK,
index 0219115e00c73f84c925045afceb96d65ea83ea3..d9e4b36edee984e3f5008b02f16d8d9becdb703f 100644 (file)
@@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client,
        chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
        i2c_set_clientdata(chip->adc, chip);
 
+       device_init_wakeup(&client->dev, 1);
+
        max8925_device_init(chip, pdata);
 
        return 0;
@@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max8925_suspend(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct max8925_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               enable_irq_wake(chip->core_irq);
+       return 0;
+}
+
+static int max8925_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct max8925_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev) && chip->wakeup_flag)
+               disable_irq_wake(chip->core_irq);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
+
 static struct i2c_driver max8925_driver = {
        .driver = {
                .name   = "max8925",
                .owner  = THIS_MODULE,
+               .pm     = &max8925_pm_ops,
        },
        .probe          = max8925_probe,
        .remove         = __devexit_p(max8925_remove),
index 5be53ae9b61cf2a6d6c318c881e43605b3dee526..cb83a7ab53e73b9825c4eb527211ab49ccd33a7e 100644 (file)
@@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = {
        { .name = "max8997-battery", },
        { .name = "max8997-haptic", },
        { .name = "max8997-muic", },
-       { .name = "max8997-flash", },
+       { .name = "max8997-led", .id = 1 },
+       { .name = "max8997-led", .id = 2 },
 };
 
 int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
index de4096aee24877fccbaf36ae981b06483d41da50..6ef56d28c05686bf298f589cebf91c43fcc707b8 100644 (file)
@@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
+       device_init_wakeup(max8998->dev, max8998->wakeup);
+
        return ret;
 
 err:
@@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev)
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 
-       if (max8998->wakeup)
+       if (device_may_wakeup(dev))
                irq_set_irq_wake(max8998->irq, 1);
        return 0;
 }
@@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev)
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
        struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
 
-       if (max8998->wakeup)
+       if (device_may_wakeup(dev))
                irq_set_irq_wake(max8998->irq, 0);
        /*
         * In LP3974, if IRQ registers are not "read & clear"
index e9619acc02375342276d84e5d9aee83e7a2597a8..7122386b4e3cf1830dbb3cab2f552efefeb43834 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/mc13xxx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 struct mc13xxx {
        struct spi_device *spidev;
        struct mutex lock;
        int irq;
+       int flags;
 
        irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
        void *irqdata[MC13XXX_NUM_IRQ];
@@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
 
 int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
 {
-       struct mc13xxx_platform_data *pdata =
-               dev_get_platdata(&mc13xxx->spidev->dev);
-
-       return pdata->flags;
+       return mc13xxx->flags;
 }
 EXPORT_SYMBOL(mc13xxx_get_flags);
 
@@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
                break;
 
        case MC13XXX_ADC_MODE_SINGLE_CHAN:
-               adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+               adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
                adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
                adc1 |= MC13XXX_ADC1_RAND;
                break;
 
        case MC13XXX_ADC_MODE_MULT_CHAN:
-               adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+               adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
                adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
                break;
 
@@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
        return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
 }
 
+#ifdef CONFIG_OF
+static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+       struct device_node *np = mc13xxx->spidev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
+               mc13xxx->flags |= MC13XXX_USE_ADC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
+               mc13xxx->flags |= MC13XXX_USE_CODEC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
+               mc13xxx->flags |= MC13XXX_USE_RTC;
+
+       if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
+               mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
+
+       return 0;
+}
+#else
+static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+       return -ENODEV;
+}
+#endif
+
+static const struct spi_device_id mc13xxx_device_id[] = {
+       {
+               .name = "mc13783",
+               .driver_data = MC13XXX_ID_MC13783,
+       }, {
+               .name = "mc13892",
+               .driver_data = MC13XXX_ID_MC13892,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
+
+static const struct of_device_id mc13xxx_dt_ids[] = {
+       { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
+       { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
+
 static int mc13xxx_probe(struct spi_device *spi)
 {
+       const struct of_device_id *of_id;
+       struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
        struct mc13xxx *mc13xxx;
        struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
        enum mc13xxx_id id;
        int ret;
 
-       if (!pdata) {
-               dev_err(&spi->dev, "invalid platform data\n");
-               return -EINVAL;
-       }
+       of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
+       if (of_id)
+               sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
 
        mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
        if (!mc13xxx)
@@ -749,28 +800,33 @@ err_revision:
 
        mc13xxx_unlock(mc13xxx);
 
-       if (pdata->flags & MC13XXX_USE_ADC)
+       if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
+               mc13xxx->flags = pdata->flags;
+
+       if (mc13xxx->flags & MC13XXX_USE_ADC)
                mc13xxx_add_subdevice(mc13xxx, "%s-adc");
 
-       if (pdata->flags & MC13XXX_USE_CODEC)
+       if (mc13xxx->flags & MC13XXX_USE_CODEC)
                mc13xxx_add_subdevice(mc13xxx, "%s-codec");
 
-       mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
-               &pdata->regulators, sizeof(pdata->regulators));
-
-       if (pdata->flags & MC13XXX_USE_RTC)
+       if (mc13xxx->flags & MC13XXX_USE_RTC)
                mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
 
-       if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+       if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
                mc13xxx_add_subdevice(mc13xxx, "%s-ts");
 
-       if (pdata->leds)
+       if (pdata) {
+               mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+                       &pdata->regulators, sizeof(pdata->regulators));
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
                                pdata->leds, sizeof(*pdata->leds));
-
-       if (pdata->buttons)
                mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
                                pdata->buttons, sizeof(*pdata->buttons));
+       } else {
+               mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
+               mc13xxx_add_subdevice(mc13xxx, "%s-led");
+               mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
+       }
 
        return 0;
 }
@@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi)
        return 0;
 }
 
-static const struct spi_device_id mc13xxx_device_id[] = {
-       {
-               .name = "mc13783",
-               .driver_data = MC13XXX_ID_MC13783,
-       }, {
-               .name = "mc13892",
-               .driver_data = MC13XXX_ID_MC13892,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
-
 static struct spi_driver mc13xxx_driver = {
        .id_table = mc13xxx_device_id,
        .driver = {
                .name = "mc13xxx",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
+               .of_match_table = mc13xxx_dt_ids,
        },
        .probe = mc13xxx_probe,
        .remove = __devexit_p(mc13xxx_remove),
index 84815f9ef636eb0e91c26c1869094bb5c83977d0..63be60bc3455396e764fa57661f497d5670b04a8 100644 (file)
 #define to_mcp(d)              container_of(d, struct mcp, attached_device)
 #define to_mcp_driver(d)       container_of(d, struct mcp_driver, drv)
 
+static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
+                                               const char *codec)
+{
+       while (id->name[0]) {
+               if (strcmp(codec, id->name) == 0)
+                       return id;
+               id++;
+       }
+       return NULL;
+}
+
+const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
+{
+       const struct mcp_driver *driver =
+               to_mcp_driver(mcp->attached_device.driver);
+
+       return mcp_match_id(driver->id_table, mcp->codec);
+}
+EXPORT_SYMBOL(mcp_get_device_id);
+
 static int mcp_bus_match(struct device *dev, struct device_driver *drv)
 {
-       return 1;
+       const struct mcp *mcp = to_mcp(dev);
+       const struct mcp_driver *driver = to_mcp_driver(drv);
+
+       if (driver->id_table)
+               return !!mcp_match_id(driver->id_table, mcp->codec);
+
+       return 0;
 }
 
 static int mcp_bus_probe(struct device *dev)
@@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev)
        return ret;
 }
 
+static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct mcp *mcp = to_mcp(dev);
+
+       add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
+       return 0;
+}
+
 static struct bus_type mcp_bus_type = {
        .name           = "mcp",
        .match          = mcp_bus_match,
+       .uevent         = mcp_bus_uevent,
        .probe          = mcp_bus_probe,
        .remove         = mcp_bus_remove,
        .suspend        = mcp_bus_suspend,
@@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
 }
 EXPORT_SYMBOL(mcp_host_alloc);
 
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_register(struct mcp *mcp, void *pdata)
 {
+       if (!mcp->codec)
+               return -EINVAL;
+
+       mcp->attached_device.platform_data = pdata;
        dev_set_name(&mcp->attached_device, "mcp0");
+       request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
        return device_register(&mcp->attached_device);
 }
 EXPORT_SYMBOL(mcp_host_register);
index 2dab02d9ac8b6f87168e3e6e1069023f9372fe93..9adc2eb6949252031b3964320d3e6e1dfa4d4ed0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mcp.h>
+#include <linux/io.h>
 
 #include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/system.h>
 #include <mach/mcp.h>
 
-#include <mach/assabet.h>
-
+/* Register offsets */
+#define MCCR0  0x00
+#define MCDR0  0x08
+#define MCDR1  0x0C
+#define MCDR2  0x10
+#define MCSR   0x18
+#define MCCR1  0x00
 
 struct mcp_sa11x0 {
-       u32     mccr0;
-       u32     mccr1;
+       u32             mccr0;
+       u32             mccr1;
+       unsigned char   *mccr0_base;
+       unsigned char   *mccr1_base;
 };
 
 #define priv(mcp)      ((struct mcp_sa11x0 *)mcp_priv(mcp))
@@ -39,25 +47,25 @@ struct mcp_sa11x0 {
 static void
 mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x00007f00;
-       mccr0 |= divisor << 8;
-       Ser4MCCR0 = mccr0;
+       priv->mccr0 &= ~0x00007f00;
+       priv->mccr0 |= divisor << 8;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 static void
 mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
 {
-       unsigned int mccr0;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
        divisor /= 32;
 
-       mccr0 = Ser4MCCR0 & ~0x0000007f;
-       mccr0 |= divisor;
-       Ser4MCCR0 = mccr0;
+       priv->mccr0 &= ~0x0000007f;
+       priv->mccr0 |= divisor;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 /*
@@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
 {
        int ret = -ETIME;
        int i;
+       u32 mcpreg;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
+       __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CWC) {
+               mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+               if (mcpreg & MCSR_CWC) {
                        ret = 0;
                        break;
                }
@@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 {
        int ret = -ETIME;
        int i;
+       u32 mcpreg;
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+       mcpreg = reg << 17 | MCDR2_Rd;
+       __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
 
        for (i = 0; i < 2; i++) {
                udelay(mcp->rw_timeout);
-               if (Ser4MCSR & MCSR_CRC) {
-                       ret = Ser4MCDR2 & 0xffff;
+               mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+               if (mcpreg & MCSR_CRC) {
+                       ret = __raw_readl(priv->mccr0_base + MCDR2)
+                               & 0xffff;
                        break;
                }
        }
@@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
 
 static void mcp_sa11x0_enable(struct mcp *mcp)
 {
-       Ser4MCSR = -1;
-       Ser4MCCR0 |= MCCR0_MCE;
+       struct mcp_sa11x0 *priv = priv(mcp);
+
+       __raw_writel(-1, priv->mccr0_base + MCSR);
+       priv->mccr0 |= MCCR0_MCE;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 static void mcp_sa11x0_disable(struct mcp *mcp)
 {
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       struct mcp_sa11x0 *priv = priv(mcp);
+
+       priv->mccr0 &= ~MCCR0_MCE;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
 }
 
 /*
@@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        struct mcp_plat_data *data = pdev->dev.platform_data;
        struct mcp *mcp;
        int ret;
+       struct mcp_sa11x0 *priv;
+       struct resource *res_mem0, *res_mem1;
+       u32 size0, size1;
 
        if (!data)
                return -ENODEV;
 
-       if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
+       if (!data->codec)
+               return -ENODEV;
+
+       res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem0)
+               return -ENODEV;
+       size0 = res_mem0->end - res_mem0->start + 1;
+
+       res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res_mem1)
+               return -ENODEV;
+       size1 = res_mem1->end - res_mem1->start + 1;
+
+       if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
                return -EBUSY;
 
+       if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
+               ret = -EBUSY;
+               goto release;
+       }
+
        mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
        if (!mcp) {
                ret = -ENOMEM;
-               goto release;
+               goto release2;
        }
 
+       priv = priv(mcp);
+
        mcp->owner              = THIS_MODULE;
        mcp->ops                = &mcp_sa11x0;
        mcp->sclk_rate          = data->sclk_rate;
-       mcp->dma_audio_rd       = DMA_Ser4MCP0Rd;
-       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
-       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
-       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
-       mcp->gpio_base          = data->gpio_base;
+       mcp->dma_audio_rd       = DDAR_DevAdd(res_mem0->start + MCDR0)
+                               + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_audio_wr       = DDAR_DevAdd(res_mem0->start + MCDR0)
+                               + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_telco_rd       = DDAR_DevAdd(res_mem0->start + MCDR1)
+                               + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->dma_telco_wr       = DDAR_DevAdd(res_mem0->start + MCDR1)
+                               + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+       mcp->codec              = data->codec;
 
        platform_set_drvdata(pdev, mcp);
 
-       if (machine_is_assabet()) {
-               ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
-       }
-
-       /*
-        * Setup the PPC unit correctly.
-        */
-       PPDR &= ~PPC_RXD4;
-       PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-       PSDR |= PPC_RXD4;
-       PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-       PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-
        /*
         * Initialise device.  Note that we initially
         * set the sampling rate to minimum.
         */
-       Ser4MCSR = -1;
-       Ser4MCCR1 = data->mccr1;
-       Ser4MCCR0 = data->mccr0 | 0x7f7f;
+       priv->mccr0_base = ioremap(res_mem0->start, size0);
+       priv->mccr1_base = ioremap(res_mem1->start, size1);
+
+       __raw_writel(-1, priv->mccr0_base + MCSR);
+       priv->mccr1 = data->mccr1;
+       priv->mccr0 = data->mccr0 | 0x7f7f;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+       __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
 
        /*
         * Calculate the read/write timeout (us) from the bit clock
@@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
        mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
                          mcp->sclk_rate;
 
-       ret = mcp_host_register(mcp);
+       ret = mcp_host_register(mcp, data->codec_pdata);
        if (ret == 0)
                goto out;
 
+ release2:
+       release_mem_region(res_mem1->start, size1);
  release:
-       release_mem_region(0x80060000, 0x60);
+       release_mem_region(res_mem0->start, size0);
        platform_set_drvdata(pdev, NULL);
 
  out:
        return ret;
 }
 
-static int mcp_sa11x0_remove(struct platform_device *dev)
+static int mcp_sa11x0_remove(struct platform_device *pdev)
 {
-       struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp *mcp = platform_get_drvdata(pdev);
+       struct mcp_sa11x0 *priv = priv(mcp);
+       struct resource *res_mem;
+       u32 size;
 
-       platform_set_drvdata(dev, NULL);
+       platform_set_drvdata(pdev, NULL);
        mcp_host_unregister(mcp);
-       release_mem_region(0x80060000, 0x60);
 
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem) {
+               size = res_mem->end - res_mem->start + 1;
+               release_mem_region(res_mem->start, size);
+       }
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res_mem) {
+               size = res_mem->end - res_mem->start + 1;
+               release_mem_region(res_mem->start, size);
+       }
+       iounmap(priv->mccr0_base);
+       iounmap(priv->mccr1_base);
        return 0;
 }
 
 static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *priv = priv(mcp);
+       u32 mccr0;
 
-       priv(mcp)->mccr0 = Ser4MCCR0;
-       priv(mcp)->mccr1 = Ser4MCCR1;
-       Ser4MCCR0 &= ~MCCR0_MCE;
+       mccr0 = priv->mccr0 & ~MCCR0_MCE;
+       __raw_writel(mccr0, priv->mccr0_base + MCCR0);
 
        return 0;
 }
@@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
 static int mcp_sa11x0_resume(struct platform_device *dev)
 {
        struct mcp *mcp = platform_get_drvdata(dev);
+       struct mcp_sa11x0 *priv = priv(mcp);
 
-       Ser4MCCR1 = priv(mcp)->mccr1;
-       Ser4MCCR0 = priv(mcp)->mccr0;
+       __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+       __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
 
        return 0;
 }
@@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = {
        .resume         = mcp_sa11x0_resume,
        .driver         = {
                .name   = "sa11x0-mcp",
+               .owner  = THIS_MODULE,
        },
 };
 
 /*
  * This needs re-working
  */
-static int __init mcp_sa11x0_init(void)
-{
-       return platform_driver_register(&mcp_sa11x0_driver);
-}
-
-static void __exit mcp_sa11x0_exit(void)
-{
-       platform_driver_unregister(&mcp_sa11x0_driver);
-}
-
-module_init(mcp_sa11x0_init);
-module_exit(mcp_sa11x0_exit);
+module_platform_driver(mcp_sa11x0_driver);
 
 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
index 3f565ef3e149438c86a0054f354627231a2258b2..68ac2c55d5ae0bb1381c0681b641846079345f54 100644 (file)
@@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *dev)
        spin_lock_irqsave(&omap->lock, flags);
 
        if (pdata->ehci_data->phy_reset) {
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
-                       gpio_request(pdata->ehci_data->reset_gpio_port[0],
-                                               "USB1 PHY reset");
-                       gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[0], 0);
-               }
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+                                        GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
 
-               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) {
-                       gpio_request(pdata->ehci_data->reset_gpio_port[1],
-                                               "USB2 PHY reset");
-                       gpio_direction_output
-                               (pdata->ehci_data->reset_gpio_port[1], 0);
-               }
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+                                        GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
 
                /* Hold the PHY in RESET for enough time till DIR is high */
                udelay(10);
index aed0d2a9b032e0b3e5babe7949037df19470e1c7..3927c17e4175d9cd4bc28b9c756286a7f1b4efd4 100644 (file)
@@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = {
        .remove = __devexit_p(pcf50633_adc_remove),
 };
 
-static int __init pcf50633_adc_init(void)
-{
-       return platform_driver_register(&pcf50633_adc_driver);
-}
-module_init(pcf50633_adc_init);
-
-static void __exit pcf50633_adc_exit(void)
-{
-       platform_driver_unregister(&pcf50633_adc_driver);
-}
-module_exit(pcf50633_adc_exit);
+module_platform_driver(pcf50633_adc_driver);
 
 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 MODULE_DESCRIPTION("PCF50633 adc driver");
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
new file mode 100644 (file)
index 0000000..e075c11
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * s5m87xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License 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/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#include <linux/mfd/s5m87xx/s5m-rtc.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell s5m87xx_devs[] = {
+       {
+               .name = "s5m8767-pmic",
+       }, {
+               .name = "s5m-rtc",
+       },
+};
+
+int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
+{
+       return regmap_read(s5m87xx->regmap, reg, dest);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_read);
+
+int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+       return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_read);
+
+int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
+{
+       return regmap_write(s5m87xx->regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_write);
+
+int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+       return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_write);
+
+int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
+{
+       return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_update);
+
+static struct regmap_config s5m_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int s5m87xx_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct s5m_platform_data *pdata = i2c->dev.platform_data;
+       struct s5m87xx_dev *s5m87xx;
+       int ret = 0;
+       int error;
+
+       s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+       if (s5m87xx == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, s5m87xx);
+       s5m87xx->dev = &i2c->dev;
+       s5m87xx->i2c = i2c;
+       s5m87xx->irq = i2c->irq;
+       s5m87xx->type = id->driver_data;
+
+       if (pdata) {
+               s5m87xx->device_type = pdata->device_type;
+               s5m87xx->ono = pdata->ono;
+               s5m87xx->irq_base = pdata->irq_base;
+               s5m87xx->wakeup = pdata->wakeup;
+       }
+
+       s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
+       if (IS_ERR(s5m87xx->regmap)) {
+               error = PTR_ERR(s5m87xx->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       error);
+               goto err;
+       }
+
+       s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
+
+       if (pdata->cfg_pmic_irq)
+               pdata->cfg_pmic_irq();
+
+       s5m_irq_init(s5m87xx);
+
+       pm_runtime_set_active(s5m87xx->dev);
+
+       ret = mfd_add_devices(s5m87xx->dev, -1,
+                               s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
+                               NULL, 0);
+
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       mfd_remove_devices(s5m87xx->dev);
+       s5m_irq_exit(s5m87xx);
+       i2c_unregister_device(s5m87xx->rtc);
+       regmap_exit(s5m87xx->regmap);
+       kfree(s5m87xx);
+       return ret;
+}
+
+static int s5m87xx_i2c_remove(struct i2c_client *i2c)
+{
+       struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
+
+       mfd_remove_devices(s5m87xx->dev);
+       s5m_irq_exit(s5m87xx);
+       i2c_unregister_device(s5m87xx->rtc);
+       regmap_exit(s5m87xx->regmap);
+       kfree(s5m87xx);
+       return 0;
+}
+
+static const struct i2c_device_id s5m87xx_i2c_id[] = {
+       { "s5m87xx", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
+
+static struct i2c_driver s5m87xx_i2c_driver = {
+       .driver = {
+                  .name = "s5m87xx",
+                  .owner = THIS_MODULE,
+       },
+       .probe = s5m87xx_i2c_probe,
+       .remove = s5m87xx_i2c_remove,
+       .id_table = s5m87xx_i2c_id,
+};
+
+static int __init s5m87xx_i2c_init(void)
+{
+       return i2c_add_driver(&s5m87xx_i2c_driver);
+}
+
+subsys_initcall(s5m87xx_i2c_init);
+
+static void __exit s5m87xx_i2c_exit(void)
+{
+       i2c_del_driver(&s5m87xx_i2c_driver);
+}
+module_exit(s5m87xx_i2c_exit);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("Core support for the S5M MFD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
new file mode 100644 (file)
index 0000000..de76dfb
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * s5m-irq.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+
+struct s5m_irq_data {
+       int reg;
+       int mask;
+};
+
+static struct s5m_irq_data s5m8767_irqs[] = {
+       [S5M8767_IRQ_PWRR] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWRR_MASK,
+       },
+       [S5M8767_IRQ_PWRF] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWRF_MASK,
+       },
+       [S5M8767_IRQ_PWR1S] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_PWR1S_MASK,
+       },
+       [S5M8767_IRQ_JIGR] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_JIGR_MASK,
+       },
+       [S5M8767_IRQ_JIGF] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_JIGF_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT2] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_LOWBAT2_MASK,
+       },
+       [S5M8767_IRQ_LOWBAT1] = {
+               .reg = 1,
+               .mask = S5M8767_IRQ_LOWBAT1_MASK,
+       },
+       [S5M8767_IRQ_MRB] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_MRB_MASK,
+       },
+       [S5M8767_IRQ_DVSOK2] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK2_MASK,
+       },
+       [S5M8767_IRQ_DVSOK3] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK3_MASK,
+       },
+       [S5M8767_IRQ_DVSOK4] = {
+               .reg = 2,
+               .mask = S5M8767_IRQ_DVSOK4_MASK,
+       },
+       [S5M8767_IRQ_RTC60S] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTC60S_MASK,
+       },
+       [S5M8767_IRQ_RTCA1] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTCA1_MASK,
+       },
+       [S5M8767_IRQ_RTCA2] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTCA2_MASK,
+       },
+       [S5M8767_IRQ_SMPL] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_SMPL_MASK,
+       },
+       [S5M8767_IRQ_RTC1S] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_RTC1S_MASK,
+       },
+       [S5M8767_IRQ_WTSR] = {
+               .reg = 3,
+               .mask = S5M8767_IRQ_WTSR_MASK,
+       },
+};
+
+static struct s5m_irq_data s5m8763_irqs[] = {
+       [S5M8763_IRQ_DCINF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_DCINF_MASK,
+       },
+       [S5M8763_IRQ_DCINR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_DCINR_MASK,
+       },
+       [S5M8763_IRQ_JIGF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_JIGF_MASK,
+       },
+       [S5M8763_IRQ_JIGR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_JIGR_MASK,
+       },
+       [S5M8763_IRQ_PWRONF] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_PWRONF_MASK,
+       },
+       [S5M8763_IRQ_PWRONR] = {
+               .reg = 1,
+               .mask = S5M8763_IRQ_PWRONR_MASK,
+       },
+       [S5M8763_IRQ_WTSREVNT] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_WTSREVNT_MASK,
+       },
+       [S5M8763_IRQ_SMPLEVNT] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_SMPLEVNT_MASK,
+       },
+       [S5M8763_IRQ_ALARM1] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_ALARM1_MASK,
+       },
+       [S5M8763_IRQ_ALARM0] = {
+               .reg = 2,
+               .mask = S5M8763_IRQ_ALARM0_MASK,
+       },
+       [S5M8763_IRQ_ONKEY1S] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_ONKEY1S_MASK,
+       },
+       [S5M8763_IRQ_TOPOFFR] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_TOPOFFR_MASK,
+       },
+       [S5M8763_IRQ_DCINOVPR] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_DCINOVPR_MASK,
+       },
+       [S5M8763_IRQ_CHGRSTF] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_CHGRSTF_MASK,
+       },
+       [S5M8763_IRQ_DONER] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_DONER_MASK,
+       },
+       [S5M8763_IRQ_CHGFAULT] = {
+               .reg = 3,
+               .mask = S5M8763_IRQ_CHGFAULT_MASK,
+       },
+       [S5M8763_IRQ_LOBAT1] = {
+               .reg = 4,
+               .mask = S5M8763_IRQ_LOBAT1_MASK,
+       },
+       [S5M8763_IRQ_LOBAT2] = {
+               .reg = 4,
+               .mask = S5M8763_IRQ_LOBAT2_MASK,
+       },
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+       return &s5m8767_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8767_irq_lock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_sync_unlock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+                                       s5m87xx->irq_masks_cur[i]);
+               }
+       }
+
+       mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_unmask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8767_irq_mask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8767_irq_chip = {
+       .name = "s5m8767",
+       .irq_bus_lock = s5m8767_irq_lock,
+       .irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
+       .irq_mask = s5m8767_irq_mask,
+       .irq_unmask = s5m8767_irq_unmask,
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+       return &s5m8763_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8763_irq_lock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_sync_unlock(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+               if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+                       s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+                                       s5m87xx->irq_masks_cur[i]);
+               }
+       }
+
+       mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_unmask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8763_irq_mask(struct irq_data *data)
+{
+       struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+       struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+                                                              data->irq);
+
+       s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8763_irq_chip = {
+       .name = "s5m8763",
+       .irq_bus_lock = s5m8763_irq_lock,
+       .irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
+       .irq_mask = s5m8763_irq_mask,
+       .irq_unmask = s5m8763_irq_unmask,
+};
+
+
+static irqreturn_t s5m8767_irq_thread(int irq, void *data)
+{
+       struct s5m87xx_dev *s5m87xx = data;
+       u8 irq_reg[NUM_IRQ_REGS-1];
+       int ret;
+       int i;
+
+
+       ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
+                               NUM_IRQ_REGS - 1, irq_reg);
+       if (ret < 0) {
+               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+                               ret);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < NUM_IRQ_REGS - 1; i++)
+               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+       for (i = 0; i < S5M8767_IRQ_NR; i++) {
+               if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
+                       handle_nested_irq(s5m87xx->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s5m8763_irq_thread(int irq, void *data)
+{
+       struct s5m87xx_dev *s5m87xx = data;
+       u8 irq_reg[NUM_IRQ_REGS];
+       int ret;
+       int i;
+
+       ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
+                               NUM_IRQ_REGS, irq_reg);
+       if (ret < 0) {
+               dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+                               ret);
+               return IRQ_NONE;
+       }
+
+       for (i = 0; i < NUM_IRQ_REGS; i++)
+               irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+       for (i = 0; i < S5M8763_IRQ_NR; i++) {
+               if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
+                       handle_nested_irq(s5m87xx->irq_base + i);
+       }
+
+       return IRQ_HANDLED;
+}
+
+int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
+{
+       if (s5m87xx->irq && s5m87xx->irq_base){
+               switch (s5m87xx->device_type) {
+               case S5M8763X:
+                       s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
+                       break;
+               case S5M8767X:
+                       s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
+                       break;
+               default:
+                       break;
+
+               }
+       }
+       return 0;
+}
+
+int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
+{
+       int i;
+       int cur_irq;
+       int ret = 0;
+       int type = s5m87xx->device_type;
+
+       if (!s5m87xx->irq) {
+               dev_warn(s5m87xx->dev,
+                        "No interrupt specified, no interrupts\n");
+               s5m87xx->irq_base = 0;
+               return 0;
+       }
+
+       if (!s5m87xx->irq_base) {
+               dev_err(s5m87xx->dev,
+                       "No interrupt base specified, no interrupts\n");
+               return 0;
+       }
+
+       mutex_init(&s5m87xx->irqlock);
+
+       switch (type) {
+       case S5M8763X:
+               for (i = 0; i < NUM_IRQ_REGS; i++) {
+                       s5m87xx->irq_masks_cur[i] = 0xff;
+                       s5m87xx->irq_masks_cache[i] = 0xff;
+                       s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+                                               0xff);
+               }
+
+               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
+               s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
+
+               for (i = 0; i < S5M8763_IRQ_NR; i++) {
+                       cur_irq = i + s5m87xx->irq_base;
+                       irq_set_chip_data(cur_irq, s5m87xx);
+                       irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
+                                                handle_edge_irq);
+                       irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(cur_irq, IRQF_VALID);
+#else
+                       irq_set_noprobe(cur_irq);
+#endif
+               }
+
+               ret = request_threaded_irq(s5m87xx->irq, NULL,
+                                       s5m8763_irq_thread,
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                       "s5m87xx-irq", s5m87xx);
+               if (ret) {
+                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                               s5m87xx->irq, ret);
+                       return ret;
+               }
+               break;
+       case S5M8767X:
+               for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
+                       s5m87xx->irq_masks_cur[i] = 0xff;
+                       s5m87xx->irq_masks_cache[i] = 0xff;
+                       s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+                                               0xff);
+               }
+               for (i = 0; i < S5M8767_IRQ_NR; i++) {
+                       cur_irq = i + s5m87xx->irq_base;
+                       irq_set_chip_data(cur_irq, s5m87xx);
+                       if (ret) {
+                               dev_err(s5m87xx->dev,
+                                       "Failed to irq_set_chip_data %d: %d\n",
+                                       s5m87xx->irq, ret);
+                               return ret;
+                       }
+
+                       irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
+                                                handle_edge_irq);
+                       irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(cur_irq, IRQF_VALID);
+#else
+                       irq_set_noprobe(cur_irq);
+#endif
+               }
+
+               ret = request_threaded_irq(s5m87xx->irq, NULL,
+                                          s5m8767_irq_thread,
+                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                          "s5m87xx-irq", s5m87xx);
+               if (ret) {
+                       dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                               s5m87xx->irq, ret);
+                       return ret;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (!s5m87xx->ono)
+               return 0;
+
+       switch (type) {
+       case S5M8763X:
+               ret = request_threaded_irq(s5m87xx->ono, NULL,
+                                               s5m8763_irq_thread,
+                                               IRQF_TRIGGER_FALLING |
+                                               IRQF_TRIGGER_RISING |
+                                               IRQF_ONESHOT, "s5m87xx-ono",
+                                               s5m87xx);
+               break;
+       case S5M8767X:
+               ret = request_threaded_irq(s5m87xx->ono, NULL,
+                                       s5m8767_irq_thread,
+                                       IRQF_TRIGGER_FALLING |
+                                       IRQF_TRIGGER_RISING |
+                                       IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
+               break;
+       default:
+               break;
+       }
+
+       if (ret)
+               dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+                       s5m87xx->ono, ret);
+
+       return 0;
+}
+
+void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
+{
+       if (s5m87xx->ono)
+               free_irq(s5m87xx->ono, s5m87xx);
+
+       if (s5m87xx->irq)
+               free_irq(s5m87xx->irq, s5m87xx);
+}
index df3702c1756df9aae08dcfbbf1bde345d7520172..f4d86117f44a21bcc140e93b8fd116798d6d5054 100644 (file)
@@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev)
        return 0;
 }
 
-static struct pci_device_id sm501_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = {
        { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0, },
 };
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
new file mode 100644 (file)
index 0000000..373f423
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * ST Microelectronics MFD: stmpe's i2c client specific driver
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_read_byte_data(i2c, reg);
+}
+
+static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_write_byte_data(i2c, reg, val);
+}
+
+static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_read_i2c_block_data(i2c, reg, length, values);
+}
+
+static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+               const u8 *values)
+{
+       struct i2c_client *i2c = stmpe->client;
+
+       return i2c_smbus_write_i2c_block_data(i2c, reg, length, values);
+}
+
+static struct stmpe_client_info i2c_ci = {
+       .read_byte = i2c_reg_read,
+       .write_byte = i2c_reg_write,
+       .read_block = i2c_block_read,
+       .write_block = i2c_block_write,
+};
+
+static int __devinit
+stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+       i2c_ci.data = (void *)id;
+       i2c_ci.irq = i2c->irq;
+       i2c_ci.client = i2c;
+       i2c_ci.dev = &i2c->dev;
+
+       return stmpe_probe(&i2c_ci, id->driver_data);
+}
+
+static int __devexit stmpe_i2c_remove(struct i2c_client *i2c)
+{
+       struct stmpe *stmpe = dev_get_drvdata(&i2c->dev);
+
+       return stmpe_remove(stmpe);
+}
+
+static const struct i2c_device_id stmpe_i2c_id[] = {
+       { "stmpe610", STMPE610 },
+       { "stmpe801", STMPE801 },
+       { "stmpe811", STMPE811 },
+       { "stmpe1601", STMPE1601 },
+       { "stmpe2401", STMPE2401 },
+       { "stmpe2403", STMPE2403 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, stmpe_id);
+
+static struct i2c_driver stmpe_i2c_driver = {
+       .driver.name    = "stmpe-i2c",
+       .driver.owner   = THIS_MODULE,
+#ifdef CONFIG_PM
+       .driver.pm      = &stmpe_dev_pm_ops,
+#endif
+       .probe          = stmpe_i2c_probe,
+       .remove         = __devexit_p(stmpe_i2c_remove),
+       .id_table       = stmpe_i2c_id,
+};
+
+static int __init stmpe_init(void)
+{
+       return i2c_add_driver(&stmpe_i2c_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+       i2c_del_driver(&stmpe_i2c_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
new file mode 100644 (file)
index 0000000..b58c43c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * ST Microelectronics MFD: stmpe's spi client specific driver
+ *
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+#define READ_CMD       (1 << 7)
+
+static int spi_reg_read(struct stmpe *stmpe, u8 reg)
+{
+       struct spi_device *spi = stmpe->client;
+       int status = spi_w8r16(spi, reg | READ_CMD);
+
+       return (status < 0) ? status : status >> 8;
+}
+
+static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+       struct spi_device *spi = stmpe->client;
+       u16 cmd = (val << 8) | reg;
+
+       return spi_write(spi, (const u8 *)&cmd, 2);
+}
+
+static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+       int ret, i;
+
+       for (i = 0; i < length; i++) {
+               ret = spi_reg_read(stmpe, reg + i);
+               if (ret < 0)
+                       return ret;
+               *(values + i) = ret;
+       }
+
+       return 0;
+}
+
+static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+               const u8 *values)
+{
+       int ret = 0, i;
+
+       for (i = length; i > 0; i--, reg++) {
+               ret = spi_reg_write(stmpe, reg, *(values + i - 1));
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void spi_init(struct stmpe *stmpe)
+{
+       struct spi_device *spi = stmpe->client;
+
+       spi->bits_per_word = 8;
+
+       /* This register is only present for stmpe811 */
+       if (stmpe->variant->id_val == 0x0811)
+               spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode);
+
+       if (spi_setup(spi) < 0)
+               dev_dbg(&spi->dev, "spi_setup failed\n");
+}
+
+static struct stmpe_client_info spi_ci = {
+       .read_byte = spi_reg_read,
+       .write_byte = spi_reg_write,
+       .read_block = spi_block_read,
+       .write_block = spi_block_write,
+       .init = spi_init,
+};
+
+static int __devinit
+stmpe_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+
+       /* don't exceed max specified rate - 1MHz - Limitation of STMPE */
+       if (spi->max_speed_hz > 1000000) {
+               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+                               (spi->max_speed_hz/1000));
+               return -EINVAL;
+       }
+
+       spi_ci.irq = spi->irq;
+       spi_ci.client = spi;
+       spi_ci.dev = &spi->dev;
+
+       return stmpe_probe(&spi_ci, id->driver_data);
+}
+
+static int __devexit stmpe_spi_remove(struct spi_device *spi)
+{
+       struct stmpe *stmpe = dev_get_drvdata(&spi->dev);
+
+       return stmpe_remove(stmpe);
+}
+
+static const struct spi_device_id stmpe_spi_id[] = {
+       { "stmpe610", STMPE610 },
+       { "stmpe801", STMPE801 },
+       { "stmpe811", STMPE811 },
+       { "stmpe1601", STMPE1601 },
+       { "stmpe2401", STMPE2401 },
+       { "stmpe2403", STMPE2403 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, stmpe_id);
+
+static struct spi_driver stmpe_spi_driver = {
+       .driver = {
+               .name   = "stmpe-spi",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &stmpe_dev_pm_ops,
+#endif
+       },
+       .probe          = stmpe_spi_probe,
+       .remove         = __devexit_p(stmpe_spi_remove),
+       .id_table       = stmpe_spi_id,
+};
+
+static int __init stmpe_init(void)
+{
+       return spi_register_driver(&stmpe_spi_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+       spi_unregister_driver(&stmpe_spi_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
index 2963689cf45c2c93dcd56e56fea26b0b4debdf92..e07947e56b2a0e2bd68d5aa7da434ae6aa5ed878 100644 (file)
@@ -1,18 +1,20 @@
 /*
+ * ST Microelectronics MFD: stmpe's driver
+ *
  * Copyright (C) ST-Ericsson SA 2010
  *
  * License Terms: GNU General Public License, version 2
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
  */
 
+#include <linux/gpio.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
-#include <linux/i2c.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/stmpe.h>
 #include "stmpe.h"
 
 static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
 {
        int ret;
 
-       ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
+       ret = stmpe->ci->read_byte(stmpe, reg);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret);
 
        dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
 
@@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
 
        dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
 
-       ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
+       ret = stmpe->ci->write_byte(stmpe, reg, val);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret);
 
        return ret;
 }
@@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
 {
        int ret;
 
-       ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
+       ret = stmpe->ci->read_block(stmpe, reg, length, values);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret);
 
        dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
        stmpe_dump_bytes("stmpe rd: ", values, length);
@@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
        dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
        stmpe_dump_bytes("stmpe wr: ", values, length);
 
-       ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
-                                            values);
+       ret = stmpe->ci->write_block(stmpe, reg, length, values);
        if (ret < 0)
-               dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
-                       reg, ret);
+               dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret);
 
        return ret;
 }
@@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
        u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
        int af_bits = variant->af_bits;
        int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
-       int afperreg = 8 / af_bits;
        int mask = (1 << af_bits) - 1;
        u8 regs[numregs];
-       int af;
-       int ret;
+       int af, afperreg, ret;
+
+       if (!variant->get_altfunc)
+               return 0;
 
+       afperreg = 8 / af_bits;
        mutex_lock(&stmpe->lock);
 
        ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
@@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = {
 };
 
 /*
- * Touchscreen (STMPE811)
+ * STMPE801
+ */
+static const u8 stmpe801_regs[] = {
+       [STMPE_IDX_CHIP_ID]     = STMPE801_REG_CHIP_ID,
+       [STMPE_IDX_ICR_LSB]     = STMPE801_REG_SYS_CTRL,
+       [STMPE_IDX_GPMR_LSB]    = STMPE801_REG_GPIO_MP_STA,
+       [STMPE_IDX_GPSR_LSB]    = STMPE801_REG_GPIO_SET_PIN,
+       [STMPE_IDX_GPCR_LSB]    = STMPE801_REG_GPIO_SET_PIN,
+       [STMPE_IDX_GPDR_LSB]    = STMPE801_REG_GPIO_DIR,
+       [STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN,
+       [STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA,
+
+};
+
+static struct stmpe_variant_block stmpe801_blocks[] = {
+       {
+               .cell   = &stmpe_gpio_cell,
+               .irq    = 0,
+               .block  = STMPE_BLOCK_GPIO,
+       },
+};
+
+static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
+                          bool enable)
+{
+       if (blocks & STMPE_BLOCK_GPIO)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static struct stmpe_variant_info stmpe801 = {
+       .name           = "stmpe801",
+       .id_val         = STMPE801_ID,
+       .id_mask        = 0xffff,
+       .num_gpios      = 8,
+       .regs           = stmpe801_regs,
+       .blocks         = stmpe801_blocks,
+       .num_blocks     = ARRAY_SIZE(stmpe801_blocks),
+       .num_irqs       = STMPE801_NR_INTERNAL_IRQS,
+       .enable         = stmpe801_enable,
+};
+
+/*
+ * Touchscreen (STMPE811 or STMPE610)
  */
 
 static struct resource stmpe_ts_resources[] = {
@@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = {
 };
 
 /*
- * STMPE811
+ * STMPE811 or STMPE610
  */
 
 static const u8 stmpe811_regs[] = {
@@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = {
        .get_altfunc    = stmpe811_get_altfunc,
 };
 
+/* Similar to 811, except number of gpios */
+static struct stmpe_variant_info stmpe610 = {
+       .name           = "stmpe610",
+       .id_val         = 0x0811,
+       .id_mask        = 0xffff,
+       .num_gpios      = 6,
+       .af_bits        = 1,
+       .regs           = stmpe811_regs,
+       .blocks         = stmpe811_blocks,
+       .num_blocks     = ARRAY_SIZE(stmpe811_blocks),
+       .num_irqs       = STMPE811_NR_INTERNAL_IRQS,
+       .enable         = stmpe811_enable,
+       .get_altfunc    = stmpe811_get_altfunc,
+};
+
 /*
  * STMPE1601
  */
@@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = {
 };
 
 static struct stmpe_variant_info *stmpe_variant_info[] = {
+       [STMPE610]      = &stmpe610,
+       [STMPE801]      = &stmpe801,
        [STMPE811]      = &stmpe811,
        [STMPE1601]     = &stmpe1601,
        [STMPE2401]     = &stmpe2401,
@@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
        int ret;
        int i;
 
+       if (variant->id_val == STMPE801_ID) {
+               handle_nested_irq(stmpe->irq_base);
+               return IRQ_HANDLED;
+       }
+
        ret = stmpe_block_read(stmpe, israddr, num, isr);
        if (ret < 0)
                return IRQ_NONE;
@@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = {
 
 static int __devinit stmpe_irq_init(struct stmpe *stmpe)
 {
+       struct irq_chip *chip = NULL;
        int num_irqs = stmpe->variant->num_irqs;
        int base = stmpe->irq_base;
        int irq;
 
+       if (stmpe->variant->id_val != STMPE801_ID)
+               chip = &stmpe_irq_chip;
+
        for (irq = base; irq < base + num_irqs; irq++) {
                irq_set_chip_data(irq, stmpe);
-               irq_set_chip_and_handler(irq, &stmpe_irq_chip,
-                                        handle_edge_irq);
+               irq_set_chip_and_handler(irq, chip, handle_edge_irq);
                irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
                set_irq_flags(irq, IRQF_VALID);
@@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        unsigned int irq_trigger = stmpe->pdata->irq_trigger;
        int autosleep_timeout = stmpe->pdata->autosleep_timeout;
        struct stmpe_variant_info *variant = stmpe->variant;
-       u8 icr = STMPE_ICR_LSB_GIM;
+       u8 icr;
        unsigned int id;
        u8 data[2];
        int ret;
@@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        if (ret)
                return ret;
 
-       if (irq_trigger == IRQF_TRIGGER_FALLING ||
-           irq_trigger == IRQF_TRIGGER_RISING)
-               icr |= STMPE_ICR_LSB_EDGE;
+       if (id == STMPE801_ID)
+               icr = STMPE801_REG_SYS_CTRL_INT_EN;
+       else
+               icr = STMPE_ICR_LSB_GIM;
+
+       /* STMPE801 doesn't support Edge interrupts */
+       if (id != STMPE801_ID) {
+               if (irq_trigger == IRQF_TRIGGER_FALLING ||
+                               irq_trigger == IRQF_TRIGGER_RISING)
+                       icr |= STMPE_ICR_LSB_EDGE;
+       }
 
        if (irq_trigger == IRQF_TRIGGER_RISING ||
-           irq_trigger == IRQF_TRIGGER_HIGH)
-               icr |= STMPE_ICR_LSB_HIGH;
+                       irq_trigger == IRQF_TRIGGER_HIGH) {
+               if (id == STMPE801_ID)
+                       icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+               else
+                       icr |= STMPE_ICR_LSB_HIGH;
+       }
 
-       if (stmpe->pdata->irq_invert_polarity)
-               icr ^= STMPE_ICR_LSB_HIGH;
+       if (stmpe->pdata->irq_invert_polarity) {
+               if (id == STMPE801_ID)
+                       icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+               else
+                       icr ^= STMPE_ICR_LSB_HIGH;
+       }
 
        if (stmpe->pdata->autosleep) {
                ret = stmpe_autosleep(stmpe, autosleep_timeout);
@@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
        return ret;
 }
 
-#ifdef CONFIG_PM
-static int stmpe_suspend(struct device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-
-       if (device_may_wakeup(&i2c->dev))
-               enable_irq_wake(i2c->irq);
-
-       return 0;
-}
-
-static int stmpe_resume(struct device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-
-       if (device_may_wakeup(&i2c->dev))
-               disable_irq_wake(i2c->irq);
-
-       return 0;
-}
-#endif
-
-static int __devinit stmpe_probe(struct i2c_client *i2c,
-                                const struct i2c_device_id *id)
+/* Called from client specific probe routines */
+int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
 {
-       struct stmpe_platform_data *pdata = i2c->dev.platform_data;
+       struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev);
        struct stmpe *stmpe;
        int ret;
 
@@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
        mutex_init(&stmpe->irq_lock);
        mutex_init(&stmpe->lock);
 
-       stmpe->dev = &i2c->dev;
-       stmpe->i2c = i2c;
-
+       stmpe->dev = ci->dev;
+       stmpe->client = ci->client;
        stmpe->pdata = pdata;
        stmpe->irq_base = pdata->irq_base;
-
-       stmpe->partnum = id->driver_data;
-       stmpe->variant = stmpe_variant_info[stmpe->partnum];
+       stmpe->ci = ci;
+       stmpe->partnum = partnum;
+       stmpe->variant = stmpe_variant_info[partnum];
        stmpe->regs = stmpe->variant->regs;
        stmpe->num_gpios = stmpe->variant->num_gpios;
+       dev_set_drvdata(stmpe->dev, stmpe);
 
-       i2c_set_clientdata(i2c, stmpe);
+       if (ci->init)
+               ci->init(stmpe);
+
+       if (pdata->irq_over_gpio) {
+               ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe");
+               if (ret) {
+                       dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n",
+                                       ret);
+                       goto out_free;
+               }
+
+               stmpe->irq = gpio_to_irq(pdata->irq_gpio);
+       } else {
+               stmpe->irq = ci->irq;
+       }
 
        ret = stmpe_chip_init(stmpe);
        if (ret)
-               goto out_free;
+               goto free_gpio;
 
        ret = stmpe_irq_init(stmpe);
        if (ret)
-               goto out_free;
+               goto free_gpio;
 
-       ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
-                                  pdata->irq_trigger | IRQF_ONESHOT,
-                                  "stmpe", stmpe);
+       ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+                       pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
        if (ret) {
                dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
                goto out_removeirq;
@@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
 
 out_removedevs:
        mfd_remove_devices(stmpe->dev);
-       free_irq(stmpe->i2c->irq, stmpe);
+       free_irq(stmpe->irq, stmpe);
 out_removeirq:
        stmpe_irq_remove(stmpe);
+free_gpio:
+       if (pdata->irq_over_gpio)
+               gpio_free(pdata->irq_gpio);
 out_free:
        kfree(stmpe);
        return ret;
 }
 
-static int __devexit stmpe_remove(struct i2c_client *client)
+int stmpe_remove(struct stmpe *stmpe)
 {
-       struct stmpe *stmpe = i2c_get_clientdata(client);
-
        mfd_remove_devices(stmpe->dev);
 
-       free_irq(stmpe->i2c->irq, stmpe);
+       free_irq(stmpe->irq, stmpe);
        stmpe_irq_remove(stmpe);
 
+       if (stmpe->pdata->irq_over_gpio)
+               gpio_free(stmpe->pdata->irq_gpio);
+
        kfree(stmpe);
 
        return 0;
 }
 
-static const struct i2c_device_id stmpe_id[] = {
-       { "stmpe811", STMPE811 },
-       { "stmpe1601", STMPE1601 },
-       { "stmpe2401", STMPE2401 },
-       { "stmpe2403", STMPE2403 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, stmpe_id);
-
 #ifdef CONFIG_PM
-static const struct dev_pm_ops stmpe_dev_pm_ops = {
-       .suspend        = stmpe_suspend,
-       .resume         = stmpe_resume,
-};
-#endif
+static int stmpe_suspend(struct device *dev)
+{
+       struct stmpe *stmpe = dev_get_drvdata(dev);
 
-static struct i2c_driver stmpe_driver = {
-       .driver.name    = "stmpe",
-       .driver.owner   = THIS_MODULE,
-#ifdef CONFIG_PM
-       .driver.pm      = &stmpe_dev_pm_ops,
-#endif
-       .probe          = stmpe_probe,
-       .remove         = __devexit_p(stmpe_remove),
-       .id_table       = stmpe_id,
-};
+       if (device_may_wakeup(dev))
+               enable_irq_wake(stmpe->irq);
 
-static int __init stmpe_init(void)
-{
-       return i2c_add_driver(&stmpe_driver);
+       return 0;
 }
-subsys_initcall(stmpe_init);
 
-static void __exit stmpe_exit(void)
+static int stmpe_resume(struct device *dev)
 {
-       i2c_del_driver(&stmpe_driver);
+       struct stmpe *stmpe = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(stmpe->irq);
+
+       return 0;
 }
-module_exit(stmpe_exit);
 
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("STMPE MFD core driver");
-MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
+const struct dev_pm_ops stmpe_dev_pm_ops = {
+       .suspend        = stmpe_suspend,
+       .resume         = stmpe_resume,
+};
+#endif
index e4ee38956583069fbf912ac78e59279dbd6615e2..7b8e13f5b764dc5fde59a8dcb8389820abe017cd 100644 (file)
@@ -8,6 +8,14 @@
 #ifndef __STMPE_H
 #define __STMPE_H
 
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+extern const struct dev_pm_ops stmpe_dev_pm_ops;
+
 #ifdef STMPE_DUMP_BYTES
 static inline void stmpe_dump_bytes(const char *str, const void *buf,
                                    size_t len)
@@ -67,10 +75,54 @@ struct stmpe_variant_info {
        int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
 };
 
+/**
+ * struct stmpe_client_info - i2c or spi specific routines/info
+ * @data: client specific data
+ * @read_byte: read single byte
+ * @write_byte: write single byte
+ * @read_block: read block or multiple bytes
+ * @write_block: write block or multiple bytes
+ * @init: client init routine, called during probe
+ */
+struct stmpe_client_info {
+       void *data;
+       int irq;
+       void *client;
+       struct device *dev;
+       int (*read_byte)(struct stmpe *stmpe, u8 reg);
+       int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val);
+       int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values);
+       int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len,
+                       const u8 *values);
+       void (*init)(struct stmpe *stmpe);
+};
+
+int stmpe_probe(struct stmpe_client_info *ci, int partnum);
+int stmpe_remove(struct stmpe *stmpe);
+
 #define STMPE_ICR_LSB_HIGH     (1 << 2)
 #define STMPE_ICR_LSB_EDGE     (1 << 1)
 #define STMPE_ICR_LSB_GIM      (1 << 0)
 
+/*
+ * STMPE801
+ */
+#define STMPE801_ID                    0x0108
+#define STMPE801_NR_INTERNAL_IRQS      1
+
+#define STMPE801_REG_CHIP_ID           0x00
+#define STMPE801_REG_VERSION_ID                0x02
+#define STMPE801_REG_SYS_CTRL          0x04
+#define STMPE801_REG_GPIO_INT_EN       0x08
+#define STMPE801_REG_GPIO_INT_STA      0x09
+#define STMPE801_REG_GPIO_MP_STA       0x10
+#define STMPE801_REG_GPIO_SET_PIN      0x11
+#define STMPE801_REG_GPIO_DIR          0x12
+
+#define STMPE801_REG_SYS_CTRL_RESET    (1 << 7)
+#define STMPE801_REG_SYS_CTRL_INT_EN   (1 << 2)
+#define STMPE801_REG_SYS_CTRL_INT_HI   (1 << 0)
+
 /*
  * STMPE811
  */
@@ -87,6 +139,7 @@ struct stmpe_variant_info {
 
 #define STMPE811_REG_CHIP_ID           0x00
 #define STMPE811_REG_SYS_CTRL2         0x04
+#define STMPE811_REG_SPI_CFG           0x08
 #define STMPE811_REG_INT_CTRL          0x09
 #define STMPE811_REG_INT_EN            0x0A
 #define STMPE811_REG_INT_STA           0x0B
index 91ad21ef7721cddd335e5470717f3f878191bf0d..2d9e8799e733c6644c18aa9335e9796ef0c0709f 100644 (file)
@@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = {
 
 /*--------------------------------------------------------------------------*/
 
-static int __init t7l66xb_init(void)
-{
-       int retval = 0;
-
-       retval = platform_driver_register(&t7l66xb_platform_driver);
-       return retval;
-}
-
-static void __exit t7l66xb_exit(void)
-{
-       platform_driver_unregister(&t7l66xb_platform_driver);
-}
-
-module_init(t7l66xb_init);
-module_exit(t7l66xb_exit);
+module_platform_driver(t7l66xb_platform_driver);
 
 MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
 MODULE_LICENSE("GPL v2");
index 71bc835324d8743d55ff95383b03027652645f7b..d20a284ad4baca528c36eb351200ff16fdd5282e 100644 (file)
@@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = {
        .resume         = tc6387xb_resume,
 };
 
-
-static int __init tc6387xb_init(void)
-{
-       return platform_driver_register(&tc6387xb_platform_driver);
-}
-
-static void __exit tc6387xb_exit(void)
-{
-       platform_driver_unregister(&tc6387xb_platform_driver);
-}
-
-module_init(tc6387xb_init);
-module_exit(tc6387xb_exit);
+module_platform_driver(tc6387xb_platform_driver);
 
 MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
 MODULE_LICENSE("GPL v2");
index af9ab0e5ca64ac9f9f9f3fe1faed06fb6b13a0fb..4fb0e6c8e8fe0fbfee94299b7c0de45920621a25 100644 (file)
@@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = {
        }
 };
 
-static int __init ti_ssp_init(void)
-{
-       return platform_driver_register(&ti_ssp_driver);
-}
-module_init(ti_ssp_init);
-
-static void __exit ti_ssp_exit(void)
-{
-       platform_driver_unregister(&ti_ssp_driver);
-}
-module_exit(ti_ssp_exit);
+module_platform_driver(ti_ssp_driver);
 
 MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
 MODULE_AUTHOR("Cyril Chemparathy");
index 02d65692ceb415a1ae95a863dd660adda46807c9..0ba26fb12cf532f948fefa1e4df6599ce7db347b 100644 (file)
@@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev)
        kfree(priv);
 }
 
-static struct pci_device_id timberdale_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
        { 0 }
 };
index a56be931551c9ac7ee34e546a18891e8a2b6549d..95c0d7978bec4a67cfaa74d8c93b430dc715974b 100644 (file)
@@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 
 int tps65910_irq_exit(struct tps65910 *tps65910)
 {
-       free_irq(tps65910->chip_irq, tps65910);
+       if (tps65910->chip_irq)
+               free_irq(tps65910->chip_irq, tps65910);
        return 0;
 }
index c1da84bc1573f563c4b698f0bc786068e7f911bc..01cf5012a08fb26c3b561fde99341d6ab84749e2 100644 (file)
@@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
 
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
-       ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
-       if (ret < 0)
-               goto err;
+       tps65910_irq_init(tps65910, init_data->irq, init_data);
 
        kfree(init_data);
        return ret;
 
 err:
-       mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
        kfree(init_data);
        return ret;
@@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
 {
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
 
-       mfd_remove_devices(tps65910->dev);
        tps65910_irq_exit(tps65910);
+       mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
 
        return 0;
index 6d71e0d2574498abb3c5d22c4b91cb24fefe4c5b..27d3302d56b8f2b13bb8ffad371c33d67d3e529c 100644 (file)
@@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi)
 static struct spi_driver tps65912_spi_driver = {
        .driver = {
                .name = "tps65912",
-               .bus = &spi_bus_type,
                .owner = THIS_MODULE,
        },
        .probe  = tps65912_spi_probe,
index 61e70cfaa774fb977adcba8cc697a06edd673210..e04e04ddc15e41f933b2a58de5f3bc8d28e86c25 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/irqdomain.h>
 
 #include <linux/regulator/machine.h>
 
 
 #define TWL_MODULE_LAST TWL4030_MODULE_LAST
 
+#define TWL4030_NR_IRQS    8
+#define TWL6030_NR_IRQS    20
+
 /* Base Address defns for twl4030_map[] */
 
 /* subchip/slave 0 - USB ID */
@@ -255,6 +263,7 @@ struct twl_client {
 
 static struct twl_client twl_modules[TWL_NUM_SLAVES];
 
+static struct irq_domain domain;
 
 /* mapping the module id to slave id and base address */
 struct twl_mapping {
@@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
        int                             status;
        unsigned                        i;
        struct twl4030_platform_data    *pdata = client->dev.platform_data;
+       struct device_node              *node = client->dev.of_node;
        u8 temp;
        int ret = 0;
+       int nr_irqs = TWL4030_NR_IRQS;
+
+       if ((id->driver_data) & TWL6030_CLASS)
+               nr_irqs = TWL6030_NR_IRQS;
+
+       if (node && !pdata) {
+               /*
+                * XXX: Temporary pdata until the information is correctly
+                * retrieved by every TWL modules from DT.
+                */
+               pdata = devm_kzalloc(&client->dev,
+                                    sizeof(struct twl4030_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+       }
 
        if (!pdata) {
                dev_dbg(&client->dev, "no platform data?\n");
                return -EINVAL;
        }
 
+       status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
+       if (IS_ERR_VALUE(status)) {
+               dev_err(&client->dev, "Fail to allocate IRQ descs\n");
+               return status;
+       }
+
+       pdata->irq_base = status;
+       pdata->irq_end = pdata->irq_base + nr_irqs;
+
+       domain.irq_base = pdata->irq_base;
+       domain.nr_irq = nr_irqs;
+#ifdef CONFIG_OF_IRQ
+       domain.of_node = of_node_get(node);
+       domain.ops = &irq_domain_simple_ops;
+#endif
+       irq_domain_add(&domain);
+
        if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
                dev_dbg(&client->dev, "can't talk I2C?\n");
                return -EIO;
@@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
                twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
        }
 
-       status = add_children(pdata, id->driver_data);
+#ifdef CONFIG_OF_DEVICE
+       if (node)
+               status = of_platform_populate(node, NULL, NULL, &client->dev);
+       else
+#endif
+               status = add_children(pdata, id->driver_data);
+
 fail:
        if (status < 0)
                twl_remove(client);
index ae51ab5d0e5d935f9be35c0465b8cd20f07fdb47..838ce4eb444e24ce44bd3b120fe21a9f977d6e75 100644 (file)
@@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = {
        },
 };
 
-static int __devinit twl4030_audio_init(void)
-{
-       return platform_driver_register(&twl4030_audio_driver);
-}
-module_init(twl4030_audio_init);
-
-static void __devexit twl4030_audio_exit(void)
-{
-       platform_driver_unregister(&twl4030_audio_driver);
-}
-module_exit(twl4030_audio_exit);
+module_platform_driver(twl4030_audio_driver);
 
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
index 29f11e0765feef54093b839b6e288ae56bc0bf3f..b69bb517b102a4595b76342afeb58e0c9b3270c2 100644 (file)
@@ -492,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
                        u8      bytes[4];
                } imr;
 
-               /* byte[0] gets overwriten as we write ... */
+               /* byte[0] gets overwritten as we write ... */
                imr.word = cpu_to_le32(agent->imr << 8);
                agent->imr_change_pending = false;
 
@@ -667,6 +667,7 @@ int twl4030_sih_setup(int module)
                irq_set_chip_data(irq, agent);
                irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip,
                                         handle_edge_irq);
+               irq_set_nested_thread(irq, 1);
                activate_irq(irq);
        }
 
index 834f824d3c11075b18098a5c0b64a1abf066cd69..456ecb5ac4fe52e1a5515f1793eda270c5407056 100644 (file)
@@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = {
                   },
 };
 
-static int __init twl4030_madc_init(void)
-{
-       return platform_driver_register(&twl4030_madc_driver);
-}
-
-module_init(twl4030_madc_init);
-
-static void __exit twl4030_madc_exit(void)
-{
-       platform_driver_unregister(&twl4030_madc_driver);
-}
-
-module_exit(twl4030_madc_exit);
+module_platform_driver(twl4030_madc_driver);
 
 MODULE_DESCRIPTION("TWL4030 ADC driver");
 MODULE_LICENSE("GPL");
index a764676f09220146fb0ebc84addfe5e79ad9943e..d905f5171153e7f5ee3d8a808c493255883dd704 100644 (file)
@@ -34,7 +34,8 @@
 static u8 twl4030_start_script_address = 0x2b;
 
 #define PWR_P1_SW_EVENTS       0x10
-#define PWR_DEVOFF     (1<<0)
+#define PWR_DEVOFF             (1 << 0)
+#define SEQ_OFFSYNC            (1 << 0)
 
 #define PHY_TO_OFF_PM_MASTER(p)                (p - 0x36)
 #define PHY_TO_OFF_PM_RECEIVER(p)      (p - 0x5b)
@@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags)
        return err;
 }
 
+/*
+ * In master mode, start the power off sequence.
+ * After a successful execution, TWL shuts down the power to the SoC
+ * and all peripherals connected to it.
+ */
+void twl4030_power_off(void)
+{
+       int err;
+
+       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
+                              TWL4030_PM_MASTER_P1_SW_EVENTS);
+       if (err)
+               pr_err("TWL4030 Unable to power off\n");
+}
+
 void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
 {
        int err = 0;
        int i;
        struct twl4030_resconfig *resconfig;
-       u8 address = twl4030_start_script_address;
+       u8 val, address = twl4030_start_script_address;
 
        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
                        TWL4030_PM_MASTER_KEY_CFG1,
@@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
                }
        }
 
+       /* Board has to be wired properly to use this feature */
+       if (twl4030_scripts->use_poweroff && !pm_power_off) {
+               /* Default for SEQ_OFFSYNC is set, lets ensure this */
+               err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+                                     TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+               if (err) {
+                       pr_warning("TWL4030 Unable to read registers\n");
+
+               } else if (!(val & SEQ_OFFSYNC)) {
+                       val |= SEQ_OFFSYNC;
+                       err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+                                       TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+                       if (err) {
+                               pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
+                               goto relock;
+                       }
+               }
+
+               pm_power_off = twl4030_power_off;
+       }
+
+relock:
        err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
                        TWL4030_PM_MASTER_PROTECT_KEY);
        if (err)
index 268f80fd04394e2e7abca10d065d0be20625d37e..dda86293dc9fc0a3f8baaf678591d764824cfe14 100644 (file)
@@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
                twl6040->audpwron = -EINVAL;
 
        if (gpio_is_valid(twl6040->audpwron)) {
-               ret = gpio_request(twl6040->audpwron, "audpwron");
+               ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
+                                      "audpwron");
                if (ret)
                        goto gpio1_err;
-
-               ret = gpio_direction_output(twl6040->audpwron, 0);
-               if (ret)
-                       goto gpio2_err;
        }
 
        /* codec interrupt */
@@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = {
        },
 };
 
-static int __devinit twl6040_init(void)
-{
-       return platform_driver_register(&twl6040_driver);
-}
-module_init(twl6040_init);
-
-static void __devexit twl6040_exit(void)
-{
-       platform_driver_unregister(&twl6040_driver);
-}
-
-module_exit(twl6040_exit);
+module_platform_driver(twl6040_driver);
 
 MODULE_DESCRIPTION("TWL6040 MFD");
 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
index b281217334eb3c68d35c7695b8104dd327e6bcf6..91c4f25e0e558fe20a04ae10e1554d98f0f3fff9 100644 (file)
@@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex);
 static LIST_HEAD(ucb1x00_drivers);
 static LIST_HEAD(ucb1x00_devices);
 
+static struct mcp_device_id ucb1x00_id[] = {
+       { "ucb1x00", 0 },  /* auto-detection */
+       { "ucb1200", UCB_ID_1200 },
+       { "ucb1300", UCB_ID_1300 },
+       { "tc35143", UCB_ID_TC35143 },
+       { }
+};
+MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
+
 /**
  *     ucb1x00_io_set_dir - set IO direction
  *     @ucb: UCB1x00 structure describing chip
@@ -527,17 +536,33 @@ static struct class ucb1x00_class = {
 
 static int ucb1x00_probe(struct mcp *mcp)
 {
+       const struct mcp_device_id *mid;
        struct ucb1x00 *ucb;
        struct ucb1x00_driver *drv;
+       struct ucb1x00_plat_data *pdata;
        unsigned int id;
        int ret = -ENODEV;
        int temp;
 
        mcp_enable(mcp);
        id = mcp_reg_read(mcp, UCB_ID);
+       mid = mcp_get_device_id(mcp);
 
-       if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
-               printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
+       if (mid && mid->driver_data) {
+               if (id != mid->driver_data) {
+                       printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
+                               mid->name, (unsigned int) mid->driver_data, id);
+                       goto err_disable;
+               }
+       } else {
+               mid = &ucb1x00_id[1];
+               while (mid->driver_data) {
+                       if (id == mid->driver_data)
+                               break;
+                       mid++;
+               }
+               printk(KERN_WARNING "%s ID not found: %04x\n",
+                       ucb1x00_id[0].name, id);
                goto err_disable;
        }
 
@@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp)
        if (!ucb)
                goto err_disable;
 
-
+       pdata = mcp->attached_device.platform_data;
        ucb->dev.class = &ucb1x00_class;
        ucb->dev.parent = &mcp->attached_device;
-       dev_set_name(&ucb->dev, "ucb1x00");
+       dev_set_name(&ucb->dev, mid->name);
 
        spin_lock_init(&ucb->lock);
        spin_lock_init(&ucb->io_lock);
        sema_init(&ucb->adc_sem, 1);
 
-       ucb->id  = id;
+       ucb->id  = mid;
        ucb->mcp = mcp;
        ucb->irq = ucb1x00_detect_irq(ucb);
        if (ucb->irq == NO_IRQ) {
-               printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+               printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
                ret = -ENODEV;
                goto err_free;
        }
 
        ucb->gpio.base = -1;
-       if (mcp->gpio_base != 0) {
+       if (pdata && (pdata->gpio_base >= 0)) {
                ucb->gpio.label = dev_name(&ucb->dev);
-               ucb->gpio.base = mcp->gpio_base;
+               ucb->gpio.base = pdata->gpio_base;
                ucb->gpio.ngpio = 10;
                ucb->gpio.set = ucb1x00_gpio_set;
                ucb->gpio.get = ucb1x00_gpio_get;
@@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp)
                dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
 
        ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
-                         "UCB1x00", ucb);
+                         mid->name, ucb);
        if (ret) {
-               printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
-                       ucb->irq, ret);
+               printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
+                       mid->name, ucb->irq, ret);
                goto err_gpio;
        }
 
@@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = {
        .remove         = ucb1x00_remove,
        .suspend        = ucb1x00_suspend,
        .resume         = ucb1x00_resume,
+       .id_table       = ucb1x00_id,
 };
 
 static int __init ucb1x00_init(void)
index 38ffbd50a0d27bc24cbc9826c5dae1e95a54b560..40ec3c118868d7f02e104d2ed10e2f766840a0f4 100644 (file)
@@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
 
        idev->name       = "Touchscreen panel";
-       idev->id.product = ts->ucb->id;
+       idev->id.product = ts->ucb->id->driver_data;
        idev->open       = ucb1x00_ts_open;
        idev->close      = ucb1x00_ts_close;
 
index d698703dbd462c73b7267d9cd1a37a55bdd99d60..b73cc15e00818d4e15f2f44f9fe0a9f12e6196a6 100644 (file)
@@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static struct pci_device_id vx855_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
        { 0, }
 };
index 0a2b8d41a7020229223c7dcf5876d2d9cc532b43..f5e54fae8ada924bb029a1afe9a0239f3eb959b3 100644 (file)
@@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
                dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
                         buf[i], reg + i, reg + i);
                ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
+               if (ret != 0)
+                       return ret;
        }
 
        return 0;
@@ -1875,7 +1877,6 @@ err_irq:
 err_regmap:
        mfd_remove_devices(wm831x->dev);
        regmap_exit(wm831x->regmap);
-       kfree(wm831x);
        return ret;
 }
 
@@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x)
                free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
        wm831x_irq_exit(wm831x);
        regmap_exit(wm831x->regmap);
-       kfree(wm831x);
 }
 
 int wm831x_device_suspend(struct wm831x *wm831x)
index ac8da1d439daab72b9118ae6cf8675f3bac6dc9a..cb15609b0a4871ff7999498440703901fb511076 100644 (file)
@@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
        struct wm831x *wm831x;
        int ret;
 
-       wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+       wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
        if (wm831x == NULL)
                return -ENOMEM;
 
@@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
                ret = PTR_ERR(wm831x->regmap);
                dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
                        ret);
-               kfree(wm831x);
                return ret;
        }
 
index f4747a4a9a93fb8d3c906d5060442117860ddaf7..bec4d053916012a696442fff39b847be647b9db0 100644 (file)
@@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
        return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
 }
 
-static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
-{
-       return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
-}
-
 static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
                                                        int irq)
 {
@@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
        if (primary & WM831X_TCHDATA_INT)
                handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
-       if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
-               goto out;
+       primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
 
        for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
                int offset = wm831x_irqs[i].reg - 1;
index 8d6a9a969dbc246e87d46eb8bf38e0b62b796149..62ef3254105ffdebef5dcdcfa476a038ca14f997 100644 (file)
@@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
 
        type = (enum wm831x_parent)id->driver_data;
 
-       wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+       wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
        if (wm831x == NULL)
                return -ENOMEM;
 
@@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
                ret = PTR_ERR(wm831x->regmap);
                dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
                        ret);
-               kfree(wm831x);
                return ret;
        }
 
@@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
 static struct spi_driver wm831x_spi_driver = {
        .driver = {
                .name   = "wm831x",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
                .pm     = &wm831x_spi_pm,
        },
index e81cc31e42020a8ceff6620d73b3f251ca6aeffd..dd1caaac55e4d4138ccc69b19997793418a76e7d 100644 (file)
@@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
        u16 id1, id2, mask_rev;
        u16 cust_id, mode, chip_rev;
 
+       dev_set_drvdata(wm8350->dev, wm8350);
+
        /* get WM8350 revision and config mode */
        ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
        if (ret != 0) {
index 5fe5de166adb39bdafb2e7714ce046f58b6ccb3b..d955faaf27c4a8f824301ae5e3e34998f4333bf0 100644 (file)
@@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
        struct wm8350 *wm8350;
        int ret = 0;
 
-       wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+       wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL);
        if (wm8350 == NULL)
                return -ENOMEM;
 
@@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
        return ret;
 
 err:
-       kfree(wm8350);
        return ret;
 }
 
@@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
        struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
 
        wm8350_device_exit(wm8350);
-       kfree(wm8350);
 
        return 0;
 }
index 62b4626f4561029102ece804a7de96708186b2cb..2204893444a6ca6a4f2a245023169e1ff9e69379 100644 (file)
@@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
        struct wm8400 *wm8400;
        int ret;
 
-       wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+       wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
        if (wm8400 == NULL) {
                ret = -ENOMEM;
                goto err;
@@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
        wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
        if (IS_ERR(wm8400->regmap)) {
                ret = PTR_ERR(wm8400->regmap);
-               goto struct_err;
+               goto err;
        }
 
        wm8400->dev = &i2c->dev;
@@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
 
 map_err:
        regmap_exit(wm8400->regmap);
-struct_err:
-       kfree(wm8400);
 err:
        return ret;
 }
@@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
 
        wm8400_release(wm8400);
        regmap_exit(wm8400->regmap);
-       kfree(wm8400);
 
        return 0;
 }
index 61894fced8ea281570bf80320fd593efa0d25740..f117e7fb932194fc174ed52439dadcd57e81684c 100644 (file)
 #include <linux/mfd/wm8994/pdata.h>
 #include <linux/mfd/wm8994/registers.h>
 
-static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
-                      int bytes, void *dest)
-{
-       return regmap_raw_read(wm8994->regmap, reg, dest, bytes);
-}
+#include "wm8994.h"
 
 /**
  * wm8994_reg_read: Read a single WM8994 register.
@@ -68,12 +64,6 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
        return regmap_bulk_read(wm8994->regmap, reg, buf, count);
 }
 
-static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
-                       int bytes, const void *src)
-{
-       return regmap_raw_write(wm8994->regmap, reg, src, bytes);
-}
-
 /**
  * wm8994_reg_write: Write a single WM8994 register.
  *
@@ -252,6 +242,20 @@ static int wm8994_suspend(struct device *dev)
                break;
        }
 
+       switch (wm8994->type) {
+       case WM1811:
+               ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to read jackdet: %d\n", ret);
+               } else if (ret & WM1811_JACKDET_MODE_MASK) {
+                       dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+                       return 0;
+               }
+               break;
+       default:
+               break;
+       }
+
        /* Disable LDO pulldowns while the device is suspended if we
         * don't know that something will be driving them. */
        if (!wm8994->ldo_ena_always_driven)
@@ -259,25 +263,14 @@ static int wm8994_suspend(struct device *dev)
                                WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
                                WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
 
-       /* GPIO configuration state is saved here since we may be configuring
-        * the GPIO alternate functions even if we're not using the gpiolib
-        * driver for them.
-        */
-       ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
-                         &wm8994->gpio_regs);
-       if (ret < 0)
-               dev_err(dev, "Failed to save GPIO registers: %d\n", ret);
-
-       /* For similar reasons we also stash the regulator states */
-       ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
-                         &wm8994->ldo_regs);
-       if (ret < 0)
-               dev_err(dev, "Failed to save LDO registers: %d\n", ret);
-
        /* Explicitly put the device into reset in case regulators
         * don't get disabled in order to ensure consistent restart.
         */
-       wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994);
+       wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+                        wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+
+       regcache_cache_only(wm8994->regmap, true);
+       regcache_mark_dirty(wm8994->regmap);
 
        wm8994->suspended = true;
 
@@ -294,7 +287,7 @@ static int wm8994_suspend(struct device *dev)
 static int wm8994_resume(struct device *dev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
-       int ret, i;
+       int ret;
 
        /* We may have lied to the PM core about suspending */
        if (!wm8994->suspended)
@@ -307,27 +300,13 @@ static int wm8994_resume(struct device *dev)
                return ret;
        }
 
-       /* Write register at a time as we use the cache on the CPU so store
-        * it in native endian.
-        */
-       for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
-               ret = wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK
-                                      + i, wm8994->irq_masks_cur[i]);
-               if (ret < 0)
-                       dev_err(dev, "Failed to restore interrupt masks: %d\n",
-                               ret);
+       regcache_cache_only(wm8994->regmap, false);
+       ret = regcache_sync(wm8994->regmap);
+       if (ret != 0) {
+               dev_err(dev, "Failed to restore register map: %d\n", ret);
+               goto err_enable;
        }
 
-       ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
-                          &wm8994->ldo_regs);
-       if (ret < 0)
-               dev_err(dev, "Failed to restore LDO registers: %d\n", ret);
-
-       ret = wm8994_write(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
-                          &wm8994->gpio_regs);
-       if (ret < 0)
-               dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
-
        /* Disable LDO pulldowns while the device is active */
        wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
                        WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
@@ -336,6 +315,11 @@ static int wm8994_resume(struct device *dev)
        wm8994->suspended = false;
 
        return 0;
+
+err_enable:
+       regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
+
+       return ret;
 }
 #endif
 
@@ -361,19 +345,16 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
 }
 #endif
 
-static struct regmap_config wm8994_regmap_config = {
-       .reg_bits = 16,
-       .val_bits = 16,
-};
-
 /*
  * Instantiate the generic non-control parts of the device.
  */
 static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 {
        struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       struct regmap_config *regmap_config;
        const char *devname;
        int ret, i;
+       int pulls = 0;
 
        dev_set_drvdata(wm8994->dev, wm8994);
 
@@ -402,9 +383,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err_regmap;
        }
 
-       wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
-                                  wm8994->num_supplies,
-                                  GFP_KERNEL);
+       wm8994->supplies = devm_kzalloc(wm8994->dev,
+                                       sizeof(struct regulator_bulk_data) *
+                                       wm8994->num_supplies, GFP_KERNEL);
        if (!wm8994->supplies) {
                ret = -ENOMEM;
                goto err_regmap;
@@ -432,7 +413,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                                 wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
-               goto err_supplies;
+               goto err_regmap;
        }
 
        ret = regulator_bulk_enable(wm8994->num_supplies,
@@ -482,25 +463,54 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                        ret);
                goto err_enable;
        }
+       wm8994->revision = ret;
 
        switch (wm8994->type) {
        case WM8994:
-               switch (ret) {
+               switch (wm8994->revision) {
                case 0:
                case 1:
                        dev_warn(wm8994->dev,
                                 "revision %c not fully supported\n",
-                                'A' + ret);
+                                'A' + wm8994->revision);
                        break;
                default:
                        break;
                }
                break;
+       case WM1811:
+               /* Revision C did not change the relevant layer */
+               if (wm8994->revision > 1)
+                       wm8994->revision++;
+               break;
        default:
                break;
        }
 
-       dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
+       dev_info(wm8994->dev, "%s revision %c\n", devname,
+                'A' + wm8994->revision);
+
+       switch (wm8994->type) {
+       case WM1811:
+               regmap_config = &wm1811_regmap_config;
+               break;
+       case WM8994:
+               regmap_config = &wm8994_regmap_config;
+               break;
+       case WM8958:
+               regmap_config = &wm8958_regmap_config;
+               break;
+       default:
+               dev_err(wm8994->dev, "Unknown device type %d\n", wm8994->type);
+               return -EINVAL;
+       }
+
+       ret = regmap_reinit_cache(wm8994->regmap, regmap_config);
+       if (ret != 0) {
+               dev_err(wm8994->dev, "Failed to reinit register cache: %d\n",
+                       ret);
+               return ret;
+       }
 
        if (pdata) {
                wm8994->irq_base = pdata->irq_base;
@@ -516,12 +526,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                }
 
                wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
+
+               if (pdata->spkmode_pu)
+                       pulls |= WM8994_SPKMODE_PU;
        }
 
-       /* Disable LDO pulldowns while the device is active */
+       /* Disable unneeded pulls */
        wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
-                       WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
-                       0);
+                       WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD |
+                       WM8994_SPKMODE_PU | WM8994_CSNADDR_PD,
+                       pulls);
 
        /* In some system designs where the regulators are not in use,
         * we can achieve a small reduction in leakage currents by
@@ -560,12 +574,9 @@ err_enable:
                               wm8994->supplies);
 err_get:
        regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
-err_supplies:
-       kfree(wm8994->supplies);
 err_regmap:
        regmap_exit(wm8994->regmap);
        mfd_remove_devices(wm8994->dev);
-       kfree(wm8994);
        return ret;
 }
 
@@ -577,18 +588,24 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
        regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
        regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
-       kfree(wm8994->supplies);
        regmap_exit(wm8994->regmap);
-       kfree(wm8994);
 }
 
+static const struct of_device_id wm8994_of_match[] = {
+       { .compatible = "wlf,wm1811", },
+       { .compatible = "wlf,wm8994", },
+       { .compatible = "wlf,wm8958", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wm8994_of_match);
+
 static int wm8994_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8994 *wm8994;
        int ret;
 
-       wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
+       wm8994 = devm_kzalloc(&i2c->dev, sizeof(struct wm8994), GFP_KERNEL);
        if (wm8994 == NULL)
                return -ENOMEM;
 
@@ -597,12 +614,11 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
        wm8994->irq = i2c->irq;
        wm8994->type = id->driver_data;
 
-       wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config);
+       wm8994->regmap = regmap_init_i2c(i2c, &wm8994_base_regmap_config);
        if (IS_ERR(wm8994->regmap)) {
                ret = PTR_ERR(wm8994->regmap);
                dev_err(wm8994->dev, "Failed to allocate register map: %d\n",
                        ret);
-               kfree(wm8994);
                return ret;
        }
 
@@ -620,6 +636,7 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
 
 static const struct i2c_device_id wm8994_i2c_id[] = {
        { "wm1811", WM1811 },
+       { "wm1811a", WM1811 },
        { "wm8994", WM8994 },
        { "wm8958", WM8958 },
        { }
@@ -634,6 +651,7 @@ static struct i2c_driver wm8994_i2c_driver = {
                .name = "wm8994",
                .owner = THIS_MODULE,
                .pm = &wm8994_pm_ops,
+               .of_match_table = wm8994_of_match,
        },
        .probe = wm8994_i2c_probe,
        .remove = wm8994_i2c_remove,
index d682f7bd112cecf45519ceb178404c958c0f4747..46b20c445ecfdfa8e1d6f189344e8d037a503f2c 100644 (file)
 #include <linux/irq.h>
 #include <linux/mfd/core.h>
 #include <linux/interrupt.h>
+#include <linux/regmap.h>
 
 #include <linux/mfd/wm8994/core.h>
 #include <linux/mfd/wm8994/registers.h>
 
 #include <linux/delay.h>
 
-struct wm8994_irq_data {
-       int reg;
-       int mask;
-};
-
-static struct wm8994_irq_data wm8994_irqs[] = {
+static struct regmap_irq wm8994_irqs[] = {
        [WM8994_IRQ_TEMP_SHUT] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_TEMP_SHUT_EINT,
        },
        [WM8994_IRQ_MIC1_DET] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_MIC1_DET_EINT,
        },
        [WM8994_IRQ_MIC1_SHRT] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_MIC1_SHRT_EINT,
        },
        [WM8994_IRQ_MIC2_DET] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_MIC2_DET_EINT,
        },
        [WM8994_IRQ_MIC2_SHRT] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_MIC2_SHRT_EINT,
        },
        [WM8994_IRQ_FLL1_LOCK] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_FLL1_LOCK_EINT,
        },
        [WM8994_IRQ_FLL2_LOCK] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_FLL2_LOCK_EINT,
        },
        [WM8994_IRQ_SRC1_LOCK] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_SRC1_LOCK_EINT,
        },
        [WM8994_IRQ_SRC2_LOCK] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_SRC2_LOCK_EINT,
        },
        [WM8994_IRQ_AIF1DRC1_SIG_DET] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_AIF1DRC1_SIG_DET,
        },
        [WM8994_IRQ_AIF1DRC2_SIG_DET] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_AIF1DRC2_SIG_DET_EINT,
        },
        [WM8994_IRQ_AIF2DRC_SIG_DET] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_AIF2DRC_SIG_DET_EINT,
        },
        [WM8994_IRQ_FIFOS_ERR] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_FIFOS_ERR_EINT,
        },
        [WM8994_IRQ_WSEQ_DONE] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_WSEQ_DONE_EINT,
        },
        [WM8994_IRQ_DCS_DONE] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_DCS_DONE_EINT,
        },
        [WM8994_IRQ_TEMP_WARN] = {
-               .reg = 2,
+               .reg_offset = 1,
                .mask = WM8994_TEMP_WARN_EINT,
        },
        [WM8994_IRQ_GPIO(1)] = {
-               .reg = 1,
                .mask = WM8994_GP1_EINT,
        },
        [WM8994_IRQ_GPIO(2)] = {
-               .reg = 1,
                .mask = WM8994_GP2_EINT,
        },
        [WM8994_IRQ_GPIO(3)] = {
-               .reg = 1,
                .mask = WM8994_GP3_EINT,
        },
        [WM8994_IRQ_GPIO(4)] = {
-               .reg = 1,
                .mask = WM8994_GP4_EINT,
        },
        [WM8994_IRQ_GPIO(5)] = {
-               .reg = 1,
                .mask = WM8994_GP5_EINT,
        },
        [WM8994_IRQ_GPIO(6)] = {
-               .reg = 1,
                .mask = WM8994_GP6_EINT,
        },
        [WM8994_IRQ_GPIO(7)] = {
-               .reg = 1,
                .mask = WM8994_GP7_EINT,
        },
        [WM8994_IRQ_GPIO(8)] = {
-               .reg = 1,
                .mask = WM8994_GP8_EINT,
        },
        [WM8994_IRQ_GPIO(9)] = {
-               .reg = 1,
                .mask = WM8994_GP8_EINT,
        },
        [WM8994_IRQ_GPIO(10)] = {
-               .reg = 1,
                .mask = WM8994_GP10_EINT,
        },
        [WM8994_IRQ_GPIO(11)] = {
-               .reg = 1,
                .mask = WM8994_GP11_EINT,
        },
 };
 
-static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data)
-{
-       return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
-}
-
-static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data)
-{
-       return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
-}
-
-static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
-                                                       int irq)
-{
-       return &wm8994_irqs[irq - wm8994->irq_base];
-}
-
-static void wm8994_irq_lock(struct irq_data *data)
-{
-       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
-
-       mutex_lock(&wm8994->irq_lock);
-}
-
-static void wm8994_irq_sync_unlock(struct irq_data *data)
-{
-       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
-               /* If there's been a change in the mask write it back
-                * to the hardware. */
-               if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
-                       wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
-                       wm8994_reg_write(wm8994,
-                                        WM8994_INTERRUPT_STATUS_1_MASK + i,
-                                        wm8994->irq_masks_cur[i]);
-               }
-       }
-
-       mutex_unlock(&wm8994->irq_lock);
-}
-
-static void wm8994_irq_enable(struct irq_data *data)
-{
-       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
-       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
-                                                            data->irq);
-
-       wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
-}
-
-static void wm8994_irq_disable(struct irq_data *data)
-{
-       struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
-       struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
-                                                            data->irq);
-
-       wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
-}
+static struct regmap_irq_chip wm8994_irq_chip = {
+       .name = "wm8994",
+       .irqs = wm8994_irqs,
+       .num_irqs = ARRAY_SIZE(wm8994_irqs),
 
-static struct irq_chip wm8994_irq_chip = {
-       .name                   = "wm8994",
-       .irq_bus_lock           = wm8994_irq_lock,
-       .irq_bus_sync_unlock    = wm8994_irq_sync_unlock,
-       .irq_disable            = wm8994_irq_disable,
-       .irq_enable             = wm8994_irq_enable,
+       .num_regs = 2,
+       .status_base = WM8994_INTERRUPT_STATUS_1,
+       .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
+       .ack_base = WM8994_INTERRUPT_STATUS_1,
 };
 
-/* The processing of the primary interrupt occurs in a thread so that
- * we can interact with the device over I2C or SPI. */
-static irqreturn_t wm8994_irq_thread(int irq, void *data)
-{
-       struct wm8994 *wm8994 = data;
-       unsigned int i;
-       u16 status[WM8994_NUM_IRQ_REGS];
-       int ret;
-
-       ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
-                              WM8994_NUM_IRQ_REGS, status);
-       if (ret < 0) {
-               dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
-                       ret);
-               return IRQ_NONE;
-       }
-
-       /* Bit swap and apply masking */
-       for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
-               status[i] = be16_to_cpu(status[i]);
-               status[i] &= ~wm8994->irq_masks_cur[i];
-       }
-
-       /* Ack any unmasked IRQs */
-       for (i = 0; i < ARRAY_SIZE(status); i++) {
-               if (status[i])
-                       wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
-                                        status[i]);
-       }
-
-       /* Report */
-       for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
-               if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
-                       handle_nested_irq(wm8994->irq_base + i);
-       }
-
-       return IRQ_HANDLED;
-}
-
 int wm8994_irq_init(struct wm8994 *wm8994)
 {
-       int i, cur_irq, ret;
-
-       mutex_init(&wm8994->irq_lock);
-
-       /* Mask the individual interrupt sources */
-       for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
-               wm8994->irq_masks_cur[i] = 0xffff;
-               wm8994->irq_masks_cache[i] = 0xffff;
-               wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
-                                0xffff);
-       }
+       int ret;
 
        if (!wm8994->irq) {
                dev_warn(wm8994->dev,
@@ -274,30 +153,12 @@ int wm8994_irq_init(struct wm8994 *wm8994)
                return 0;
        }
 
-       /* Register them with genirq */
-       for (cur_irq = wm8994->irq_base;
-            cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base;
-            cur_irq++) {
-               irq_set_chip_data(cur_irq, wm8994);
-               irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip,
-                                        handle_edge_irq);
-               irq_set_nested_thread(cur_irq, 1);
-
-               /* ARM needs us to explicitly flag the IRQ as valid
-                * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
-               set_irq_flags(cur_irq, IRQF_VALID);
-#else
-               irq_set_noprobe(cur_irq);
-#endif
-       }
-
-       ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
-                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                                  "wm8994", wm8994);
+       ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
+                                 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                 wm8994->irq_base, &wm8994_irq_chip,
+                                 &wm8994->irq_data);
        if (ret != 0) {
-               dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n",
-                       wm8994->irq, ret);
+               dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
                return ret;
        }
 
@@ -309,6 +170,5 @@ int wm8994_irq_init(struct wm8994 *wm8994)
 
 void wm8994_irq_exit(struct wm8994 *wm8994)
 {
-       if (wm8994->irq)
-               free_irq(wm8994->irq, wm8994);
+       regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
 }
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c
new file mode 100644 (file)
index 0000000..c598ae6
--- /dev/null
@@ -0,0 +1,1238 @@
+/*
+ * wm8994-regmap.c  --  Register map data for WM8994 series devices
+ *
+ * Copyright 2011 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.
+ *
+ */
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/regmap.h>
+
+#include "wm8994.h"
+
+static struct reg_default wm1811_defaults[] = {
+       { 0x0000, 0x1811 },    /* R0    - Software Reset */
+       { 0x0001, 0x0000 },    /* R1    - Power Management (1) */
+       { 0x0002, 0x6000 },    /* R2    - Power Management (2) */
+       { 0x0003, 0x0000 },    /* R3    - Power Management (3) */
+       { 0x0004, 0x0000 },    /* R4    - Power Management (4) */
+       { 0x0005, 0x0000 },    /* R5    - Power Management (5) */
+       { 0x0006, 0x0000 },    /* R6    - Power Management (6) */
+       { 0x0015, 0x0000 },    /* R21   - Input Mixer (1) */
+       { 0x0018, 0x008B },    /* R24   - Left Line Input 1&2 Volume */
+       { 0x0019, 0x008B },    /* R25   - Left Line Input 3&4 Volume */
+       { 0x001A, 0x008B },    /* R26   - Right Line Input 1&2 Volume */
+       { 0x001B, 0x008B },    /* R27   - Right Line Input 3&4 Volume */
+       { 0x001C, 0x006D },    /* R28   - Left Output Volume */
+       { 0x001D, 0x006D },    /* R29   - Right Output Volume */
+       { 0x001E, 0x0066 },    /* R30   - Line Outputs Volume */
+       { 0x001F, 0x0020 },    /* R31   - HPOUT2 Volume */
+       { 0x0020, 0x0079 },    /* R32   - Left OPGA Volume */
+       { 0x0021, 0x0079 },    /* R33   - Right OPGA Volume */
+       { 0x0022, 0x0003 },    /* R34   - SPKMIXL Attenuation */
+       { 0x0023, 0x0003 },    /* R35   - SPKMIXR Attenuation */
+       { 0x0024, 0x0011 },    /* R36   - SPKOUT Mixers */
+       { 0x0025, 0x0140 },    /* R37   - ClassD */
+       { 0x0026, 0x0079 },    /* R38   - Speaker Volume Left */
+       { 0x0027, 0x0079 },    /* R39   - Speaker Volume Right */
+       { 0x0028, 0x0000 },    /* R40   - Input Mixer (2) */
+       { 0x0029, 0x0000 },    /* R41   - Input Mixer (3) */
+       { 0x002A, 0x0000 },    /* R42   - Input Mixer (4) */
+       { 0x002B, 0x0000 },    /* R43   - Input Mixer (5) */
+       { 0x002C, 0x0000 },    /* R44   - Input Mixer (6) */
+       { 0x002D, 0x0000 },    /* R45   - Output Mixer (1) */
+       { 0x002E, 0x0000 },    /* R46   - Output Mixer (2) */
+       { 0x002F, 0x0000 },    /* R47   - Output Mixer (3) */
+       { 0x0030, 0x0000 },    /* R48   - Output Mixer (4) */
+       { 0x0031, 0x0000 },    /* R49   - Output Mixer (5) */
+       { 0x0032, 0x0000 },    /* R50   - Output Mixer (6) */
+       { 0x0033, 0x0000 },    /* R51   - HPOUT2 Mixer */
+       { 0x0034, 0x0000 },    /* R52   - Line Mixer (1) */
+       { 0x0035, 0x0000 },    /* R53   - Line Mixer (2) */
+       { 0x0036, 0x0000 },    /* R54   - Speaker Mixer */
+       { 0x0037, 0x0000 },    /* R55   - Additional Control */
+       { 0x0038, 0x0000 },    /* R56   - AntiPOP (1) */
+       { 0x0039, 0x0180 },    /* R57   - AntiPOP (2) */
+       { 0x003B, 0x000D },    /* R59   - LDO 1 */
+       { 0x003C, 0x0003 },    /* R60   - LDO 2 */
+       { 0x003D, 0x0039 },    /* R61   - MICBIAS1 */
+       { 0x003E, 0x0039 },    /* R62   - MICBIAS2 */
+       { 0x004C, 0x1F25 },    /* R76   - Charge Pump (1) */
+       { 0x004D, 0xAB19 },    /* R77   - Charge Pump (2) */
+       { 0x0051, 0x0004 },    /* R81   - Class W (1) */
+       { 0x0054, 0x0000 },    /* R84   - DC Servo (1) */
+       { 0x0055, 0x054A },    /* R85   - DC Servo (2) */
+       { 0x0058, 0x0000 },    /* R88   - DC Servo Readback */
+       { 0x0059, 0x0000 },    /* R89   - DC Servo (4) */
+       { 0x0060, 0x0000 },    /* R96   - Analogue HP (1) */
+       { 0x00C5, 0x0000 },    /* R197  - Class D Test (5) */
+       { 0x00D0, 0x7600 },    /* R208  - Mic Detect 1 */
+       { 0x00D1, 0x007F },    /* R209  - Mic Detect 2 */
+       { 0x00D2, 0x0000 },    /* R210  - Mic Detect 3 */
+       { 0x0100, 0x0100 },    /* R256  - Chip Revision */
+       { 0x0101, 0x8004 },    /* R257  - Control Interface */
+       { 0x0200, 0x0000 },    /* R512  - AIF1 Clocking (1) */
+       { 0x0201, 0x0000 },    /* R513  - AIF1 Clocking (2) */
+       { 0x0204, 0x0000 },    /* R516  - AIF2 Clocking (1) */
+       { 0x0205, 0x0000 },    /* R517  - AIF2 Clocking (2) */
+       { 0x0208, 0x0000 },    /* R520  - Clocking (1) */
+       { 0x0209, 0x0000 },    /* R521  - Clocking (2) */
+       { 0x0210, 0x0083 },    /* R528  - AIF1 Rate */
+       { 0x0211, 0x0083 },    /* R529  - AIF2 Rate */
+       { 0x0212, 0x0000 },    /* R530  - Rate Status */
+       { 0x0220, 0x0000 },    /* R544  - FLL1 Control (1) */
+       { 0x0221, 0x0000 },    /* R545  - FLL1 Control (2) */
+       { 0x0222, 0x0000 },    /* R546  - FLL1 Control (3) */
+       { 0x0223, 0x0000 },    /* R547  - FLL1 Control (4) */
+       { 0x0224, 0x0C80 },    /* R548  - FLL1 Control (5) */
+       { 0x0226, 0x0000 },    /* R550  - FLL1 EFS 1 */
+       { 0x0227, 0x0006 },    /* R551  - FLL1 EFS 2 */
+       { 0x0240, 0x0000 },    /* R576  - FLL2Control (1) */
+       { 0x0241, 0x0000 },    /* R577  - FLL2Control (2) */
+       { 0x0242, 0x0000 },    /* R578  - FLL2Control (3) */
+       { 0x0243, 0x0000 },    /* R579  - FLL2 Control (4) */
+       { 0x0244, 0x0C80 },    /* R580  - FLL2Control (5) */
+       { 0x0246, 0x0000 },    /* R582  - FLL2 EFS 1 */
+       { 0x0247, 0x0006 },    /* R583  - FLL2 EFS 2 */
+       { 0x0300, 0x4050 },    /* R768  - AIF1 Control (1) */
+       { 0x0301, 0x4000 },    /* R769  - AIF1 Control (2) */
+       { 0x0302, 0x0000 },    /* R770  - AIF1 Master/Slave */
+       { 0x0303, 0x0040 },    /* R771  - AIF1 BCLK */
+       { 0x0304, 0x0040 },    /* R772  - AIF1ADC LRCLK */
+       { 0x0305, 0x0040 },    /* R773  - AIF1DAC LRCLK */
+       { 0x0306, 0x0004 },    /* R774  - AIF1DAC Data */
+       { 0x0307, 0x0100 },    /* R775  - AIF1ADC Data */
+       { 0x0310, 0x4050 },    /* R784  - AIF2 Control (1) */
+       { 0x0311, 0x4000 },    /* R785  - AIF2 Control (2) */
+       { 0x0312, 0x0000 },    /* R786  - AIF2 Master/Slave */
+       { 0x0313, 0x0040 },    /* R787  - AIF2 BCLK */
+       { 0x0314, 0x0040 },    /* R788  - AIF2ADC LRCLK */
+       { 0x0315, 0x0040 },    /* R789  - AIF2DAC LRCLK */
+       { 0x0316, 0x0000 },    /* R790  - AIF2DAC Data */
+       { 0x0317, 0x0000 },    /* R791  - AIF2ADC Data */
+       { 0x0318, 0x0003 },    /* R792  - AIF2TX Control */
+       { 0x0320, 0x0040 },    /* R800  - AIF3 Control (1) */
+       { 0x0321, 0x0000 },    /* R801  - AIF3 Control (2) */
+       { 0x0322, 0x0000 },    /* R802  - AIF3DAC Data */
+       { 0x0323, 0x0000 },    /* R803  - AIF3ADC Data */
+       { 0x0400, 0x00C0 },    /* R1024 - AIF1 ADC1 Left Volume */
+       { 0x0401, 0x00C0 },    /* R1025 - AIF1 ADC1 Right Volume */
+       { 0x0402, 0x00C0 },    /* R1026 - AIF1 DAC1 Left Volume */
+       { 0x0403, 0x00C0 },    /* R1027 - AIF1 DAC1 Right Volume */
+       { 0x0410, 0x0000 },    /* R1040 - AIF1 ADC1 Filters */
+       { 0x0420, 0x0200 },    /* R1056 - AIF1 DAC1 Filters (1) */
+       { 0x0421, 0x0010 },    /* R1057 - AIF1 DAC1 Filters (2) */
+       { 0x0430, 0x0068 },    /* R1072 - AIF1 DAC1 Noise Gate */
+       { 0x0440, 0x0098 },    /* R1088 - AIF1 DRC1 (1) */
+       { 0x0441, 0x0845 },    /* R1089 - AIF1 DRC1 (2) */
+       { 0x0442, 0x0000 },    /* R1090 - AIF1 DRC1 (3) */
+       { 0x0443, 0x0000 },    /* R1091 - AIF1 DRC1 (4) */
+       { 0x0444, 0x0000 },    /* R1092 - AIF1 DRC1 (5) */
+       { 0x0480, 0x6318 },    /* R1152 - AIF1 DAC1 EQ Gains (1) */
+       { 0x0481, 0x6300 },    /* R1153 - AIF1 DAC1 EQ Gains (2) */
+       { 0x0482, 0x0FCA },    /* R1154 - AIF1 DAC1 EQ Band 1 A */
+       { 0x0483, 0x0400 },    /* R1155 - AIF1 DAC1 EQ Band 1 B */
+       { 0x0484, 0x00D8 },    /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+       { 0x0485, 0x1EB5 },    /* R1157 - AIF1 DAC1 EQ Band 2 A */
+       { 0x0486, 0xF145 },    /* R1158 - AIF1 DAC1 EQ Band 2 B */
+       { 0x0487, 0x0B75 },    /* R1159 - AIF1 DAC1 EQ Band 2 C */
+       { 0x0488, 0x01C5 },    /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+       { 0x0489, 0x1C58 },    /* R1161 - AIF1 DAC1 EQ Band 3 A */
+       { 0x048A, 0xF373 },    /* R1162 - AIF1 DAC1 EQ Band 3 B */
+       { 0x048B, 0x0A54 },    /* R1163 - AIF1 DAC1 EQ Band 3 C */
+       { 0x048C, 0x0558 },    /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+       { 0x048D, 0x168E },    /* R1165 - AIF1 DAC1 EQ Band 4 A */
+       { 0x048E, 0xF829 },    /* R1166 - AIF1 DAC1 EQ Band 4 B */
+       { 0x048F, 0x07AD },    /* R1167 - AIF1 DAC1 EQ Band 4 C */
+       { 0x0490, 0x1103 },    /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+       { 0x0491, 0x0564 },    /* R1169 - AIF1 DAC1 EQ Band 5 A */
+       { 0x0492, 0x0559 },    /* R1170 - AIF1 DAC1 EQ Band 5 B */
+       { 0x0493, 0x4000 },    /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+       { 0x0494, 0x0000 },    /* R1172 - AIF1 DAC1 EQ Band 1 C */
+       { 0x0500, 0x00C0 },    /* R1280 - AIF2 ADC Left Volume */
+       { 0x0501, 0x00C0 },    /* R1281 - AIF2 ADC Right Volume */
+       { 0x0502, 0x00C0 },    /* R1282 - AIF2 DAC Left Volume */
+       { 0x0503, 0x00C0 },    /* R1283 - AIF2 DAC Right Volume */
+       { 0x0510, 0x0000 },    /* R1296 - AIF2 ADC Filters */
+       { 0x0520, 0x0200 },    /* R1312 - AIF2 DAC Filters (1) */
+       { 0x0521, 0x0010 },    /* R1313 - AIF2 DAC Filters (2) */
+       { 0x0530, 0x0068 },    /* R1328 - AIF2 DAC Noise Gate */
+       { 0x0540, 0x0098 },    /* R1344 - AIF2 DRC (1) */
+       { 0x0541, 0x0845 },    /* R1345 - AIF2 DRC (2) */
+       { 0x0542, 0x0000 },    /* R1346 - AIF2 DRC (3) */
+       { 0x0543, 0x0000 },    /* R1347 - AIF2 DRC (4) */
+       { 0x0544, 0x0000 },    /* R1348 - AIF2 DRC (5) */
+       { 0x0580, 0x6318 },    /* R1408 - AIF2 EQ Gains (1) */
+       { 0x0581, 0x6300 },    /* R1409 - AIF2 EQ Gains (2) */
+       { 0x0582, 0x0FCA },    /* R1410 - AIF2 EQ Band 1 A */
+       { 0x0583, 0x0400 },    /* R1411 - AIF2 EQ Band 1 B */
+       { 0x0584, 0x00D8 },    /* R1412 - AIF2 EQ Band 1 PG */
+       { 0x0585, 0x1EB5 },    /* R1413 - AIF2 EQ Band 2 A */
+       { 0x0586, 0xF145 },    /* R1414 - AIF2 EQ Band 2 B */
+       { 0x0587, 0x0B75 },    /* R1415 - AIF2 EQ Band 2 C */
+       { 0x0588, 0x01C5 },    /* R1416 - AIF2 EQ Band 2 PG */
+       { 0x0589, 0x1C58 },    /* R1417 - AIF2 EQ Band 3 A */
+       { 0x058A, 0xF373 },    /* R1418 - AIF2 EQ Band 3 B */
+       { 0x058B, 0x0A54 },    /* R1419 - AIF2 EQ Band 3 C */
+       { 0x058C, 0x0558 },    /* R1420 - AIF2 EQ Band 3 PG */
+       { 0x058D, 0x168E },    /* R1421 - AIF2 EQ Band 4 A */
+       { 0x058E, 0xF829 },    /* R1422 - AIF2 EQ Band 4 B */
+       { 0x058F, 0x07AD },    /* R1423 - AIF2 EQ Band 4 C */
+       { 0x0590, 0x1103 },    /* R1424 - AIF2 EQ Band 4 PG */
+       { 0x0591, 0x0564 },    /* R1425 - AIF2 EQ Band 5 A */
+       { 0x0592, 0x0559 },    /* R1426 - AIF2 EQ Band 5 B */
+       { 0x0593, 0x4000 },    /* R1427 - AIF2 EQ Band 5 PG */
+       { 0x0594, 0x0000 },    /* R1428 - AIF2 EQ Band 1 C */
+       { 0x0600, 0x0000 },    /* R1536 - DAC1 Mixer Volumes */
+       { 0x0601, 0x0000 },    /* R1537 - DAC1 Left Mixer Routing */
+       { 0x0602, 0x0000 },    /* R1538 - DAC1 Right Mixer Routing */
+       { 0x0603, 0x0000 },    /* R1539 - AIF2ADC Mixer Volumes */
+       { 0x0604, 0x0000 },    /* R1540 - AIF2ADC Left Mixer Routing */
+       { 0x0605, 0x0000 },    /* R1541 - AIF2ADC Right Mixer Routing */
+       { 0x0606, 0x0000 },    /* R1542 - AIF1 ADC1 Left Mixer Routing */
+       { 0x0607, 0x0000 },    /* R1543 - AIF1 ADC1 Right Mixer Routing */
+       { 0x0610, 0x02C0 },    /* R1552 - DAC1 Left Volume */
+       { 0x0611, 0x02C0 },    /* R1553 - DAC1 Right Volume */
+       { 0x0612, 0x02C0 },    /* R1554 - AIF2TX Left Volume */
+       { 0x0613, 0x02C0 },    /* R1555 - AIF2TX Right Volume */
+       { 0x0614, 0x0000 },    /* R1556 - DAC Softmute */
+       { 0x0620, 0x0002 },    /* R1568 - Oversampling */
+       { 0x0621, 0x0000 },    /* R1569 - Sidetone */
+       { 0x0700, 0x8100 },    /* R1792 - GPIO 1 */
+       { 0x0701, 0xA101 },    /* R1793 - Pull Control (MCLK2) */
+       { 0x0702, 0xA101 },    /* R1794 - Pull Control (BCLK2) */
+       { 0x0703, 0xA101 },    /* R1795 - Pull Control (DACLRCLK2) */
+       { 0x0704, 0xA101 },    /* R1796 - Pull Control (DACDAT2) */
+       { 0x0707, 0xA101 },    /* R1799 - GPIO 8 */
+       { 0x0708, 0xA101 },    /* R1800 - GPIO 9 */
+       { 0x0709, 0xA101 },    /* R1801 - GPIO 10 */
+       { 0x070A, 0xA101 },    /* R1802 - GPIO 11 */
+       { 0x0720, 0x0000 },    /* R1824 - Pull Control (1) */
+       { 0x0721, 0x0156 },    /* R1825 - Pull Control (2) */
+       { 0x0730, 0x0000 },    /* R1840 - Interrupt Status 1 */
+       { 0x0731, 0x0000 },    /* R1841 - Interrupt Status 2 */
+       { 0x0732, 0x0000 },    /* R1842 - Interrupt Raw Status 2 */
+       { 0x0738, 0x07FF },    /* R1848 - Interrupt Status 1 Mask */
+       { 0x0739, 0xDFEF },    /* R1849 - Interrupt Status 2 Mask */
+       { 0x0740, 0x0000 },    /* R1856 - Interrupt Control */
+       { 0x0748, 0x003F },    /* R1864 - IRQ Debounce */
+};
+
+static struct reg_default wm8994_defaults[] = {
+       { 0x0000, 0x8994 },    /* R0     - Software Reset */ 
+       { 0x0001, 0x0000 },    /* R1     - Power Management (1) */ 
+       { 0x0002, 0x6000 },    /* R2     - Power Management (2) */ 
+       { 0x0003, 0x0000 },    /* R3     - Power Management (3) */ 
+       { 0x0004, 0x0000 },    /* R4     - Power Management (4) */ 
+       { 0x0005, 0x0000 },    /* R5     - Power Management (5) */ 
+       { 0x0006, 0x0000 },    /* R6     - Power Management (6) */ 
+       { 0x0015, 0x0000 },    /* R21    - Input Mixer (1) */ 
+       { 0x0018, 0x008B },    /* R24    - Left Line Input 1&2 Volume */ 
+       { 0x0019, 0x008B },    /* R25    - Left Line Input 3&4 Volume */ 
+       { 0x001A, 0x008B },    /* R26    - Right Line Input 1&2 Volume */ 
+       { 0x001B, 0x008B },    /* R27    - Right Line Input 3&4 Volume */ 
+       { 0x001C, 0x006D },    /* R28    - Left Output Volume */ 
+       { 0x001D, 0x006D },    /* R29    - Right Output Volume */ 
+       { 0x001E, 0x0066 },    /* R30    - Line Outputs Volume */ 
+       { 0x001F, 0x0020 },    /* R31    - HPOUT2 Volume */ 
+       { 0x0020, 0x0079 },    /* R32    - Left OPGA Volume */ 
+       { 0x0021, 0x0079 },    /* R33    - Right OPGA Volume */ 
+       { 0x0022, 0x0003 },    /* R34    - SPKMIXL Attenuation */ 
+       { 0x0023, 0x0003 },    /* R35    - SPKMIXR Attenuation */ 
+       { 0x0024, 0x0011 },    /* R36    - SPKOUT Mixers */ 
+       { 0x0025, 0x0140 },    /* R37    - ClassD */ 
+       { 0x0026, 0x0079 },    /* R38    - Speaker Volume Left */ 
+       { 0x0027, 0x0079 },    /* R39    - Speaker Volume Right */ 
+       { 0x0028, 0x0000 },    /* R40    - Input Mixer (2) */ 
+       { 0x0029, 0x0000 },    /* R41    - Input Mixer (3) */ 
+       { 0x002A, 0x0000 },    /* R42    - Input Mixer (4) */ 
+       { 0x002B, 0x0000 },    /* R43    - Input Mixer (5) */ 
+       { 0x002C, 0x0000 },    /* R44    - Input Mixer (6) */ 
+       { 0x002D, 0x0000 },    /* R45    - Output Mixer (1) */ 
+       { 0x002E, 0x0000 },    /* R46    - Output Mixer (2) */ 
+       { 0x002F, 0x0000 },    /* R47    - Output Mixer (3) */ 
+       { 0x0030, 0x0000 },    /* R48    - Output Mixer (4) */ 
+       { 0x0031, 0x0000 },    /* R49    - Output Mixer (5) */ 
+       { 0x0032, 0x0000 },    /* R50    - Output Mixer (6) */ 
+       { 0x0033, 0x0000 },    /* R51    - HPOUT2 Mixer */ 
+       { 0x0034, 0x0000 },    /* R52    - Line Mixer (1) */ 
+       { 0x0035, 0x0000 },    /* R53    - Line Mixer (2) */ 
+       { 0x0036, 0x0000 },    /* R54    - Speaker Mixer */ 
+       { 0x0037, 0x0000 },    /* R55    - Additional Control */ 
+       { 0x0038, 0x0000 },    /* R56    - AntiPOP (1) */ 
+       { 0x0039, 0x0000 },    /* R57    - AntiPOP (2) */ 
+       { 0x003A, 0x0000 },    /* R58    - MICBIAS */ 
+       { 0x003B, 0x000D },    /* R59    - LDO 1 */ 
+       { 0x003C, 0x0003 },    /* R60    - LDO 2 */ 
+       { 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */ 
+       { 0x0051, 0x0004 },    /* R81    - Class W (1) */ 
+       { 0x0054, 0x0000 },    /* R84    - DC Servo (1) */ 
+       { 0x0055, 0x054A },    /* R85    - DC Servo (2) */ 
+       { 0x0057, 0x0000 },    /* R87    - DC Servo (4) */ 
+       { 0x0058, 0x0000 },    /* R88    - DC Servo Readback */ 
+       { 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */ 
+       { 0x0100, 0x0003 },    /* R256   - Chip Revision */ 
+       { 0x0101, 0x8004 },    /* R257   - Control Interface */ 
+       { 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */ 
+       { 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */ 
+       { 0x0200, 0x0000 },    /* R512   - AIF1 Clocking (1) */ 
+       { 0x0201, 0x0000 },    /* R513   - AIF1 Clocking (2) */ 
+       { 0x0204, 0x0000 },    /* R516   - AIF2 Clocking (1) */ 
+       { 0x0205, 0x0000 },    /* R517   - AIF2 Clocking (2) */ 
+       { 0x0208, 0x0000 },    /* R520   - Clocking (1) */ 
+       { 0x0209, 0x0000 },    /* R521   - Clocking (2) */ 
+       { 0x0210, 0x0083 },    /* R528   - AIF1 Rate */ 
+       { 0x0211, 0x0083 },    /* R529   - AIF2 Rate */ 
+       { 0x0212, 0x0000 },    /* R530   - Rate Status */ 
+       { 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */ 
+       { 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */ 
+       { 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */ 
+       { 0x0223, 0x0000 },    /* R547   - FLL1 Control (4) */ 
+       { 0x0224, 0x0C80 },    /* R548   - FLL1 Control (5) */ 
+       { 0x0240, 0x0000 },    /* R576   - FLL2 Control (1) */ 
+       { 0x0241, 0x0000 },    /* R577   - FLL2 Control (2) */ 
+       { 0x0242, 0x0000 },    /* R578   - FLL2 Control (3) */ 
+       { 0x0243, 0x0000 },    /* R579   - FLL2 Control (4) */ 
+       { 0x0244, 0x0C80 },    /* R580   - FLL2 Control (5) */ 
+       { 0x0300, 0x4050 },    /* R768   - AIF1 Control (1) */ 
+       { 0x0301, 0x4000 },    /* R769   - AIF1 Control (2) */ 
+       { 0x0302, 0x0000 },    /* R770   - AIF1 Master/Slave */ 
+       { 0x0303, 0x0040 },    /* R771   - AIF1 BCLK */ 
+       { 0x0304, 0x0040 },    /* R772   - AIF1ADC LRCLK */ 
+       { 0x0305, 0x0040 },    /* R773   - AIF1DAC LRCLK */ 
+       { 0x0306, 0x0004 },    /* R774   - AIF1DAC Data */ 
+       { 0x0307, 0x0100 },    /* R775   - AIF1ADC Data */ 
+       { 0x0310, 0x4050 },    /* R784   - AIF2 Control (1) */ 
+       { 0x0311, 0x4000 },    /* R785   - AIF2 Control (2) */ 
+       { 0x0312, 0x0000 },    /* R786   - AIF2 Master/Slave */ 
+       { 0x0313, 0x0040 },    /* R787   - AIF2 BCLK */ 
+       { 0x0314, 0x0040 },    /* R788   - AIF2ADC LRCLK */ 
+       { 0x0315, 0x0040 },    /* R789   - AIF2DAC LRCLK */ 
+       { 0x0316, 0x0000 },    /* R790   - AIF2DAC Data */ 
+       { 0x0317, 0x0000 },    /* R791   - AIF2ADC Data */ 
+       { 0x0400, 0x00C0 },    /* R1024  - AIF1 ADC1 Left Volume */ 
+       { 0x0401, 0x00C0 },    /* R1025  - AIF1 ADC1 Right Volume */ 
+       { 0x0402, 0x00C0 },    /* R1026  - AIF1 DAC1 Left Volume */ 
+       { 0x0403, 0x00C0 },    /* R1027  - AIF1 DAC1 Right Volume */ 
+       { 0x0404, 0x00C0 },    /* R1028  - AIF1 ADC2 Left Volume */ 
+       { 0x0405, 0x00C0 },    /* R1029  - AIF1 ADC2 Right Volume */ 
+       { 0x0406, 0x00C0 },    /* R1030  - AIF1 DAC2 Left Volume */ 
+       { 0x0407, 0x00C0 },    /* R1031  - AIF1 DAC2 Right Volume */ 
+       { 0x0410, 0x0000 },    /* R1040  - AIF1 ADC1 Filters */ 
+       { 0x0411, 0x0000 },    /* R1041  - AIF1 ADC2 Filters */ 
+       { 0x0420, 0x0200 },    /* R1056  - AIF1 DAC1 Filters (1) */ 
+       { 0x0421, 0x0010 },    /* R1057  - AIF1 DAC1 Filters (2) */ 
+       { 0x0422, 0x0200 },    /* R1058  - AIF1 DAC2 Filters (1) */ 
+       { 0x0423, 0x0010 },    /* R1059  - AIF1 DAC2 Filters (2) */ 
+       { 0x0440, 0x0098 },    /* R1088  - AIF1 DRC1 (1) */ 
+       { 0x0441, 0x0845 },    /* R1089  - AIF1 DRC1 (2) */ 
+       { 0x0442, 0x0000 },    /* R1090  - AIF1 DRC1 (3) */ 
+       { 0x0443, 0x0000 },    /* R1091  - AIF1 DRC1 (4) */ 
+       { 0x0444, 0x0000 },    /* R1092  - AIF1 DRC1 (5) */ 
+       { 0x0450, 0x0098 },    /* R1104  - AIF1 DRC2 (1) */ 
+       { 0x0451, 0x0845 },    /* R1105  - AIF1 DRC2 (2) */ 
+       { 0x0452, 0x0000 },    /* R1106  - AIF1 DRC2 (3) */ 
+       { 0x0453, 0x0000 },    /* R1107  - AIF1 DRC2 (4) */ 
+       { 0x0454, 0x0000 },    /* R1108  - AIF1 DRC2 (5) */ 
+       { 0x0480, 0x6318 },    /* R1152  - AIF1 DAC1 EQ Gains (1) */ 
+       { 0x0481, 0x6300 },    /* R1153  - AIF1 DAC1 EQ Gains (2) */ 
+       { 0x0482, 0x0FCA },    /* R1154  - AIF1 DAC1 EQ Band 1 A */ 
+       { 0x0483, 0x0400 },    /* R1155  - AIF1 DAC1 EQ Band 1 B */ 
+       { 0x0484, 0x00D8 },    /* R1156  - AIF1 DAC1 EQ Band 1 PG */ 
+       { 0x0485, 0x1EB5 },    /* R1157  - AIF1 DAC1 EQ Band 2 A */ 
+       { 0x0486, 0xF145 },    /* R1158  - AIF1 DAC1 EQ Band 2 B */ 
+       { 0x0487, 0x0B75 },    /* R1159  - AIF1 DAC1 EQ Band 2 C */ 
+       { 0x0488, 0x01C5 },    /* R1160  - AIF1 DAC1 EQ Band 2 PG */ 
+       { 0x0489, 0x1C58 },    /* R1161  - AIF1 DAC1 EQ Band 3 A */ 
+       { 0x048A, 0xF373 },    /* R1162  - AIF1 DAC1 EQ Band 3 B */ 
+       { 0x048B, 0x0A54 },    /* R1163  - AIF1 DAC1 EQ Band 3 C */ 
+       { 0x048C, 0x0558 },    /* R1164  - AIF1 DAC1 EQ Band 3 PG */ 
+       { 0x048D, 0x168E },    /* R1165  - AIF1 DAC1 EQ Band 4 A */ 
+       { 0x048E, 0xF829 },    /* R1166  - AIF1 DAC1 EQ Band 4 B */ 
+       { 0x048F, 0x07AD },    /* R1167  - AIF1 DAC1 EQ Band 4 C */ 
+       { 0x0490, 0x1103 },    /* R1168  - AIF1 DAC1 EQ Band 4 PG */ 
+       { 0x0491, 0x0564 },    /* R1169  - AIF1 DAC1 EQ Band 5 A */ 
+       { 0x0492, 0x0559 },    /* R1170  - AIF1 DAC1 EQ Band 5 B */ 
+       { 0x0493, 0x4000 },    /* R1171  - AIF1 DAC1 EQ Band 5 PG */ 
+       { 0x04A0, 0x6318 },    /* R1184  - AIF1 DAC2 EQ Gains (1) */ 
+       { 0x04A1, 0x6300 },    /* R1185  - AIF1 DAC2 EQ Gains (2) */ 
+       { 0x04A2, 0x0FCA },    /* R1186  - AIF1 DAC2 EQ Band 1 A */ 
+       { 0x04A3, 0x0400 },    /* R1187  - AIF1 DAC2 EQ Band 1 B */ 
+       { 0x04A4, 0x00D8 },    /* R1188  - AIF1 DAC2 EQ Band 1 PG */ 
+       { 0x04A5, 0x1EB5 },    /* R1189  - AIF1 DAC2 EQ Band 2 A */ 
+       { 0x04A6, 0xF145 },    /* R1190  - AIF1 DAC2 EQ Band 2 B */ 
+       { 0x04A7, 0x0B75 },    /* R1191  - AIF1 DAC2 EQ Band 2 C */ 
+       { 0x04A8, 0x01C5 },    /* R1192  - AIF1 DAC2 EQ Band 2 PG */ 
+       { 0x04A9, 0x1C58 },    /* R1193  - AIF1 DAC2 EQ Band 3 A */ 
+       { 0x04AA, 0xF373 },    /* R1194  - AIF1 DAC2 EQ Band 3 B */ 
+       { 0x04AB, 0x0A54 },    /* R1195  - AIF1 DAC2 EQ Band 3 C */ 
+       { 0x04AC, 0x0558 },    /* R1196  - AIF1 DAC2 EQ Band 3 PG */ 
+       { 0x04AD, 0x168E },    /* R1197  - AIF1 DAC2 EQ Band 4 A */ 
+       { 0x04AE, 0xF829 },    /* R1198  - AIF1 DAC2 EQ Band 4 B */ 
+       { 0x04AF, 0x07AD },    /* R1199  - AIF1 DAC2 EQ Band 4 C */ 
+       { 0x04B0, 0x1103 },    /* R1200  - AIF1 DAC2 EQ Band 4 PG */ 
+       { 0x04B1, 0x0564 },    /* R1201  - AIF1 DAC2 EQ Band 5 A */ 
+       { 0x04B2, 0x0559 },    /* R1202  - AIF1 DAC2 EQ Band 5 B */ 
+       { 0x04B3, 0x4000 },    /* R1203  - AIF1 DAC2 EQ Band 5 PG */ 
+       { 0x0500, 0x00C0 },    /* R1280  - AIF2 ADC Left Volume */ 
+       { 0x0501, 0x00C0 },    /* R1281  - AIF2 ADC Right Volume */ 
+       { 0x0502, 0x00C0 },    /* R1282  - AIF2 DAC Left Volume */ 
+       { 0x0503, 0x00C0 },    /* R1283  - AIF2 DAC Right Volume */ 
+       { 0x0510, 0x0000 },    /* R1296  - AIF2 ADC Filters */ 
+       { 0x0520, 0x0200 },    /* R1312  - AIF2 DAC Filters (1) */ 
+       { 0x0521, 0x0010 },    /* R1313  - AIF2 DAC Filters (2) */ 
+       { 0x0540, 0x0098 },    /* R1344  - AIF2 DRC (1) */ 
+       { 0x0541, 0x0845 },    /* R1345  - AIF2 DRC (2) */ 
+       { 0x0542, 0x0000 },    /* R1346  - AIF2 DRC (3) */ 
+       { 0x0543, 0x0000 },    /* R1347  - AIF2 DRC (4) */ 
+       { 0x0544, 0x0000 },    /* R1348  - AIF2 DRC (5) */ 
+       { 0x0580, 0x6318 },    /* R1408  - AIF2 EQ Gains (1) */ 
+       { 0x0581, 0x6300 },    /* R1409  - AIF2 EQ Gains (2) */ 
+       { 0x0582, 0x0FCA },    /* R1410  - AIF2 EQ Band 1 A */ 
+       { 0x0583, 0x0400 },    /* R1411  - AIF2 EQ Band 1 B */ 
+       { 0x0584, 0x00D8 },    /* R1412  - AIF2 EQ Band 1 PG */ 
+       { 0x0585, 0x1EB5 },    /* R1413  - AIF2 EQ Band 2 A */ 
+       { 0x0586, 0xF145 },    /* R1414  - AIF2 EQ Band 2 B */ 
+       { 0x0587, 0x0B75 },    /* R1415  - AIF2 EQ Band 2 C */ 
+       { 0x0588, 0x01C5 },    /* R1416  - AIF2 EQ Band 2 PG */ 
+       { 0x0589, 0x1C58 },    /* R1417  - AIF2 EQ Band 3 A */ 
+       { 0x058A, 0xF373 },    /* R1418  - AIF2 EQ Band 3 B */ 
+       { 0x058B, 0x0A54 },    /* R1419  - AIF2 EQ Band 3 C */ 
+       { 0x058C, 0x0558 },    /* R1420  - AIF2 EQ Band 3 PG */ 
+       { 0x058D, 0x168E },    /* R1421  - AIF2 EQ Band 4 A */ 
+       { 0x058E, 0xF829 },    /* R1422  - AIF2 EQ Band 4 B */ 
+       { 0x058F, 0x07AD },    /* R1423  - AIF2 EQ Band 4 C */ 
+       { 0x0590, 0x1103 },    /* R1424  - AIF2 EQ Band 4 PG */ 
+       { 0x0591, 0x0564 },    /* R1425  - AIF2 EQ Band 5 A */ 
+       { 0x0592, 0x0559 },    /* R1426  - AIF2 EQ Band 5 B */ 
+       { 0x0593, 0x4000 },    /* R1427  - AIF2 EQ Band 5 PG */ 
+       { 0x0600, 0x0000 },    /* R1536  - DAC1 Mixer Volumes */ 
+       { 0x0601, 0x0000 },    /* R1537  - DAC1 Left Mixer Routing */ 
+       { 0x0602, 0x0000 },    /* R1538  - DAC1 Right Mixer Routing */ 
+       { 0x0603, 0x0000 },    /* R1539  - DAC2 Mixer Volumes */ 
+       { 0x0604, 0x0000 },    /* R1540  - DAC2 Left Mixer Routing */ 
+       { 0x0605, 0x0000 },    /* R1541  - DAC2 Right Mixer Routing */ 
+       { 0x0606, 0x0000 },    /* R1542  - AIF1 ADC1 Left Mixer Routing */ 
+       { 0x0607, 0x0000 },    /* R1543  - AIF1 ADC1 Right Mixer Routing */ 
+       { 0x0608, 0x0000 },    /* R1544  - AIF1 ADC2 Left Mixer Routing */ 
+       { 0x0609, 0x0000 },    /* R1545  - AIF1 ADC2 Right mixer Routing */ 
+       { 0x0610, 0x02C0 },    /* R1552  - DAC1 Left Volume */ 
+       { 0x0611, 0x02C0 },    /* R1553  - DAC1 Right Volume */ 
+       { 0x0612, 0x02C0 },    /* R1554  - DAC2 Left Volume */ 
+       { 0x0613, 0x02C0 },    /* R1555  - DAC2 Right Volume */ 
+       { 0x0614, 0x0000 },    /* R1556  - DAC Softmute */ 
+       { 0x0620, 0x0002 },    /* R1568  - Oversampling */ 
+       { 0x0621, 0x0000 },    /* R1569  - Sidetone */ 
+       { 0x0700, 0x8100 },    /* R1792  - GPIO 1 */ 
+       { 0x0701, 0xA101 },    /* R1793  - GPIO 2 */ 
+       { 0x0702, 0xA101 },    /* R1794  - GPIO 3 */ 
+       { 0x0703, 0xA101 },    /* R1795  - GPIO 4 */ 
+       { 0x0704, 0xA101 },    /* R1796  - GPIO 5 */ 
+       { 0x0705, 0xA101 },    /* R1797  - GPIO 6 */ 
+       { 0x0706, 0xA101 },    /* R1798  - GPIO 7 */ 
+       { 0x0707, 0xA101 },    /* R1799  - GPIO 8 */ 
+       { 0x0708, 0xA101 },    /* R1800  - GPIO 9 */ 
+       { 0x0709, 0xA101 },    /* R1801  - GPIO 10 */ 
+       { 0x070A, 0xA101 },    /* R1802  - GPIO 11 */ 
+       { 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */ 
+       { 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */ 
+       { 0x0730, 0x0000 },    /* R1840  - Interrupt Status 1 */ 
+       { 0x0731, 0x0000 },    /* R1841  - Interrupt Status 2 */ 
+       { 0x0732, 0x0000 },    /* R1842  - Interrupt Raw Status 2 */ 
+       { 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */ 
+       { 0x0739, 0xFFFF },    /* R1849  - Interrupt Status 2 Mask */ 
+       { 0x0740, 0x0000 },    /* R1856  - Interrupt Control */ 
+       { 0x0748, 0x003F },    /* R1864  - IRQ Debounce */ 
+};
+
+static struct reg_default wm8958_defaults[] = {
+       { 0x0000, 0x8958 },    /* R0     - Software Reset */ 
+       { 0x0001, 0x0000 },    /* R1     - Power Management (1) */
+       { 0x0002, 0x6000 },    /* R2     - Power Management (2) */
+       { 0x0003, 0x0000 },    /* R3     - Power Management (3) */
+       { 0x0004, 0x0000 },    /* R4     - Power Management (4) */
+       { 0x0005, 0x0000 },    /* R5     - Power Management (5) */
+       { 0x0006, 0x0000 },    /* R6     - Power Management (6) */
+       { 0x0015, 0x0000 },    /* R21    - Input Mixer (1) */
+       { 0x0018, 0x008B },    /* R24    - Left Line Input 1&2 Volume */
+       { 0x0019, 0x008B },    /* R25    - Left Line Input 3&4 Volume */
+       { 0x001A, 0x008B },    /* R26    - Right Line Input 1&2 Volume */
+       { 0x001B, 0x008B },    /* R27    - Right Line Input 3&4 Volume */
+       { 0x001C, 0x006D },    /* R28    - Left Output Volume */
+       { 0x001D, 0x006D },    /* R29    - Right Output Volume */
+       { 0x001E, 0x0066 },    /* R30    - Line Outputs Volume */
+       { 0x001F, 0x0020 },    /* R31    - HPOUT2 Volume */
+       { 0x0020, 0x0079 },    /* R32    - Left OPGA Volume */
+       { 0x0021, 0x0079 },    /* R33    - Right OPGA Volume */
+       { 0x0022, 0x0003 },    /* R34    - SPKMIXL Attenuation */
+       { 0x0023, 0x0003 },    /* R35    - SPKMIXR Attenuation */
+       { 0x0024, 0x0011 },    /* R36    - SPKOUT Mixers */
+       { 0x0025, 0x0140 },    /* R37    - ClassD */
+       { 0x0026, 0x0079 },    /* R38    - Speaker Volume Left */
+       { 0x0027, 0x0079 },    /* R39    - Speaker Volume Right */
+       { 0x0028, 0x0000 },    /* R40    - Input Mixer (2) */
+       { 0x0029, 0x0000 },    /* R41    - Input Mixer (3) */
+       { 0x002A, 0x0000 },    /* R42    - Input Mixer (4) */
+       { 0x002B, 0x0000 },    /* R43    - Input Mixer (5) */
+       { 0x002C, 0x0000 },    /* R44    - Input Mixer (6) */
+       { 0x002D, 0x0000 },    /* R45    - Output Mixer (1) */
+       { 0x002E, 0x0000 },    /* R46    - Output Mixer (2) */
+       { 0x002F, 0x0000 },    /* R47    - Output Mixer (3) */
+       { 0x0030, 0x0000 },    /* R48    - Output Mixer (4) */
+       { 0x0031, 0x0000 },    /* R49    - Output Mixer (5) */
+       { 0x0032, 0x0000 },    /* R50    - Output Mixer (6) */
+       { 0x0033, 0x0000 },    /* R51    - HPOUT2 Mixer */
+       { 0x0034, 0x0000 },    /* R52    - Line Mixer (1) */
+       { 0x0035, 0x0000 },    /* R53    - Line Mixer (2) */
+       { 0x0036, 0x0000 },    /* R54    - Speaker Mixer */
+       { 0x0037, 0x0000 },    /* R55    - Additional Control */
+       { 0x0038, 0x0000 },    /* R56    - AntiPOP (1) */
+       { 0x0039, 0x0180 },    /* R57    - AntiPOP (2) */
+       { 0x003B, 0x000D },    /* R59    - LDO 1 */
+       { 0x003C, 0x0005 },    /* R60    - LDO 2 */
+       { 0x003D, 0x0039 },    /* R61    - MICBIAS1 */
+       { 0x003E, 0x0039 },    /* R62    - MICBIAS2 */
+       { 0x004C, 0x1F25 },    /* R76    - Charge Pump (1) */
+       { 0x004D, 0xAB19 },    /* R77    - Charge Pump (2) */
+       { 0x0051, 0x0004 },    /* R81    - Class W (1) */
+       { 0x0055, 0x054A },    /* R85    - DC Servo (2) */
+       { 0x0057, 0x0000 },    /* R87    - DC Servo (4) */
+       { 0x0060, 0x0000 },    /* R96    - Analogue HP (1) */
+       { 0x00C5, 0x0000 },    /* R197   - Class D Test (5) */
+       { 0x00D0, 0x5600 },    /* R208   - Mic Detect 1 */
+       { 0x00D1, 0x007F },    /* R209   - Mic Detect 2 */
+       { 0x0101, 0x8004 },    /* R257   - Control Interface */
+       { 0x0110, 0x0000 },    /* R272   - Write Sequencer Ctrl (1) */
+       { 0x0111, 0x0000 },    /* R273   - Write Sequencer Ctrl (2) */
+       { 0x0200, 0x0000 },    /* R512   - AIF1 Clocking (1) */
+       { 0x0201, 0x0000 },    /* R513   - AIF1 Clocking (2) */
+       { 0x0204, 0x0000 },    /* R516   - AIF2 Clocking (1) */
+       { 0x0205, 0x0000 },    /* R517   - AIF2 Clocking (2) */
+       { 0x0208, 0x0000 },    /* R520   - Clocking (1) */
+       { 0x0209, 0x0000 },    /* R521   - Clocking (2) */
+       { 0x0210, 0x0083 },    /* R528   - AIF1 Rate */
+       { 0x0211, 0x0083 },    /* R529   - AIF2 Rate */
+       { 0x0220, 0x0000 },    /* R544   - FLL1 Control (1) */
+       { 0x0221, 0x0000 },    /* R545   - FLL1 Control (2) */
+       { 0x0222, 0x0000 },    /* R546   - FLL1 Control (3) */
+       { 0x0223, 0x0000 },    /* R547   - FLL1 Control (4) */
+       { 0x0224, 0x0C80 },    /* R548   - FLL1 Control (5) */
+       { 0x0226, 0x0000 },    /* R550   - FLL1 EFS 1 */
+       { 0x0227, 0x0006 },    /* R551   - FLL1 EFS 2 */
+       { 0x0240, 0x0000 },    /* R576   - FLL2Control (1) */
+       { 0x0241, 0x0000 },    /* R577   - FLL2Control (2) */
+       { 0x0242, 0x0000 },    /* R578   - FLL2Control (3) */
+       { 0x0243, 0x0000 },    /* R579   - FLL2 Control (4) */
+       { 0x0244, 0x0C80 },    /* R580   - FLL2Control (5) */
+       { 0x0246, 0x0000 },    /* R582   - FLL2 EFS 1 */
+       { 0x0247, 0x0006 },    /* R583   - FLL2 EFS 2 */
+       { 0x0300, 0x4050 },    /* R768   - AIF1 Control (1) */
+       { 0x0301, 0x4000 },    /* R769   - AIF1 Control (2) */
+       { 0x0302, 0x0000 },    /* R770   - AIF1 Master/Slave */
+       { 0x0303, 0x0040 },    /* R771   - AIF1 BCLK */
+       { 0x0304, 0x0040 },    /* R772   - AIF1ADC LRCLK */
+       { 0x0305, 0x0040 },    /* R773   - AIF1DAC LRCLK */
+       { 0x0306, 0x0004 },    /* R774   - AIF1DAC Data */
+       { 0x0307, 0x0100 },    /* R775   - AIF1ADC Data */
+       { 0x0310, 0x4053 },    /* R784   - AIF2 Control (1) */
+       { 0x0311, 0x4000 },    /* R785   - AIF2 Control (2) */
+       { 0x0312, 0x0000 },    /* R786   - AIF2 Master/Slave */
+       { 0x0313, 0x0040 },    /* R787   - AIF2 BCLK */
+       { 0x0314, 0x0040 },    /* R788   - AIF2ADC LRCLK */
+       { 0x0315, 0x0040 },    /* R789   - AIF2DAC LRCLK */
+       { 0x0316, 0x0000 },    /* R790   - AIF2DAC Data */
+       { 0x0317, 0x0000 },    /* R791   - AIF2ADC Data */
+       { 0x0320, 0x0040 },    /* R800   - AIF3 Control (1) */
+       { 0x0321, 0x0000 },    /* R801   - AIF3 Control (2) */
+       { 0x0322, 0x0000 },    /* R802   - AIF3DAC Data */
+       { 0x0323, 0x0000 },    /* R803   - AIF3ADC Data */
+       { 0x0400, 0x00C0 },    /* R1024  - AIF1 ADC1 Left Volume */
+       { 0x0401, 0x00C0 },    /* R1025  - AIF1 ADC1 Right Volume */
+       { 0x0402, 0x00C0 },    /* R1026  - AIF1 DAC1 Left Volume */
+       { 0x0403, 0x00C0 },    /* R1027  - AIF1 DAC1 Right Volume */
+       { 0x0404, 0x00C0 },    /* R1028  - AIF1 ADC2 Left Volume */
+       { 0x0405, 0x00C0 },    /* R1029  - AIF1 ADC2 Right Volume */
+       { 0x0406, 0x00C0 },    /* R1030  - AIF1 DAC2 Left Volume */
+       { 0x0407, 0x00C0 },    /* R1031  - AIF1 DAC2 Right Volume */
+       { 0x0410, 0x0000 },    /* R1040  - AIF1 ADC1 Filters */
+       { 0x0411, 0x0000 },    /* R1041  - AIF1 ADC2 Filters */
+       { 0x0420, 0x0200 },    /* R1056  - AIF1 DAC1 Filters (1) */
+       { 0x0421, 0x0010 },    /* R1057  - AIF1 DAC1 Filters (2) */
+       { 0x0422, 0x0200 },    /* R1058  - AIF1 DAC2 Filters (1) */
+       { 0x0423, 0x0010 },    /* R1059  - AIF1 DAC2 Filters (2) */
+       { 0x0430, 0x0068 },    /* R1072  - AIF1 DAC1 Noise Gate */
+       { 0x0431, 0x0068 },    /* R1073  - AIF1 DAC2 Noise Gate */
+       { 0x0440, 0x0098 },    /* R1088  - AIF1 DRC1 (1) */
+       { 0x0441, 0x0845 },    /* R1089  - AIF1 DRC1 (2) */
+       { 0x0442, 0x0000 },    /* R1090  - AIF1 DRC1 (3) */
+       { 0x0443, 0x0000 },    /* R1091  - AIF1 DRC1 (4) */
+       { 0x0444, 0x0000 },    /* R1092  - AIF1 DRC1 (5) */
+       { 0x0450, 0x0098 },    /* R1104  - AIF1 DRC2 (1) */
+       { 0x0451, 0x0845 },    /* R1105  - AIF1 DRC2 (2) */
+       { 0x0452, 0x0000 },    /* R1106  - AIF1 DRC2 (3) */
+       { 0x0453, 0x0000 },    /* R1107  - AIF1 DRC2 (4) */
+       { 0x0454, 0x0000 },    /* R1108  - AIF1 DRC2 (5) */
+       { 0x0480, 0x6318 },    /* R1152  - AIF1 DAC1 EQ Gains (1) */
+       { 0x0481, 0x6300 },    /* R1153  - AIF1 DAC1 EQ Gains (2) */
+       { 0x0482, 0x0FCA },    /* R1154  - AIF1 DAC1 EQ Band 1 A */
+       { 0x0483, 0x0400 },    /* R1155  - AIF1 DAC1 EQ Band 1 B */
+       { 0x0484, 0x00D8 },    /* R1156  - AIF1 DAC1 EQ Band 1 PG */
+       { 0x0485, 0x1EB5 },    /* R1157  - AIF1 DAC1 EQ Band 2 A */
+       { 0x0486, 0xF145 },    /* R1158  - AIF1 DAC1 EQ Band 2 B */
+       { 0x0487, 0x0B75 },    /* R1159  - AIF1 DAC1 EQ Band 2 C */
+       { 0x0488, 0x01C5 },    /* R1160  - AIF1 DAC1 EQ Band 2 PG */
+       { 0x0489, 0x1C58 },    /* R1161  - AIF1 DAC1 EQ Band 3 A */
+       { 0x048A, 0xF373 },    /* R1162  - AIF1 DAC1 EQ Band 3 B */
+       { 0x048B, 0x0A54 },    /* R1163  - AIF1 DAC1 EQ Band 3 C */
+       { 0x048C, 0x0558 },    /* R1164  - AIF1 DAC1 EQ Band 3 PG */
+       { 0x048D, 0x168E },    /* R1165  - AIF1 DAC1 EQ Band 4 A */
+       { 0x048E, 0xF829 },    /* R1166  - AIF1 DAC1 EQ Band 4 B */
+       { 0x048F, 0x07AD },    /* R1167  - AIF1 DAC1 EQ Band 4 C */
+       { 0x0490, 0x1103 },    /* R1168  - AIF1 DAC1 EQ Band 4 PG */
+       { 0x0491, 0x0564 },    /* R1169  - AIF1 DAC1 EQ Band 5 A */
+       { 0x0492, 0x0559 },    /* R1170  - AIF1 DAC1 EQ Band 5 B */
+       { 0x0493, 0x4000 },    /* R1171  - AIF1 DAC1 EQ Band 5 PG */
+       { 0x0494, 0x0000 },    /* R1172  - AIF1 DAC1 EQ Band 1 C */
+       { 0x04A0, 0x6318 },    /* R1184  - AIF1 DAC2 EQ Gains (1) */
+       { 0x04A1, 0x6300 },    /* R1185  - AIF1 DAC2 EQ Gains (2) */
+       { 0x04A2, 0x0FCA },    /* R1186  - AIF1 DAC2 EQ Band 1 A */
+       { 0x04A3, 0x0400 },    /* R1187  - AIF1 DAC2 EQ Band 1 B */
+       { 0x04A4, 0x00D8 },    /* R1188  - AIF1 DAC2 EQ Band 1 PG */
+       { 0x04A5, 0x1EB5 },    /* R1189  - AIF1 DAC2 EQ Band 2 A */
+       { 0x04A6, 0xF145 },    /* R1190  - AIF1 DAC2 EQ Band 2 B */
+       { 0x04A7, 0x0B75 },    /* R1191  - AIF1 DAC2 EQ Band 2 C */
+       { 0x04A8, 0x01C5 },    /* R1192  - AIF1 DAC2 EQ Band 2 PG */
+       { 0x04A9, 0x1C58 },    /* R1193  - AIF1 DAC2 EQ Band 3 A */
+       { 0x04AA, 0xF373 },    /* R1194  - AIF1 DAC2 EQ Band 3 B */
+       { 0x04AB, 0x0A54 },    /* R1195  - AIF1 DAC2 EQ Band 3 C */
+       { 0x04AC, 0x0558 },    /* R1196  - AIF1 DAC2 EQ Band 3 PG */
+       { 0x04AD, 0x168E },    /* R1197  - AIF1 DAC2 EQ Band 4 A */
+       { 0x04AE, 0xF829 },    /* R1198  - AIF1 DAC2 EQ Band 4 B */
+       { 0x04AF, 0x07AD },    /* R1199  - AIF1 DAC2 EQ Band 4 C */
+       { 0x04B0, 0x1103 },    /* R1200  - AIF1 DAC2 EQ Band 4 PG */
+       { 0x04B1, 0x0564 },    /* R1201  - AIF1 DAC2 EQ Band 5 A */
+       { 0x04B2, 0x0559 },    /* R1202  - AIF1 DAC2 EQ Band 5 B */
+       { 0x04B3, 0x4000 },    /* R1203  - AIF1 DAC2 EQ Band 5 PG */
+       { 0x04B4, 0x0000 },    /* R1204  - AIF1 DAC2EQ Band 1 C */
+       { 0x0500, 0x00C0 },    /* R1280  - AIF2 ADC Left Volume */
+       { 0x0501, 0x00C0 },    /* R1281  - AIF2 ADC Right Volume */
+       { 0x0502, 0x00C0 },    /* R1282  - AIF2 DAC Left Volume */
+       { 0x0503, 0x00C0 },    /* R1283  - AIF2 DAC Right Volume */
+       { 0x0510, 0x0000 },    /* R1296  - AIF2 ADC Filters */
+       { 0x0520, 0x0200 },    /* R1312  - AIF2 DAC Filters (1) */
+       { 0x0521, 0x0010 },    /* R1313  - AIF2 DAC Filters (2) */
+       { 0x0530, 0x0068 },    /* R1328  - AIF2 DAC Noise Gate */
+       { 0x0540, 0x0098 },    /* R1344  - AIF2 DRC (1) */
+       { 0x0541, 0x0845 },    /* R1345  - AIF2 DRC (2) */
+       { 0x0542, 0x0000 },    /* R1346  - AIF2 DRC (3) */
+       { 0x0543, 0x0000 },    /* R1347  - AIF2 DRC (4) */
+       { 0x0544, 0x0000 },    /* R1348  - AIF2 DRC (5) */
+       { 0x0580, 0x6318 },    /* R1408  - AIF2 EQ Gains (1) */
+       { 0x0581, 0x6300 },    /* R1409  - AIF2 EQ Gains (2) */
+       { 0x0582, 0x0FCA },    /* R1410  - AIF2 EQ Band 1 A */
+       { 0x0583, 0x0400 },    /* R1411  - AIF2 EQ Band 1 B */
+       { 0x0584, 0x00D8 },    /* R1412  - AIF2 EQ Band 1 PG */
+       { 0x0585, 0x1EB5 },    /* R1413  - AIF2 EQ Band 2 A */
+       { 0x0586, 0xF145 },    /* R1414  - AIF2 EQ Band 2 B */
+       { 0x0587, 0x0B75 },    /* R1415  - AIF2 EQ Band 2 C */
+       { 0x0588, 0x01C5 },    /* R1416  - AIF2 EQ Band 2 PG */
+       { 0x0589, 0x1C58 },    /* R1417  - AIF2 EQ Band 3 A */
+       { 0x058A, 0xF373 },    /* R1418  - AIF2 EQ Band 3 B */
+       { 0x058B, 0x0A54 },    /* R1419  - AIF2 EQ Band 3 C */
+       { 0x058C, 0x0558 },    /* R1420  - AIF2 EQ Band 3 PG */
+       { 0x058D, 0x168E },    /* R1421  - AIF2 EQ Band 4 A */
+       { 0x058E, 0xF829 },    /* R1422  - AIF2 EQ Band 4 B */
+       { 0x058F, 0x07AD },    /* R1423  - AIF2 EQ Band 4 C */
+       { 0x0590, 0x1103 },    /* R1424  - AIF2 EQ Band 4 PG */
+       { 0x0591, 0x0564 },    /* R1425  - AIF2 EQ Band 5 A */
+       { 0x0592, 0x0559 },    /* R1426  - AIF2 EQ Band 5 B */
+       { 0x0593, 0x4000 },    /* R1427  - AIF2 EQ Band 5 PG */
+       { 0x0594, 0x0000 },    /* R1428  - AIF2 EQ Band 1 C */
+       { 0x0600, 0x0000 },    /* R1536  - DAC1 Mixer Volumes */
+       { 0x0601, 0x0000 },    /* R1537  - DAC1 Left Mixer Routing */
+       { 0x0602, 0x0000 },    /* R1538  - DAC1 Right Mixer Routing */
+       { 0x0603, 0x0000 },    /* R1539  - DAC2 Mixer Volumes */
+       { 0x0604, 0x0000 },    /* R1540  - DAC2 Left Mixer Routing */
+       { 0x0605, 0x0000 },    /* R1541  - DAC2 Right Mixer Routing */
+       { 0x0606, 0x0000 },    /* R1542  - AIF1 ADC1 Left Mixer Routing */
+       { 0x0607, 0x0000 },    /* R1543  - AIF1 ADC1 Right Mixer Routing */
+       { 0x0608, 0x0000 },    /* R1544  - AIF1 ADC2 Left Mixer Routing */
+       { 0x0609, 0x0000 },    /* R1545  - AIF1 ADC2 Right mixer Routing */
+       { 0x0610, 0x02C0 },    /* R1552  - DAC1 Left Volume */
+       { 0x0611, 0x02C0 },    /* R1553  - DAC1 Right Volume */
+       { 0x0612, 0x02C0 },    /* R1554  - DAC2 Left Volume */
+       { 0x0613, 0x02C0 },    /* R1555  - DAC2 Right Volume */
+       { 0x0614, 0x0000 },    /* R1556  - DAC Softmute */
+       { 0x0620, 0x0002 },    /* R1568  - Oversampling */
+       { 0x0621, 0x0000 },    /* R1569  - Sidetone */
+       { 0x0700, 0x8100 },    /* R1792  - GPIO 1 */
+       { 0x0701, 0xA101 },    /* R1793  - Pull Control (MCLK2) */
+       { 0x0702, 0xA101 },    /* R1794  - Pull Control (BCLK2) */
+       { 0x0703, 0xA101 },    /* R1795  - Pull Control (DACLRCLK2) */
+       { 0x0704, 0xA101 },    /* R1796  - Pull Control (DACDAT2) */
+       { 0x0705, 0xA101 },    /* R1797  - GPIO 6 */
+       { 0x0707, 0xA101 },    /* R1799  - GPIO 8 */
+       { 0x0708, 0xA101 },    /* R1800  - GPIO 9 */
+       { 0x0709, 0xA101 },    /* R1801  - GPIO 10 */
+       { 0x070A, 0xA101 },    /* R1802  - GPIO 11 */
+       { 0x0720, 0x0000 },    /* R1824  - Pull Control (1) */
+       { 0x0721, 0x0156 },    /* R1825  - Pull Control (2) */
+       { 0x0738, 0x07FF },    /* R1848  - Interrupt Status 1 Mask */
+       { 0x0739, 0xFFEF },    /* R1849  - Interrupt Status 2 Mask */
+       { 0x0740, 0x0000 },    /* R1856  - Interrupt Control */
+       { 0x0748, 0x003F },    /* R1864  - IRQ Debounce */
+       { 0x0900, 0x1C00 },    /* R2304  - DSP2_Program */
+       { 0x0901, 0x0000 },    /* R2305  - DSP2_Config */
+       { 0x0A0D, 0x0000 },    /* R2573  - DSP2_ExecControl */
+       { 0x2400, 0x003F },    /* R9216  - MBC Band 1 K (1) */
+       { 0x2401, 0x8BD8 },    /* R9217  - MBC Band 1 K (2) */
+       { 0x2402, 0x0032 },    /* R9218  - MBC Band 1 N1 (1) */
+       { 0x2403, 0xF52D },    /* R9219  - MBC Band 1 N1 (2) */
+       { 0x2404, 0x0065 },    /* R9220  - MBC Band 1 N2 (1) */
+       { 0x2405, 0xAC8C },    /* R9221  - MBC Band 1 N2 (2) */
+       { 0x2406, 0x006B },    /* R9222  - MBC Band 1 N3 (1) */
+       { 0x2407, 0xE087 },    /* R9223  - MBC Band 1 N3 (2) */
+       { 0x2408, 0x0072 },    /* R9224  - MBC Band 1 N4 (1) */
+       { 0x2409, 0x1483 },    /* R9225  - MBC Band 1 N4 (2) */
+       { 0x240A, 0x0072 },    /* R9226  - MBC Band 1 N5 (1) */
+       { 0x240B, 0x1483 },    /* R9227  - MBC Band 1 N5 (2) */
+       { 0x240C, 0x0043 },    /* R9228  - MBC Band 1 X1 (1) */
+       { 0x240D, 0x3525 },    /* R9229  - MBC Band 1 X1 (2) */
+       { 0x240E, 0x0006 },    /* R9230  - MBC Band 1 X2 (1) */
+       { 0x240F, 0x6A4A },    /* R9231  - MBC Band 1 X2 (2) */
+       { 0x2410, 0x0043 },    /* R9232  - MBC Band 1 X3 (1) */
+       { 0x2411, 0x6079 },    /* R9233  - MBC Band 1 X3 (2) */
+       { 0x2412, 0x000C },    /* R9234  - MBC Band 1 Attack (1) */
+       { 0x2413, 0xCCCD },    /* R9235  - MBC Band 1 Attack (2) */
+       { 0x2414, 0x0000 },    /* R9236  - MBC Band 1 Decay (1) */
+       { 0x2415, 0x0800 },    /* R9237  - MBC Band 1 Decay (2) */
+       { 0x2416, 0x003F },    /* R9238  - MBC Band 2 K (1) */
+       { 0x2417, 0x8BD8 },    /* R9239  - MBC Band 2 K (2) */
+       { 0x2418, 0x0032 },    /* R9240  - MBC Band 2 N1 (1) */
+       { 0x2419, 0xF52D },    /* R9241  - MBC Band 2 N1 (2) */
+       { 0x241A, 0x0065 },    /* R9242  - MBC Band 2 N2 (1) */
+       { 0x241B, 0xAC8C },    /* R9243  - MBC Band 2 N2 (2) */
+       { 0x241C, 0x006B },    /* R9244  - MBC Band 2 N3 (1) */
+       { 0x241D, 0xE087 },    /* R9245  - MBC Band 2 N3 (2) */
+       { 0x241E, 0x0072 },    /* R9246  - MBC Band 2 N4 (1) */
+       { 0x241F, 0x1483 },    /* R9247  - MBC Band 2 N4 (2) */
+       { 0x2420, 0x0072 },    /* R9248  - MBC Band 2 N5 (1) */
+       { 0x2421, 0x1483 },    /* R9249  - MBC Band 2 N5 (2) */
+       { 0x2422, 0x0043 },    /* R9250  - MBC Band 2 X1 (1) */
+       { 0x2423, 0x3525 },    /* R9251  - MBC Band 2 X1 (2) */
+       { 0x2424, 0x0006 },    /* R9252  - MBC Band 2 X2 (1) */
+       { 0x2425, 0x6A4A },    /* R9253  - MBC Band 2 X2 (2) */
+       { 0x2426, 0x0043 },    /* R9254  - MBC Band 2 X3 (1) */
+       { 0x2427, 0x6079 },    /* R9255  - MBC Band 2 X3 (2) */
+       { 0x2428, 0x000C },    /* R9256  - MBC Band 2 Attack (1) */
+       { 0x2429, 0xCCCD },    /* R9257  - MBC Band 2 Attack (2) */
+       { 0x242A, 0x0000 },    /* R9258  - MBC Band 2 Decay (1) */
+       { 0x242B, 0x0800 },    /* R9259  - MBC Band 2 Decay (2) */
+       { 0x242C, 0x005A },    /* R9260  - MBC_B2_PG2 (1) */
+       { 0x242D, 0x7EFA },    /* R9261  - MBC_B2_PG2 (2) */
+       { 0x242E, 0x005A },    /* R9262  - MBC_B1_PG2 (1) */
+       { 0x242F, 0x7EFA },    /* R9263  - MBC_B1_PG2 (2) */
+       { 0x2600, 0x00A7 },    /* R9728  - MBC Crossover (1) */
+       { 0x2601, 0x0D1C },    /* R9729  - MBC Crossover (2) */
+       { 0x2602, 0x0083 },    /* R9730  - MBC HPF (1) */
+       { 0x2603, 0x98AD },    /* R9731  - MBC HPF (2) */
+       { 0x2606, 0x0008 },    /* R9734  - MBC LPF (1) */
+       { 0x2607, 0xE7A2 },    /* R9735  - MBC LPF (2) */
+       { 0x260A, 0x0055 },    /* R9738  - MBC RMS Limit (1) */
+       { 0x260B, 0x8C4B },    /* R9739  - MBC RMS Limit (2) */
+};
+
+static bool wm1811_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8994_SOFTWARE_RESET:
+       case WM8994_POWER_MANAGEMENT_1:
+       case WM8994_POWER_MANAGEMENT_2:
+       case WM8994_POWER_MANAGEMENT_3:
+       case WM8994_POWER_MANAGEMENT_4:
+       case WM8994_POWER_MANAGEMENT_5:
+       case WM8994_POWER_MANAGEMENT_6:
+       case WM8994_INPUT_MIXER_1:
+       case WM8994_LEFT_LINE_INPUT_1_2_VOLUME:
+       case WM8994_LEFT_LINE_INPUT_3_4_VOLUME:
+       case WM8994_RIGHT_LINE_INPUT_1_2_VOLUME:
+       case WM8994_RIGHT_LINE_INPUT_3_4_VOLUME:
+       case WM8994_LEFT_OUTPUT_VOLUME:
+       case WM8994_RIGHT_OUTPUT_VOLUME:
+       case WM8994_LINE_OUTPUTS_VOLUME:
+       case WM8994_HPOUT2_VOLUME:
+       case WM8994_LEFT_OPGA_VOLUME:
+       case WM8994_RIGHT_OPGA_VOLUME:
+       case WM8994_SPKMIXL_ATTENUATION:
+       case WM8994_SPKMIXR_ATTENUATION:
+       case WM8994_SPKOUT_MIXERS:
+       case WM8994_CLASSD:
+       case WM8994_SPEAKER_VOLUME_LEFT:
+       case WM8994_SPEAKER_VOLUME_RIGHT:
+       case WM8994_INPUT_MIXER_2:
+       case WM8994_INPUT_MIXER_3:
+       case WM8994_INPUT_MIXER_4:
+       case WM8994_INPUT_MIXER_5:
+       case WM8994_INPUT_MIXER_6:
+       case WM8994_OUTPUT_MIXER_1:
+       case WM8994_OUTPUT_MIXER_2:
+       case WM8994_OUTPUT_MIXER_3:
+       case WM8994_OUTPUT_MIXER_4:
+       case WM8994_OUTPUT_MIXER_5:
+       case WM8994_OUTPUT_MIXER_6:
+       case WM8994_HPOUT2_MIXER:
+       case WM8994_LINE_MIXER_1:
+       case WM8994_LINE_MIXER_2:
+       case WM8994_SPEAKER_MIXER:
+       case WM8994_ADDITIONAL_CONTROL:
+       case WM8994_ANTIPOP_1:
+       case WM8994_ANTIPOP_2:
+       case WM8994_LDO_1:
+       case WM8994_LDO_2:
+       case WM8958_MICBIAS1:
+       case WM8958_MICBIAS2:
+       case WM8994_CHARGE_PUMP_1:
+       case WM8958_CHARGE_PUMP_2:
+       case WM8994_CLASS_W_1:
+       case WM8994_DC_SERVO_1:
+       case WM8994_DC_SERVO_2:
+       case WM8994_DC_SERVO_READBACK:
+       case WM8994_DC_SERVO_4:
+       case WM8994_ANALOGUE_HP_1:
+       case WM8958_MIC_DETECT_1:
+       case WM8958_MIC_DETECT_2:
+       case WM8958_MIC_DETECT_3:
+       case WM8994_CHIP_REVISION:
+       case WM8994_CONTROL_INTERFACE:
+       case WM8994_AIF1_CLOCKING_1:
+       case WM8994_AIF1_CLOCKING_2:
+       case WM8994_AIF2_CLOCKING_1:
+       case WM8994_AIF2_CLOCKING_2:
+       case WM8994_CLOCKING_1:
+       case WM8994_CLOCKING_2:
+       case WM8994_AIF1_RATE:
+       case WM8994_AIF2_RATE:
+       case WM8994_RATE_STATUS:
+       case WM8994_FLL1_CONTROL_1:
+       case WM8994_FLL1_CONTROL_2:
+       case WM8994_FLL1_CONTROL_3:
+       case WM8994_FLL1_CONTROL_4:
+       case WM8994_FLL1_CONTROL_5:
+       case WM8958_FLL1_EFS_1:
+       case WM8958_FLL1_EFS_2:
+       case WM8994_FLL2_CONTROL_1:
+       case WM8994_FLL2_CONTROL_2:
+       case WM8994_FLL2_CONTROL_3:
+       case WM8994_FLL2_CONTROL_4:
+       case WM8994_FLL2_CONTROL_5:
+       case WM8958_FLL2_EFS_1:
+       case WM8958_FLL2_EFS_2:
+       case WM8994_AIF1_CONTROL_1:
+       case WM8994_AIF1_CONTROL_2:
+       case WM8994_AIF1_MASTER_SLAVE:
+       case WM8994_AIF1_BCLK:
+       case WM8994_AIF1ADC_LRCLK:
+       case WM8994_AIF1DAC_LRCLK:
+       case WM8994_AIF1DAC_DATA:
+       case WM8994_AIF1ADC_DATA:
+       case WM8994_AIF2_CONTROL_1:
+       case WM8994_AIF2_CONTROL_2:
+       case WM8994_AIF2_MASTER_SLAVE:
+       case WM8994_AIF2_BCLK:
+       case WM8994_AIF2ADC_LRCLK:
+       case WM8994_AIF2DAC_LRCLK:
+       case WM8994_AIF2DAC_DATA:
+       case WM8994_AIF2ADC_DATA:
+       case WM1811_AIF2TX_CONTROL:
+       case WM8958_AIF3_CONTROL_1:
+       case WM8958_AIF3_CONTROL_2:
+       case WM8958_AIF3DAC_DATA:
+       case WM8958_AIF3ADC_DATA:
+       case WM8994_AIF1_ADC1_LEFT_VOLUME:
+       case WM8994_AIF1_ADC1_RIGHT_VOLUME:
+       case WM8994_AIF1_DAC1_LEFT_VOLUME:
+       case WM8994_AIF1_DAC1_RIGHT_VOLUME:
+       case WM8994_AIF1_ADC1_FILTERS:
+       case WM8994_AIF1_DAC1_FILTERS_1:
+       case WM8994_AIF1_DAC1_FILTERS_2:
+       case WM8958_AIF1_DAC1_NOISE_GATE:
+       case WM8994_AIF1_DRC1_1:
+       case WM8994_AIF1_DRC1_2:
+       case WM8994_AIF1_DRC1_3:
+       case WM8994_AIF1_DRC1_4:
+       case WM8994_AIF1_DRC1_5:
+       case WM8994_AIF1_DAC1_EQ_GAINS_1:
+       case WM8994_AIF1_DAC1_EQ_GAINS_2:
+       case WM8994_AIF1_DAC1_EQ_BAND_1_A:
+       case WM8994_AIF1_DAC1_EQ_BAND_1_B:
+       case WM8994_AIF1_DAC1_EQ_BAND_1_PG:
+       case WM8994_AIF1_DAC1_EQ_BAND_2_A:
+       case WM8994_AIF1_DAC1_EQ_BAND_2_B:
+       case WM8994_AIF1_DAC1_EQ_BAND_2_C:
+       case WM8994_AIF1_DAC1_EQ_BAND_2_PG:
+       case WM8994_AIF1_DAC1_EQ_BAND_3_A:
+       case WM8994_AIF1_DAC1_EQ_BAND_3_B:
+       case WM8994_AIF1_DAC1_EQ_BAND_3_C:
+       case WM8994_AIF1_DAC1_EQ_BAND_3_PG:
+       case WM8994_AIF1_DAC1_EQ_BAND_4_A:
+       case WM8994_AIF1_DAC1_EQ_BAND_4_B:
+       case WM8994_AIF1_DAC1_EQ_BAND_4_C:
+       case WM8994_AIF1_DAC1_EQ_BAND_4_PG:
+       case WM8994_AIF1_DAC1_EQ_BAND_5_A:
+       case WM8994_AIF1_DAC1_EQ_BAND_5_B:
+       case WM8994_AIF1_DAC1_EQ_BAND_5_PG:
+       case WM8994_AIF1_DAC1_EQ_BAND_1_C:
+       case WM8994_AIF2_ADC_LEFT_VOLUME:
+       case WM8994_AIF2_ADC_RIGHT_VOLUME:
+       case WM8994_AIF2_DAC_LEFT_VOLUME:
+       case WM8994_AIF2_DAC_RIGHT_VOLUME:
+       case WM8994_AIF2_ADC_FILTERS:
+       case WM8994_AIF2_DAC_FILTERS_1:
+       case WM8994_AIF2_DAC_FILTERS_2:
+       case WM8958_AIF2_DAC_NOISE_GATE:
+       case WM8994_AIF2_DRC_1:
+       case WM8994_AIF2_DRC_2:
+       case WM8994_AIF2_DRC_3:
+       case WM8994_AIF2_DRC_4:
+       case WM8994_AIF2_DRC_5:
+       case WM8994_AIF2_EQ_GAINS_1:
+       case WM8994_AIF2_EQ_GAINS_2:
+       case WM8994_AIF2_EQ_BAND_1_A:
+       case WM8994_AIF2_EQ_BAND_1_B:
+       case WM8994_AIF2_EQ_BAND_1_PG:
+       case WM8994_AIF2_EQ_BAND_2_A:
+       case WM8994_AIF2_EQ_BAND_2_B:
+       case WM8994_AIF2_EQ_BAND_2_C:
+       case WM8994_AIF2_EQ_BAND_2_PG:
+       case WM8994_AIF2_EQ_BAND_3_A:
+       case WM8994_AIF2_EQ_BAND_3_B:
+       case WM8994_AIF2_EQ_BAND_3_C:
+       case WM8994_AIF2_EQ_BAND_3_PG:
+       case WM8994_AIF2_EQ_BAND_4_A:
+       case WM8994_AIF2_EQ_BAND_4_B:
+       case WM8994_AIF2_EQ_BAND_4_C:
+       case WM8994_AIF2_EQ_BAND_4_PG:
+       case WM8994_AIF2_EQ_BAND_5_A:
+       case WM8994_AIF2_EQ_BAND_5_B:
+       case WM8994_AIF2_EQ_BAND_5_PG:
+       case WM8994_AIF2_EQ_BAND_1_C:
+       case WM8994_DAC1_MIXER_VOLUMES:
+       case WM8994_DAC1_LEFT_MIXER_ROUTING:
+       case WM8994_DAC1_RIGHT_MIXER_ROUTING:
+       case WM8994_DAC2_MIXER_VOLUMES:
+       case WM8994_DAC2_LEFT_MIXER_ROUTING:
+       case WM8994_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING:
+       case WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING:
+       case WM8994_DAC1_LEFT_VOLUME:
+       case WM8994_DAC1_RIGHT_VOLUME:
+       case WM8994_DAC2_LEFT_VOLUME:
+       case WM8994_DAC2_RIGHT_VOLUME:
+       case WM8994_DAC_SOFTMUTE:
+       case WM8994_OVERSAMPLING:
+       case WM8994_SIDETONE:
+       case WM8994_GPIO_1:
+       case WM8994_GPIO_2:
+       case WM8994_GPIO_3:
+       case WM8994_GPIO_4:
+       case WM8994_GPIO_5:
+       case WM8994_GPIO_6:
+       case WM8994_GPIO_8:
+       case WM8994_GPIO_9:
+       case WM8994_GPIO_10:
+       case WM8994_GPIO_11:
+       case WM8994_PULL_CONTROL_1:
+       case WM8994_PULL_CONTROL_2:
+       case WM8994_INTERRUPT_STATUS_1:
+       case WM8994_INTERRUPT_STATUS_2:
+       case WM8994_INTERRUPT_RAW_STATUS_2:
+       case WM8994_INTERRUPT_STATUS_1_MASK:
+       case WM8994_INTERRUPT_STATUS_2_MASK:
+       case WM8994_INTERRUPT_CONTROL:
+       case WM8994_IRQ_DEBOUNCE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm8994_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8994_DC_SERVO_READBACK:
+       case WM8994_WRITE_SEQUENCER_CTRL_1:
+       case WM8994_WRITE_SEQUENCER_CTRL_2:
+       case WM8994_AIF1_ADC2_LEFT_VOLUME:
+       case WM8994_AIF1_ADC2_RIGHT_VOLUME:
+       case WM8994_AIF1_DAC2_LEFT_VOLUME:
+       case WM8994_AIF1_DAC2_RIGHT_VOLUME:
+       case WM8994_AIF1_ADC2_FILTERS:
+       case WM8994_AIF1_DAC2_FILTERS_1:
+       case WM8994_AIF1_DAC2_FILTERS_2:
+       case WM8958_AIF1_DAC2_NOISE_GATE:
+       case WM8994_AIF1_DRC2_1:
+       case WM8994_AIF1_DRC2_2:
+       case WM8994_AIF1_DRC2_3:
+       case WM8994_AIF1_DRC2_4:
+       case WM8994_AIF1_DRC2_5:
+       case WM8994_AIF1_DAC2_EQ_GAINS_1:
+       case WM8994_AIF1_DAC2_EQ_GAINS_2:
+       case WM8994_AIF1_DAC2_EQ_BAND_1_A:
+       case WM8994_AIF1_DAC2_EQ_BAND_1_B:
+       case WM8994_AIF1_DAC2_EQ_BAND_1_PG:
+       case WM8994_AIF1_DAC2_EQ_BAND_2_A:
+       case WM8994_AIF1_DAC2_EQ_BAND_2_B:
+       case WM8994_AIF1_DAC2_EQ_BAND_2_C:
+       case WM8994_AIF1_DAC2_EQ_BAND_2_PG:
+       case WM8994_AIF1_DAC2_EQ_BAND_3_A:
+       case WM8994_AIF1_DAC2_EQ_BAND_3_B:
+       case WM8994_AIF1_DAC2_EQ_BAND_3_C:
+       case WM8994_AIF1_DAC2_EQ_BAND_3_PG:
+       case WM8994_AIF1_DAC2_EQ_BAND_4_A:
+       case WM8994_AIF1_DAC2_EQ_BAND_4_B:
+       case WM8994_AIF1_DAC2_EQ_BAND_4_C:
+       case WM8994_AIF1_DAC2_EQ_BAND_4_PG:
+       case WM8994_AIF1_DAC2_EQ_BAND_5_A:
+       case WM8994_AIF1_DAC2_EQ_BAND_5_B:
+       case WM8994_AIF1_DAC2_EQ_BAND_5_PG:
+       case WM8994_AIF1_DAC2_EQ_BAND_1_C:
+       case WM8994_DAC2_MIXER_VOLUMES:
+       case WM8994_DAC2_LEFT_MIXER_ROUTING:
+       case WM8994_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING:
+       case WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING:
+       case WM8994_DAC2_LEFT_VOLUME:
+       case WM8994_DAC2_RIGHT_VOLUME:
+               return true;
+       default:
+               return wm1811_readable_register(dev, reg);
+       }
+}
+
+static bool wm8958_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8958_DSP2_PROGRAM:
+       case WM8958_DSP2_CONFIG:
+       case WM8958_DSP2_MAGICNUM:
+       case WM8958_DSP2_RELEASEYEAR:
+       case WM8958_DSP2_RELEASEMONTHDAY:
+       case WM8958_DSP2_RELEASETIME:
+       case WM8958_DSP2_VERMAJMIN:
+       case WM8958_DSP2_VERBUILD:
+       case WM8958_DSP2_TESTREG:
+       case WM8958_DSP2_XORREG:
+       case WM8958_DSP2_SHIFTMAXX:
+       case WM8958_DSP2_SHIFTMAXY:
+       case WM8958_DSP2_SHIFTMAXZ:
+       case WM8958_DSP2_SHIFTMAXEXTLO:
+       case WM8958_DSP2_AESSELECT:
+       case WM8958_DSP2_EXECCONTROL:
+       case WM8958_DSP2_SAMPLEBREAK:
+       case WM8958_DSP2_COUNTBREAK:
+       case WM8958_DSP2_INTSTATUS:
+       case WM8958_DSP2_EVENTSTATUS:
+       case WM8958_DSP2_INTMASK:
+       case WM8958_DSP2_CONFIGDWIDTH:
+       case WM8958_DSP2_CONFIGINSTR:
+       case WM8958_DSP2_CONFIGDMEM:
+       case WM8958_DSP2_CONFIGDELAYS:
+       case WM8958_DSP2_CONFIGNUMIO:
+       case WM8958_DSP2_CONFIGEXTDEPTH:
+       case WM8958_DSP2_CONFIGMULTIPLIER:
+       case WM8958_DSP2_CONFIGCTRLDWIDTH:
+       case WM8958_DSP2_CONFIGPIPELINE:
+       case WM8958_DSP2_SHIFTMAXEXTHI:
+       case WM8958_DSP2_SWVERSIONREG:
+       case WM8958_DSP2_CONFIGXMEM:
+       case WM8958_DSP2_CONFIGYMEM:
+       case WM8958_DSP2_CONFIGZMEM:
+       case WM8958_FW_BUILD_1:
+       case WM8958_FW_BUILD_0:
+       case WM8958_FW_ID_1:
+       case WM8958_FW_ID_0:
+       case WM8958_FW_MAJOR_1:
+       case WM8958_FW_MAJOR_0:
+       case WM8958_FW_MINOR_1:
+       case WM8958_FW_MINOR_0:
+       case WM8958_FW_PATCH_1:
+       case WM8958_FW_PATCH_0:
+       case WM8958_MBC_BAND_1_K_1:
+       case WM8958_MBC_BAND_1_K_2:
+       case WM8958_MBC_BAND_1_N1_1:
+       case WM8958_MBC_BAND_1_N1_2:
+       case WM8958_MBC_BAND_1_N2_1:
+       case WM8958_MBC_BAND_1_N2_2:
+       case WM8958_MBC_BAND_1_N3_1:
+       case WM8958_MBC_BAND_1_N3_2:
+       case WM8958_MBC_BAND_1_N4_1:
+       case WM8958_MBC_BAND_1_N4_2:
+       case WM8958_MBC_BAND_1_N5_1:
+       case WM8958_MBC_BAND_1_N5_2:
+       case WM8958_MBC_BAND_1_X1_1:
+       case WM8958_MBC_BAND_1_X1_2:
+       case WM8958_MBC_BAND_1_X2_1:
+       case WM8958_MBC_BAND_1_X2_2:
+       case WM8958_MBC_BAND_1_X3_1:
+       case WM8958_MBC_BAND_1_X3_2:
+       case WM8958_MBC_BAND_1_ATTACK_1:
+       case WM8958_MBC_BAND_1_ATTACK_2:
+       case WM8958_MBC_BAND_1_DECAY_1:
+       case WM8958_MBC_BAND_1_DECAY_2:
+       case WM8958_MBC_BAND_2_K_1:
+       case WM8958_MBC_BAND_2_K_2:
+       case WM8958_MBC_BAND_2_N1_1:
+       case WM8958_MBC_BAND_2_N1_2:
+       case WM8958_MBC_BAND_2_N2_1:
+       case WM8958_MBC_BAND_2_N2_2:
+       case WM8958_MBC_BAND_2_N3_1:
+       case WM8958_MBC_BAND_2_N3_2:
+       case WM8958_MBC_BAND_2_N4_1:
+       case WM8958_MBC_BAND_2_N4_2:
+       case WM8958_MBC_BAND_2_N5_1:
+       case WM8958_MBC_BAND_2_N5_2:
+       case WM8958_MBC_BAND_2_X1_1:
+       case WM8958_MBC_BAND_2_X1_2:
+       case WM8958_MBC_BAND_2_X2_1:
+       case WM8958_MBC_BAND_2_X2_2:
+       case WM8958_MBC_BAND_2_X3_1:
+       case WM8958_MBC_BAND_2_X3_2:
+       case WM8958_MBC_BAND_2_ATTACK_1:
+       case WM8958_MBC_BAND_2_ATTACK_2:
+       case WM8958_MBC_BAND_2_DECAY_1:
+       case WM8958_MBC_BAND_2_DECAY_2:
+       case WM8958_MBC_B2_PG2_1:
+       case WM8958_MBC_B2_PG2_2:
+       case WM8958_MBC_B1_PG2_1:
+       case WM8958_MBC_B1_PG2_2:
+       case WM8958_MBC_CROSSOVER_1:
+       case WM8958_MBC_CROSSOVER_2:
+       case WM8958_MBC_HPF_1:
+       case WM8958_MBC_HPF_2:
+       case WM8958_MBC_LPF_1:
+       case WM8958_MBC_LPF_2:
+       case WM8958_MBC_RMS_LIMIT_1:
+       case WM8958_MBC_RMS_LIMIT_2:
+               return true;
+       default:
+               return wm8994_readable_register(dev, reg);
+       }
+}
+
+static bool wm8994_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8994_SOFTWARE_RESET:
+       case WM8994_DC_SERVO_1:
+       case WM8994_DC_SERVO_READBACK:
+       case WM8994_RATE_STATUS:
+       case WM8958_MIC_DETECT_3:
+       case WM8994_DC_SERVO_4E:
+       case WM8994_CHIP_REVISION:
+       case WM8994_INTERRUPT_STATUS_1:
+       case WM8994_INTERRUPT_STATUS_2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm1811_volatile_register(struct device *dev, unsigned int reg)
+{
+       struct wm8994 *wm8994 = dev_get_drvdata(dev);
+
+       switch (reg) {
+       case WM8994_GPIO_6:
+               if (wm8994->revision > 1)
+                       return true;
+               else
+                       return false;
+       default:
+               return wm8994_volatile_register(dev, reg);
+       }
+}
+
+static bool wm8958_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8958_DSP2_MAGICNUM:
+       case WM8958_DSP2_RELEASEYEAR:
+       case WM8958_DSP2_RELEASEMONTHDAY:
+       case WM8958_DSP2_RELEASETIME:
+       case WM8958_DSP2_VERMAJMIN:
+       case WM8958_DSP2_VERBUILD:
+       case WM8958_DSP2_EXECCONTROL:
+       case WM8958_DSP2_SWVERSIONREG:
+       case WM8958_DSP2_CONFIGXMEM:
+       case WM8958_DSP2_CONFIGYMEM:
+       case WM8958_DSP2_CONFIGZMEM:
+       case WM8958_FW_BUILD_1:
+       case WM8958_FW_BUILD_0:
+       case WM8958_FW_ID_1:
+       case WM8958_FW_ID_0:
+       case WM8958_FW_MAJOR_1:
+       case WM8958_FW_MAJOR_0:
+       case WM8958_FW_MINOR_1:
+       case WM8958_FW_MINOR_0:
+       case WM8958_FW_PATCH_1:
+       case WM8958_FW_PATCH_0:
+               return true;
+       default:
+               return wm8994_volatile_register(dev, reg);
+       }
+}
+
+struct regmap_config wm1811_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .reg_defaults = wm1811_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm1811_defaults),
+
+       .max_register = WM8994_MAX_REGISTER,
+       .volatile_reg = wm1811_volatile_register,
+       .readable_reg = wm1811_readable_register,
+};
+
+struct regmap_config wm8994_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .reg_defaults = wm8994_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8994_defaults),
+
+       .max_register = WM8994_MAX_REGISTER,
+       .volatile_reg = wm8994_volatile_register,
+       .readable_reg = wm8994_readable_register,
+};
+
+struct regmap_config wm8958_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .reg_defaults = wm8958_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8958_defaults),
+
+       .max_register = WM8994_MAX_REGISTER,
+       .volatile_reg = wm8958_volatile_register,
+       .readable_reg = wm8958_readable_register,
+};
+
+struct regmap_config wm8994_base_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 16,
+};
diff --git a/drivers/mfd/wm8994.h b/drivers/mfd/wm8994.h
new file mode 100644 (file)
index 0000000..6f39a84
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * wm8994.h -- WM8994 MFD internals
+ *
+ * Copyright 2011 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_H__
+#define __MFD_WM8994_H__
+
+#include <linux/regmap.h>
+
+extern struct regmap_config wm1811_regmap_config;
+extern struct regmap_config wm8994_regmap_config;
+extern struct regmap_config wm8958_regmap_config;
+extern struct regmap_config wm8994_base_regmap_config;
+
+#endif
index 5664696f2d3a8512c6ef96aca461dde22e5d486f..6a1a092db1461f3413defc6d11ca74ce68b9d282 100644 (file)
@@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480
          stereo and mono audio, video, microphone and UART data to use
          a common connector port.
 
+config MAX8997_MUIC
+       tristate "MAX8997 MUIC Support"
+       depends on MFD_MAX8997
+       help
+         If you say yes here you get support for the MUIC device of
+         Maxim MAX8997 PMIC.
+         The MAX8997 MUIC is a USB port accessory detector and switch.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
index b26495a0255494d7c1ee03f987d4a12ac39b8196..3e1d80106f04e36fad4b82806b8939afcfae50cc 100644 (file)
@@ -48,3 +48,4 @@ obj-y                         += lis3lv02d/
 obj-y                          += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_ALTERA_STAPL)     +=altera-stapl/
+obj-$(CONFIG_MAX8997_MUIC)     += max8997-muic.o
index 2208a9d526222a9ebb30a0f2538553029e6f4e19..d7a9aa14e5d5aafd8c0efc907b127147a202d197 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/pwm.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/module.h>
 
 /*
diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c
new file mode 100644 (file)
index 0000000..d74ef41
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * max8997-muic.c - MAX8997 muic driver for the Maxim 8997
+ *
+ *  Copyright (C) 2011 Samsung Electrnoics
+ *  Donggeun Kim <dg77.kim@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+/* MAX8997-MUIC STATUS1 register */
+#define STATUS1_ADC_SHIFT              0
+#define STATUS1_ADCLOW_SHIFT           5
+#define STATUS1_ADCERR_SHIFT           6
+#define STATUS1_ADC_MASK               (0x1f << STATUS1_ADC_SHIFT)
+#define STATUS1_ADCLOW_MASK            (0x1 << STATUS1_ADCLOW_SHIFT)
+#define STATUS1_ADCERR_MASK            (0x1 << STATUS1_ADCERR_SHIFT)
+
+/* MAX8997-MUIC STATUS2 register */
+#define STATUS2_CHGTYP_SHIFT           0
+#define STATUS2_CHGDETRUN_SHIFT                3
+#define STATUS2_DCDTMR_SHIFT           4
+#define STATUS2_DBCHG_SHIFT            5
+#define STATUS2_VBVOLT_SHIFT           6
+#define STATUS2_CHGTYP_MASK            (0x7 << STATUS2_CHGTYP_SHIFT)
+#define STATUS2_CHGDETRUN_MASK         (0x1 << STATUS2_CHGDETRUN_SHIFT)
+#define STATUS2_DCDTMR_MASK            (0x1 << STATUS2_DCDTMR_SHIFT)
+#define STATUS2_DBCHG_MASK             (0x1 << STATUS2_DBCHG_SHIFT)
+#define STATUS2_VBVOLT_MASK            (0x1 << STATUS2_VBVOLT_SHIFT)
+
+/* MAX8997-MUIC STATUS3 register */
+#define STATUS3_OVP_SHIFT              2
+#define STATUS3_OVP_MASK               (0x1 << STATUS3_OVP_SHIFT)
+
+/* MAX8997-MUIC CONTROL1 register */
+#define COMN1SW_SHIFT                  0
+#define COMP2SW_SHIFT                  3
+#define COMN1SW_MASK                   (0x7 << COMN1SW_SHIFT)
+#define COMP2SW_MASK                   (0x7 << COMP2SW_SHIFT)
+#define SW_MASK                                (COMP2SW_MASK | COMN1SW_MASK)
+
+#define MAX8997_SW_USB         ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
+#define MAX8997_SW_AUDIO       ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
+#define MAX8997_SW_UART                ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
+#define MAX8997_SW_OPEN                ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
+
+#define        MAX8997_ADC_GROUND              0x00
+#define        MAX8997_ADC_MHL                 0x01
+#define        MAX8997_ADC_JIG_USB_1           0x18
+#define        MAX8997_ADC_JIG_USB_2           0x19
+#define        MAX8997_ADC_DESKDOCK            0x1a
+#define        MAX8997_ADC_JIG_UART            0x1c
+#define        MAX8997_ADC_CARDOCK             0x1d
+#define        MAX8997_ADC_OPEN                0x1f
+
+struct max8997_muic_irq {
+       unsigned int irq;
+       const char *name;
+};
+
+static struct max8997_muic_irq muic_irqs[] = {
+       { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
+       { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
+       { MAX8997_MUICIRQ_ADC, "muic-ADC" },
+       { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
+       { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
+       { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
+       { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
+       { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
+       { MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
+};
+
+struct max8997_muic_info {
+       struct device *dev;
+       struct max8997_dev *iodev;
+       struct i2c_client *muic;
+       struct max8997_muic_platform_data *muic_pdata;
+
+       int irq;
+       struct work_struct irq_work;
+
+       enum max8997_muic_charger_type pre_charger_type;
+       int pre_adc;
+
+       struct mutex mutex;
+};
+
+static int max8997_muic_handle_usb(struct max8997_muic_info *info,
+                       enum max8997_muic_usb_type usb_type, bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       if (usb_type == MAX8997_USB_HOST) {
+               /* switch to USB */
+               ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
+                               SW_MASK);
+               if (ret) {
+                       dev_err(info->dev, "failed to update muic register\n");
+                       goto out;
+               }
+       }
+
+       if (mdata->usb_callback)
+               mdata->usb_callback(usb_type, attached);
+out:
+       return ret;
+}
+
+static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
+                       bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+
+       if (mdata->mhl_callback)
+               mdata->mhl_callback(attached);
+}
+
+static int max8997_muic_handle_dock(struct max8997_muic_info *info,
+                       int adc, bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       /* switch to AUDIO */
+       ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
+                               SW_MASK);
+       if (ret) {
+               dev_err(info->dev, "failed to update muic register\n");
+               goto out;
+       }
+
+       switch (adc) {
+       case MAX8997_ADC_DESKDOCK:
+               if (mdata->deskdock_callback)
+                       mdata->deskdock_callback(attached);
+               break;
+       case MAX8997_ADC_CARDOCK:
+               if (mdata->cardock_callback)
+                       mdata->cardock_callback(attached);
+               break;
+       default:
+               break;
+       }
+out:
+       return ret;
+}
+
+static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
+                       bool attached)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int ret = 0;
+
+       /* switch to UART */
+       ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
+                               attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
+                               SW_MASK);
+       if (ret) {
+               dev_err(info->dev, "failed to update muic register\n");
+               goto out;
+       }
+
+       if (mdata->uart_callback)
+               mdata->uart_callback(attached);
+out:
+       return ret;
+}
+
+static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
+{
+       int ret = 0;
+
+       switch (info->pre_adc) {
+       case MAX8997_ADC_GROUND:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
+               break;
+       case MAX8997_ADC_MHL:
+               max8997_muic_handle_mhl(info, false);
+               break;
+       case MAX8997_ADC_JIG_USB_1:
+       case MAX8997_ADC_JIG_USB_2:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
+               break;
+       case MAX8997_ADC_DESKDOCK:
+       case MAX8997_ADC_CARDOCK:
+               ret = max8997_muic_handle_dock(info, info->pre_adc, false);
+               break;
+       case MAX8997_ADC_JIG_UART:
+               ret = max8997_muic_handle_jig_uart(info, false);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
+{
+       int ret = 0;
+
+       switch (adc) {
+       case MAX8997_ADC_GROUND:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
+               break;
+       case MAX8997_ADC_MHL:
+               max8997_muic_handle_mhl(info, true);
+               break;
+       case MAX8997_ADC_JIG_USB_1:
+       case MAX8997_ADC_JIG_USB_2:
+               ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
+               break;
+       case MAX8997_ADC_DESKDOCK:
+       case MAX8997_ADC_CARDOCK:
+               ret = max8997_muic_handle_dock(info, adc, true);
+               break;
+       case MAX8997_ADC_JIG_UART:
+               ret = max8997_muic_handle_jig_uart(info, true);
+               break;
+       case MAX8997_ADC_OPEN:
+               ret = max8997_muic_handle_adc_detach(info);
+               break;
+       default:
+               break;
+       }
+
+       info->pre_adc = adc;
+
+       return ret;
+}
+
+static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
+                               enum max8997_muic_charger_type charger_type)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       u8 adc;
+       int ret;
+
+       ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               goto out;
+       }
+
+       switch (charger_type) {
+       case MAX8997_CHARGER_TYPE_NONE:
+               if (mdata->charger_callback)
+                       mdata->charger_callback(false, charger_type);
+               if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
+                       max8997_muic_handle_usb(info,
+                                       MAX8997_USB_DEVICE, false);
+               }
+               break;
+       case MAX8997_CHARGER_TYPE_USB:
+               if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
+                       max8997_muic_handle_usb(info,
+                                       MAX8997_USB_DEVICE, true);
+               }
+               if (mdata->charger_callback)
+                       mdata->charger_callback(true, charger_type);
+               break;
+       case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+       case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+       case MAX8997_CHARGER_TYPE_500MA:
+       case MAX8997_CHARGER_TYPE_1A:
+               if (mdata->charger_callback)
+                       mdata->charger_callback(true, charger_type);
+               break;
+       default:
+               break;
+       }
+
+       info->pre_charger_type = charger_type;
+out:
+       return ret;
+}
+
+static void max8997_muic_irq_work(struct work_struct *work)
+{
+       struct max8997_muic_info *info = container_of(work,
+                       struct max8997_muic_info, irq_work);
+       struct max8997_platform_data *pdata =
+                               dev_get_platdata(info->iodev->dev);
+       u8 status[3];
+       u8 adc, chg_type;
+
+       int irq_type = info->irq - pdata->irq_base;
+       int ret;
+
+       mutex_lock(&info->mutex);
+
+       ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+                               3, status);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               mutex_unlock(&info->mutex);
+               return;
+       }
+
+       dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
+                       status[0], status[1]);
+
+       switch (irq_type) {
+       case MAX8997_MUICIRQ_ADC:
+               adc = status[0] & STATUS1_ADC_MASK;
+               adc >>= STATUS1_ADC_SHIFT;
+
+               max8997_muic_handle_adc(info, adc);
+               break;
+       case MAX8997_MUICIRQ_ChgTyp:
+               chg_type = status[1] & STATUS2_CHGTYP_MASK;
+               chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+               max8997_muic_handle_charger_type(info, chg_type);
+               break;
+       default:
+               dev_info(info->dev, "misc interrupt: %s occurred\n",
+                        muic_irqs[irq_type].name);
+               break;
+       }
+
+       mutex_unlock(&info->mutex);
+
+       return;
+}
+
+static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
+{
+       struct max8997_muic_info *info = data;
+
+       dev_dbg(info->dev, "irq:%d\n", irq);
+       info->irq = irq;
+
+       schedule_work(&info->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static void max8997_muic_detect_dev(struct max8997_muic_info *info)
+{
+       int ret;
+       u8 status[2], adc, chg_type;
+
+       ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
+                               2, status);
+       if (ret) {
+               dev_err(info->dev, "failed to read muic register\n");
+               return;
+       }
+
+       dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
+                       status[0], status[1]);
+
+       adc = status[0] & STATUS1_ADC_MASK;
+       adc >>= STATUS1_ADC_SHIFT;
+
+       chg_type = status[1] & STATUS2_CHGTYP_MASK;
+       chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+       max8997_muic_handle_adc(info, adc);
+       max8997_muic_handle_charger_type(info, chg_type);
+}
+
+static void max8997_initialize_device(struct max8997_muic_info *info)
+{
+       struct max8997_muic_platform_data *mdata = info->muic_pdata;
+       int i;
+
+       for (i = 0; i < mdata->num_init_data; i++) {
+               max8997_write_reg(info->muic, mdata->init_data[i].addr,
+                               mdata->init_data[i].data);
+       }
+}
+
+static int __devinit max8997_muic_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8997_muic_info *info;
+       int ret, i;
+
+       info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+
+       if (!pdata->muic_pdata) {
+               dev_err(&pdev->dev, "failed to get platform_data\n");
+               ret = -EINVAL;
+               goto err_pdata;
+       }
+       info->muic_pdata = pdata->muic_pdata;
+
+       info->dev = &pdev->dev;
+       info->iodev = iodev;
+       info->muic = iodev->muic;
+
+       platform_set_drvdata(pdev, info);
+       mutex_init(&info->mutex);
+
+       INIT_WORK(&info->irq_work, max8997_muic_irq_work);
+
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
+               struct max8997_muic_irq *muic_irq = &muic_irqs[i];
+
+               ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
+                               NULL, max8997_muic_irq_handler,
+                               0, muic_irq->name,
+                               info);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed: irq request (IRQ: %d,"
+                               " error :%d)\n",
+                               muic_irq->irq, ret);
+
+                       for (i = i - 1; i >= 0; i--)
+                               free_irq(muic_irq->irq, info);
+
+                       goto err_irq;
+               }
+       }
+
+       /* Initialize registers according to platform data */
+       max8997_initialize_device(info);
+
+       /* Initial device detection */
+       max8997_muic_detect_dev(info);
+
+       return ret;
+
+err_irq:
+err_pdata:
+       kfree(info);
+err_kfree:
+       return ret;
+}
+
+static int __devexit max8997_muic_remove(struct platform_device *pdev)
+{
+       struct max8997_muic_info *info = platform_get_drvdata(pdev);
+       struct max8997_platform_data *pdata =
+                               dev_get_platdata(info->iodev->dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
+               free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+       cancel_work_sync(&info->irq_work);
+
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver max8997_muic_driver = {
+       .driver         = {
+               .name   = "max8997-muic",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max8997_muic_probe,
+       .remove         = __devexit_p(max8997_muic_remove),
+};
+
+static int __init max8997_muic_init(void)
+{
+       return platform_driver_register(&max8997_muic_driver);
+}
+module_init(max8997_muic_init);
+
+static void __exit max8997_muic_exit(void)
+{
+       platform_driver_unregister(&max8997_muic_driver);
+}
+module_exit(max8997_muic_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
index 12eef393e2160103ac3e63dadcefd5817e99a6a9..400756ec7c492dfd527dc5154b6601ae0ef1060d 100644 (file)
@@ -6,5 +6,4 @@ subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_MMC)              += core/
 obj-$(CONFIG_MMC)              += card/
-obj-$(CONFIG_MMC)              += host/
-
+obj-$(subst m,y,$(CONFIG_MMC)) += host/
index 1e0e27cbe98786e82abf3d5d9e6ede36cc8f0eb2..0cad48a284a85366e6ad72aa607fd6d9f3da59ce 100644 (file)
@@ -107,6 +107,8 @@ struct mmc_blk_data {
         */
        unsigned int    part_curr;
        struct device_attribute force_ro;
+       struct device_attribute power_ro_lock;
+       int     area_type;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -119,6 +121,7 @@ enum mmc_blk_status {
        MMC_BLK_ABORT,
        MMC_BLK_DATA_ERR,
        MMC_BLK_ECC_ERR,
+       MMC_BLK_NOMEDIUM,
 };
 
 module_param(perdev_minors, int, 0444);
@@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        mutex_unlock(&open_lock);
 }
 
+static ssize_t power_ro_lock_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       int ret;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       struct mmc_card *card = md->queue.card;
+       int locked = 0;
+
+       if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
+               locked = 2;
+       else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
+               locked = 1;
+
+       ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
+
+       return ret;
+}
+
+static ssize_t power_ro_lock_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       struct mmc_blk_data *md, *part_md;
+       struct mmc_card *card;
+       unsigned long set;
+
+       if (kstrtoul(buf, 0, &set))
+               return -EINVAL;
+
+       if (set != 1)
+               return count;
+
+       md = mmc_blk_get(dev_to_disk(dev));
+       card = md->queue.card;
+
+       mmc_claim_host(card->host);
+
+       ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
+                               card->ext_csd.boot_ro_lock |
+                               EXT_CSD_BOOT_WP_B_PWR_WP_EN,
+                               card->ext_csd.part_time);
+       if (ret)
+               pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
+       else
+               card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
+
+       mmc_release_host(card->host);
+
+       if (!ret) {
+               pr_info("%s: Locking boot partition ro until next power on\n",
+                       md->disk->disk_name);
+               set_disk_ro(md->disk, 1);
+
+               list_for_each_entry(part_md, &md->part, part)
+                       if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
+                               pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
+                               set_disk_ro(part_md->disk, 1);
+                       }
+       }
+
+       mmc_blk_put(md);
+       return count;
+}
+
 static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
@@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
                goto idata_err;
        }
 
+       if (!idata->buf_bytes)
+               return idata;
+
        idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
        if (!idata->buf) {
                err = -ENOMEM;
@@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        if (IS_ERR(idata))
                return PTR_ERR(idata);
 
-       cmd.opcode = idata->ic.opcode;
-       cmd.arg = idata->ic.arg;
-       cmd.flags = idata->ic.flags;
-
-       data.sg = &sg;
-       data.sg_len = 1;
-       data.blksz = idata->ic.blksz;
-       data.blocks = idata->ic.blocks;
-
-       sg_init_one(data.sg, idata->buf, idata->buf_bytes);
-
-       if (idata->ic.write_flag)
-               data.flags = MMC_DATA_WRITE;
-       else
-               data.flags = MMC_DATA_READ;
-
-       mrq.cmd = &cmd;
-       mrq.data = &data;
-
        md = mmc_blk_get(bdev->bd_disk);
        if (!md) {
                err = -EINVAL;
@@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                goto cmd_done;
        }
 
+       cmd.opcode = idata->ic.opcode;
+       cmd.arg = idata->ic.arg;
+       cmd.flags = idata->ic.flags;
+
+       if (idata->buf_bytes) {
+               data.sg = &sg;
+               data.sg_len = 1;
+               data.blksz = idata->ic.blksz;
+               data.blocks = idata->ic.blocks;
+
+               sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+               if (idata->ic.write_flag)
+                       data.flags = MMC_DATA_WRITE;
+               else
+                       data.flags = MMC_DATA_READ;
+
+               /* data.flags must already be set before doing this. */
+               mmc_set_data_timeout(&data, card);
+
+               /* Allow overriding the timeout_ns for empirical tuning. */
+               if (idata->ic.data_timeout_ns)
+                       data.timeout_ns = idata->ic.data_timeout_ns;
+
+               if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+                       /*
+                        * Pretend this is a data transfer and rely on the
+                        * host driver to compute timeout.  When all host
+                        * drivers support cmd.cmd_timeout for R1B, this
+                        * can be changed to:
+                        *
+                        *     mrq.data = NULL;
+                        *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+                        */
+                       data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+               }
+
+               mrq.data = &data;
+       }
+
+       mrq.cmd = &cmd;
+
        mmc_claim_host(card->host);
 
        if (idata->ic.is_acmd) {
@@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                        goto cmd_rel_host;
        }
 
-       /* data.flags must already be set before doing this. */
-       mmc_set_data_timeout(&data, card);
-       /* Allow overriding the timeout_ns for empirical tuning. */
-       if (idata->ic.data_timeout_ns)
-               data.timeout_ns = idata->ic.data_timeout_ns;
-
-       if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
-               /*
-                * Pretend this is a data transfer and rely on the host driver
-                * to compute timeout.  When all host drivers support
-                * cmd.cmd_timeout for R1B, this can be changed to:
-                *
-                *     mrq.data = NULL;
-                *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
-                */
-               data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
-       }
-
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {
@@ -565,6 +640,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
        return err;
 }
 
+#define ERR_NOMEDIUM   3
 #define ERR_RETRY      2
 #define ERR_ABORT      1
 #define ERR_CONTINUE   0
@@ -632,6 +708,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
        u32 status, stop_status = 0;
        int err, retry;
 
+       if (mmc_card_removed(card))
+               return ERR_NOMEDIUM;
+
        /*
         * Try to get card status which indicates both the card state
         * and why there was no response.  If the first attempt fails,
@@ -648,8 +727,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
        }
 
        /* We couldn't get a response from the card.  Give up. */
-       if (err)
+       if (err) {
+               /* Check if the card is removed */
+               if (mmc_detect_card_removed(card->host))
+                       return ERR_NOMEDIUM;
                return ERR_ABORT;
+       }
 
        /* Flag ECC errors */
        if ((status & R1_CARD_ECC_FAILED) ||
@@ -922,6 +1005,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
                        return MMC_BLK_RETRY;
                case ERR_ABORT:
                        return MMC_BLK_ABORT;
+               case ERR_NOMEDIUM:
+                       return MMC_BLK_NOMEDIUM;
                case ERR_CONTINUE:
                        break;
                }
@@ -1255,6 +1340,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                        if (!ret)
                                goto start_new_req;
                        break;
+               case MMC_BLK_NOMEDIUM:
+                       goto cmd_abort;
                }
 
                if (ret) {
@@ -1271,6 +1358,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
 
  cmd_abort:
        spin_lock_irq(&md->lock);
+       if (mmc_card_removed(card))
+               req->cmd_flags |= REQ_QUIET;
        while (ret)
                ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
        spin_unlock_irq(&md->lock);
@@ -1339,7 +1428,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
                                              struct device *parent,
                                              sector_t size,
                                              bool default_ro,
-                                             const char *subname)
+                                             const char *subname,
+                                             int area_type)
 {
        struct mmc_blk_data *md;
        int devidx, ret;
@@ -1364,11 +1454,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        if (!subname) {
                md->name_idx = find_first_zero_bit(name_use, max_devices);
                __set_bit(md->name_idx, name_use);
-       }
-       else
+       } else
                md->name_idx = ((struct mmc_blk_data *)
                                dev_to_disk(parent)->private_data)->name_idx;
 
+       md->area_type = area_type;
+
        /*
         * Set the read-only status based on the supported commands
         * and the write protect switch.
@@ -1462,7 +1553,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
                size = card->csd.capacity << (card->csd.read_blkbits - 9);
        }
 
-       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
+       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
+                                       MMC_BLK_DATA_AREA_MAIN);
        return md;
 }
 
@@ -1471,13 +1563,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
                              unsigned int part_type,
                              sector_t size,
                              bool default_ro,
-                             const char *subname)
+                             const char *subname,
+                             int area_type)
 {
        char cap_str[10];
        struct mmc_blk_data *part_md;
 
        part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
-                                   subname);
+                                   subname, area_type);
        if (IS_ERR(part_md))
                return PTR_ERR(part_md);
        part_md->part_type = part_type;
@@ -1510,7 +1603,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
                                card->part[idx].part_cfg,
                                card->part[idx].size >> 9,
                                card->part[idx].force_ro,
-                               card->part[idx].name);
+                               card->part[idx].name,
+                               card->part[idx].area_type);
                        if (ret)
                                return ret;
                }
@@ -1539,9 +1633,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 
 static void mmc_blk_remove_req(struct mmc_blk_data *md)
 {
+       struct mmc_card *card;
+
        if (md) {
+               card = md->queue.card;
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+                       if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+                                       card->ext_csd.boot_ro_lockable)
+                               device_remove_file(disk_to_dev(md->disk),
+                                       &md->power_ro_lock);
 
                        /* Stop new requests from getting into the queue */
                        del_gendisk(md->disk);
@@ -1570,6 +1671,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 static int mmc_add_disk(struct mmc_blk_data *md)
 {
        int ret;
+       struct mmc_card *card = md->queue.card;
 
        add_disk(md->disk);
        md->force_ro.show = force_ro_show;
@@ -1579,18 +1681,53 @@ static int mmc_add_disk(struct mmc_blk_data *md)
        md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
        ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
        if (ret)
-               del_gendisk(md->disk);
+               goto force_ro_fail;
+
+       if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+            card->ext_csd.boot_ro_lockable) {
+               mode_t mode;
+
+               if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
+                       mode = S_IRUGO;
+               else
+                       mode = S_IRUGO | S_IWUSR;
+
+               md->power_ro_lock.show = power_ro_lock_show;
+               md->power_ro_lock.store = power_ro_lock_store;
+               md->power_ro_lock.attr.mode = mode;
+               md->power_ro_lock.attr.name =
+                                       "ro_lock_until_next_power_on";
+               ret = device_create_file(disk_to_dev(md->disk),
+                               &md->power_ro_lock);
+               if (ret)
+                       goto power_ro_lock_fail;
+       }
+       return ret;
+
+power_ro_lock_fail:
+       device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+force_ro_fail:
+       del_gendisk(md->disk);
 
        return ret;
 }
 
+#define CID_MANFID_SANDISK     0x2
+#define CID_MANFID_TOSHIBA     0x11
+#define CID_MANFID_MICRON      0x13
+
 static const struct mmc_fixup blk_fixups[] =
 {
-       MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
 
        /*
         * Some MMC cards experience performance degradation with CMD23
@@ -1600,18 +1737,18 @@ static const struct mmc_fixup blk_fixups[] =
         *
         * N.B. This doesn't affect SD cards.
         */
-       MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+       MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_BLK_NO_CMD23),
 
        /*
         * Some Micron MMC cards needs longer data read timeout than
         * indicated in CSD.
         */
-       MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc,
+       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
                  MMC_QUIRK_LONG_READ_TIME),
 
        END_FIXUP
index e99bdc18002df76b09b54e269714401596419f7c..759714ed6bee8f791b2cbd4a5959f2ca12d7e9ec 100644 (file)
@@ -1581,6 +1581,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
 
        t->max_segs = test->card->host->max_segs;
        t->max_seg_sz = test->card->host->max_seg_size;
+       t->max_seg_sz -= t->max_seg_sz % 512;
 
        t->max_tfr = t->max_sz;
        if (t->max_tfr >> 9 > test->card->host->max_blk_count)
index dcad59cbfef11a873b0dfa49ef9dcd4e8fcf1d83..2517547b4366a9bbdc6eea69ce1f1dc35ef09f08 100644 (file)
@@ -29,6 +29,8 @@
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
+       struct mmc_queue *mq = q->queuedata;
+
        /*
         * We only like normal block requests and discards.
         */
@@ -37,6 +39,9 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
                return BLKPREP_KILL;
        }
 
+       if (mq && mmc_card_removed(mq->card))
+               return BLKPREP_KILL;
+
        req->cmd_flags |= REQ_DONTPREP;
 
        return BLKPREP_OK;
index 639501970b412c7315c4d516da44aa9bf930a203..dca4428380f15c53adf73ce79810e7e26c0543f9 100644 (file)
@@ -7,6 +7,6 @@ mmc_core-y                      := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
                                   sdio_cis.o sdio_io.o sdio_irq.o \
-                                  quirks.o
+                                  quirks.o cd-gpio.o
 
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
index 6be49249895a21bab3c06cd4bc658f347ed99124..5d011a39dfff3b68a88813e202c76a4722fa3c57 100644 (file)
@@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card)
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type);
        } else {
-               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
+               pr_info("%s: new %s%s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
-                       mmc_sd_card_uhs(card) ? "ultra high speed " :
+                       mmc_card_uhs(card) ? "ultra high speed " :
                        (mmc_card_highspeed(card) ? "high speed " : ""),
+                       (mmc_card_hs200(card) ? "HS200 " : ""),
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
new file mode 100644 (file)
index 0000000..082202a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Generic GPIO card-detect helper
+ *
+ * Copyright (C) 2011, 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/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/mmc/host.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+struct mmc_cd_gpio {
+       unsigned int gpio;
+       char label[0];
+};
+
+static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
+{
+       /* Schedule a card detection after a debounce timeout */
+       mmc_detect_change(dev_id, msecs_to_jiffies(100));
+       return IRQ_HANDLED;
+}
+
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
+                       unsigned int irq, unsigned long flags)
+{
+       size_t len = strlen(dev_name(host->parent)) + 4;
+       struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
+       int ret;
+
+       if (!cd)
+               return -ENOMEM;
+
+       snprintf(cd->label, len, "%s cd", dev_name(host->parent));
+
+       ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
+       if (ret < 0)
+               goto egpioreq;
+
+       ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
+                                  flags, cd->label, host);
+       if (ret < 0)
+               goto eirqreq;
+
+       cd->gpio = gpio;
+       host->hotplug.irq = irq;
+       host->hotplug.handler_priv = cd;
+
+       return 0;
+
+eirqreq:
+       gpio_free(gpio);
+egpioreq:
+       kfree(cd);
+       return ret;
+}
+EXPORT_SYMBOL(mmc_cd_gpio_request);
+
+void mmc_cd_gpio_free(struct mmc_host *host)
+{
+       struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
+
+       free_irq(host->hotplug.irq, host);
+       gpio_free(cd->gpio);
+       kfree(cd);
+}
+EXPORT_SYMBOL(mmc_cd_gpio_free);
index 950b97d7412a4f6f5f562401f132ed0d568a969a..bec0bf21c8793ba13d40701ca9f22ee1bb51db2d 100644 (file)
@@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
                        cmd->retries = 0;
        }
 
-       if (err && cmd->retries) {
+       if (err && cmd->retries && !mmc_card_removed(host->card)) {
                /*
                 * Request starter must handle retries - see
                 * mmc_wait_for_req_done().
@@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
        init_completion(&mrq->completion);
        mrq->done = mmc_wait_done;
+       if (mmc_card_removed(host->card)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               complete(&mrq->completion);
+               return;
+       }
        mmc_start_request(host, mrq);
 }
 
@@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
-               if (!cmd->error || !cmd->retries)
+               if (!cmd->error || !cmd->retries ||
+                   mmc_card_removed(host->card))
                        break;
 
                pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
@@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
        WARN_ON(host->removed);
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
-
+       host->detect_change = 1;
        mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
        return -EIO;
 }
 
+int _mmc_detect_card_removed(struct mmc_host *host)
+{
+       int ret;
+
+       if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+               return 0;
+
+       if (!host->card || mmc_card_removed(host->card))
+               return 1;
+
+       ret = host->bus_ops->alive(host);
+       if (ret) {
+               mmc_card_set_removed(host->card);
+               pr_debug("%s: card remove detected\n", mmc_hostname(host));
+       }
+
+       return ret;
+}
+
+int mmc_detect_card_removed(struct mmc_host *host)
+{
+       struct mmc_card *card = host->card;
+
+       WARN_ON(!host->claimed);
+       /*
+        * The card will be considered unchanged unless we have been asked to
+        * detect a change or host requires polling to provide card detection.
+        */
+       if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
+               return mmc_card_removed(card);
+
+       host->detect_change = 0;
+
+       return _mmc_detect_card_removed(host);
+}
+EXPORT_SYMBOL(mmc_detect_card_removed);
+
 void mmc_rescan(struct work_struct *work)
 {
        static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
@@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work)
            && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
+       host->detect_change = 0;
+
        /*
         * Let mmc_bus_put() free the bus/bus_ops if we've found that
         * the card is no longer present.
@@ -2130,6 +2175,7 @@ void mmc_stop_host(struct mmc_host *host)
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
                if (host->bus_ops->remove)
                        host->bus_ops->remove(host);
 
@@ -2201,6 +2247,9 @@ int mmc_card_awake(struct mmc_host *host)
 {
        int err = -ENOSYS;
 
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
        mmc_bus_get(host);
 
        if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
@@ -2216,6 +2265,9 @@ int mmc_card_sleep(struct mmc_host *host)
 {
        int err = -ENOSYS;
 
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
        mmc_bus_get(host);
 
        if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
@@ -2270,6 +2322,7 @@ EXPORT_SYMBOL(mmc_flush_cache);
 int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
 {
        struct mmc_card *card = host->card;
+       unsigned int timeout;
        int err = 0;
 
        if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
@@ -2280,16 +2333,18 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
                        (card->ext_csd.cache_size > 0)) {
                enable = !!enable;
 
-               if (card->ext_csd.cache_ctrl ^ enable)
+               if (card->ext_csd.cache_ctrl ^ enable) {
+                       timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_CACHE_CTRL, enable, 0);
-               if (err)
-                       pr_err("%s: cache %s error %d\n",
-                                       mmc_hostname(card->host),
-                                       enable ? "on" : "off",
-                                       err);
-               else
-                       card->ext_csd.cache_ctrl = enable;
+                                       EXT_CSD_CACHE_CTRL, enable, timeout);
+                       if (err)
+                               pr_err("%s: cache %s error %d\n",
+                                               mmc_hostname(card->host),
+                                               enable ? "on" : "off",
+                                               err);
+                       else
+                               card->ext_csd.cache_ctrl = enable;
+               }
        }
 
        return err;
@@ -2310,7 +2365,13 @@ int mmc_suspend_host(struct mmc_host *host)
                cancel_delayed_work(&host->disable);
        cancel_delayed_work(&host->detect);
        mmc_flush_scheduled_work();
-       err = mmc_cache_ctrl(host, 0);
+       if (mmc_try_claim_host(host)) {
+               err = mmc_cache_ctrl(host, 0);
+               mmc_do_release_host(host);
+       } else {
+               err = -EBUSY;
+       }
+
        if (err)
                goto out;
 
@@ -2338,7 +2399,9 @@ int mmc_suspend_host(struct mmc_host *host)
                        if (err == -ENOSYS || !host->bus_ops->resume) {
                                /*
                                 * We simply "remove" the card in this case.
-                                * It will be redetected on resume.
+                                * It will be redetected on resume.  (Calling
+                                * bus_ops->remove() with a claimed host can
+                                * deadlock.)
                                 */
                                if (host->bus_ops->remove)
                                        host->bus_ops->remove(host);
@@ -2431,11 +2494,11 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                if (!host->bus_ops || host->bus_ops->suspend)
                        break;
 
-               mmc_claim_host(host);
-
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
                if (host->bus_ops->remove)
                        host->bus_ops->remove(host);
 
+               mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
                mmc_release_host(host);
index 14664f1fb16fb560c526dd30817cc10ae6db1adf..34009241213c4640aa6ba28aa5d66c63484ec655 100644 (file)
@@ -24,6 +24,7 @@ struct mmc_bus_ops {
        int (*resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
+       int (*alive)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -59,6 +60,8 @@ void mmc_rescan(struct work_struct *work);
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+int _mmc_detect_card_removed(struct mmc_host *host);
+
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
index 3923880118b64d0519d7eb00d084e9709b271b59..9ab5b17d488ae45f63756a43bfe8917e88b52e86 100644 (file)
@@ -57,6 +57,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        const char *str;
 
        seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
+       if (host->actual_clock)
+               seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);
        seq_printf(s, "vdd:\t\t%u ", ios->vdd);
        if ((1 << ios->vdd) & MMC_VDD_165_195)
                seq_printf(s, "(1.65 - 1.95 V)\n");
@@ -133,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        case MMC_TIMING_UHS_DDR50:
                str = "sd uhs DDR50";
                break;
+       case MMC_TIMING_MMC_HS200:
+               str = "mmc high-speed SDR200";
+               break;
        default:
                str = "invalid";
                break;
index d31c78b72b0fd8d1e53adb2f403454790896fafe..30055f2b0d445b3e0c08ed131f939146fef68626 100644 (file)
@@ -54,6 +54,27 @@ static DEFINE_IDR(mmc_host_idr);
 static DEFINE_SPINLOCK(mmc_host_lock);
 
 #ifdef CONFIG_MMC_CLKGATE
+static ssize_t clkgate_delay_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
+}
+
+static ssize_t clkgate_delay_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       unsigned long flags, value;
+
+       if (kstrtoul(buf, 0, &value))
+               return -EINVAL;
+
+       spin_lock_irqsave(&host->clk_lock, flags);
+       host->clkgate_delay = value;
+       spin_unlock_irqrestore(&host->clk_lock, flags);
+       return count;
+}
 
 /*
  * Enabling clock gating will make the core call out to the host
@@ -114,7 +135,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host)
 static void mmc_host_clk_gate_work(struct work_struct *work)
 {
        struct mmc_host *host = container_of(work, struct mmc_host,
-                                             clk_gate_work);
+                                             clk_gate_work.work);
 
        mmc_host_clk_gate_delayed(host);
 }
@@ -131,6 +152,8 @@ void mmc_host_clk_hold(struct mmc_host *host)
 {
        unsigned long flags;
 
+       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
+       cancel_delayed_work_sync(&host->clk_gate_work);
        mutex_lock(&host->clk_gate_mutex);
        spin_lock_irqsave(&host->clk_lock, flags);
        if (host->clk_gated) {
@@ -180,7 +203,8 @@ void mmc_host_clk_release(struct mmc_host *host)
        host->clk_requests--;
        if (mmc_host_may_gate_card(host->card) &&
            !host->clk_requests)
-               queue_work(system_nrt_wq, &host->clk_gate_work);
+               queue_delayed_work(system_nrt_wq, &host->clk_gate_work,
+                               msecs_to_jiffies(host->clkgate_delay));
        spin_unlock_irqrestore(&host->clk_lock, flags);
 }
 
@@ -213,8 +237,13 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
        host->clk_requests = 0;
        /* Hold MCI clock for 8 cycles by default */
        host->clk_delay = 8;
+       /*
+        * Default clock gating delay is 200ms.
+        * This value can be tuned by writing into sysfs entry.
+        */
+       host->clkgate_delay = 200;
        host->clk_gated = false;
-       INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
+       INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
        spin_lock_init(&host->clk_lock);
        mutex_init(&host->clk_gate_mutex);
 }
@@ -229,7 +258,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
         * Wait for any outstanding gate and then make sure we're
         * ungated before exiting.
         */
-       if (cancel_work_sync(&host->clk_gate_work))
+       if (cancel_delayed_work_sync(&host->clk_gate_work))
                mmc_host_clk_gate_delayed(host);
        if (host->clk_gated)
                mmc_host_clk_hold(host);
@@ -237,6 +266,17 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
        WARN_ON(host->clk_requests > 1);
 }
 
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+       host->clkgate_delay_attr.show = clkgate_delay_show;
+       host->clkgate_delay_attr.store = clkgate_delay_store;
+       sysfs_attr_init(&host->clkgate_delay_attr.attr);
+       host->clkgate_delay_attr.attr.name = "clkgate_delay";
+       host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
+       if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
+               pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
+                               mmc_hostname(host));
+}
 #else
 
 static inline void mmc_host_clk_init(struct mmc_host *host)
@@ -247,6 +287,10 @@ static inline void mmc_host_clk_exit(struct mmc_host *host)
 {
 }
 
+static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
+{
+}
+
 #endif
 
 /**
@@ -335,6 +379,7 @@ int mmc_add_host(struct mmc_host *host)
 #ifdef CONFIG_DEBUG_FS
        mmc_add_host_debugfs(host);
 #endif
+       mmc_host_clk_sysfs_init(host);
 
        mmc_start_host(host);
        register_pm_notifier(&host->pm_notify);
index d240427c12462dd545b233d6d6e75787e4b48abb..59b9ba52e66a1fb420ae26f7da3350b0c8d1d592 100644 (file)
@@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+       case EXT_CSD_CARD_TYPE_SDR_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
+               break;
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
+               break;
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
+       case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
+               card->ext_csd.hs_max_dtr = 200000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
+               break;
        case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
             EXT_CSD_CARD_TYPE_26:
                card->ext_csd.hs_max_dtr = 52000000;
@@ -348,7 +369,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                                part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
                                mmc_part_add(card, part_size,
                                        EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
-                                       "boot%d", idx, true);
+                                       "boot%d", idx, true,
+                                       MMC_BLK_DATA_AREA_BOOT);
                        }
                }
        }
@@ -435,7 +457,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                                        hc_wp_grp_sz);
                                mmc_part_add(card, part_size << 19,
                                        EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
-                                       "gp%d", idx, false);
+                                       "gp%d", idx, false,
+                                       MMC_BLK_DATA_AREA_GP);
                        }
                }
                card->ext_csd.sec_trim_mult =
@@ -446,6 +469,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
                card->ext_csd.trim_timeout = 300 *
                        ext_csd[EXT_CSD_TRIM_MULT];
+
+               /*
+                * Note that the call to mmc_part_add above defaults to read
+                * only. If this default assumption is changed, the call must
+                * take into account the value of boot_locked below.
+                */
+               card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
+               card->ext_csd.boot_ro_lockable = true;
        }
 
        if (card->ext_csd.rev >= 5) {
@@ -689,6 +720,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
        return err;
 }
 
+/*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+       int idx, err = 0;
+       struct mmc_host *host;
+       static unsigned ext_csd_bits[] = {
+               EXT_CSD_BUS_WIDTH_4,
+               EXT_CSD_BUS_WIDTH_8,
+       };
+       static unsigned bus_widths[] = {
+               MMC_BUS_WIDTH_4,
+               MMC_BUS_WIDTH_8,
+       };
+
+       BUG_ON(!card);
+
+       host = card->host;
+
+       if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
+           host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+               if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+                       err = mmc_set_signal_voltage(host,
+                                                    MMC_SIGNAL_VOLTAGE_180, 0);
+
+       /* If fails try again during next card power cycle */
+       if (err)
+               goto err;
+
+       idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+
+       /*
+        * Unlike SD, MMC cards dont have a configuration register to notify
+        * supported bus width. So bus test command should be run to identify
+        * the supported bus width or compare the ext csd values of current
+        * bus width and ext csd values of 1 bit mode read earlier.
+        */
+       for (; idx >= 0; idx--) {
+
+               /*
+                * Host is capable of 8bit transfer, then switch
+                * the device to work in 8bit transfer mode. If the
+                * mmc switch command returns error then switch to
+                * 4bit transfer mode. On success set the corresponding
+                * bus width on the host.
+                */
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_BUS_WIDTH,
+                                ext_csd_bits[idx],
+                                card->ext_csd.generic_cmd6_time);
+               if (err)
+                       continue;
+
+               mmc_set_bus_width(card->host, bus_widths[idx]);
+
+               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+                       err = mmc_compare_ext_csds(card, bus_widths[idx]);
+               else
+                       err = mmc_bus_test(card, bus_widths[idx]);
+               if (!err)
+                       break;
+       }
+
+       /* switch to HS200 mode if bus width set successfully */
+       if (!err)
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_HS_TIMING, 2, 0);
+err:
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -895,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        /*
         * Activate high speed (if supported)
         */
-       if ((card->ext_csd.hs_max_dtr != 0) &&
-               (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_HS_TIMING, 1,
-                                card->ext_csd.generic_cmd6_time);
+       if (card->ext_csd.hs_max_dtr != 0) {
+               err = 0;
+               if (card->ext_csd.hs_max_dtr > 52000000 &&
+                   host->caps2 & MMC_CAP2_HS200)
+                       err = mmc_select_hs200(card);
+               else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        EXT_CSD_HS_TIMING, 1, 0);
+
                if (err && err != -EBADMSG)
                        goto free_card;
 
@@ -908,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                               mmc_hostname(card->host));
                        err = 0;
                } else {
-                       mmc_card_set_highspeed(card);
-                       mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+                       if (card->ext_csd.hs_max_dtr > 52000000 &&
+                           host->caps2 & MMC_CAP2_HS200) {
+                               mmc_card_set_hs200(card);
+                               mmc_set_timing(card->host,
+                                              MMC_TIMING_MMC_HS200);
+                       } else {
+                               mmc_card_set_highspeed(card);
+                               mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+                       }
                }
        }
 
@@ -934,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        max_dtr = (unsigned int)-1;
 
-       if (mmc_card_highspeed(card)) {
+       if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
                if (max_dtr > card->ext_csd.hs_max_dtr)
                        max_dtr = card->ext_csd.hs_max_dtr;
        } else if (max_dtr > card->csd.max_dtr) {
@@ -959,10 +1074,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                ddr = MMC_1_2V_DDR_MODE;
        }
 
+       /*
+        * Indicate HS200 SDR mode (if supported).
+        */
+       if (mmc_card_hs200(card)) {
+               u32 ext_csd_bits;
+               u32 bus_width = card->host->ios.bus_width;
+
+               /*
+                * For devices supporting HS200 mode, the bus width has
+                * to be set before executing the tuning function. If
+                * set before tuning, then device will respond with CRC
+                * errors for responses on CMD line. So for HS200 the
+                * sequence will be
+                * 1. set bus width 4bit / 8 bit (1 bit not supported)
+                * 2. switch to HS200 mode
+                * 3. set the clock to > 52Mhz <=200MHz and
+                * 4. execute tuning for HS200
+                */
+               if ((host->caps2 & MMC_CAP2_HS200) &&
+                   card->host->ops->execute_tuning)
+                       err = card->host->ops->execute_tuning(card->host,
+                               MMC_SEND_TUNING_BLOCK_HS200);
+               if (err) {
+                       pr_warning("%s: tuning execution failed\n",
+                                  mmc_hostname(card->host));
+                       goto err;
+               }
+
+               ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+                               EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
+               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+               if (err) {
+                       pr_err("%s: power class selection to bus width %d failed\n",
+                               mmc_hostname(card->host), 1 << bus_width);
+                       goto err;
+               }
+       }
+
        /*
         * Activate wide bus and DDR (if supported).
         */
-       if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+       if (!mmc_card_hs200(card) &&
+           (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
                static unsigned ext_csd_bits[][2] = {
                        { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
@@ -1048,7 +1202,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                         *
                         * WARNING: eMMC rules are NOT the same as SD DDR
                         */
-                       if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+                       if (ddr == MMC_1_2V_DDR_MODE) {
                                err = mmc_set_signal_voltage(host,
                                        MMC_SIGNAL_VOLTAGE_120, 0);
                                if (err)
@@ -1067,14 +1221,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
                        card->ext_csd.cache_size > 0) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_CACHE_CTRL, 1, 0);
+                               EXT_CSD_CACHE_CTRL, 1,
+                               card->ext_csd.generic_cmd6_time);
                if (err && err != -EBADMSG)
                        goto free_card;
 
                /*
                 * Only if no error, cache is turned on successfully.
                 */
-               card->ext_csd.cache_ctrl = err ? 0 : 1;
+               if (err) {
+                       pr_warning("%s: Cache is supported, "
+                                       "but failed to turn on (%d)\n",
+                                       mmc_hostname(card->host), err);
+                       card->ext_csd.cache_ctrl = 0;
+                       err = 0;
+               } else {
+                       card->ext_csd.cache_ctrl = 1;
+               }
        }
 
        if (!oldcard)
@@ -1104,6 +1267,14 @@ static void mmc_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -1119,7 +1290,7 @@ static void mmc_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -1224,6 +1395,7 @@ static const struct mmc_bus_ops mmc_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1234,6 +1406,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
        .suspend = mmc_suspend,
        .resume = mmc_resume,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
index f2a05ea40f2a3ed705e220fd5216d508d538b033..c63ad03c29c7ff61065ec64d66ae28eeb90884cc 100644 (file)
@@ -307,8 +307,8 @@ static int mmc_read_switch(struct mmc_card *card)
                goto out;
        }
 
-       if (status[13] & UHS_SDR50_BUS_SPEED)
-               card->sw_caps.hs_max_dtr = 50000000;
+       if (status[13] & SD_MODE_HIGH_SPEED)
+               card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
 
        if (card->scr.sda_spec3) {
                card->sw_caps.sd3_bus_mode = status[13];
@@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
 
        /* SPI mode doesn't define CMD19 */
        if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
-               err = card->host->ops->execute_tuning(card->host);
+               err = card->host->ops->execute_tuning(card->host,
+                                                     MMC_SEND_TUNING_BLOCK);
 
 out:
        kfree(status);
@@ -960,7 +961,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
 
                /* Card is an ultra-high-speed card */
-               mmc_sd_card_set_uhs(card);
+               mmc_card_set_uhs(card);
 
                /*
                 * Since initialization is now complete, enable preset
@@ -1018,6 +1019,14 @@ static void mmc_sd_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_sd_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -1033,7 +1042,7 @@ static void mmc_sd_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -1102,6 +1111,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1110,6 +1120,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
index 3ab565e32a6aca624d6f462879a0c19b7cae7697..bd7bacc950dc03b386d2a6907aff047f870bc14d 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
@@ -102,6 +103,7 @@ static int sdio_read_cccr(struct mmc_card *card)
        int ret;
        int cccr_vsn;
        unsigned char data;
+       unsigned char speed;
 
        memset(&card->cccr, 0, sizeof(struct sdio_cccr));
 
@@ -140,12 +142,60 @@ static int sdio_read_cccr(struct mmc_card *card)
        }
 
        if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
-               ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+               ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
                if (ret)
                        goto out;
 
-               if (data & SDIO_SPEED_SHS)
-                       card->cccr.high_speed = 1;
+               card->scr.sda_spec3 = 0;
+               card->sw_caps.sd3_bus_mode = 0;
+               card->sw_caps.sd3_drv_type = 0;
+               if (cccr_vsn >= SDIO_CCCR_REV_3_00) {
+                       card->scr.sda_spec3 = 1;
+                       ret = mmc_io_rw_direct(card, 0, 0,
+                               SDIO_CCCR_UHS, 0, &data);
+                       if (ret)
+                               goto out;
+
+                       if (card->host->caps &
+                               (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                                MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                                MMC_CAP_UHS_DDR50)) {
+                               if (data & SDIO_UHS_DDR50)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_DDR50;
+
+                               if (data & SDIO_UHS_SDR50)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_SDR50;
+
+                               if (data & SDIO_UHS_SDR104)
+                                       card->sw_caps.sd3_bus_mode
+                                               |= SD_MODE_UHS_SDR104;
+                       }
+
+                       ret = mmc_io_rw_direct(card, 0, 0,
+                               SDIO_CCCR_DRIVE_STRENGTH, 0, &data);
+                       if (ret)
+                               goto out;
+
+                       if (data & SDIO_DRIVE_SDTA)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A;
+                       if (data & SDIO_DRIVE_SDTC)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
+                       if (data & SDIO_DRIVE_SDTD)
+                               card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+               }
+
+               /* if no uhs mode ensure we check for high speed */
+               if (!card->sw_caps.sd3_bus_mode) {
+                       if (speed & SDIO_SPEED_SHS) {
+                               card->cccr.high_speed = 1;
+                               card->sw_caps.hs_max_dtr = 50000000;
+                       } else {
+                               card->cccr.high_speed = 0;
+                               card->sw_caps.hs_max_dtr = 25000000;
+                       }
+               }
        }
 
 out:
@@ -327,6 +377,194 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
        return max_dtr;
 }
 
+static unsigned char host_drive_to_sdio_drive(int host_strength)
+{
+       switch (host_strength) {
+       case MMC_SET_DRIVER_TYPE_A:
+               return SDIO_DTSx_SET_TYPE_A;
+       case MMC_SET_DRIVER_TYPE_B:
+               return SDIO_DTSx_SET_TYPE_B;
+       case MMC_SET_DRIVER_TYPE_C:
+               return SDIO_DTSx_SET_TYPE_C;
+       case MMC_SET_DRIVER_TYPE_D:
+               return SDIO_DTSx_SET_TYPE_D;
+       default:
+               return SDIO_DTSx_SET_TYPE_B;
+       }
+}
+
+static void sdio_select_driver_type(struct mmc_card *card)
+{
+       int host_drv_type = SD_DRIVER_TYPE_B;
+       int card_drv_type = SD_DRIVER_TYPE_B;
+       int drive_strength;
+       unsigned char card_strength;
+       int err;
+
+       /*
+        * If the host doesn't support any of the Driver Types A,C or D,
+        * or there is no board specific handler then default Driver
+        * Type B is used.
+        */
+       if (!(card->host->caps &
+               (MMC_CAP_DRIVER_TYPE_A |
+                MMC_CAP_DRIVER_TYPE_C |
+                MMC_CAP_DRIVER_TYPE_D)))
+               return;
+
+       if (!card->host->ops->select_drive_strength)
+               return;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
+               host_drv_type |= SD_DRIVER_TYPE_A;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
+               host_drv_type |= SD_DRIVER_TYPE_C;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
+               host_drv_type |= SD_DRIVER_TYPE_D;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+               card_drv_type |= SD_DRIVER_TYPE_A;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+               card_drv_type |= SD_DRIVER_TYPE_C;
+
+       if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
+               card_drv_type |= SD_DRIVER_TYPE_D;
+
+       /*
+        * The drive strength that the hardware can support
+        * depends on the board design.  Pass the appropriate
+        * information and let the hardware specific code
+        * return what is possible given the options
+        */
+       drive_strength = card->host->ops->select_drive_strength(
+               card->sw_caps.uhs_max_dtr,
+               host_drv_type, card_drv_type);
+
+       /* if error just use default for drive strength B */
+       err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
+               &card_strength);
+       if (err)
+               return;
+
+       card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
+       card_strength |= host_drive_to_sdio_drive(drive_strength);
+
+       err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH,
+               card_strength, NULL);
+
+       /* if error default to drive strength B */
+       if (!err)
+               mmc_set_driver_type(card->host, drive_strength);
+}
+
+
+static int sdio_set_bus_speed_mode(struct mmc_card *card)
+{
+       unsigned int bus_speed, timing;
+       int err;
+       unsigned char speed;
+
+       /*
+        * If the host doesn't support any of the UHS-I modes, fallback on
+        * default speed.
+        */
+       if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+               return 0;
+
+       bus_speed = SDIO_SPEED_SDR12;
+       timing = MMC_TIMING_UHS_SDR12;
+       if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
+           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+                       bus_speed = SDIO_SPEED_SDR104;
+                       timing = MMC_TIMING_UHS_SDR104;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+                       bus_speed = SDIO_SPEED_DDR50;
+                       timing = MMC_TIMING_UHS_DDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR50)) {
+                       bus_speed = SDIO_SPEED_SDR50;
+                       timing = MMC_TIMING_UHS_SDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+                       bus_speed = SDIO_SPEED_SDR25;
+                       timing = MMC_TIMING_UHS_SDR25;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+                   MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR12)) {
+                       bus_speed = SDIO_SPEED_SDR12;
+                       timing = MMC_TIMING_UHS_SDR12;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+       }
+
+       err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+       if (err)
+               return err;
+
+       speed &= ~SDIO_SPEED_BSS_MASK;
+       speed |= bus_speed;
+       err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+       if (err)
+               return err;
+
+       if (bus_speed) {
+               mmc_set_timing(card->host, timing);
+               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+       }
+
+       return 0;
+}
+
+/*
+ * UHS-I specific initialization procedure
+ */
+static int mmc_sdio_init_uhs_card(struct mmc_card *card)
+{
+       int err;
+
+       if (!card->scr.sda_spec3)
+               return 0;
+
+       /*
+        * Switch to wider bus (if supported).
+        */
+       if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+               err = sdio_enable_4bit_bus(card);
+               if (err > 0) {
+                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+                       err = 0;
+               }
+       }
+
+       /* Set the driver strength for the card */
+       sdio_select_driver_type(card);
+
+       /* Set bus speed mode of the card */
+       err = sdio_set_bus_speed_mode(card);
+       if (err)
+               goto out;
+
+       /* Initialize and start re-tuning timer */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+               err = card->host->ops->execute_tuning(card->host,
+                                                     MMC_SEND_TUNING_BLOCK);
+
+out:
+
+       return err;
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -393,6 +631,30 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
        if (host->ops->init_card)
                host->ops->init_card(host, card);
 
+       /*
+        * If the host and card support UHS-I mode request the card
+        * to switch to 1.8V signaling level.  No 1.8v signalling if
+        * UHS mode is not enabled to maintain compatibilty and some
+        * systems that claim 1.8v signalling in fact do not support
+        * it.
+        */
+       if ((ocr & R4_18V_PRESENT) &&
+               (host->caps &
+                       (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                        MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                        MMC_CAP_UHS_DDR50))) {
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
+                               true);
+               if (err) {
+                       ocr &= ~R4_18V_PRESENT;
+                       host->ocr &= ~R4_18V_PRESENT;
+               }
+               err = 0;
+       } else {
+               ocr &= ~R4_18V_PRESENT;
+               host->ocr &= ~R4_18V_PRESENT;
+       }
+
        /*
         * For native busses:  set card RCA and quit open drain mode.
         */
@@ -492,29 +754,39 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
        if (err)
                goto remove;
 
-       /*
-        * Switch to high-speed (if supported).
-        */
-       err = sdio_enable_hs(card);
-       if (err > 0)
-               mmc_sd_go_highspeed(card);
-       else if (err)
-               goto remove;
+       /* Initialization sequence for UHS-I cards */
+       /* Only if card supports 1.8v and UHS signaling */
+       if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
+               err = mmc_sdio_init_uhs_card(card);
+               if (err)
+                       goto remove;
 
-       /*
-        * Change to the card's maximum speed.
-        */
-       mmc_set_clock(host, mmc_sdio_get_max_clock(card));
+               /* Card is an ultra-high-speed card */
+               mmc_card_set_uhs(card);
+       } else {
+               /*
+                * Switch to high-speed (if supported).
+                */
+               err = sdio_enable_hs(card);
+               if (err > 0)
+                       mmc_sd_go_highspeed(card);
+               else if (err)
+                       goto remove;
 
-       /*
-        * Switch to wider bus (if supported).
-        */
-       err = sdio_enable_4bit_bus(card);
-       if (err > 0)
-               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
-       else if (err)
-               goto remove;
+               /*
+                * Change to the card's maximum speed.
+                */
+               mmc_set_clock(host, mmc_sdio_get_max_clock(card));
 
+               /*
+                * Switch to wider bus (if supported).
+                */
+               err = sdio_enable_4bit_bus(card);
+               if (err > 0)
+                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+               else if (err)
+                       goto remove;
+       }
 finish:
        if (!oldcard)
                host->card = card;
@@ -549,6 +821,14 @@ static void mmc_sdio_remove(struct mmc_host *host)
        host->card = NULL;
 }
 
+/*
+ * Card detection - card is alive.
+ */
+static int mmc_sdio_alive(struct mmc_host *host)
+{
+       return mmc_select_card(host->card);
+}
+
 /*
  * Card detection callback from host.
  */
@@ -571,7 +851,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_select_card(host->card);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -749,6 +1029,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
        .power_restore = mmc_sdio_power_restore,
+       .alive = mmc_sdio_alive,
 };
 
 
@@ -797,8 +1078,17 @@ int mmc_attach_sdio(struct mmc_host *host)
         * Detect and init the card.
         */
        err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
-       if (err)
-               goto err;
+       if (err) {
+               if (err == -EAGAIN) {
+                       /*
+                        * Retry initialization with S18R set to 0.
+                        */
+                       host->ocr &= ~R4_18V_PRESENT;
+                       err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
+               }
+               if (err)
+                       goto err;
+       }
        card = host->card;
 
        /*
index b1f3168f791b5fcbabe144faf9c6f23243957c5d..8f6f5ac131fc43cd44e544151826d0e0ad29ac61 100644 (file)
@@ -196,6 +196,9 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
        else
                mval = min(mval, func->max_blksize);
 
+       if (mmc_card_broken_byte_mode_512(func->card))
+               return min(mval, 511u);
+
        return min(mval, 512u); /* maximum size for byte mode */
 }
 
@@ -314,7 +317,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
                        func->card->host->max_seg_size / func->cur_blksize);
                max_blocks = min(max_blocks, 511u);
 
-               while (remainder > func->cur_blksize) {
+               while (remainder >= func->cur_blksize) {
                        unsigned blocks;
 
                        blocks = remainder / func->cur_blksize;
@@ -339,8 +342,9 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
        while (remainder > 0) {
                size = min(remainder, sdio_max_byte_size(func));
 
+               /* Indicate byte mode by setting "blocks" = 0 */
                ret = mmc_io_rw_extended(func->card, write, func->num, addr,
-                        incr_addr, buf, 1, size);
+                        incr_addr, buf, 0, size);
                if (ret)
                        return ret;
 
index b0517cc06200177d16766c84f237214a6f813d2f..d29e20630eed9249d339240d8e3ddd114d606a0a 100644 (file)
@@ -128,8 +128,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
 
        BUG_ON(!card);
        BUG_ON(fn > 7);
-       BUG_ON(blocks == 1 && blksz > 512);
-       WARN_ON(blocks == 0);
        WARN_ON(blksz == 0);
 
        /* sanity check */
@@ -144,22 +142,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        cmd.arg |= fn << 28;
        cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
        cmd.arg |= addr << 9;
-       if (blocks == 1 && blksz < 512)
-               cmd.arg |= blksz;                       /* byte mode */
-       else if (blocks == 1 && blksz == 512 &&
-                !(mmc_card_broken_byte_mode_512(card)))
-               cmd.arg |= 0;                           /* byte mode, 0==512 */
+       if (blocks == 0)
+               cmd.arg |= (blksz == 512) ? 0 : blksz;  /* byte mode */
        else
                cmd.arg |= 0x08000000 | blocks;         /* block mode */
        cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
 
        data.blksz = blksz;
-       data.blocks = blocks;
+       /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
+       data.blocks = blocks ? blocks : 1;
        data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
        data.sg = &sg;
        data.sg_len = 1;
 
-       sg_init_one(&sg, buf, blksz * blocks);
+       sg_init_one(&sg, buf, data.blksz * data.blocks);
 
        mmc_set_data_timeout(&data, card);
 
index b4b83f302e325f52a9d138884644cf8c9eb52819..745f8fce251986278b408951fd1d5b4a12015893 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXC)           += mxcmmc.o
 obj-$(CONFIG_MMC_MXS)          += mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
+obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))       += sdhci-pci-data.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)  += sdhci-pxav3.o
 obj-$(CONFIG_MMC_SDHCI_PXAV2)  += sdhci-pxav2.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
index f437c3e6f3aaa9b5cf5b96df2d5128c6029dfac1..947faa5d2ce4ebb243f049bca62430541c286efa 100644 (file)
@@ -236,7 +236,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
 
                sg = &data->sg[i];
 
-               sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
 
@@ -252,7 +252,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
                        dmabuf = (unsigned *)tmpv;
                }
 
-               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(sgbuffer);
 
                if (size == 0)
                        break;
@@ -302,7 +302,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
 
                sg = &data->sg[i];
 
-               sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
                amount = min(size, sg->length);
                size -= amount;
 
@@ -318,7 +318,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
                }
 
                flush_kernel_dcache_page(sg_page(sg));
-               kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(sgbuffer);
                data->bytes_xfered += amount;
                if (size == 0)
                        break;
index 0371bf502249baf416d78b85c88ca1ba218f28b0..03666174ca483e61a351626ad428a9bc833ef981 100644 (file)
@@ -627,17 +627,7 @@ static struct platform_driver sdh_driver = {
        },
 };
 
-static int __init sdh_init(void)
-{
-       return platform_driver_register(&sdh_driver);
-}
-module_init(sdh_init);
-
-static void __exit sdh_exit(void)
-{
-       platform_driver_unregister(&sdh_driver);
-}
-module_exit(sdh_exit);
+module_platform_driver(sdh_driver);
 
 MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver");
 MODULE_AUTHOR("Cliff Cai, Roy Huang");
index ce2a47b71dd6a0fe8b73d5eefb616607d04fe731..83693fd7c6b35718e5a65d81d3e8499a7694a378 100644 (file)
@@ -780,18 +780,7 @@ static struct platform_driver cb710_mmc_driver = {
 #endif
 };
 
-static int __init cb710_mmc_init_module(void)
-{
-       return platform_driver_register(&cb710_mmc_driver);
-}
-
-static void __exit cb710_mmc_cleanup_module(void)
-{
-       platform_driver_unregister(&cb710_mmc_driver);
-}
-
-module_init(cb710_mmc_init_module);
-module_exit(cb710_mmc_cleanup_module);
+module_platform_driver(cb710_mmc_driver);
 
 MODULE_AUTHOR("MichaÅ‚ MirosÅ‚aw <mirq-linux@rere.qmqm.pl>");
 MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part");
index 3aaeb0841914f6a1fdc790de71e6dbaaf15e735b..0e342793ff142f2f2616da2a6bce85542e9e4cf7 100644 (file)
@@ -588,11 +588,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
        mci_writel(host, CTYPE, (slot->ctype << slot->id));
 }
 
-static void dw_mci_start_request(struct dw_mci *host,
-                                struct dw_mci_slot *slot)
+static void __dw_mci_start_request(struct dw_mci *host,
+                                  struct dw_mci_slot *slot,
+                                  struct mmc_command *cmd)
 {
        struct mmc_request *mrq;
-       struct mmc_command *cmd;
        struct mmc_data *data;
        u32 cmdflags;
 
@@ -610,14 +610,13 @@ static void dw_mci_start_request(struct dw_mci *host,
        host->completed_events = 0;
        host->data_status = 0;
 
-       data = mrq->data;
+       data = cmd->data;
        if (data) {
                dw_mci_set_timeout(host);
                mci_writel(host, BYTCNT, data->blksz*data->blocks);
                mci_writel(host, BLKSIZ, data->blksz);
        }
 
-       cmd = mrq->cmd;
        cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
 
        /* this is the first command, send the initialization clock */
@@ -635,6 +634,16 @@ static void dw_mci_start_request(struct dw_mci *host,
                host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
 }
 
+static void dw_mci_start_request(struct dw_mci *host,
+                                struct dw_mci_slot *slot)
+{
+       struct mmc_request *mrq = slot->mrq;
+       struct mmc_command *cmd;
+
+       cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
+       __dw_mci_start_request(host, slot, cmd);
+}
+
 /* must be called with host->lock held */
 static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
                                 struct mmc_request *mrq)
@@ -698,12 +707,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                break;
        }
 
+       regs = mci_readl(slot->host, UHS_REG);
+
        /* DDR mode set */
-       if (ios->timing == MMC_TIMING_UHS_DDR50) {
-               regs = mci_readl(slot->host, UHS_REG);
+       if (ios->timing == MMC_TIMING_UHS_DDR50)
                regs |= (0x1 << slot->id) << 16;
-               mci_writel(slot->host, UHS_REG, regs);
-       }
+       else
+               regs &= ~(0x1 << slot->id) << 16;
+
+       mci_writel(slot->host, UHS_REG, regs);
 
        if (ios->clock) {
                /*
@@ -889,7 +901,14 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        cmd = host->cmd;
                        host->cmd = NULL;
                        set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
-                       dw_mci_command_complete(host, host->mrq->cmd);
+                       dw_mci_command_complete(host, cmd);
+                       if (cmd == host->mrq->sbc && !cmd->error) {
+                               prev_state = state = STATE_SENDING_CMD;
+                               __dw_mci_start_request(host, host->cur_slot,
+                                                      host->mrq->cmd);
+                               goto unlock;
+                       }
+
                        if (!host->mrq->data || cmd->error) {
                                dw_mci_request_end(host, host->mrq);
                                goto unlock;
@@ -967,6 +986,12 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                goto unlock;
                        }
 
+                       if (host->mrq->sbc && !data->error) {
+                               data->stop->error = 0;
+                               dw_mci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
                        prev_state = state = STATE_SENDING_STOP;
                        if (!data->error)
                                send_stop_cmd(host, data);
@@ -1678,8 +1703,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
-       else
-               mmc->caps = 0;
+
+       if (host->pdata->caps2)
+               mmc->caps2 = host->pdata->caps2;
 
        if (host->pdata->get_bus_wd)
                if (host->pdata->get_bus_wd(slot->id) >= 4)
@@ -1923,7 +1949,7 @@ static int dw_mci_probe(struct platform_device *pdev)
                 * should put it in the platform data.
                 */
                fifo_size = mci_readl(host, FIFOTH);
-               fifo_size = 1 + ((fifo_size >> 16) & 0x7ff);
+               fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
        } else {
                fifo_size = host->pdata->fifo_depth;
        }
@@ -2062,14 +2088,14 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
-static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int dw_mci_suspend(struct device *dev)
 {
        int i, ret;
-       struct dw_mci *host = platform_get_drvdata(pdev);
+       struct dw_mci *host = dev_get_drvdata(dev);
 
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
@@ -2092,10 +2118,10 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
        return 0;
 }
 
-static int dw_mci_resume(struct platform_device *pdev)
+static int dw_mci_resume(struct device *dev)
 {
        int i, ret;
-       struct dw_mci *host = platform_get_drvdata(pdev);
+       struct dw_mci *host = dev_get_drvdata(dev);
 
        if (host->vmmc)
                regulator_enable(host->vmmc);
@@ -2103,7 +2129,7 @@ static int dw_mci_resume(struct platform_device *pdev)
        if (host->dma_ops->init)
                host->dma_ops->init(host);
 
-       if (!mci_wait_reset(&pdev->dev, host)) {
+       if (!mci_wait_reset(dev, host)) {
                ret = -ENODEV;
                return ret;
        }
@@ -2131,14 +2157,15 @@ static int dw_mci_resume(struct platform_device *pdev)
 #else
 #define dw_mci_suspend NULL
 #define dw_mci_resume  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
 
 static struct platform_driver dw_mci_driver = {
        .remove         = __exit_p(dw_mci_remove),
-       .suspend        = dw_mci_suspend,
-       .resume         = dw_mci_resume,
        .driver         = {
                .name           = "dw_mmc",
+               .pm             = &dw_mci_pmops,
        },
 };
 
index 72c071f6e0015c7c0d254560fc3d3c344569de39..df392a1143f279d75e798a89e37c4e13356f8291 100644 (file)
 #define SDMMC_CMD_RESP_EXP             BIT(6)
 #define SDMMC_CMD_INDX(n)              ((n) & 0x1F)
 /* Status register defines */
-#define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FF)
+#define SDMMC_GET_FCNT(x)              (((x)>>17) & 0x1FFF)
 /* Internal DMAC interrupt defines */
 #define SDMMC_IDMAC_INT_AI             BIT(9)
 #define SDMMC_IDMAC_INT_NI             BIT(8)
index 74218ad677e4955d2dcb0941f68ed45c3fa4e85b..c8852a8128a90c119d7d53c5eec5381aa9678008 100644 (file)
@@ -1012,17 +1012,7 @@ static struct platform_driver jz4740_mmc_driver = {
        },
 };
 
-static int __init jz4740_mmc_init(void)
-{
-       return platform_driver_register(&jz4740_mmc_driver);
-}
-module_init(jz4740_mmc_init);
-
-static void __exit jz4740_mmc_exit(void)
-{
-       platform_driver_unregister(&jz4740_mmc_driver);
-}
-module_exit(jz4740_mmc_exit);
+module_platform_driver(jz4740_mmc_driver);
 
 MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
 MODULE_LICENSE("GPL");
index 92946b84e9faa58e9958a1cbf7e371332748afd3..273306c68d58e916d8a588fffb8fd73385c405f2 100644 (file)
@@ -1525,7 +1525,6 @@ static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
 static struct spi_driver mmc_spi_driver = {
        .driver = {
                .name =         "mmc_spi",
-               .bus =          &spi_bus_type,
                .owner =        THIS_MODULE,
                .of_match_table = mmc_spi_of_match_table,
        },
index fa8dd2fda4b270d0858f144ed34abfc30a30da4a..ece03b491c7db824fe7a698353f2c14f9f0cb6d2 100644 (file)
@@ -1245,6 +1245,7 @@ static int __devinit mmci_probe(struct amba_device *dev,
        if (host->vcc == NULL)
                mmc->ocr_avail = plat->ocr_mask;
        mmc->caps = plat->capabilities;
+       mmc->caps2 = plat->capabilities2;
 
        /*
         * We can do SGIO
index 80d8eb143b486c92ee143f6e70992570625e33e3..1d14cda95e56c8191c2168b26d4e0543eb39ddac 100644 (file)
@@ -689,8 +689,8 @@ msmsdcc_pio_irq(int irq, void *dev_id)
 
                /* Map the current scatter buffer */
                local_irq_save(flags);
-               buffer = kmap_atomic(sg_page(host->pio.sg),
-                                    KM_BIO_SRC_IRQ) + host->pio.sg->offset;
+               buffer = kmap_atomic(sg_page(host->pio.sg))
+                                    + host->pio.sg->offset;
                buffer += host->pio.sg_off;
                remain = host->pio.sg->length - host->pio.sg_off;
                len = 0;
@@ -700,7 +700,7 @@ msmsdcc_pio_irq(int irq, void *dev_id)
                        len = msmsdcc_pio_write(host, buffer, remain, status);
 
                /* Unmap the buffer */
-               kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+               kunmap_atomic(buffer);
                local_irq_restore(flags);
 
                host->pio.sg_off += len;
@@ -1480,18 +1480,7 @@ static struct platform_driver msmsdcc_driver = {
        },
 };
 
-static int __init msmsdcc_init(void)
-{
-       return platform_driver_register(&msmsdcc_driver);
-}
-
-static void __exit msmsdcc_exit(void)
-{
-       platform_driver_unregister(&msmsdcc_driver);
-}
-
-module_init(msmsdcc_init);
-module_exit(msmsdcc_exit);
+module_platform_driver(msmsdcc_driver);
 
 MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
 MODULE_LICENSE("GPL");
index 8e0fbe99404778ee1cc4f512b767479d7dad9855..7088b40f95797b00172edf0bdf4f50437b18947f 100644 (file)
@@ -1047,18 +1047,7 @@ static struct platform_driver mxcmci_driver = {
        }
 };
 
-static int __init mxcmci_init(void)
-{
-       return platform_driver_register(&mxcmci_driver);
-}
-
-static void __exit mxcmci_exit(void)
-{
-       platform_driver_unregister(&mxcmci_driver);
-}
-
-module_init(mxcmci_init);
-module_exit(mxcmci_exit);
+module_platform_driver(mxcmci_driver);
 
 MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
index 973011f9a298ba7ecf9e49d26847d25d5ad99518..4e2e019dd5c94e02a8a6b54b413dcf2e162e7777 100644 (file)
@@ -855,18 +855,7 @@ static struct platform_driver mxs_mmc_driver = {
        },
 };
 
-static int __init mxs_mmc_init(void)
-{
-       return platform_driver_register(&mxs_mmc_driver);
-}
-
-static void __exit mxs_mmc_exit(void)
-{
-       platform_driver_unregister(&mxs_mmc_driver);
-}
-
-module_init(mxs_mmc_init);
-module_exit(mxs_mmc_exit);
+module_platform_driver(mxs_mmc_driver);
 
 MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");
 MODULE_AUTHOR("Freescale Semiconductor");
index d1fb561e089d8e0ba24888d702b01ef428745b25..fd0c661bbad38a7152a37955146ff6068d4d7137 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
 
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20
-#define OMAP_MMC_MASTER_CLOCK  96000000
 #define OMAP_MMC_MIN_CLOCK     400000
 #define OMAP_MMC_MAX_CLOCK     52000000
 #define DRIVER_NAME            "omap_hsmmc"
@@ -163,7 +161,6 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       struct  work_struct     mmc_carddetect_work;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
@@ -598,12 +595,12 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
 }
 
 /* Calculate divisor for the given clock frequency */
-static u16 calc_divisor(struct mmc_ios *ios)
+static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
 {
        u16 dsor = 0;
 
        if (ios->clock) {
-               dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock);
+               dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
                if (dsor > 250)
                        dsor = 250;
        }
@@ -623,7 +620,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 
        regval = OMAP_HSMMC_READ(host->base, SYSCTL);
        regval = regval & ~(CLKD_MASK | DTO_MASK);
-       regval = regval | (calc_divisor(ios) << 6) | (DTO << 16);
+       regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
        OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
        OMAP_HSMMC_WRITE(host->base, SYSCTL,
                OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -1280,17 +1277,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
 }
 
 /*
- * Work Item to notify the core about card insertion/removal
+ * irq handler to notify the core about card insertion/removal
  */
-static void omap_hsmmc_detect(struct work_struct *work)
+static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
 {
-       struct omap_hsmmc_host *host =
-               container_of(work, struct omap_hsmmc_host, mmc_carddetect_work);
+       struct omap_hsmmc_host *host = dev_id;
        struct omap_mmc_slot_data *slot = &mmc_slot(host);
        int carddetect;
 
        if (host->suspended)
-               return;
+               return IRQ_HANDLED;
 
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
 
@@ -1305,19 +1301,6 @@ static void omap_hsmmc_detect(struct work_struct *work)
                mmc_detect_change(host->mmc, (HZ * 200) / 1000);
        else
                mmc_detect_change(host->mmc, (HZ * 50) / 1000);
-}
-
-/*
- * ISR for handling card insertion and removal
- */
-static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id)
-{
-       struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id;
-
-       if (host->suspended)
-               return IRQ_HANDLED;
-       schedule_work(&host->mmc_carddetect_work);
-
        return IRQ_HANDLED;
 }
 
@@ -1919,7 +1902,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        host->next_data.cookie = 1;
 
        platform_set_drvdata(pdev, host);
-       INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect);
 
        mmc->ops        = &omap_hsmmc_ops;
 
@@ -2049,10 +2031,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        /* Request IRQ for card detect */
        if ((mmc_slot(host).card_detect_irq)) {
-               ret = request_irq(mmc_slot(host).card_detect_irq,
-                                 omap_hsmmc_cd_handler,
-                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                                 mmc_hostname(mmc), host);
+               ret = request_threaded_irq(mmc_slot(host).card_detect_irq,
+                                          NULL,
+                                          omap_hsmmc_detect,
+                                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                          mmc_hostname(mmc), host);
                if (ret) {
                        dev_dbg(mmc_dev(host->mmc),
                                "Unable to grab MMC CD IRQ\n");
@@ -2131,7 +2114,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
                free_irq(host->irq, host);
                if (mmc_slot(host).card_detect_irq)
                        free_irq(mmc_slot(host).card_detect_irq, host);
-               flush_work_sync(&host->mmc_carddetect_work);
 
                pm_runtime_put_sync(host->dev);
                pm_runtime_disable(host->dev);
@@ -2178,7 +2160,6 @@ static int omap_hsmmc_suspend(struct device *dev)
                                return ret;
                        }
                }
-               cancel_work_sync(&host->mmc_carddetect_work);
                ret = mmc_suspend_host(host->mmc);
 
                if (ret) {
index fc4356e00d46ff7366ed38a6f76ab2f3e2c9cbce..cb2dc0e75ba7fc1ff8d6610176326fa4eb675a5d 100644 (file)
@@ -872,18 +872,7 @@ static struct platform_driver pxamci_driver = {
        },
 };
 
-static int __init pxamci_init(void)
-{
-       return platform_driver_register(&pxamci_driver);
-}
-
-static void __exit pxamci_exit(void)
-{
-       platform_driver_unregister(&pxamci_driver);
-}
-
-module_init(pxamci_init);
-module_exit(pxamci_exit);
+module_platform_driver(pxamci_driver);
 
 MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
 MODULE_LICENSE("GPL");
index 720f99334a7f95ffb7f133b2710b7294abe70369..1bcfd6dbb5cc242eb97de198f3eb383d85655e98 100644 (file)
@@ -1914,18 +1914,7 @@ static struct platform_driver s3cmci_driver = {
        .shutdown       = s3cmci_shutdown,
 };
 
-static int __init s3cmci_init(void)
-{
-       return platform_driver_register(&s3cmci_driver);
-}
-
-static void __exit s3cmci_exit(void)
-{
-       platform_driver_unregister(&s3cmci_driver);
-}
-
-module_init(s3cmci_init);
-module_exit(s3cmci_exit);
+module_platform_driver(s3cmci_driver);
 
 MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
 MODULE_LICENSE("GPL v2");
index b4257e700617c6e4f51455a462df1f063dfa0294..28a870804f60bc3cb0dbbe5e7a9d48e3e9088004 100644 (file)
@@ -115,17 +115,7 @@ static struct platform_driver sdhci_cns3xxx_driver = {
        .remove         = __devexit_p(sdhci_cns3xxx_remove),
 };
 
-static int __init sdhci_cns3xxx_init(void)
-{
-       return platform_driver_register(&sdhci_cns3xxx_driver);
-}
-module_init(sdhci_cns3xxx_init);
-
-static void __exit sdhci_cns3xxx_exit(void)
-{
-       platform_driver_unregister(&sdhci_cns3xxx_driver);
-}
-module_exit(sdhci_cns3xxx_exit);
+module_platform_driver(sdhci_cns3xxx_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for CNS3xxx");
 MODULE_AUTHOR("Scott Shu, "
index a81312c91f7086625d10f963df9f31c0b64e0c4c..46fd1fd1b605033b8f437a70da844f11f5e04226 100644 (file)
@@ -88,17 +88,7 @@ static struct platform_driver sdhci_dove_driver = {
        .remove         = __devexit_p(sdhci_dove_remove),
 };
 
-static int __init sdhci_dove_init(void)
-{
-       return platform_driver_register(&sdhci_dove_driver);
-}
-module_init(sdhci_dove_init);
-
-static void __exit sdhci_dove_exit(void)
-{
-       platform_driver_unregister(&sdhci_dove_driver);
-}
-module_exit(sdhci_dove_exit);
+module_platform_driver(sdhci_dove_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Dove");
 MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, "
index 38ebc4ea259fcb659f855fe446e45e0dc7fa9952..d601e41af282105ad5c3a86d30d569dfef3def8c 100644 (file)
@@ -606,17 +606,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
        .remove         = __devexit_p(sdhci_esdhc_imx_remove),
 };
 
-static int __init sdhci_esdhc_imx_init(void)
-{
-       return platform_driver_register(&sdhci_esdhc_imx_driver);
-}
-module_init(sdhci_esdhc_imx_init);
-
-static void __exit sdhci_esdhc_imx_exit(void)
-{
-       platform_driver_unregister(&sdhci_esdhc_imx_driver);
-}
-module_exit(sdhci_esdhc_imx_exit);
+module_platform_driver(sdhci_esdhc_imx_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
index c3b08f1119426d66d7f7ee1f4e0d466038631f9d..b97b2f5dafdb4d15160701dd12060b05c394b464 100644 (file)
@@ -73,7 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
                | (div << ESDHC_DIVIDER_SHIFT)
                | (pre_div << ESDHC_PREDIV_SHIFT));
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-       mdelay(100);
+       mdelay(1);
 out:
        host->clock = clock;
 }
index 01e5f627e0f047b2a7c63474a931fbedab0a1444..ff4adc0180418578ff10594f3f80cb2c0564d756 100644 (file)
@@ -131,17 +131,7 @@ static struct platform_driver sdhci_esdhc_driver = {
        .remove = __devexit_p(sdhci_esdhc_remove),
 };
 
-static int __init sdhci_esdhc_init(void)
-{
-       return platform_driver_register(&sdhci_esdhc_driver);
-}
-module_init(sdhci_esdhc_init);
-
-static void __exit sdhci_esdhc_exit(void)
-{
-       platform_driver_unregister(&sdhci_esdhc_driver);
-}
-module_exit(sdhci_esdhc_exit);
+module_platform_driver(sdhci_esdhc_driver);
 
 MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
 MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
index 3619adc7d9fc36548283386f82e08be2d195a608..0ce088ae02289ecf743e00c120a210e7de550d45 100644 (file)
@@ -93,17 +93,7 @@ static struct platform_driver sdhci_hlwd_driver = {
        .remove = __devexit_p(sdhci_hlwd_remove),
 };
 
-static int __init sdhci_hlwd_init(void)
-{
-       return platform_driver_register(&sdhci_hlwd_driver);
-}
-module_init(sdhci_hlwd_init);
-
-static void __exit sdhci_hlwd_exit(void)
-{
-       platform_driver_unregister(&sdhci_hlwd_driver);
-}
-module_exit(sdhci_hlwd_exit);
+module_platform_driver(sdhci_hlwd_driver);
 
 MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver");
 MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz");
diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c
new file mode 100644 (file)
index 0000000..a611217
--- /dev/null
@@ -0,0 +1,5 @@
+#include <linux/module.h>
+#include <linux/mmc/sdhci-pci-data.h>
+
+struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
+EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
index 6878a94626bc35b18bf493a4dcbf522dc3403255..7165e6a092742e82f9b7cf108ad9f034a1173304 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/scatterlist.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
-#include <linux/sfi.h>
 #include <linux/pm_runtime.h>
+#include <linux/mmc/sdhci-pci-data.h>
 
 #include "sdhci.h"
 
@@ -61,6 +61,7 @@ struct sdhci_pci_fixes {
 struct sdhci_pci_slot {
        struct sdhci_pci_chip   *chip;
        struct sdhci_host       *host;
+       struct sdhci_pci_data   *data;
 
        int                     pci_bar;
        int                     rst_n_gpio;
@@ -171,32 +172,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip)
        return 0;
 }
 
-/* Medfield eMMC hardware reset GPIOs */
-static int mfd_emmc0_rst_gpio = -EINVAL;
-static int mfd_emmc1_rst_gpio = -EINVAL;
-
-static int mfd_emmc_gpio_parse(struct sfi_table_header *table)
-{
-       struct sfi_table_simple *sb = (struct sfi_table_simple *)table;
-       struct sfi_gpio_table_entry *entry;
-       int i, num;
-
-       num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
-       entry = (struct sfi_gpio_table_entry *)sb->pentry;
-
-       for (i = 0; i < num; i++, entry++) {
-               if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN))
-                       mfd_emmc0_rst_gpio = entry->pin_no;
-               else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN))
-                       mfd_emmc1_rst_gpio = entry->pin_no;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_PM_RUNTIME
 
-static irqreturn_t mfd_sd_cd(int irq, void *dev_id)
+static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
 {
        struct sdhci_pci_slot *slot = dev_id;
        struct sdhci_host *host = slot->host;
@@ -205,15 +183,16 @@ static irqreturn_t mfd_sd_cd(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#define MFLD_SD_CD_PIN 69
-
-static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot)
+static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
 {
-       int err, irq, gpio = MFLD_SD_CD_PIN;
+       int err, irq, gpio = slot->cd_gpio;
 
        slot->cd_gpio = -EINVAL;
        slot->cd_irq = -EINVAL;
 
+       if (!gpio_is_valid(gpio))
+               return;
+
        err = gpio_request(gpio, "sd_cd");
        if (err < 0)
                goto out;
@@ -226,72 +205,53 @@ static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot)
        if (irq < 0)
                goto out_free;
 
-       err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING |
+       err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
                          IRQF_TRIGGER_FALLING, "sd_cd", slot);
        if (err)
                goto out_free;
 
        slot->cd_gpio = gpio;
        slot->cd_irq = irq;
-       slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION;
 
-       return 0;
+       return;
 
 out_free:
        gpio_free(gpio);
 out:
        dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
-       return 0;
 }
 
-static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead)
+static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
 {
        if (slot->cd_irq >= 0)
                free_irq(slot->cd_irq, slot);
-       gpio_free(slot->cd_gpio);
+       if (gpio_is_valid(slot->cd_gpio))
+               gpio_free(slot->cd_gpio);
 }
 
 #else
 
-#define mfd_sd_probe_slot      NULL
-#define mfd_sd_remove_slot     NULL
+static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
+{
+}
+
+static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
+{
+}
 
 #endif
 
 static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
-       const char *name = NULL;
-       int gpio = -EINVAL;
-
-       sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse);
-
-       switch (slot->chip->pdev->device) {
-       case PCI_DEVICE_ID_INTEL_MFD_EMMC0:
-               gpio = mfd_emmc0_rst_gpio;
-               name = "eMMC0_reset";
-               break;
-       case PCI_DEVICE_ID_INTEL_MFD_EMMC1:
-               gpio = mfd_emmc1_rst_gpio;
-               name = "eMMC1_reset";
-               break;
-       }
-
-       if (!gpio_request(gpio, name)) {
-               gpio_direction_output(gpio, 1);
-               slot->rst_n_gpio = gpio;
-               slot->host->mmc->caps |= MMC_CAP_HW_RESET;
-       }
-
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
-
        slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
-
        return 0;
 }
 
-static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead)
+static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
-       gpio_free(slot->rst_n_gpio);
+       slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD;
+       return 0;
 }
 
 static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
@@ -307,20 +267,18 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
-       .probe_slot     = mfd_sd_probe_slot,
-       .remove_slot    = mfd_sd_remove_slot,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
+       .probe_slot     = mfd_sdio_probe_slot,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .allow_runtime_pm = true,
        .probe_slot     = mfd_emmc_probe_slot,
-       .remove_slot    = mfd_emmc_remove_slot,
 };
 
 /* O2Micro extra registers */
@@ -1012,11 +970,8 @@ static int sdhci_pci_suspend(struct device *dev)
 
                ret = sdhci_suspend_host(slot->host);
 
-               if (ret) {
-                       for (i--; i >= 0; i--)
-                               sdhci_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_suspend;
 
                slot_pm_flags = slot->host->mmc->pm_flags;
                if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
@@ -1027,11 +982,8 @@ static int sdhci_pci_suspend(struct device *dev)
 
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip);
-               if (ret) {
-                       for (i = chip->num_slots - 1; i >= 0; i--)
-                               sdhci_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_suspend;
        }
 
        pci_save_state(pdev);
@@ -1048,6 +1000,11 @@ static int sdhci_pci_suspend(struct device *dev)
        }
 
        return 0;
+
+err_pci_suspend:
+       while (--i >= 0)
+               sdhci_resume_host(chip->slots[i]->host);
+       return ret;
 }
 
 static int sdhci_pci_resume(struct device *dev)
@@ -1113,23 +1070,22 @@ static int sdhci_pci_runtime_suspend(struct device *dev)
 
                ret = sdhci_runtime_suspend_host(slot->host);
 
-               if (ret) {
-                       for (i--; i >= 0; i--)
-                               sdhci_runtime_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_runtime_suspend;
        }
 
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip);
-               if (ret) {
-                       for (i = chip->num_slots - 1; i >= 0; i--)
-                               sdhci_runtime_resume_host(chip->slots[i]->host);
-                       return ret;
-               }
+               if (ret)
+                       goto err_pci_runtime_suspend;
        }
 
        return 0;
+
+err_pci_runtime_suspend:
+       while (--i >= 0)
+               sdhci_runtime_resume_host(chip->slots[i]->host);
+       return ret;
 }
 
 static int sdhci_pci_runtime_resume(struct device *dev)
@@ -1190,11 +1146,12 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
 \*****************************************************************************/
 
 static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
-       struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar)
+       struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
+       int slotno)
 {
        struct sdhci_pci_slot *slot;
        struct sdhci_host *host;
-       int ret;
+       int ret, bar = first_bar + slotno;
 
        if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
                dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
@@ -1228,6 +1185,23 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        slot->host = host;
        slot->pci_bar = bar;
        slot->rst_n_gpio = -EINVAL;
+       slot->cd_gpio = -EINVAL;
+
+       /* Retrieve platform data if there is any */
+       if (*sdhci_pci_get_data)
+               slot->data = sdhci_pci_get_data(pdev, slotno);
+
+       if (slot->data) {
+               if (slot->data->setup) {
+                       ret = slot->data->setup(slot->data);
+                       if (ret) {
+                               dev_err(&pdev->dev, "platform setup failed\n");
+                               goto free;
+                       }
+               }
+               slot->rst_n_gpio = slot->data->rst_n_gpio;
+               slot->cd_gpio = slot->data->cd_gpio;
+       }
 
        host->hw_name = "PCI";
        host->ops = &sdhci_pci_ops;
@@ -1238,7 +1212,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
        if (ret) {
                dev_err(&pdev->dev, "cannot request region\n");
-               goto free;
+               goto cleanup;
        }
 
        host->ioaddr = pci_ioremap_bar(pdev, bar);
@@ -1254,15 +1228,30 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                        goto unmap;
        }
 
+       if (gpio_is_valid(slot->rst_n_gpio)) {
+               if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
+                       gpio_direction_output(slot->rst_n_gpio, 1);
+                       slot->host->mmc->caps |= MMC_CAP_HW_RESET;
+               } else {
+                       dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
+                       slot->rst_n_gpio = -EINVAL;
+               }
+       }
+
        host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
 
        ret = sdhci_add_host(host);
        if (ret)
                goto remove;
 
+       sdhci_pci_add_own_cd(slot);
+
        return slot;
 
 remove:
+       if (gpio_is_valid(slot->rst_n_gpio))
+               gpio_free(slot->rst_n_gpio);
+
        if (chip->fixes && chip->fixes->remove_slot)
                chip->fixes->remove_slot(slot, 0);
 
@@ -1272,6 +1261,10 @@ unmap:
 release:
        pci_release_region(pdev, bar);
 
+cleanup:
+       if (slot->data && slot->data->cleanup)
+               slot->data->cleanup(slot->data);
+
 free:
        sdhci_free_host(host);
 
@@ -1283,6 +1276,8 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
        int dead;
        u32 scratch;
 
+       sdhci_pci_remove_own_cd(slot);
+
        dead = 0;
        scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
        if (scratch == (u32)-1)
@@ -1290,9 +1285,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 
        sdhci_remove_host(slot->host, dead);
 
+       if (gpio_is_valid(slot->rst_n_gpio))
+               gpio_free(slot->rst_n_gpio);
+
        if (slot->chip->fixes && slot->chip->fixes->remove_slot)
                slot->chip->fixes->remove_slot(slot, dead);
 
+       if (slot->data && slot->data->cleanup)
+               slot->data->cleanup(slot->data);
+
        pci_release_region(slot->chip->pdev, slot->pci_bar);
 
        sdhci_free_host(slot->host);
@@ -1379,7 +1380,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        slots = chip->num_slots;        /* Quirk may have changed this */
 
        for (i = 0; i < slots; i++) {
-               slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
+               slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
                if (IS_ERR(slot)) {
                        for (i--; i >= 0; i--)
                                sdhci_pci_remove_slot(chip->slots[i]);
index 7a039c3cb1f10a8651ae04091c8303008ad2cbe2..dbb75bfbcffb3e181f6d0af195209e5187c3b210 100644 (file)
@@ -223,18 +223,8 @@ static struct platform_driver sdhci_pxav2_driver = {
        .probe          = sdhci_pxav2_probe,
        .remove         = __devexit_p(sdhci_pxav2_remove),
 };
-static int __init sdhci_pxav2_init(void)
-{
-       return platform_driver_register(&sdhci_pxav2_driver);
-}
-
-static void __exit sdhci_pxav2_exit(void)
-{
-       platform_driver_unregister(&sdhci_pxav2_driver);
-}
 
-module_init(sdhci_pxav2_init);
-module_exit(sdhci_pxav2_exit);
+module_platform_driver(sdhci_pxav2_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for pxav2");
 MODULE_AUTHOR("Marvell International Ltd.");
index 15673a7ee6a59a70d7455179f3afe30b3fb15588..f29695683556df8f7c01ad6f145a9fc36583e410 100644 (file)
@@ -269,18 +269,8 @@ static struct platform_driver sdhci_pxav3_driver = {
        .probe          = sdhci_pxav3_probe,
        .remove         = __devexit_p(sdhci_pxav3_remove),
 };
-static int __init sdhci_pxav3_init(void)
-{
-       return platform_driver_register(&sdhci_pxav3_driver);
-}
-
-static void __exit sdhci_pxav3_exit(void)
-{
-       platform_driver_unregister(&sdhci_pxav3_driver);
-}
 
-module_init(sdhci_pxav3_init);
-module_exit(sdhci_pxav3_exit);
+module_platform_driver(sdhci_pxav3_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for pxav3");
 MODULE_AUTHOR("Marvell International Ltd.");
index 9a20d1f55bb7a616408f3bc5fc0f41cefec0c64f..1af756ee0f9ab5e43db1a348505021a6fd5eee28 100644 (file)
@@ -80,7 +80,7 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host)
 
                tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
                tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(tmp, host->ioaddr + 0x80);
+               writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2);
        }
 }
 
@@ -521,6 +521,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->host_caps)
                host->mmc->caps |= pdata->host_caps;
 
+       if (pdata->pm_caps)
+               host->mmc->pm_caps |= pdata->pm_caps;
+
        host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
                         SDHCI_QUIRK_32BIT_DMA_SIZE);
 
@@ -654,18 +657,7 @@ static struct platform_driver sdhci_s3c_driver = {
        },
 };
 
-static int __init sdhci_s3c_init(void)
-{
-       return platform_driver_register(&sdhci_s3c_driver);
-}
-
-static void __exit sdhci_s3c_exit(void)
-{
-       platform_driver_unregister(&sdhci_s3c_driver);
-}
-
-module_init(sdhci_s3c_init);
-module_exit(sdhci_s3c_exit);
+module_platform_driver(sdhci_s3c_driver);
 
 MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
index 63cc8b6a1c9e6335113f67b5dd84766819b7cb80..b7f8b33c5f19f7202f66d65fd90ff14b503f8dd4 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-spear.h>
@@ -271,26 +272,54 @@ static int __devexit sdhci_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sdhci_suspend(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       int ret;
+
+       ret = sdhci_suspend_host(host);
+       if (!ret)
+               clk_disable(sdhci->clk);
+
+       return ret;
+}
+
+static int sdhci_resume(struct device *dev)
+{
+       struct sdhci_host *host = dev_get_drvdata(dev);
+       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       int ret;
+
+       ret = clk_enable(sdhci->clk);
+       if (ret) {
+               dev_dbg(dev, "Resume: Error enabling clock\n");
+               return ret;
+       }
+
+       return sdhci_resume_host(host);
+}
+
+const struct dev_pm_ops sdhci_pm_ops = {
+       .suspend        = sdhci_suspend,
+       .resume         = sdhci_resume,
+};
+#endif
+
 static struct platform_driver sdhci_driver = {
        .driver = {
                .name   = "sdhci",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &sdhci_pm_ops,
+#endif
        },
        .probe          = sdhci_probe,
        .remove         = __devexit_p(sdhci_remove),
 };
 
-static int __init sdhci_init(void)
-{
-       return platform_driver_register(&sdhci_driver);
-}
-module_init(sdhci_init);
-
-static void __exit sdhci_exit(void)
-{
-       platform_driver_unregister(&sdhci_driver);
-}
-module_exit(sdhci_exit);
+module_platform_driver(sdhci_driver);
 
 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
 MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
index e2e18d3f949c45dda79395646484a848a84d9326..78a36eba4df0b77d5fd433a3a805373484c50c22 100644 (file)
@@ -324,17 +324,7 @@ static struct platform_driver sdhci_tegra_driver = {
        .remove         = __devexit_p(sdhci_tegra_remove),
 };
 
-static int __init sdhci_tegra_init(void)
-{
-       return platform_driver_register(&sdhci_tegra_driver);
-}
-module_init(sdhci_tegra_init);
-
-static void __exit sdhci_tegra_exit(void)
-{
-       platform_driver_unregister(&sdhci_tegra_driver);
-}
-module_exit(sdhci_tegra_exit);
+module_platform_driver(sdhci_tegra_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Tegra");
 MODULE_AUTHOR(" Google, Inc.");
index 19ed580f2cabf2fca09ae59d52cb86f5265f9ab8..8d66706824a6105ceeac2f63526372a4f0c521fd 100644 (file)
@@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
-static int sdhci_execute_tuning(struct mmc_host *mmc);
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
 
 #ifdef CONFIG_PM_RUNTIME
@@ -146,10 +146,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
        u32 present, irqs;
 
-       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-               return;
-
-       if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION)
+       if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
+           !mmc_card_is_removable(host->mmc))
                return;
 
        present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
@@ -214,6 +212,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+
+       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+               if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
+                       host->ops->enable_dma(host);
+       }
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
@@ -423,12 +426,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
 static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
 {
        local_irq_save(*flags);
-       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+       return kmap_atomic(sg_page(sg)) + sg->offset;
 }
 
 static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
 {
-       kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+       kunmap_atomic(buffer);
        local_irq_restore(*flags);
 }
 
@@ -1016,7 +1019,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                flags |= SDHCI_CMD_INDEX;
 
        /* CMD19 is special in that the Data Present Select should be set */
-       if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
+       if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+           cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
                flags |= SDHCI_CMD_DATA;
 
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
@@ -1066,12 +1070,15 @@ static void sdhci_finish_command(struct sdhci_host *host)
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        int div = 0; /* Initialized for compiler warning */
+       int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
 
-       if (clock == host->clock)
+       if (clock && clock == host->clock)
                return;
 
+       host->mmc->actual_clock = 0;
+
        if (host->ops->set_clock) {
                host->ops->set_clock(host, clock);
                if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
@@ -1109,6 +1116,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                                 * Control register.
                                 */
                                clk = SDHCI_PROG_CLOCK_MODE;
+                               real_div = div;
+                               clk_mul = host->clk_mul;
                                div--;
                        }
                } else {
@@ -1122,6 +1131,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                                                break;
                                }
                        }
+                       real_div = div;
                        div >>= 1;
                }
        } else {
@@ -1130,9 +1140,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        if ((host->max_clk / div) <= clock)
                                break;
                }
+               real_div = div;
                div >>= 1;
        }
 
+       if (real_div)
+               host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
+
        clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
@@ -1160,7 +1174,7 @@ out:
        host->clock = clock;
 }
 
-static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
        u8 pwr = 0;
 
@@ -1183,13 +1197,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
        }
 
        if (host->pwr == pwr)
-               return;
+               return -1;
 
        host->pwr = pwr;
 
        if (pwr == 0) {
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-               return;
+               return 0;
        }
 
        /*
@@ -1216,6 +1230,8 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
         */
        if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
                mdelay(10);
+
+       return power;
 }
 
 /*****************************************************************************\
@@ -1277,7 +1293,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
                    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
                        spin_unlock_irqrestore(&host->lock, flags);
-                       sdhci_execute_tuning(mmc);
+                       sdhci_execute_tuning(mmc, mrq->cmd->opcode);
                        spin_lock_irqsave(&host->lock, flags);
 
                        /* Restore original mmc_request structure */
@@ -1297,12 +1313,17 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
        unsigned long flags;
+       int vdd_bit = -1;
        u8 ctrl;
 
        spin_lock_irqsave(&host->lock, flags);
 
-       if (host->flags & SDHCI_DEVICE_DEAD)
-               goto out;
+       if (host->flags & SDHCI_DEVICE_DEAD) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
+                       mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
+               return;
+       }
 
        /*
         * Reset the chip on each power off.
@@ -1316,9 +1337,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        sdhci_set_clock(host, ios->clock);
 
        if (ios->power_mode == MMC_POWER_OFF)
-               sdhci_set_power(host, -1);
+               vdd_bit = sdhci_set_power(host, -1);
        else
-               sdhci_set_power(host, ios->vdd);
+               vdd_bit = sdhci_set_power(host, ios->vdd);
+
+       if (host->vmmc && vdd_bit != -1) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
+               spin_lock_irqsave(&host->lock, flags);
+       }
 
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1361,11 +1388,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                unsigned int clock;
 
                /* In case of UHS-I modes, set High Speed Enable */
-               if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
+               if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
-                   (ios->timing == MMC_TIMING_UHS_SDR25) ||
-                   (ios->timing == MMC_TIMING_UHS_SDR12))
+                   (ios->timing == MMC_TIMING_UHS_SDR25))
                        ctrl |= SDHCI_CTRL_HISPD;
 
                ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@@ -1415,7 +1442,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        /* Select Bus Speed Mode for host */
                        ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-                       if (ios->timing == MMC_TIMING_UHS_SDR12)
+                       if (ios->timing == MMC_TIMING_MMC_HS200)
+                               ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR12)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
                        else if (ios->timing == MMC_TIMING_UHS_SDR25)
                                ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
@@ -1443,7 +1472,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
                sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
-out:
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -1663,7 +1691,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
        return err;
 }
 
-static int sdhci_execute_tuning(struct mmc_host *mmc)
+static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host;
        u16 ctrl;
@@ -1671,6 +1699,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
        int tuning_loop_counter = MAX_TUNING_LOOP;
        unsigned long timeout;
        int err = 0;
+       bool requires_tuning_nonuhs = false;
 
        host = mmc_priv(mmc);
 
@@ -1681,13 +1710,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 
        /*
-        * Host Controller needs tuning only in case of SDR104 mode
-        * and for SDR50 mode when Use Tuning for SDR50 is set in
+        * The Host Controller needs tuning only in case of SDR104 mode
+        * and for SDR50 mode when Use Tuning for SDR50 is set in the
         * Capabilities register.
+        * If the Host Controller supports the HS200 mode then the
+        * tuning function has to be executed.
         */
+       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+           (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
+            host->flags & SDHCI_HS200_NEEDS_TUNING))
+               requires_tuning_nonuhs = true;
+
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
-           (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
-           (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
+           requires_tuning_nonuhs)
                ctrl |= SDHCI_CTRL_EXEC_TUNING;
        else {
                spin_unlock(&host->lock);
@@ -1723,7 +1758,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
                if (!tuning_loop_counter && !timeout)
                        break;
 
-               cmd.opcode = MMC_SEND_TUNING_BLOCK;
+               cmd.opcode = opcode;
                cmd.arg = 0;
                cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
                cmd.retries = 0;
@@ -1738,7 +1773,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc)
                 * block to the Host Controller. So we set the block size
                 * to 64 here.
                 */
-               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+               if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+                       if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
+                                            SDHCI_BLOCK_SIZE);
+                       else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+                               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                                            SDHCI_BLOCK_SIZE);
+               } else {
+                       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
+                                    SDHCI_BLOCK_SIZE);
+               }
 
                /*
                 * The tuning block is sent by the card to the host controller.
@@ -2121,12 +2166,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { }
 
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
+       u32 command;
        BUG_ON(intmask == 0);
 
        /* CMD19 generates _only_ Buffer Read Ready interrupt */
        if (intmask & SDHCI_INT_DATA_AVAIL) {
-               if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
-                   MMC_SEND_TUNING_BLOCK) {
+               command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
+               if (command == MMC_SEND_TUNING_BLOCK ||
+                   command == MMC_SEND_TUNING_BLOCK_HS200) {
                        host->tuning_done = 1;
                        wake_up(&host->buf_ready_int);
                        return;
@@ -2330,26 +2377,33 @@ out:
 int sdhci_suspend_host(struct sdhci_host *host)
 {
        int ret;
+       bool has_tuning_timer;
 
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
-       if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
-           host->tuning_mode == SDHCI_TUNING_MODE_1) {
+       has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
+               host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
+       if (has_tuning_timer) {
+               del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
-               mod_timer(&host->tuning_timer, jiffies +
-                       host->tuning_count * HZ);
        }
 
        ret = mmc_suspend_host(host->mmc);
-       if (ret)
+       if (ret) {
+               if (has_tuning_timer) {
+                       host->flags |= SDHCI_NEEDS_RETUNING;
+                       mod_timer(&host->tuning_timer, jiffies +
+                                       host->tuning_count * HZ);
+               }
+
+               sdhci_enable_card_detection(host);
+
                return ret;
+       }
 
        free_irq(host->irq, host);
 
-       if (host->vmmc)
-               ret = regulator_disable(host->vmmc);
-
        return ret;
 }
 
@@ -2359,12 +2413,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 {
        int ret;
 
-       if (host->vmmc) {
-               int ret = regulator_enable(host->vmmc);
-               if (ret)
-                       return ret;
-       }
-
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma)
                        host->ops->enable_dma(host);
@@ -2727,10 +2775,14 @@ int sdhci_add_host(struct sdhci_host *host)
        if (caps[1] & SDHCI_SUPPORT_DDR50)
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
-       /* Does the host needs tuning for SDR50? */
+       /* Does the host need tuning for SDR50? */
        if (caps[1] & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
+       /* Does the host need tuning for HS200? */
+       if (mmc->caps2 & MMC_CAP2_HS200)
+               host->flags |= SDHCI_HS200_NEEDS_TUNING;
+
        /* Driver Type(s) (A, C, D) supported by the host */
        if (caps[1] & SDHCI_DRIVER_TYPE_A)
                mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
@@ -2926,8 +2978,6 @@ int sdhci_add_host(struct sdhci_host *host)
        if (IS_ERR(host->vmmc)) {
                pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
                host->vmmc = NULL;
-       } else {
-               regulator_enable(host->vmmc);
        }
 
        sdhci_init(host, 0);
@@ -3016,10 +3066,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
-       if (host->vmmc) {
-               regulator_disable(host->vmmc);
+       if (host->vmmc)
                regulator_put(host->vmmc);
-       }
 
        kfree(host->adma_desc);
        kfree(host->align_buffer);
index a04d4d0c6fd20911c29f59a4f0132eea2cffa6b7..ad265b96b75b4f25262186ff68a171202c4474ee 100644 (file)
 #define   SDHCI_CTRL_UHS_SDR50         0x0002
 #define   SDHCI_CTRL_UHS_SDR104                0x0003
 #define   SDHCI_CTRL_UHS_DDR50         0x0004
+#define   SDHCI_CTRL_HS_SDR200         0x0005 /* reserved value in SDIO spec */
 #define  SDHCI_CTRL_VDD_180            0x0008
 #define  SDHCI_CTRL_DRV_TYPE_MASK      0x0030
 #define   SDHCI_CTRL_DRV_TYPE_B                0x0000
index d5505f3fe2a170d04fc9011c5b5d2ff886a31df7..4a2c5b2355f21d81887e0f92d7f3350c1c51f288 100644 (file)
  *
  */
 
+/*
+ * The MMCIF driver is now processing MMC requests asynchronously, according
+ * to the Linux MMC API requirement.
+ *
+ * The MMCIF driver processes MMC requests in up to 3 stages: command, optional
+ * data, and optional stop. To achieve asynchronous processing each of these
+ * stages is split into two halves: a top and a bottom half. The top half
+ * initialises the hardware, installs a timeout handler to handle completion
+ * timeouts, and returns. In case of the command stage this immediately returns
+ * control to the caller, leaving all further processing to run asynchronously.
+ * All further request processing is performed by the bottom halves.
+ *
+ * The bottom half further consists of a "hard" IRQ handler, an IRQ handler
+ * thread, a DMA completion callback, if DMA is used, a timeout work, and
+ * request- and stage-specific handler methods.
+ *
+ * Each bottom half run begins with either a hardware interrupt, a DMA callback
+ * invocation, or a timeout work run. In case of an error or a successful
+ * processing completion, the MMC core is informed and the request processing is
+ * finished. In case processing has to continue, i.e., if data has to be read
+ * from or written to the card, or if a stop command has to be sent, the next
+ * top half is called, which performs the necessary hardware handling and
+ * reschedules the timeout work. This returns the driver state machine into the
+ * bottom half waiting state.
+ */
+
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
 #define MASK_MRBSYTO           (1 << 1)
 #define MASK_MRSPTO            (1 << 0)
 
+#define MASK_START_CMD         (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \
+                                MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \
+                                MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \
+                                MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO)
+
 /* CE_HOST_STS1 */
 #define STS1_CMDSEQ            (1 << 31)
 
@@ -162,9 +194,21 @@ enum mmcif_state {
        STATE_IOS,
 };
 
+enum mmcif_wait_for {
+       MMCIF_WAIT_FOR_REQUEST,
+       MMCIF_WAIT_FOR_CMD,
+       MMCIF_WAIT_FOR_MREAD,
+       MMCIF_WAIT_FOR_MWRITE,
+       MMCIF_WAIT_FOR_READ,
+       MMCIF_WAIT_FOR_WRITE,
+       MMCIF_WAIT_FOR_READ_END,
+       MMCIF_WAIT_FOR_WRITE_END,
+       MMCIF_WAIT_FOR_STOP,
+};
+
 struct sh_mmcif_host {
        struct mmc_host *mmc;
-       struct mmc_data *data;
+       struct mmc_request *mrq;
        struct platform_device *pd;
        struct sh_dmae_slave dma_slave_tx;
        struct sh_dmae_slave dma_slave_rx;
@@ -172,11 +216,17 @@ struct sh_mmcif_host {
        unsigned int clk;
        int bus_width;
        bool sd_error;
+       bool dying;
        long timeout;
        void __iomem *addr;
-       struct completion intr_wait;
+       u32 *pio_ptr;
+       spinlock_t lock;                /* protect sh_mmcif_host::state */
        enum mmcif_state state;
-       spinlock_t lock;
+       enum mmcif_wait_for wait_for;
+       struct delayed_work timeout_work;
+       size_t blocksize;
+       int sg_idx;
+       int sg_blkidx;
        bool power;
        bool card_present;
 
@@ -202,19 +252,21 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
 static void mmcif_dma_complete(void *arg)
 {
        struct sh_mmcif_host *host = arg;
+       struct mmc_data *data = host->mrq->data;
+
        dev_dbg(&host->pd->dev, "Command completed\n");
 
-       if (WARN(!host->data, "%s: NULL data in DMA completion!\n",
+       if (WARN(!data, "%s: NULL data in DMA completion!\n",
                 dev_name(&host->pd->dev)))
                return;
 
-       if (host->data->flags & MMC_DATA_READ)
+       if (data->flags & MMC_DATA_READ)
                dma_unmap_sg(host->chan_rx->device->dev,
-                            host->data->sg, host->data->sg_len,
+                            data->sg, data->sg_len,
                             DMA_FROM_DEVICE);
        else
                dma_unmap_sg(host->chan_tx->device->dev,
-                            host->data->sg, host->data->sg_len,
+                            data->sg, data->sg_len,
                             DMA_TO_DEVICE);
 
        complete(&host->dma_complete);
@@ -222,13 +274,14 @@ static void mmcif_dma_complete(void *arg)
 
 static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
 {
-       struct scatterlist *sg = host->data->sg;
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_rx;
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+       ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
                         DMA_FROM_DEVICE);
        if (ret > 0) {
                host->dma_active = true;
@@ -244,7 +297,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
                dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
-               __func__, host->data->sg_len, ret, cookie);
+               __func__, data->sg_len, ret, cookie);
 
        if (!desc) {
                /* DMA failed, fall back to PIO */
@@ -265,18 +318,19 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
        }
 
        dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
-               desc, cookie, host->data->sg_len);
+               desc, cookie, data->sg_len);
 }
 
 static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
 {
-       struct scatterlist *sg = host->data->sg;
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *chan = host->chan_tx;
        dma_cookie_t cookie = -EINVAL;
        int ret;
 
-       ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+       ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
                         DMA_TO_DEVICE);
        if (ret > 0) {
                host->dma_active = true;
@@ -292,7 +346,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
                dma_async_issue_pending(chan);
        }
        dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
-               __func__, host->data->sg_len, ret, cookie);
+               __func__, data->sg_len, ret, cookie);
 
        if (!desc) {
                /* DMA failed, fall back to PIO */
@@ -399,7 +453,7 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
        else
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
-                       (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16));
+                               ((fls(host->clk / clk) - 1) << 16));
 
        sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
 }
@@ -421,7 +475,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
 static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
 {
        u32 state1, state2;
-       int ret, timeout = 10000000;
+       int ret, timeout;
 
        host->sd_error = false;
 
@@ -433,155 +487,212 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
        if (state1 & STS1_CMDSEQ) {
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
                sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
-               while (1) {
-                       timeout--;
-                       if (timeout < 0) {
-                               dev_err(&host->pd->dev,
-                                       "Forceed end of command sequence timeout err\n");
-                               return -EIO;
-                       }
+               for (timeout = 10000000; timeout; timeout--) {
                        if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
-                                                               & STS1_CMDSEQ))
+                             & STS1_CMDSEQ))
                                break;
                        mdelay(1);
                }
+               if (!timeout) {
+                       dev_err(&host->pd->dev,
+                               "Forced end of command sequence timeout err\n");
+                       return -EIO;
+               }
                sh_mmcif_sync_reset(host);
                dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
                return -EIO;
        }
 
        if (state2 & STS2_CRC_ERR) {
-               dev_dbg(&host->pd->dev, ": Happened CRC error\n");
+               dev_dbg(&host->pd->dev, ": CRC error\n");
                ret = -EIO;
        } else if (state2 & STS2_TIMEOUT_ERR) {
-               dev_dbg(&host->pd->dev, ": Happened Timeout error\n");
+               dev_dbg(&host->pd->dev, ": Timeout\n");
                ret = -ETIMEDOUT;
        } else {
-               dev_dbg(&host->pd->dev, ": Happened End/Index error\n");
+               dev_dbg(&host->pd->dev, ": End/Index error\n");
                ret = -EIO;
        }
        return ret;
 }
 
-static int sh_mmcif_single_read(struct sh_mmcif_host *host,
-                                       struct mmc_request *mrq)
+static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p)
 {
-       struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, *p = sg_virt(data->sg);
+       struct mmc_data *data = host->mrq->data;
+
+       host->sg_blkidx += host->blocksize;
+
+       /* data->sg->length must be a multiple of host->blocksize? */
+       BUG_ON(host->sg_blkidx > data->sg->length);
+
+       if (host->sg_blkidx == data->sg->length) {
+               host->sg_blkidx = 0;
+               if (++host->sg_idx < data->sg_len)
+                       host->pio_ptr = sg_virt(++data->sg);
+       } else {
+               host->pio_ptr = p;
+       }
+
+       if (host->sg_idx == data->sg_len)
+               return false;
+
+       return true;
+}
+
+static void sh_mmcif_single_read(struct sh_mmcif_host *host,
+                                struct mmc_request *mrq)
+{
+       host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+                          BLOCK_SIZE_MASK) + 3;
+
+       host->wait_for = MMCIF_WAIT_FOR_READ;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 
        /* buf read enable */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       blocksize = (BLOCK_SIZE_MASK &
-                       sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
-       for (i = 0; i < blocksize / 4; i++)
+}
+
+static bool sh_mmcif_read_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = sg_virt(data->sg);
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
+       }
+
+       for (i = 0; i < host->blocksize / 4; i++)
                *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
 
        /* buffer read end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
+       host->wait_for = MMCIF_WAIT_FOR_READ_END;
 
-       return 0;
+       return true;
 }
 
-static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
-                                       struct mmc_request *mrq)
+static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq)
 {
        struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, j, sec, *p;
-
-       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
-                                                    MMCIF_CE_BLOCK_SET);
-       for (j = 0; j < data->sg_len; j++) {
-               p = sg_virt(data->sg);
-               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
-                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-                       /* buf read enable */
-                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                               host->timeout);
-
-                       if (time <= 0 || host->sd_error)
-                               return sh_mmcif_error_manage(host);
-
-                       for (i = 0; i < blocksize / 4; i++)
-                               *p++ = sh_mmcif_readl(host->addr,
-                                                     MMCIF_CE_DATA);
-               }
-               if (j < data->sg_len - 1)
-                       data->sg++;
+
+       if (!data->sg_len || !data->sg->length)
+               return;
+
+       host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+               BLOCK_SIZE_MASK;
+
+       host->wait_for = MMCIF_WAIT_FOR_MREAD;
+       host->sg_idx = 0;
+       host->sg_blkidx = 0;
+       host->pio_ptr = sg_virt(data->sg);
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+}
+
+static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = host->pio_ptr;
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
        }
-       return 0;
+
+       BUG_ON(!data->sg->length);
+
+       for (i = 0; i < host->blocksize / 4; i++)
+               *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
+
+       if (!sh_mmcif_next_block(host, p))
+               return false;
+
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+
+       return true;
 }
 
-static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+static void sh_mmcif_single_write(struct sh_mmcif_host *host,
                                        struct mmc_request *mrq)
 {
-       struct mmc_data *data = mrq->data;
-       long time;
-       u32 blocksize, i, *p = sg_virt(data->sg);
+       host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+                          BLOCK_SIZE_MASK) + 3;
 
-       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+       host->wait_for = MMCIF_WAIT_FOR_WRITE;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 
        /* buf write enable */
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       blocksize = (BLOCK_SIZE_MASK &
-                       sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
-       for (i = 0; i < blocksize / 4; i++)
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
+
+static bool sh_mmcif_write_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = sg_virt(data->sg);
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
+       }
+
+       for (i = 0; i < host->blocksize / 4; i++)
                sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
 
        /* buffer write end */
        sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+       host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error)
-               return sh_mmcif_error_manage(host);
-
-       return 0;
+       return true;
 }
 
-static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
-                                               struct mmc_request *mrq)
+static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq)
 {
        struct mmc_data *data = mrq->data;
-       long time;
-       u32 i, sec, j, blocksize, *p;
 
-       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
-                                                    MMCIF_CE_BLOCK_SET);
+       if (!data->sg_len || !data->sg->length)
+               return;
 
-       for (j = 0; j < data->sg_len; j++) {
-               p = sg_virt(data->sg);
-               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
-                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
-                       /* buf write enable*/
-                       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                               host->timeout);
+       host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+               BLOCK_SIZE_MASK;
 
-                       if (time <= 0 || host->sd_error)
-                               return sh_mmcif_error_manage(host);
+       host->wait_for = MMCIF_WAIT_FOR_MWRITE;
+       host->sg_idx = 0;
+       host->sg_blkidx = 0;
+       host->pio_ptr = sg_virt(data->sg);
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
 
-                       for (i = 0; i < blocksize / 4; i++)
-                               sh_mmcif_writel(host->addr,
-                                               MMCIF_CE_DATA, *p++);
-               }
-               if (j < data->sg_len - 1)
-                       data->sg++;
+static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p = host->pio_ptr;
+       int i;
+
+       if (host->sd_error) {
+               data->error = sh_mmcif_error_manage(host);
+               return false;
        }
-       return 0;
+
+       BUG_ON(!data->sg->length);
+
+       for (i = 0; i < host->blocksize / 4; i++)
+               sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
+
+       if (!sh_mmcif_next_block(host, p))
+               return false;
+
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+
+       return true;
 }
 
 static void sh_mmcif_get_response(struct sh_mmcif_host *host,
@@ -603,8 +714,11 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
 }
 
 static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
-               struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
+                           struct mmc_request *mrq)
 {
+       struct mmc_data *data = mrq->data;
+       struct mmc_command *cmd = mrq->cmd;
+       u32 opc = cmd->opcode;
        u32 tmp = 0;
 
        /* Response Type check */
@@ -636,7 +750,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                break;
        }
        /* WDAT / DATW */
-       if (host->data) {
+       if (data) {
                tmp |= CMD_SET_WDAT;
                switch (host->bus_width) {
                case MMC_BUS_WIDTH_1:
@@ -660,7 +774,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
        if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
                tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
                sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
-                                       mrq->data->blocks << 16);
+                               data->blocks << 16);
        }
        /* RIDXC[1:0] check bits */
        if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
@@ -674,68 +788,60 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
                opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
                tmp |= CMD_SET_CRC7C_INTERNAL;
 
-       return opc = ((opc << 24) | tmp);
+       return (opc << 24) | tmp;
 }
 
 static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
-                               struct mmc_request *mrq, u32 opc)
+                              struct mmc_request *mrq, u32 opc)
 {
-       int ret;
-
        switch (opc) {
        case MMC_READ_MULTIPLE_BLOCK:
-               ret = sh_mmcif_multi_read(host, mrq);
-               break;
+               sh_mmcif_multi_read(host, mrq);
+               return 0;
        case MMC_WRITE_MULTIPLE_BLOCK:
-               ret = sh_mmcif_multi_write(host, mrq);
-               break;
+               sh_mmcif_multi_write(host, mrq);
+               return 0;
        case MMC_WRITE_BLOCK:
-               ret = sh_mmcif_single_write(host, mrq);
-               break;
+               sh_mmcif_single_write(host, mrq);
+               return 0;
        case MMC_READ_SINGLE_BLOCK:
        case MMC_SEND_EXT_CSD:
-               ret = sh_mmcif_single_read(host, mrq);
-               break;
+               sh_mmcif_single_read(host, mrq);
+               return 0;
        default:
                dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
-               ret = -EINVAL;
-               break;
+               return -EINVAL;
        }
-       return ret;
 }
 
 static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
-                       struct mmc_request *mrq, struct mmc_command *cmd)
+                              struct mmc_request *mrq)
 {
-       long time;
-       int ret = 0, mask = 0;
+       struct mmc_command *cmd = mrq->cmd;
        u32 opc = cmd->opcode;
+       u32 mask;
 
        switch (opc) {
-       /* respons busy check */
+       /* response busy check */
        case MMC_SWITCH:
        case MMC_STOP_TRANSMISSION:
        case MMC_SET_WRITE_PROT:
        case MMC_CLR_WRITE_PROT:
        case MMC_ERASE:
        case MMC_GEN_CMD:
-               mask = MASK_MRBSYE;
+               mask = MASK_START_CMD | MASK_MRBSYE;
                break;
        default:
-               mask = MASK_MCRSPE;
+               mask = MASK_START_CMD | MASK_MCRSPE;
                break;
        }
-       mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
-               MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
-               MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
-               MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
 
-       if (host->data) {
+       if (mrq->data) {
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
                                mrq->data->blksz);
        }
-       opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
+       opc = sh_mmcif_set_cmd(host, mrq);
 
        sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
@@ -744,80 +850,28 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        /* set cmd */
        sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-               host->timeout);
-       if (time <= 0) {
-               cmd->error = sh_mmcif_error_manage(host);
-               return;
-       }
-       if (host->sd_error) {
-               switch (cmd->opcode) {
-               case MMC_ALL_SEND_CID:
-               case MMC_SELECT_CARD:
-               case MMC_APP_CMD:
-                       cmd->error = -ETIMEDOUT;
-                       break;
-               default:
-                       dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n",
-                                       cmd->opcode);
-                       cmd->error = sh_mmcif_error_manage(host);
-                       break;
-               }
-               host->sd_error = false;
-               return;
-       }
-       if (!(cmd->flags & MMC_RSP_PRESENT)) {
-               cmd->error = 0;
-               return;
-       }
-       sh_mmcif_get_response(host, cmd);
-       if (host->data) {
-               if (!host->dma_active) {
-                       ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
-               } else {
-                       long time =
-                               wait_for_completion_interruptible_timeout(&host->dma_complete,
-                                                                         host->timeout);
-                       if (!time)
-                               ret = -ETIMEDOUT;
-                       else if (time < 0)
-                               ret = time;
-                       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
-                                       BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
-                       host->dma_active = false;
-               }
-               if (ret < 0)
-                       mrq->data->bytes_xfered = 0;
-               else
-                       mrq->data->bytes_xfered =
-                               mrq->data->blocks * mrq->data->blksz;
-       }
-       cmd->error = ret;
+       host->wait_for = MMCIF_WAIT_FOR_CMD;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 }
 
 static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
-               struct mmc_request *mrq, struct mmc_command *cmd)
+                             struct mmc_request *mrq)
 {
-       long time;
-
-       if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
+       switch (mrq->cmd->opcode) {
+       case MMC_READ_MULTIPLE_BLOCK:
                sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
-       else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+               break;
+       case MMC_WRITE_MULTIPLE_BLOCK:
                sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
-       else {
+               break;
+       default:
                dev_err(&host->pd->dev, "unsupported stop cmd\n");
-               cmd->error = sh_mmcif_error_manage(host);
+               mrq->stop->error = sh_mmcif_error_manage(host);
                return;
        }
 
-       time = wait_for_completion_interruptible_timeout(&host->intr_wait,
-                       host->timeout);
-       if (time <= 0 || host->sd_error) {
-               cmd->error = sh_mmcif_error_manage(host);
-               return;
-       }
-       sh_mmcif_get_cmd12response(host, cmd);
-       cmd->error = 0;
+       host->wait_for = MMCIF_WAIT_FOR_STOP;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
 }
 
 static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -856,23 +910,10 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        default:
                break;
        }
-       host->data = mrq->data;
-       if (mrq->data) {
-               if (mrq->data->flags & MMC_DATA_READ) {
-                       if (host->chan_rx)
-                               sh_mmcif_start_dma_rx(host);
-               } else {
-                       if (host->chan_tx)
-                               sh_mmcif_start_dma_tx(host);
-               }
-       }
-       sh_mmcif_start_cmd(host, mrq, mrq->cmd);
-       host->data = NULL;
 
-       if (!mrq->cmd->error && mrq->stop)
-               sh_mmcif_stop_cmd(host, mrq, mrq->stop);
-       host->state = STATE_IDLE;
-       mmc_request_done(mmc, mrq);
+       host->mrq = mrq;
+
+       sh_mmcif_start_cmd(host, mrq);
 }
 
 static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -947,9 +988,156 @@ static struct mmc_host_ops sh_mmcif_ops = {
        .get_cd         = sh_mmcif_get_cd,
 };
 
-static void sh_mmcif_detect(struct mmc_host *mmc)
+static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
 {
-       mmc_detect_change(mmc, 0);
+       struct mmc_command *cmd = host->mrq->cmd;
+       struct mmc_data *data = host->mrq->data;
+       long time;
+
+       if (host->sd_error) {
+               switch (cmd->opcode) {
+               case MMC_ALL_SEND_CID:
+               case MMC_SELECT_CARD:
+               case MMC_APP_CMD:
+                       cmd->error = -ETIMEDOUT;
+                       host->sd_error = false;
+                       break;
+               default:
+                       cmd->error = sh_mmcif_error_manage(host);
+                       dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n",
+                               cmd->opcode, cmd->error);
+                       break;
+               }
+               return false;
+       }
+       if (!(cmd->flags & MMC_RSP_PRESENT)) {
+               cmd->error = 0;
+               return false;
+       }
+
+       sh_mmcif_get_response(host, cmd);
+
+       if (!data)
+               return false;
+
+       if (data->flags & MMC_DATA_READ) {
+               if (host->chan_rx)
+                       sh_mmcif_start_dma_rx(host);
+       } else {
+               if (host->chan_tx)
+                       sh_mmcif_start_dma_tx(host);
+       }
+
+       if (!host->dma_active) {
+               data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
+               if (!data->error)
+                       return true;
+               return false;
+       }
+
+       /* Running in the IRQ thread, can sleep */
+       time = wait_for_completion_interruptible_timeout(&host->dma_complete,
+                                                        host->timeout);
+       if (host->sd_error) {
+               dev_err(host->mmc->parent,
+                       "Error IRQ while waiting for DMA completion!\n");
+               /* Woken up by an error IRQ: abort DMA */
+               if (data->flags & MMC_DATA_READ)
+                       dmaengine_terminate_all(host->chan_rx);
+               else
+                       dmaengine_terminate_all(host->chan_tx);
+               data->error = sh_mmcif_error_manage(host);
+       } else if (!time) {
+               data->error = -ETIMEDOUT;
+       } else if (time < 0) {
+               data->error = time;
+       }
+       sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
+                       BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+       host->dma_active = false;
+
+       if (data->error)
+               data->bytes_xfered = 0;
+
+       return false;
+}
+
+static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
+{
+       struct sh_mmcif_host *host = dev_id;
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data = mrq->data;
+
+       cancel_delayed_work_sync(&host->timeout_work);
+
+       /*
+        * All handlers return true, if processing continues, and false, if the
+        * request has to be completed - successfully or not
+        */
+       switch (host->wait_for) {
+       case MMCIF_WAIT_FOR_REQUEST:
+               /* We're too late, the timeout has already kicked in */
+               return IRQ_HANDLED;
+       case MMCIF_WAIT_FOR_CMD:
+               if (sh_mmcif_end_cmd(host))
+                       /* Wait for data */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_MREAD:
+               if (sh_mmcif_mread_block(host))
+                       /* Wait for more data */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_READ:
+               if (sh_mmcif_read_block(host))
+                       /* Wait for data end */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_MWRITE:
+               if (sh_mmcif_mwrite_block(host))
+                       /* Wait data to write */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_WRITE:
+               if (sh_mmcif_write_block(host))
+                       /* Wait for data end */
+                       return IRQ_HANDLED;
+               break;
+       case MMCIF_WAIT_FOR_STOP:
+               if (host->sd_error) {
+                       mrq->stop->error = sh_mmcif_error_manage(host);
+                       break;
+               }
+               sh_mmcif_get_cmd12response(host, mrq->stop);
+               mrq->stop->error = 0;
+               break;
+       case MMCIF_WAIT_FOR_READ_END:
+       case MMCIF_WAIT_FOR_WRITE_END:
+               if (host->sd_error)
+                       data->error = sh_mmcif_error_manage(host);
+               break;
+       default:
+               BUG();
+       }
+
+       if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
+               if (!mrq->cmd->error && data && !data->error)
+                       data->bytes_xfered =
+                               data->blocks * data->blksz;
+
+               if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
+                       sh_mmcif_stop_cmd(host, mrq);
+                       if (!mrq->stop->error)
+                               return IRQ_HANDLED;
+               }
+       }
+
+       host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+       host->state = STATE_IDLE;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
@@ -960,7 +1148,12 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
 
-       if (state & INT_RBSYE) {
+       if (state & INT_ERR_STS) {
+               /* error interrupts - process first */
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
+               err = 1;
+       } else if (state & INT_RBSYE) {
                sh_mmcif_writel(host->addr, MMCIF_CE_INT,
                                ~(INT_RBSYE | INT_CRSPE));
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
@@ -988,11 +1181,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                sh_mmcif_writel(host->addr, MMCIF_CE_INT,
                                ~(INT_CMD12RBE | INT_CMD12CRE));
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
-       } else if (state & INT_ERR_STS) {
-               /* err interrupts */
-               sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
-               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
-               err = 1;
        } else {
                dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
                sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
@@ -1003,14 +1191,57 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                host->sd_error = true;
                dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
        }
-       if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
-               complete(&host->intr_wait);
-       else
+       if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
+               if (!host->dma_active)
+                       return IRQ_WAKE_THREAD;
+               else if (host->sd_error)
+                       mmcif_dma_complete(host);
+       } else {
                dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
+       }
 
        return IRQ_HANDLED;
 }
 
+static void mmcif_timeout_work(struct work_struct *work)
+{
+       struct delayed_work *d = container_of(work, struct delayed_work, work);
+       struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work);
+       struct mmc_request *mrq = host->mrq;
+
+       if (host->dying)
+               /* Don't run after mmc_remove_host() */
+               return;
+
+       /*
+        * Handle races with cancel_delayed_work(), unless
+        * cancel_delayed_work_sync() is used
+        */
+       switch (host->wait_for) {
+       case MMCIF_WAIT_FOR_CMD:
+               mrq->cmd->error = sh_mmcif_error_manage(host);
+               break;
+       case MMCIF_WAIT_FOR_STOP:
+               mrq->stop->error = sh_mmcif_error_manage(host);
+               break;
+       case MMCIF_WAIT_FOR_MREAD:
+       case MMCIF_WAIT_FOR_MWRITE:
+       case MMCIF_WAIT_FOR_READ:
+       case MMCIF_WAIT_FOR_WRITE:
+       case MMCIF_WAIT_FOR_READ_END:
+       case MMCIF_WAIT_FOR_WRITE_END:
+               mrq->data->error = sh_mmcif_error_manage(host);
+               break;
+       default:
+               BUG();
+       }
+
+       host->state = STATE_IDLE;
+       host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
 static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 {
        int ret = 0, irq[2];
@@ -1064,7 +1295,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        host->clk = clk_get_rate(host->hclk);
        host->pd = pdev;
 
-       init_completion(&host->intr_wait);
        spin_lock_init(&host->lock);
 
        mmc->ops = &sh_mmcif_ops;
@@ -1101,19 +1331,21 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
-       ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
+       ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
                goto clean_up3;
        }
-       ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
+       ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
        if (ret) {
                free_irq(irq[0], host);
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
                goto clean_up3;
        }
 
-       sh_mmcif_detect(host->mmc);
+       INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
+
+       mmc_detect_change(host->mmc, 0);
 
        dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
        dev_dbg(&pdev->dev, "chip ver H'%04x\n",
@@ -1139,11 +1371,19 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
        int irq[2];
 
+       host->dying = true;
        pm_runtime_get_sync(&pdev->dev);
 
        mmc_remove_host(host->mmc);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
+       /*
+        * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the
+        * mmc_remove_host() call above. But swapping order doesn't help either
+        * (a query on the linux-mmc mailing list didn't bring any replies).
+        */
+       cancel_delayed_work_sync(&host->timeout_work);
+
        if (host->addr)
                iounmap(host->addr);
 
@@ -1206,19 +1446,7 @@ static struct platform_driver sh_mmcif_driver = {
        },
 };
 
-static int __init sh_mmcif_init(void)
-{
-       return platform_driver_register(&sh_mmcif_driver);
-}
-
-static void __exit sh_mmcif_exit(void)
-{
-       platform_driver_unregister(&sh_mmcif_driver);
-}
-
-module_init(sh_mmcif_init);
-module_exit(sh_mmcif_exit);
-
+module_platform_driver(sh_mmcif_driver);
 
 MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
 MODULE_LICENSE("GPL");
index 41ae6466bd83e8b65b87d0da122afe54bdc93fb3..58da3c44acc5d129428198b7ec80f987fe73d68a 100644 (file)
@@ -282,18 +282,7 @@ static struct platform_driver sh_mobile_sdhi_driver = {
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
 };
 
-static int __init sh_mobile_sdhi_init(void)
-{
-       return platform_driver_register(&sh_mobile_sdhi_driver);
-}
-
-static void __exit sh_mobile_sdhi_exit(void)
-{
-       platform_driver_unregister(&sh_mobile_sdhi_driver);
-}
-
-module_init(sh_mobile_sdhi_init);
-module_exit(sh_mobile_sdhi_exit);
+module_platform_driver(sh_mobile_sdhi_driver);
 
 MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
 MODULE_AUTHOR("Magnus Damm");
index f70d04664cac8aff6223df5d2965e630db826044..fc00081687b9a45e93847f1c0ba3d674ced22a95 100644 (file)
@@ -118,7 +118,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
        unsigned char *buf;
        unsigned int pos = 0, val;
 
-       buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+       buf = kmap_atomic(pg) + off;
        if (host->cmd_flags & DATA_CARRY) {
                buf[pos++] = host->bounce_buf_data[0];
                host->cmd_flags &= ~DATA_CARRY;
@@ -134,7 +134,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
                }
                buf[pos++] = (val >> 8) & 0xff;
        }
-       kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
+       kunmap_atomic(buf - off);
 }
 
 static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
@@ -144,7 +144,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
        unsigned char *buf;
        unsigned int pos = 0, val;
 
-       buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+       buf = kmap_atomic(pg) + off;
        if (host->cmd_flags & DATA_CARRY) {
                val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
                writel(val, sock->addr + SOCK_MMCSD_DATA);
@@ -161,7 +161,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
                val |= (buf[pos++] << 8) & 0xff00;
                writel(val, sock->addr + SOCK_MMCSD_DATA);
        }
-       kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+       kunmap_atomic(buf - off);
 }
 
 static void tifm_sd_transfer_data(struct tifm_sd *host)
@@ -212,13 +212,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
                              struct page *src, unsigned int src_off,
                              unsigned int count)
 {
-       unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
-       unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+       unsigned char *src_buf = kmap_atomic(src) + src_off;
+       unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
 
        memcpy(dst_buf, src_buf, count);
 
-       kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
-       kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+       kunmap_atomic(dst_buf - dst_off);
+       kunmap_atomic(src_buf - src_off);
 }
 
 static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
index a4ea10242787465d21f99e93e11516d8090cdef1..113ce6c9cf3203d1ad71f445ce62b63be6f2eca5 100644 (file)
@@ -138,19 +138,7 @@ static struct platform_driver tmio_mmc_driver = {
        .resume = tmio_mmc_resume,
 };
 
-
-static int __init tmio_mmc_init(void)
-{
-       return platform_driver_register(&tmio_mmc_driver);
-}
-
-static void __exit tmio_mmc_exit(void)
-{
-       platform_driver_unregister(&tmio_mmc_driver);
-}
-
-module_init(tmio_mmc_init);
-module_exit(tmio_mmc_exit);
+module_platform_driver(tmio_mmc_driver);
 
 MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
index 3020f98218f0104d5082dd4d94a84a3c9a5160eb..a95e6d901726031275066ca7b394fc9be7b6a96c 100644 (file)
@@ -105,13 +105,13 @@ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
                                         unsigned long *flags)
 {
        local_irq_save(*flags);
-       return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
+       return kmap_atomic(sg_page(sg)) + sg->offset;
 }
 
 static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
                                          unsigned long *flags, void *virt)
 {
-       kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ);
+       kunmap_atomic(virt - sg->offset);
        local_irq_restore(*flags);
 }
 
index 4208b3958069119e68e8da8ad03e3eadf5862b8c..abad01b37cfbbab50761cafda285d40e67346b3b 100644 (file)
@@ -800,8 +800,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        } else if (ios->power_mode != MMC_POWER_UP) {
                if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
                        host->set_pwr(host->pdev, 0);
-               if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
-                   pdata->power) {
+               if (pdata->power) {
                        pdata->power = false;
                        pm_runtime_put(&host->pdev->dev);
                }
@@ -915,6 +914,23 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (ret < 0)
                goto pm_disable;
 
+       /*
+        * There are 4 different scenarios for the card detection:
+        *  1) an external gpio irq handles the cd (best for power savings)
+        *  2) internal sdhi irq handles the cd
+        *  3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
+        *  4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
+        *
+        *  While we increment the rtpm counter for all scenarios when the mmc
+        *  core activates us by calling an appropriate set_ios(), we must
+        *  additionally ensure that in case 2) the tmio mmc hardware stays
+        *  powered on during runtime for the card detection to work.
+        */
+       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD
+               || mmc->caps & MMC_CAP_NEEDS_POLL
+               || mmc->caps & MMC_CAP_NONREMOVABLE))
+               pm_runtime_get_noresume(&pdev->dev);
+
        tmio_mmc_clk_stop(_host);
        tmio_mmc_reset(_host);
 
@@ -933,12 +949,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       /* We have to keep the device powered for its card detection to work */
-       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) {
-               pdata->power = true;
-               pm_runtime_get_noresume(&pdev->dev);
-       }
-
        mmc_add_host(mmc);
 
        /* Unmask the IRQs we want to know about */
@@ -974,7 +984,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
         * the controller, the runtime PM is suspended and pdata->power == false,
         * so, our .runtime_resume() will not try to detect a card in the slot.
         */
-       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD)
+       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD
+               || host->mmc->caps & MMC_CAP_NEEDS_POLL
+               || host->mmc->caps & MMC_CAP_NONREMOVABLE)
                pm_runtime_get_sync(&pdev->dev);
 
        mmc_remove_host(host->mmc);
index db8e8272d69b04d08aebbf99f6f668220e2b994a..3ce99e00a49e89f558796c5a426934bb97e91a84 100644 (file)
@@ -315,8 +315,7 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,
        char *dst;
 
        if (reason != KMSG_DUMP_OOPS &&
-           reason != KMSG_DUMP_PANIC &&
-           reason != KMSG_DUMP_KEXEC)
+           reason != KMSG_DUMP_PANIC)
                return;
 
        /* Only dump oopses if dump_oops is set */
index 64fbb002182518310e56693cc88b294465cc2383..ead2cd16ba7588f7e1ea21866df9da6795ce3d5e 100644 (file)
        pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
 
 /* Just a debugging messages not related to any specific UBI subsystem */
-#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                    \
+       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+              current->pid, __func__, ##__VA_ARGS__)
+
 /* General debugging messages */
 #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Messages from the eraseblock association sub-system */
index fb7f19b62d91fabe2fdc785bf08aa1a32f523497..cd26da8ad225b882d918188e46c6c2d38cccc803 100644 (file)
@@ -1028,12 +1028,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
         * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
         * LEB is already locked, we just do not move it and return
-        * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later.
+        * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because
+        * we do not know the reasons of the contention - it may be just a
+        * normal I/O on this LEB, so we want to re-try.
         */
        err = leb_write_trylock(ubi, vol_id, lnum);
        if (err) {
                dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum);
-               return MOVE_CANCEL_RACE;
+               return MOVE_RETRY;
        }
 
        /*
index dc64c767fd2175e2503510bb1cea51d3ffb63f47..d51d75d344462c1ec3b0ae657b423594f5857517 100644 (file)
@@ -120,6 +120,7 @@ enum {
  *                     PEB
  * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
  *                       target PEB
+ * MOVE_RETRY: retry scrubbing the PEB
  */
 enum {
        MOVE_CANCEL_RACE = 1,
@@ -127,6 +128,7 @@ enum {
        MOVE_TARGET_RD_ERR,
        MOVE_TARGET_WR_ERR,
        MOVE_CANCEL_BITFLIPS,
+       MOVE_RETRY,
 };
 
 /**
index 9ad18da1891de31d2e792de57ede91626764e431..890754c9f3272a490c360c8e6e8d67d194839a32 100644 (file)
@@ -306,7 +306,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
                       int copy, void *vtbl)
 {
        int err, tries = 0;
-       static struct ubi_vid_hdr *vid_hdr;
+       struct ubi_vid_hdr *vid_hdr;
        struct ubi_scan_leb *new_seb;
 
        ubi_msg("create volume table (copy #%d)", copy + 1);
index 42c684cf368815814614be19b0398d65fc99fcf0..0696e36b053939e878d0215aefe4f4598ba61ac3 100644 (file)
@@ -795,7 +795,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                        protect = 1;
                        goto out_not_moved;
                }
-
+               if (err == MOVE_RETRY) {
+                       scrubbing = 1;
+                       goto out_not_moved;
+               }
                if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
                    err == MOVE_TARGET_RD_ERR) {
                        /*
@@ -1049,7 +1052,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 
        ubi_err("failed to erase PEB %d, error %d", pnum, err);
        kfree(wl_wrk);
-       kmem_cache_free(ubi_wl_entry_slab, e);
 
        if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
            err == -EBUSY) {
@@ -1062,14 +1064,16 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                        goto out_ro;
                }
                return err;
-       } else if (err != -EIO) {
+       }
+
+       kmem_cache_free(ubi_wl_entry_slab, e);
+       if (err != -EIO)
                /*
                 * If this is not %-EIO, we have no idea what to do. Scheduling
                 * this physical eraseblock for erasure again would cause
                 * errors again and again. Well, lets switch to R/O mode.
                 */
                goto out_ro;
-       }
 
        /* It is %-EIO, the PEB went bad */
 
index 106b88a04738fb25fa5bd850537653beaa5b4aa5..342626f4bc4641d197f1c322bbdfebb0619d289c 100644 (file)
@@ -99,16 +99,26 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
 
 /*********************** tlb specific functions ***************************/
 
-static inline void _lock_tx_hashtbl(struct bonding *bond)
+static inline void _lock_tx_hashtbl_bh(struct bonding *bond)
 {
        spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
 }
 
-static inline void _unlock_tx_hashtbl(struct bonding *bond)
+static inline void _unlock_tx_hashtbl_bh(struct bonding *bond)
 {
        spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
 }
 
+static inline void _lock_tx_hashtbl(struct bonding *bond)
+{
+       spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+}
+
+static inline void _unlock_tx_hashtbl(struct bonding *bond)
+{
+       spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+}
+
 /* Caller must hold tx_hashtbl lock */
 static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load)
 {
@@ -129,14 +139,13 @@ static inline void tlb_init_slave(struct slave *slave)
        SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX;
 }
 
-/* Caller must hold bond lock for read */
-static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load)
+/* Caller must hold bond lock for read, BH disabled */
+static void __tlb_clear_slave(struct bonding *bond, struct slave *slave,
+                        int save_load)
 {
        struct tlb_client_info *tx_hash_table;
        u32 index;
 
-       _lock_tx_hashtbl(bond);
-
        /* clear slave from tx_hashtbl */
        tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl;
 
@@ -151,8 +160,15 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_
        }
 
        tlb_init_slave(slave);
+}
 
-       _unlock_tx_hashtbl(bond);
+/* Caller must hold bond lock for read */
+static void tlb_clear_slave(struct bonding *bond, struct slave *slave,
+                        int save_load)
+{
+       _lock_tx_hashtbl_bh(bond);
+       __tlb_clear_slave(bond, slave, save_load);
+       _unlock_tx_hashtbl_bh(bond);
 }
 
 /* Must be called before starting the monitor timer */
@@ -169,7 +185,7 @@ static int tlb_initialize(struct bonding *bond)
                       bond->dev->name);
                return -1;
        }
-       _lock_tx_hashtbl(bond);
+       _lock_tx_hashtbl_bh(bond);
 
        bond_info->tx_hashtbl = new_hashtbl;
 
@@ -177,7 +193,7 @@ static int tlb_initialize(struct bonding *bond)
                tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
        }
 
-       _unlock_tx_hashtbl(bond);
+       _unlock_tx_hashtbl_bh(bond);
 
        return 0;
 }
@@ -187,12 +203,12 @@ static void tlb_deinitialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
-       _lock_tx_hashtbl(bond);
+       _lock_tx_hashtbl_bh(bond);
 
        kfree(bond_info->tx_hashtbl);
        bond_info->tx_hashtbl = NULL;
 
-       _unlock_tx_hashtbl(bond);
+       _unlock_tx_hashtbl_bh(bond);
 }
 
 static long long compute_gap(struct slave *slave)
@@ -226,15 +242,13 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
        return least_loaded;
 }
 
-/* Caller must hold bond lock for read */
-static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len)
+static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
+                                               u32 skb_len)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        struct tlb_client_info *hash_table;
        struct slave *assigned_slave;
 
-       _lock_tx_hashtbl(bond);
-
        hash_table = bond_info->tx_hashtbl;
        assigned_slave = hash_table[hash_index].tx_slave;
        if (!assigned_slave) {
@@ -263,22 +277,46 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3
                hash_table[hash_index].tx_bytes += skb_len;
        }
 
-       _unlock_tx_hashtbl(bond);
-
        return assigned_slave;
 }
 
+/* Caller must hold bond lock for read */
+static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index,
+                                       u32 skb_len)
+{
+       struct slave *tx_slave;
+       /*
+        * We don't need to disable softirq here, becase
+        * tlb_choose_channel() is only called by bond_alb_xmit()
+        * which already has softirq disabled.
+        */
+       _lock_tx_hashtbl(bond);
+       tx_slave = __tlb_choose_channel(bond, hash_index, skb_len);
+       _unlock_tx_hashtbl(bond);
+       return tx_slave;
+}
+
 /*********************** rlb specific functions ***************************/
-static inline void _lock_rx_hashtbl(struct bonding *bond)
+static inline void _lock_rx_hashtbl_bh(struct bonding *bond)
 {
        spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
 }
 
-static inline void _unlock_rx_hashtbl(struct bonding *bond)
+static inline void _unlock_rx_hashtbl_bh(struct bonding *bond)
 {
        spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
 }
 
+static inline void _lock_rx_hashtbl(struct bonding *bond)
+{
+       spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+}
+
+static inline void _unlock_rx_hashtbl(struct bonding *bond)
+{
+       spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+}
+
 /* when an ARP REPLY is received from a client update its info
  * in the rx_hashtbl
  */
@@ -288,7 +326,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
        struct rlb_client_info *client_info;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
        client_info = &(bond_info->rx_hashtbl[hash_index]);
@@ -303,7 +341,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
                bond_info->rx_ntt = 1;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
@@ -401,7 +439,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
        u32 index, next_index;
 
        /* clear slave from rx_hashtbl */
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        rx_hash_table = bond_info->rx_hashtbl;
        index = bond_info->rx_hashtbl_head;
@@ -432,7 +470,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
                }
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 
        write_lock_bh(&bond->curr_slave_lock);
 
@@ -489,7 +527,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
        struct rlb_client_info *client_info;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = bond_info->rx_hashtbl_head;
        for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
@@ -507,7 +545,7 @@ static void rlb_update_rx_clients(struct bonding *bond)
         */
        bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY;
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* The slave was assigned a new mac address - update the clients */
@@ -518,7 +556,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
        int ntt = 0;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        hash_index = bond_info->rx_hashtbl_head;
        for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
@@ -538,7 +576,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
                bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* mark all clients using src_ip to be updated */
@@ -709,7 +747,7 @@ static void rlb_rebalance(struct bonding *bond)
        int ntt;
        u32 hash_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        ntt = 0;
        hash_index = bond_info->rx_hashtbl_head;
@@ -727,7 +765,7 @@ static void rlb_rebalance(struct bonding *bond)
        if (ntt) {
                bond_info->rx_ntt = 1;
        }
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /* Caller must hold rx_hashtbl lock */
@@ -751,7 +789,7 @@ static int rlb_initialize(struct bonding *bond)
                       bond->dev->name);
                return -1;
        }
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        bond_info->rx_hashtbl = new_hashtbl;
 
@@ -761,7 +799,7 @@ static int rlb_initialize(struct bonding *bond)
                rlb_init_table_entry(bond_info->rx_hashtbl + i);
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 
        /* register to receive ARPs */
        bond->recv_probe = rlb_arp_recv;
@@ -773,13 +811,13 @@ static void rlb_deinitialize(struct bonding *bond)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        kfree(bond_info->rx_hashtbl);
        bond_info->rx_hashtbl = NULL;
        bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
@@ -787,7 +825,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
        u32 curr_index;
 
-       _lock_rx_hashtbl(bond);
+       _lock_rx_hashtbl_bh(bond);
 
        curr_index = bond_info->rx_hashtbl_head;
        while (curr_index != RLB_NULL_INDEX) {
@@ -812,7 +850,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
                curr_index = next_index;
        }
 
-       _unlock_rx_hashtbl(bond);
+       _unlock_rx_hashtbl_bh(bond);
 }
 
 /*********************** tlb/rlb shared functions *********************/
@@ -1320,7 +1358,9 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                res = bond_dev_queue_xmit(bond, skb, tx_slave->dev);
        } else {
                if (tx_slave) {
-                       tlb_clear_slave(bond, tx_slave, 0);
+                       _lock_tx_hashtbl(bond);
+                       __tlb_clear_slave(bond, tx_slave, 0);
+                       _unlock_tx_hashtbl(bond);
                }
        }
 
index 9e8ba4f5636bd71bcf2c9946450b76c587dbddb8..0f92e3567f687ea6e9107d7786cc808a792ab025 100644 (file)
@@ -623,7 +623,8 @@ static int ax_mii_init(struct net_device *dev)
 
        ax->mii_bus->name = "ax88796_mii_bus";
        ax->mii_bus->parent = dev->dev.parent;
-       snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
 
        ax->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
        if (!ax->mii_bus->irq) {
index b6d69c91db96dcf89af8a3e414c91cd39a7b7664..d812a103e032788ee6b3456dc6bb29e33c0decdb 100644 (file)
@@ -1670,7 +1670,8 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
        miibus->name = "bfin_mii_bus";
        miibus->phy_mask = mii_bus_pd->phy_mask;
 
-       snprintf(miibus->id, MII_BUS_ID_SIZE, "0");
+       snprintf(miibus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
        miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
        if (!miibus->irq)
                goto out_err_irq_alloc;
index cc9262be69c86c68020f7f4568662f0068bb2f4c..8b95dd314253ab4e36bbbcb01b09a7c35d8e8585 100644 (file)
@@ -1171,7 +1171,8 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        aup->mii_bus->write = au1000_mdiobus_write;
        aup->mii_bus->reset = au1000_mdiobus_reset;
        aup->mii_bus->name = "au1000_eth_mii";
-       snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
+       snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, aup->mac_id);
        aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
        if (aup->mii_bus->irq == NULL)
                goto err_out;
index d44331eb07fef00dae3f8e42e1e43a40bf3672bf..986019b2c8490726f74ad31770aeece308117168 100644 (file)
@@ -1727,7 +1727,7 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
                bus->priv = priv;
                bus->read = bcm_enet_mdio_read_phylib;
                bus->write = bcm_enet_mdio_write_phylib;
-               sprintf(bus->id, "%d", priv->mac_id);
+               sprintf(bus->id, "%s-%d", pdev->name, priv->mac_id);
 
                /* only probe bus where we think the PHY is, because
                 * the mdio read operation return 0 instead of 0xffff
index 8fa7abc53ec69a38fce149dbf37acb5eca2a2cf1..084904ceaa301b4fd76f00a8411433ec1711b49e 100644 (file)
@@ -2259,7 +2259,8 @@ static int sbmac_init(struct platform_device *pldev, long long base)
        }
 
        sc->mii_bus->name = sbmac_mdio_string;
-       snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
+       snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pldev->name, idx);
        sc->mii_bus->priv = sc;
        sc->mii_bus->read = sbmac_mii_read;
        sc->mii_bus->write = sbmac_mii_write;
index f3d5c65d99cf20ae57f14fc9b7dd2007d81bba85..23200680d4c16e08ab0b384b93340e81fb12f04f 100644 (file)
@@ -243,7 +243,8 @@ static int macb_mii_init(struct macb *bp)
        bp->mii_bus->read = &macb_mdio_read;
        bp->mii_bus->write = &macb_mdio_write;
        bp->mii_bus->reset = &macb_mdio_reset;
-       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id);
+       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bp->pdev->name, bp->pdev->id);
        bp->mii_bus->priv = bp;
        bp->mii_bus->parent = &bp->dev->dev;
        pdata = bp->pdev->dev.platform_data;
index ce88c0f399f68903333bbabdf546ea55abfed888..925c9bafc9b99519183eccc42b1b564a4bda3001 100644 (file)
@@ -325,7 +325,8 @@ static int dnet_mii_init(struct dnet *bp)
        bp->mii_bus->write = &dnet_mdio_write;
        bp->mii_bus->reset = &dnet_mdio_reset;
 
-       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bp->pdev->name, bp->pdev->id);
 
        bp->mii_bus->priv = bp;
 
index ddcbbb34d1b910e07947622bf537d0478001cf20..7b25e9cf13f6ff5a6c141cd6c6bd478fe5e5c6fb 100644 (file)
@@ -476,6 +476,7 @@ fec_restart(struct net_device *ndev, int duplex)
        } else {
 #ifdef FEC_MIIGSK_ENR
                if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
+                       u32 cfgr;
                        /* disable the gasket and wait */
                        writel(0, fep->hwp + FEC_MIIGSK_ENR);
                        while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
@@ -486,9 +487,11 @@ fec_restart(struct net_device *ndev, int duplex)
                         *   RMII, 50 MHz, no loopback, no echo
                         *   MII, 25 MHz, no loopback, no echo
                         */
-                       writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ?
-                                       1 : 0, fep->hwp + FEC_MIIGSK_CFGR);
-
+                       cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+                               ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII;
+                       if (fep->phy_dev && fep->phy_dev->speed == SPEED_10)
+                               cfgr |= BM_MIIGSK_CFGR_FRCONT_10M;
+                       writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR);
 
                        /* re-enable the gasket */
                        writel(2, fep->hwp + FEC_MIIGSK_ENR);
@@ -1077,7 +1080,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        fep->mii_bus->read = fec_enet_mdio_read;
        fep->mii_bus->write = fec_enet_mdio_write;
        fep->mii_bus->reset = fec_enet_mdio_reset;
-       snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1);
+       snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
        fep->mii_bus->parent = &pdev->dev;
 
index 8b2c6d797e6ddee6fe6dd165a22ba2ea9a8e8567..8408c627b1953a230c1f25d24b05217b0718d19f 100644 (file)
 #define FEC_MIIGSK_CFGR                0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR         0x308 /* MIIGSK Enable reg */
 
+#define BM_MIIGSK_CFGR_MII             0x00
+#define BM_MIIGSK_CFGR_RMII            0x01
+#define BM_MIIGSK_CFGR_FRCONT_10M      0x40
+
 #else
 
 #define FEC_ECNTRL             0x000 /* Ethernet control reg */
index e01cdaa722a977eac9b6c66513dfe13a44b97a44..39d160d353a41f3afbefcedb35f2397f5ec1ecb5 100644 (file)
@@ -1984,7 +1984,8 @@ static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
        return fcb;
 }
 
-static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
+               int fcb_length)
 {
        u8 flags = 0;
 
@@ -2006,7 +2007,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
         * frame (skb->data) and the start of the IP hdr.
         * l4os is the distance between the start of the
         * l3 hdr and the l4 hdr */
-       fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN);
+       fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length);
        fcb->l4os = skb_network_header_len(skb);
 
        fcb->flags = flags;
@@ -2046,7 +2047,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, rq = 0, do_tstamp = 0;
        u32 bufaddr;
        unsigned long flags;
-       unsigned int nr_frags, nr_txbds, length;
+       unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
 
        /*
         * TOE=1 frames larger than 2500 bytes may see excess delays
@@ -2070,22 +2071,28 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* check if time stamp should be generated */
        if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
-                    priv->hwts_tx_en))
+                       priv->hwts_tx_en)) {
                do_tstamp = 1;
+               fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
+       }
 
        /* make space for additional header when fcb is needed */
        if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
                        vlan_tx_tag_present(skb) ||
                        unlikely(do_tstamp)) &&
-                       (skb_headroom(skb) < GMAC_FCB_LEN)) {
+                       (skb_headroom(skb) < fcb_length)) {
                struct sk_buff *skb_new;
 
-               skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN);
+               skb_new = skb_realloc_headroom(skb, fcb_length);
                if (!skb_new) {
                        dev->stats.tx_errors++;
                        kfree_skb(skb);
                        return NETDEV_TX_OK;
                }
+
+               /* Steal sock reference for processing TX time stamps */
+               swap(skb_new->sk, skb->sk);
+               swap(skb_new->destructor, skb->destructor);
                kfree_skb(skb);
                skb = skb_new;
        }
@@ -2154,6 +2161,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                lstatus = txbdp_start->lstatus;
        }
 
+       /* Add TxPAL between FCB and frame if required */
+       if (unlikely(do_tstamp)) {
+               skb_push(skb, GMAC_TXPAL_LEN);
+               memset(skb->data, 0, GMAC_TXPAL_LEN);
+       }
+
        /* Set up checksumming */
        if (CHECKSUM_PARTIAL == skb->ip_summed) {
                fcb = gfar_add_fcb(skb);
@@ -2164,7 +2177,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        skb_checksum_help(skb);
                } else {
                        lstatus |= BD_LFLAG(TXBD_TOE);
-                       gfar_tx_checksum(skb, fcb);
+                       gfar_tx_checksum(skb, fcb, fcb_length);
                }
        }
 
@@ -2196,9 +2209,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * the full frame length.
         */
        if (unlikely(do_tstamp)) {
-               txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN;
+               txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length;
                txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) |
-                               (skb_headlen(skb) - GMAC_FCB_LEN);
+                               (skb_headlen(skb) - fcb_length);
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
        } else {
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
@@ -2490,7 +2503,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
                if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
                        next = next_txbd(bdp, base, tx_ring_size);
-                       buflen = next->length + GMAC_FCB_LEN;
+                       buflen = next->length + GMAC_FCB_LEN + GMAC_TXPAL_LEN;
                } else
                        buflen = bdp->length;
 
@@ -2502,6 +2515,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                        u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
                        shhwtstamps.hwtstamp = ns_to_ktime(*ns);
+                       skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
                        skb_tstamp_tx(skb, &shhwtstamps);
                        bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
                        bdp = next;
index fe7ac3a83194d8407f191227e710fe19a699e13a..40c33a7554c057c01273062339f8e8f5836626a4 100644 (file)
@@ -63,6 +63,9 @@ struct ethtool_rx_list {
 /* Length for FCB */
 #define GMAC_FCB_LEN 8
 
+/* Length for TxPAL */
+#define GMAC_TXPAL_LEN 16
+
 /* Default padding amount */
 #define DEFAULT_PADDING 2
 
index 0b3567ab812151f00210544cc805815b0953a90d..85e2c6cd9708b6a394f95dacc2a35e8d5e60fd9b 100644 (file)
@@ -98,6 +98,7 @@ struct ltq_etop_chan {
 
 struct ltq_etop_priv {
        struct net_device *netdev;
+       struct platform_device *pdev;
        struct ltq_eth_data *pldata;
        struct resource *res;
 
@@ -436,7 +437,8 @@ ltq_etop_mdio_init(struct net_device *dev)
        priv->mii_bus->read = ltq_etop_mdio_rd;
        priv->mii_bus->write = ltq_etop_mdio_wr;
        priv->mii_bus->name = "ltq_mii";
-       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+       snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               priv->pdev->name, priv->pdev->id);
        priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
        if (!priv->mii_bus->irq) {
                err = -ENOMEM;
@@ -734,6 +736,7 @@ ltq_etop_probe(struct platform_device *pdev)
        dev->ethtool_ops = &ltq_etop_ethtool_ops;
        priv = netdev_priv(dev);
        priv->res = res;
+       priv->pdev = pdev;
        priv->pldata = dev_get_platdata(&pdev->dev);
        priv->netdev = dev;
        spin_lock_init(&priv->lock);
index 80aab4e5d695351b4eec8f9267459f3b06c6bd34..9c049d2cb97d00142b1fbfaa6a1b14b6f8fac580 100644 (file)
@@ -2613,7 +2613,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
                msp->smi_bus->name = "mv643xx_eth smi";
                msp->smi_bus->read = smi_bus_read;
                msp->smi_bus->write = smi_bus_write,
-               snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+               snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
+                       pdev->name, pdev->id);
                msp->smi_bus->parent = &pdev->dev;
                msp->smi_bus->phy_mask = 0xffffffff;
                if (mdiobus_register(msp->smi_bus) < 0)
index 5ec409e3da090d6657afb2bf45e5ffa6d4e339e4..953ba5851f7b44174f2800a163214409cc7ebb3a 100644 (file)
@@ -1552,7 +1552,8 @@ static int pxa168_eth_probe(struct platform_device *pdev)
        pep->smi_bus->name = "pxa168_eth smi";
        pep->smi_bus->read = pxa168_smi_read;
        pep->smi_bus->write = pxa168_smi_write;
-       snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+       snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
+               pdev->name, pdev->id);
        pep->smi_bus->parent = &pdev->dev;
        pep->smi_bus->phy_mask = 0xffffffff;
        err = mdiobus_register(pep->smi_bus);
index 6ed09a85f03506ae7679e23ec5bc4425545cc5fd..e52cd310ae76147f0bbf54cc41f63da4e7f4013c 100644 (file)
 #define MAC_ADDR_ORDER(i)              (ETH_ALEN - 1 - (i))
 
 #define MAX_ETHERNET_BODY_SIZE         1500
-#define ETHERNET_HEADER_SIZE           14
+#define ETHERNET_HEADER_SIZE           (14 + VLAN_HLEN)
 
 #define MAX_ETHERNET_PACKET_SIZE       \
        (MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE)
index fc9bda9bc36c841597b13e231941343ba9486ee2..6ece4295d78fd8cd16deafd28cf377f937b4aa92 100644 (file)
@@ -1702,7 +1702,8 @@ static int sh_mdio_init(struct net_device *ndev, int id,
        /* Hook up MII support for ethtool */
        mdp->mii_bus->name = "sh_mii";
        mdp->mii_bus->parent = &ndev->dev;
-       snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%x", id);
+       snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               mdp->pdev->name, pdid);
 
        /* PHY IRQ */
        mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
index a7ff8ea342b4329baae598c4f1b08a704e016356..22e9c0181ce84dca1742c6b563f50491f925dac2 100644 (file)
@@ -1004,7 +1004,7 @@ static int __devinit s6gmac_probe(struct platform_device *pdev)
        mb->write = s6mii_write;
        mb->reset = s6mii_reset;
        mb->priv = pd;
-       snprintf(mb->id, MII_BUS_ID_SIZE, "0");
+       snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id);
        mb->phy_mask = ~(1 << 0);
        mb->irq = &pd->mii.irq[0];
        for (i = 0; i < PHY_MAX_ADDR; i++) {
index 9d0b8ced0234b5ae7468abcf732af6b080618d8d..24d2df068d717dd2163742dd479c1a97db003235 100644 (file)
@@ -1044,7 +1044,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
        }
 
        pdata->mii_bus->name = SMSC_MDIONAME;
-       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
        pdata->mii_bus->priv = pdata;
        pdata->mii_bus->read = smsc911x_mii_read;
        pdata->mii_bus->write = smsc911x_mii_write;
index 41e6b33e1b084724132d11369442f43269c12108..c07cfe989f6ef35716c59d3b5e29cdeefa4f1f2a 100644 (file)
@@ -22,6 +22,7 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/kernel.h>
 #include <linux/io.h>
 #include "mmc.h"
 
index 3738b47005489ef35afe054e868a7868a5d1c9b5..96fa2da307630f1e46df75441af10c91f0fd4c79 100644 (file)
@@ -307,7 +307,7 @@ static int stmmac_init_phy(struct net_device *dev)
        priv->speed = 0;
        priv->oldduplex = -1;
 
-       snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id);
+       snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", priv->plat->bus_id);
        snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
                 priv->plat->phy_addr);
        pr_debug("stmmac_init_phy:  trying to attach to %s\n", phy_id);
@@ -772,7 +772,7 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
                dwmac_mmc_ctrl(priv->ioaddr, mode);
                memset(&priv->mmc, 0, sizeof(struct stmmac_counters));
        } else
-               pr_info(" No MAC Management Counters available");
+               pr_info(" No MAC Management Counters available\n");
 }
 
 static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
index 51f4412339627c4a09cbd1ac0fae90ddd1d4f40d..da4a1042523a633e5781f86df7ffe4e123c09910 100644 (file)
@@ -158,7 +158,8 @@ int stmmac_mdio_register(struct net_device *ndev)
        new_bus->read = &stmmac_mdio_read;
        new_bus->write = &stmmac_mdio_write;
        new_bus->reset = &stmmac_mdio_reset;
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id);
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               new_bus->name, mdio_bus_data->bus_id);
        new_bus->priv = ndev;
        new_bus->irq = irqlist;
        new_bus->phy_mask = mdio_bus_data->phy_mask;
index 7b1594f4944e24f1005582be6511f1aa5167a773..1ac83243649a2d4c44ad4efa7fd0393c6869fbce 100644 (file)
@@ -62,7 +62,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
        priv = stmmac_dvr_probe(&(pdev->dev), plat_dat);
        if (!priv) {
                pr_err("%s: main drivr probe failed", __func__);
-               goto out_release_region;
+               goto out_unmap;
        }
 
        priv->ioaddr = addr;
index aaac0c7ad111192605075348264d1ddc38ceb2e6..4d9a28ffd3c3ac20d2764ea72ada7e70cadc04f0 100644 (file)
@@ -1269,7 +1269,7 @@ int __devinit cpmac_init(void)
        }
 
        cpmac_mii->phy_mask = ~(mask | 0x80000000);
-       snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "1");
+       snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "cpmac-1");
 
        res = mdiobus_register(cpmac_mii);
        if (res)
index 7615040df75621dda0684732017e4d21fac425eb..ef7c9c17bfffccbebd94ba0530fc1643e947812e 100644 (file)
@@ -313,7 +313,8 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev)
        data->bus->reset        = davinci_mdio_reset,
        data->bus->parent       = dev;
        data->bus->priv         = data;
-       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               pdev->name, pdev->id);
 
        data->clk = clk_get(dev, NULL);
        if (IS_ERR(data->clk)) {
index a9ce01bafd200c34265f33e4cff8d202719a5312..164fb775d7b333387cedacb80752c1c0b29bd566 100644 (file)
@@ -1604,7 +1604,7 @@ tsi108_init_one(struct platform_device *pdev)
        data->phyregs = ioremap(einfo->phyregs, 0x400);
        if (NULL == data->phyregs) {
                err = -ENOMEM;
-               goto regs_fail;
+               goto phyregs_fail;
        }
 /* MII setup */
        data->mii_if.dev = dev;
@@ -1663,9 +1663,11 @@ tsi108_init_one(struct platform_device *pdev)
        return 0;
 
 register_fail:
-       iounmap(data->regs);
        iounmap(data->phyregs);
 
+phyregs_fail:
+       iounmap(data->regs);
+
 regs_fail:
        free_netdev(dev);
        return err;
index 5c4983b2870a9c7a5dd7adefba08a8c054671a9b..10b18eb63d254834fc7a9b58f59eadd8078a75d9 100644 (file)
 
 /* A few user-configurable values.
    These may be modified when a driver module is loaded. */
-
-#define DEBUG
-static int debug = 1;  /* 1 normal messages, 0 quiet .. 7 verbose. */
-static int max_interrupt_work = 20;
+static int debug = 0;
+#define RHINE_MSG_DEFAULT \
+        (0x0000)
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
@@ -128,12 +127,10 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 
-module_param(max_interrupt_work, int, 0);
 module_param(debug, int, 0);
 module_param(rx_copybreak, int, 0);
 module_param(avoid_D3, bool, 0);
-MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
-MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
+MODULE_PARM_DESC(debug, "VIA Rhine debug message flags");
 MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
 
@@ -351,16 +348,25 @@ static const int mmio_verify_registers[] = {
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
-       IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
-       IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
-       IntrPCIErr=0x0040,
-       IntrStatsMax=0x0080, IntrRxEarly=0x0100,
-       IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
-       IntrTxAborted=0x2000, IntrLinkChange=0x4000,
-       IntrRxWakeUp=0x8000,
-       IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
-       IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
-       IntrTxErrSummary=0x082218,
+       IntrRxDone      = 0x0001,
+       IntrTxDone      = 0x0002,
+       IntrRxErr       = 0x0004,
+       IntrTxError     = 0x0008,
+       IntrRxEmpty     = 0x0020,
+       IntrPCIErr      = 0x0040,
+       IntrStatsMax    = 0x0080,
+       IntrRxEarly     = 0x0100,
+       IntrTxUnderrun  = 0x0210,
+       IntrRxOverflow  = 0x0400,
+       IntrRxDropped   = 0x0800,
+       IntrRxNoBuf     = 0x1000,
+       IntrTxAborted   = 0x2000,
+       IntrLinkChange  = 0x4000,
+       IntrRxWakeUp    = 0x8000,
+       IntrTxDescRace          = 0x080000,     /* mapped from IntrStatus2 */
+       IntrNormalSummary       = IntrRxDone | IntrTxDone,
+       IntrTxErrSummary        = IntrTxDescRace | IntrTxAborted | IntrTxError |
+                                 IntrTxUnderrun,
 };
 
 /* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */
@@ -439,8 +445,13 @@ struct rhine_private {
        struct net_device *dev;
        struct napi_struct napi;
        spinlock_t lock;
+       struct mutex task_lock;
+       bool task_enable;
+       struct work_struct slow_event_task;
        struct work_struct reset_task;
 
+       u32 msg_enable;
+
        /* Frequently used values: keep some adjacent for cache effect. */
        u32 quirks;
        struct rx_desc *rx_head_desc;
@@ -476,41 +487,50 @@ static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int  rhine_open(struct net_device *dev);
 static void rhine_reset_task(struct work_struct *work);
+static void rhine_slow_event_task(struct work_struct *work);
 static void rhine_tx_timeout(struct net_device *dev);
 static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                                  struct net_device *dev);
 static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
 static void rhine_tx(struct net_device *dev);
 static int rhine_rx(struct net_device *dev, int limit);
-static void rhine_error(struct net_device *dev, int intr_status);
 static void rhine_set_rx_mode(struct net_device *dev);
 static struct net_device_stats *rhine_get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
-static void rhine_shutdown (struct pci_dev *pdev);
 static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
 static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
-static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr);
-static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr);
-static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask);
-static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
-static void rhine_init_cam_filter(struct net_device *dev);
-static void rhine_update_vcam(struct net_device *dev);
-
-#define RHINE_WAIT_FOR(condition)                              \
-do {                                                           \
-       int i = 1024;                                           \
-       while (!(condition) && --i)                             \
-               ;                                               \
-       if (debug > 1 && i < 512)                               \
-               pr_info("%4d cycles used @ %s:%d\n",            \
-                       1024 - i, __func__, __LINE__);          \
-} while (0)
-
-static inline u32 get_intr_status(struct net_device *dev)
+static void rhine_restart_tx(struct net_device *dev);
+
+static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high)
+{
+       void __iomem *ioaddr = rp->base;
+       int i;
+
+       for (i = 0; i < 1024; i++) {
+               if (high ^ !!(ioread8(ioaddr + reg) & mask))
+                       break;
+               udelay(10);
+       }
+       if (i > 64) {
+               netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle "
+                         "count: %04d\n", high ? "high" : "low", reg, mask, i);
+       }
+}
+
+static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask)
+{
+       rhine_wait_bit(rp, reg, mask, true);
+}
+
+static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask)
+{
+       rhine_wait_bit(rp, reg, mask, false);
+}
+
+static u32 rhine_get_events(struct rhine_private *rp)
 {
-       struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
        u32 intr_status;
 
@@ -521,6 +541,16 @@ static inline u32 get_intr_status(struct net_device *dev)
        return intr_status;
 }
 
+static void rhine_ack_events(struct rhine_private *rp, u32 mask)
+{
+       void __iomem *ioaddr = rp->base;
+
+       if (rp->quirks & rqStatusWBRace)
+               iowrite8(mask >> 16, ioaddr + IntrStatus2);
+       iowrite16(mask, ioaddr + IntrStatus);
+       mmiowb();
+}
+
 /*
  * Get power related registers into sane state.
  * Notify user about past WOL event.
@@ -585,6 +615,7 @@ static void rhine_chip_reset(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
+       u8 cmd1;
 
        iowrite8(Cmd1Reset, ioaddr + ChipCmd1);
        IOSYNC;
@@ -597,13 +628,12 @@ static void rhine_chip_reset(struct net_device *dev)
                        iowrite8(0x40, ioaddr + MiscCmd);
 
                /* Reset can take somewhat longer (rare) */
-               RHINE_WAIT_FOR(!(ioread8(ioaddr + ChipCmd1) & Cmd1Reset));
+               rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset);
        }
 
-       if (debug > 1)
-               netdev_info(dev, "Reset %s\n",
-                           (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ?
-                           "failed" : "succeeded");
+       cmd1 = ioread8(ioaddr + ChipCmd1);
+       netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ?
+                  "failed" : "succeeded");
 }
 
 #ifdef USE_MMIO
@@ -629,9 +659,15 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
+       int i;
 
        outb(0x20, pioaddr + MACRegEEcsr);
-       RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20));
+       for (i = 0; i < 1024; i++) {
+               if (!(inb(pioaddr + MACRegEEcsr) & 0x20))
+                       break;
+       }
+       if (i > 512)
+               pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__);
 
 #ifdef USE_MMIO
        /*
@@ -657,23 +693,127 @@ static void rhine_poll(struct net_device *dev)
 }
 #endif
 
+static void rhine_kick_tx_threshold(struct rhine_private *rp)
+{
+       if (rp->tx_thresh < 0xe0) {
+               void __iomem *ioaddr = rp->base;
+
+               rp->tx_thresh += 0x20;
+               BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig);
+       }
+}
+
+static void rhine_tx_err(struct rhine_private *rp, u32 status)
+{
+       struct net_device *dev = rp->dev;
+
+       if (status & IntrTxAborted) {
+               netif_info(rp, tx_err, dev,
+                          "Abort %08x, frame dropped\n", status);
+       }
+
+       if (status & IntrTxUnderrun) {
+               rhine_kick_tx_threshold(rp);
+               netif_info(rp, tx_err ,dev, "Transmitter underrun, "
+                          "Tx threshold now %02x\n", rp->tx_thresh);
+       }
+
+       if (status & IntrTxDescRace)
+               netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n");
+
+       if ((status & IntrTxError) &&
+           (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) {
+               rhine_kick_tx_threshold(rp);
+               netif_info(rp, tx_err, dev, "Unspecified error. "
+                          "Tx threshold now %02x\n", rp->tx_thresh);
+       }
+
+       rhine_restart_tx(dev);
+}
+
+static void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp)
+{
+       void __iomem *ioaddr = rp->base;
+       struct net_device_stats *stats = &rp->dev->stats;
+
+       stats->rx_crc_errors    += ioread16(ioaddr + RxCRCErrs);
+       stats->rx_missed_errors += ioread16(ioaddr + RxMissed);
+
+       /*
+        * Clears the "tally counters" for CRC errors and missed frames(?).
+        * It has been reported that some chips need a write of 0 to clear
+        * these, for others the counters are set to 1 when written to and
+        * instead cleared when read. So we clear them both ways ...
+        */
+       iowrite32(0, ioaddr + RxMissed);
+       ioread16(ioaddr + RxCRCErrs);
+       ioread16(ioaddr + RxMissed);
+}
+
+#define RHINE_EVENT_NAPI_RX    (IntrRxDone | \
+                                IntrRxErr | \
+                                IntrRxEmpty | \
+                                IntrRxOverflow | \
+                                IntrRxDropped | \
+                                IntrRxNoBuf | \
+                                IntrRxWakeUp)
+
+#define RHINE_EVENT_NAPI_TX_ERR        (IntrTxError | \
+                                IntrTxAborted | \
+                                IntrTxUnderrun | \
+                                IntrTxDescRace)
+#define RHINE_EVENT_NAPI_TX    (IntrTxDone | RHINE_EVENT_NAPI_TX_ERR)
+
+#define RHINE_EVENT_NAPI       (RHINE_EVENT_NAPI_RX | \
+                                RHINE_EVENT_NAPI_TX | \
+                                IntrStatsMax)
+#define RHINE_EVENT_SLOW       (IntrPCIErr | IntrLinkChange)
+#define RHINE_EVENT            (RHINE_EVENT_NAPI | RHINE_EVENT_SLOW)
+
 static int rhine_napipoll(struct napi_struct *napi, int budget)
 {
        struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
        struct net_device *dev = rp->dev;
        void __iomem *ioaddr = rp->base;
-       int work_done;
+       u16 enable_mask = RHINE_EVENT & 0xffff;
+       int work_done = 0;
+       u32 status;
+
+       status = rhine_get_events(rp);
+       rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW);
+
+       if (status & RHINE_EVENT_NAPI_RX)
+               work_done += rhine_rx(dev, budget);
+
+       if (status & RHINE_EVENT_NAPI_TX) {
+               if (status & RHINE_EVENT_NAPI_TX_ERR) {
+                       /* Avoid scavenging before Tx engine turned off */
+                       rhine_wait_bit_low(rp, ChipCmd, CmdTxOn);
+                       if (ioread8(ioaddr + ChipCmd) & CmdTxOn)
+                               netif_warn(rp, tx_err, dev, "Tx still on\n");
+               }
 
-       work_done = rhine_rx(dev, budget);
+               rhine_tx(dev);
+
+               if (status & RHINE_EVENT_NAPI_TX_ERR)
+                       rhine_tx_err(rp, status);
+       }
+
+       if (status & IntrStatsMax) {
+               spin_lock(&rp->lock);
+               rhine_update_rx_crc_and_missed_errord(rp);
+               spin_unlock(&rp->lock);
+       }
+
+       if (status & RHINE_EVENT_SLOW) {
+               enable_mask &= ~RHINE_EVENT_SLOW;
+               schedule_work(&rp->slow_event_task);
+       }
 
        if (work_done < budget) {
                napi_complete(napi);
-
-               iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
-                         IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
-                         IntrTxDone | IntrTxError | IntrTxUnderrun |
-                         IntrPCIErr | IntrStatsMax | IntrLinkChange,
-                         ioaddr + IntrEnable);
+               iowrite16(enable_mask, ioaddr + IntrEnable);
+               mmiowb();
        }
        return work_done;
 }
@@ -797,6 +937,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
        rp->quirks = quirks;
        rp->pioaddr = pioaddr;
        rp->pdev = pdev;
+       rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT);
 
        rc = pci_request_regions(pdev, DRV_NAME);
        if (rc)
@@ -856,7 +997,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
        dev->irq = pdev->irq;
 
        spin_lock_init(&rp->lock);
+       mutex_init(&rp->task_lock);
        INIT_WORK(&rp->reset_task, rhine_reset_task);
+       INIT_WORK(&rp->slow_event_task, rhine_slow_event_task);
 
        rp->mii_if.dev = dev;
        rp->mii_if.mdio_read = mdio_read;
@@ -916,8 +1059,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
                }
        }
        rp->mii_if.phy_id = phy_id;
-       if (debug > 1 && avoid_D3)
-               netdev_info(dev, "No D3 power state at shutdown\n");
+       if (avoid_D3)
+               netif_info(rp, probe, dev, "No D3 power state at shutdown\n");
 
        return 0;
 
@@ -1093,7 +1236,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
-       mii_check_media(&rp->mii_if, debug, init_media);
+       mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
 
        if (rp->mii_if.full_duplex)
            iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex,
@@ -1101,24 +1244,26 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
        else
            iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
                   ioaddr + ChipCmd1);
-       if (debug > 1)
-               netdev_info(dev, "force_media %d, carrier %d\n",
-                           rp->mii_if.force_media, netif_carrier_ok(dev));
+
+       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
+                  rp->mii_if.force_media, netif_carrier_ok(dev));
 }
 
 /* Called after status of force_media possibly changed */
 static void rhine_set_carrier(struct mii_if_info *mii)
 {
+       struct net_device *dev = mii->dev;
+       struct rhine_private *rp = netdev_priv(dev);
+
        if (mii->force_media) {
                /* autoneg is off: Link is always assumed to be up */
-               if (!netif_carrier_ok(mii->dev))
-                       netif_carrier_on(mii->dev);
-       }
-       else    /* Let MMI library update carrier status */
-               rhine_check_media(mii->dev, 0);
-       if (debug > 1)
-               netdev_info(mii->dev, "force_media %d, carrier %d\n",
-                           mii->force_media, netif_carrier_ok(mii->dev));
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else  /* Let MMI library update carrier status */
+               rhine_check_media(dev, 0);
+
+       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
+                  mii->force_media, netif_carrier_ok(dev));
 }
 
 /**
@@ -1266,10 +1411,10 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       spin_lock_irq(&rp->lock);
+       spin_lock_bh(&rp->lock);
        set_bit(vid, rp->active_vlans);
        rhine_update_vcam(dev);
-       spin_unlock_irq(&rp->lock);
+       spin_unlock_bh(&rp->lock);
        return 0;
 }
 
@@ -1277,10 +1422,10 @@ static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       spin_lock_irq(&rp->lock);
+       spin_lock_bh(&rp->lock);
        clear_bit(vid, rp->active_vlans);
        rhine_update_vcam(dev);
-       spin_unlock_irq(&rp->lock);
+       spin_unlock_bh(&rp->lock);
        return 0;
 }
 
@@ -1310,12 +1455,7 @@ static void init_registers(struct net_device *dev)
 
        napi_enable(&rp->napi);
 
-       /* Enable interrupts by setting the interrupt mask. */
-       iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
-              IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
-              IntrTxDone | IntrTxError | IntrTxUnderrun |
-              IntrPCIErr | IntrStatsMax | IntrLinkChange,
-              ioaddr + IntrEnable);
+       iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable);
 
        iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8),
               ioaddr + ChipCmd);
@@ -1323,23 +1463,27 @@ static void init_registers(struct net_device *dev)
 }
 
 /* Enable MII link status auto-polling (required for IntrLinkChange) */
-static void rhine_enable_linkmon(void __iomem *ioaddr)
+static void rhine_enable_linkmon(struct rhine_private *rp)
 {
+       void __iomem *ioaddr = rp->base;
+
        iowrite8(0, ioaddr + MIICmd);
        iowrite8(MII_BMSR, ioaddr + MIIRegAddr);
        iowrite8(0x80, ioaddr + MIICmd);
 
-       RHINE_WAIT_FOR((ioread8(ioaddr + MIIRegAddr) & 0x20));
+       rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
 
        iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr);
 }
 
 /* Disable MII link status auto-polling (required for MDIO access) */
-static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
+static void rhine_disable_linkmon(struct rhine_private *rp)
 {
+       void __iomem *ioaddr = rp->base;
+
        iowrite8(0, ioaddr + MIICmd);
 
-       if (quirks & rqRhineI) {
+       if (rp->quirks & rqRhineI) {
                iowrite8(0x01, ioaddr + MIIRegAddr);    // MII_BMSR
 
                /* Can be called from ISR. Evil. */
@@ -1348,13 +1492,13 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
                /* 0x80 must be set immediately before turning it off */
                iowrite8(0x80, ioaddr + MIICmd);
 
-               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x20);
+               rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
 
                /* Heh. Now clear 0x80 again. */
                iowrite8(0, ioaddr + MIICmd);
        }
        else
-               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x80);
+               rhine_wait_bit_high(rp, MIIRegAddr, 0x80);
 }
 
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
@@ -1365,16 +1509,16 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
        void __iomem *ioaddr = rp->base;
        int result;
 
-       rhine_disable_linkmon(ioaddr, rp->quirks);
+       rhine_disable_linkmon(rp);
 
        /* rhine_disable_linkmon already cleared MIICmd */
        iowrite8(phy_id, ioaddr + MIIPhyAddr);
        iowrite8(regnum, ioaddr + MIIRegAddr);
        iowrite8(0x40, ioaddr + MIICmd);                /* Trigger read */
-       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x40));
+       rhine_wait_bit_low(rp, MIICmd, 0x40);
        result = ioread16(ioaddr + MIIData);
 
-       rhine_enable_linkmon(ioaddr);
+       rhine_enable_linkmon(rp);
        return result;
 }
 
@@ -1383,16 +1527,33 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
-       rhine_disable_linkmon(ioaddr, rp->quirks);
+       rhine_disable_linkmon(rp);
 
        /* rhine_disable_linkmon already cleared MIICmd */
        iowrite8(phy_id, ioaddr + MIIPhyAddr);
        iowrite8(regnum, ioaddr + MIIRegAddr);
        iowrite16(value, ioaddr + MIIData);
        iowrite8(0x20, ioaddr + MIICmd);                /* Trigger write */
-       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x20));
+       rhine_wait_bit_low(rp, MIICmd, 0x20);
 
-       rhine_enable_linkmon(ioaddr);
+       rhine_enable_linkmon(rp);
+}
+
+static void rhine_task_disable(struct rhine_private *rp)
+{
+       mutex_lock(&rp->task_lock);
+       rp->task_enable = false;
+       mutex_unlock(&rp->task_lock);
+
+       cancel_work_sync(&rp->slow_event_task);
+       cancel_work_sync(&rp->reset_task);
+}
+
+static void rhine_task_enable(struct rhine_private *rp)
+{
+       mutex_lock(&rp->task_lock);
+       rp->task_enable = true;
+       mutex_unlock(&rp->task_lock);
 }
 
 static int rhine_open(struct net_device *dev)
@@ -1406,8 +1567,7 @@ static int rhine_open(struct net_device *dev)
        if (rc)
                return rc;
 
-       if (debug > 1)
-               netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq);
+       netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq);
 
        rc = alloc_ring(dev);
        if (rc) {
@@ -1417,11 +1577,12 @@ static int rhine_open(struct net_device *dev)
        alloc_rbufs(dev);
        alloc_tbufs(dev);
        rhine_chip_reset(dev);
+       rhine_task_enable(rp);
        init_registers(dev);
-       if (debug > 2)
-               netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n",
-                          __func__, ioread16(ioaddr + ChipCmd),
-                          mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
+
+       netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n",
+                 __func__, ioread16(ioaddr + ChipCmd),
+                 mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
 
        netif_start_queue(dev);
 
@@ -1434,11 +1595,12 @@ static void rhine_reset_task(struct work_struct *work)
                                                reset_task);
        struct net_device *dev = rp->dev;
 
-       /* protect against concurrent rx interrupts */
-       disable_irq(rp->pdev->irq);
+       mutex_lock(&rp->task_lock);
 
-       napi_disable(&rp->napi);
+       if (!rp->task_enable)
+               goto out_unlock;
 
+       napi_disable(&rp->napi);
        spin_lock_bh(&rp->lock);
 
        /* clear all descriptors */
@@ -1452,11 +1614,13 @@ static void rhine_reset_task(struct work_struct *work)
        init_registers(dev);
 
        spin_unlock_bh(&rp->lock);
-       enable_irq(rp->pdev->irq);
 
        dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
        netif_wake_queue(dev);
+
+out_unlock:
+       mutex_unlock(&rp->task_lock);
 }
 
 static void rhine_tx_timeout(struct net_device *dev)
@@ -1477,7 +1641,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
        unsigned entry;
-       unsigned long flags;
 
        /* Caution: the write order is important here, set the field
           with the "ownership" bits last. */
@@ -1529,7 +1692,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                rp->tx_ring[entry].tx_status = 0;
 
        /* lock eth irq */
-       spin_lock_irqsave(&rp->lock, flags);
        wmb();
        rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
        wmb();
@@ -1550,78 +1712,43 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
                netif_stop_queue(dev);
 
-       spin_unlock_irqrestore(&rp->lock, flags);
+       netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n",
+                 rp->cur_tx - 1, entry);
 
-       if (debug > 4) {
-               netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
-                          rp->cur_tx-1, entry);
-       }
        return NETDEV_TX_OK;
 }
 
+static void rhine_irq_disable(struct rhine_private *rp)
+{
+       iowrite16(0x0000, rp->base + IntrEnable);
+       mmiowb();
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
-       u32 intr_status;
-       int boguscnt = max_interrupt_work;
+       u32 status;
        int handled = 0;
 
-       while ((intr_status = get_intr_status(dev))) {
-               handled = 1;
-
-               /* Acknowledge all of the current interrupt sources ASAP. */
-               if (intr_status & IntrTxDescRace)
-                       iowrite8(0x08, ioaddr + IntrStatus2);
-               iowrite16(intr_status & 0xffff, ioaddr + IntrStatus);
-               IOSYNC;
+       status = rhine_get_events(rp);
 
-               if (debug > 4)
-                       netdev_dbg(dev, "Interrupt, status %08x\n",
-                                  intr_status);
-
-               if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
-                                  IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) {
-                       iowrite16(IntrTxAborted |
-                                 IntrTxDone | IntrTxError | IntrTxUnderrun |
-                                 IntrPCIErr | IntrStatsMax | IntrLinkChange,
-                                 ioaddr + IntrEnable);
-
-                       napi_schedule(&rp->napi);
-               }
+       netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status);
 
-               if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
-                       if (intr_status & IntrTxErrSummary) {
-                               /* Avoid scavenging before Tx engine turned off */
-                               RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
-                               if (debug > 2 &&
-                                   ioread8(ioaddr+ChipCmd) & CmdTxOn)
-                                       netdev_warn(dev,
-                                                   "%s: Tx engine still on\n",
-                                                   __func__);
-                       }
-                       rhine_tx(dev);
-               }
+       if (status & RHINE_EVENT) {
+               handled = 1;
 
-               /* Abnormal error summary/uncommon events handlers. */
-               if (intr_status & (IntrPCIErr | IntrLinkChange |
-                                  IntrStatsMax | IntrTxError | IntrTxAborted |
-                                  IntrTxUnderrun | IntrTxDescRace))
-                       rhine_error(dev, intr_status);
+               rhine_irq_disable(rp);
+               napi_schedule(&rp->napi);
+       }
 
-               if (--boguscnt < 0) {
-                       netdev_warn(dev, "Too much work at interrupt, status=%#08x\n",
-                                   intr_status);
-                       break;
-               }
+       if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) {
+               netif_err(rp, intr, dev, "Something Wicked happened! %08x\n",
+                         status);
        }
 
-       if (debug > 3)
-               netdev_dbg(dev, "exiting interrupt, status=%08x\n",
-                          ioread16(ioaddr + IntrStatus));
        return IRQ_RETVAL(handled);
 }
 
@@ -1632,20 +1759,16 @@ static void rhine_tx(struct net_device *dev)
        struct rhine_private *rp = netdev_priv(dev);
        int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
 
-       spin_lock(&rp->lock);
-
        /* find and cleanup dirty tx descriptors */
        while (rp->dirty_tx != rp->cur_tx) {
                txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
-               if (debug > 6)
-                       netdev_dbg(dev, "Tx scavenge %d status %08x\n",
-                                  entry, txstatus);
+               netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n",
+                         entry, txstatus);
                if (txstatus & DescOwn)
                        break;
                if (txstatus & 0x8000) {
-                       if (debug > 1)
-                               netdev_dbg(dev, "Transmit error, Tx status %08x\n",
-                                          txstatus);
+                       netif_dbg(rp, tx_done, dev,
+                                 "Transmit error, Tx status %08x\n", txstatus);
                        dev->stats.tx_errors++;
                        if (txstatus & 0x0400)
                                dev->stats.tx_carrier_errors++;
@@ -1667,10 +1790,8 @@ static void rhine_tx(struct net_device *dev)
                                dev->stats.collisions += (txstatus >> 3) & 0x0F;
                        else
                                dev->stats.collisions += txstatus & 0x0F;
-                       if (debug > 6)
-                               netdev_dbg(dev, "collisions: %1.1x:%1.1x\n",
-                                          (txstatus >> 3) & 0xF,
-                                          txstatus & 0xF);
+                       netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
+                                 (txstatus >> 3) & 0xF, txstatus & 0xF);
                        dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
                        dev->stats.tx_packets++;
                }
@@ -1687,8 +1808,6 @@ static void rhine_tx(struct net_device *dev)
        }
        if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
                netif_wake_queue(dev);
-
-       spin_unlock(&rp->lock);
 }
 
 /**
@@ -1713,11 +1832,8 @@ static int rhine_rx(struct net_device *dev, int limit)
        int count;
        int entry = rp->cur_rx % RX_RING_SIZE;
 
-       if (debug > 4) {
-               netdev_dbg(dev, "%s(), entry %d status %08x\n",
-                          __func__, entry,
-                          le32_to_cpu(rp->rx_head_desc->rx_status));
-       }
+       netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__,
+                 entry, le32_to_cpu(rp->rx_head_desc->rx_status));
 
        /* If EOP is set on the next entry, it's a new packet. Send it up. */
        for (count = 0; count < limit; ++count) {
@@ -1729,9 +1845,8 @@ static int rhine_rx(struct net_device *dev, int limit)
                if (desc_status & DescOwn)
                        break;
 
-               if (debug > 4)
-                       netdev_dbg(dev, "%s() status is %08x\n",
-                                  __func__, desc_status);
+               netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__,
+                         desc_status);
 
                if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
                        if ((desc_status & RxWholePkt) != RxWholePkt) {
@@ -1747,9 +1862,9 @@ static int rhine_rx(struct net_device *dev, int limit)
                                dev->stats.rx_length_errors++;
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
-                               if (debug > 2)
-                                       netdev_dbg(dev, "%s() Rx error was %08x\n",
-                                                  __func__, desc_status);
+                               netif_dbg(rp, rx_err, dev,
+                                         "%s() Rx error %08x\n", __func__,
+                                         desc_status);
                                dev->stats.rx_errors++;
                                if (desc_status & 0x0030)
                                        dev->stats.rx_length_errors++;
@@ -1839,19 +1954,6 @@ static int rhine_rx(struct net_device *dev, int limit)
        return count;
 }
 
-/*
- * Clears the "tally counters" for CRC errors and missed frames(?).
- * It has been reported that some chips need a write of 0 to clear
- * these, for others the counters are set to 1 when written to and
- * instead cleared when read. So we clear them both ways ...
- */
-static inline void clear_tally_counters(void __iomem *ioaddr)
-{
-       iowrite32(0, ioaddr + RxMissed);
-       ioread16(ioaddr + RxCRCErrs);
-       ioread16(ioaddr + RxMissed);
-}
-
 static void rhine_restart_tx(struct net_device *dev) {
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
@@ -1862,7 +1964,7 @@ static void rhine_restart_tx(struct net_device *dev) {
         * If new errors occurred, we need to sort them out before doing Tx.
         * In that case the ISR will be back here RSN anyway.
         */
-       intr_status = get_intr_status(dev);
+       intr_status = rhine_get_events(rp);
 
        if ((intr_status & IntrTxErrSummary) == 0) {
 
@@ -1883,79 +1985,50 @@ static void rhine_restart_tx(struct net_device *dev) {
        }
        else {
                /* This should never happen */
-               if (debug > 1)
-                       netdev_warn(dev, "%s() Another error occurred %08x\n",
-                                  __func__, intr_status);
+               netif_warn(rp, tx_err, dev, "another error occurred %08x\n",
+                          intr_status);
        }
 
 }
 
-static void rhine_error(struct net_device *dev, int intr_status)
+static void rhine_slow_event_task(struct work_struct *work)
 {
-       struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
+       struct rhine_private *rp =
+               container_of(work, struct rhine_private, slow_event_task);
+       struct net_device *dev = rp->dev;
+       u32 intr_status;
 
-       spin_lock(&rp->lock);
+       mutex_lock(&rp->task_lock);
+
+       if (!rp->task_enable)
+               goto out_unlock;
+
+       intr_status = rhine_get_events(rp);
+       rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW);
 
        if (intr_status & IntrLinkChange)
                rhine_check_media(dev, 0);
-       if (intr_status & IntrStatsMax) {
-               dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-               dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
-               clear_tally_counters(ioaddr);
-       }
-       if (intr_status & IntrTxAborted) {
-               if (debug > 1)
-                       netdev_info(dev, "Abort %08x, frame dropped\n",
-                                   intr_status);
-       }
-       if (intr_status & IntrTxUnderrun) {
-               if (rp->tx_thresh < 0xE0)
-                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
-               if (debug > 1)
-                       netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n",
-                                   rp->tx_thresh);
-       }
-       if (intr_status & IntrTxDescRace) {
-               if (debug > 2)
-                       netdev_info(dev, "Tx descriptor write-back race\n");
-       }
-       if ((intr_status & IntrTxError) &&
-           (intr_status & (IntrTxAborted |
-            IntrTxUnderrun | IntrTxDescRace)) == 0) {
-               if (rp->tx_thresh < 0xE0) {
-                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
-               }
-               if (debug > 1)
-                       netdev_info(dev, "Unspecified error. Tx threshold now %02x\n",
-                                   rp->tx_thresh);
-       }
-       if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
-                          IntrTxError))
-               rhine_restart_tx(dev);
-
-       if (intr_status & ~(IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
-                           IntrTxError | IntrTxAborted | IntrNormalSummary |
-                           IntrTxDescRace)) {
-               if (debug > 1)
-                       netdev_err(dev, "Something Wicked happened! %08x\n",
-                                  intr_status);
-       }
 
-       spin_unlock(&rp->lock);
+       if (intr_status & IntrPCIErr)
+               netif_warn(rp, hw, dev, "PCI error\n");
+
+       napi_disable(&rp->napi);
+       rhine_irq_disable(rp);
+       /* Slow and safe. Consider __napi_schedule as a replacement ? */
+       napi_enable(&rp->napi);
+       napi_schedule(&rp->napi);
+
+out_unlock:
+       mutex_unlock(&rp->task_lock);
 }
 
 static struct net_device_stats *rhine_get_stats(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
-       void __iomem *ioaddr = rp->base;
-       unsigned long flags;
 
-       spin_lock_irqsave(&rp->lock, flags);
-       dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-       dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
-       clear_tally_counters(ioaddr);
-       spin_unlock_irqrestore(&rp->lock, flags);
+       spin_lock_bh(&rp->lock);
+       rhine_update_rx_crc_and_missed_errord(rp);
+       spin_unlock_bh(&rp->lock);
 
        return &dev->stats;
 }
@@ -2022,9 +2095,9 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct rhine_private *rp = netdev_priv(dev);
        int rc;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = mii_ethtool_gset(&rp->mii_if, cmd);
-       spin_unlock_irq(&rp->lock);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2034,10 +2107,10 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct rhine_private *rp = netdev_priv(dev);
        int rc;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = mii_ethtool_sset(&rp->mii_if, cmd);
-       spin_unlock_irq(&rp->lock);
        rhine_set_carrier(&rp->mii_if);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2058,12 +2131,16 @@ static u32 netdev_get_link(struct net_device *dev)
 
 static u32 netdev_get_msglevel(struct net_device *dev)
 {
-       return debug;
+       struct rhine_private *rp = netdev_priv(dev);
+
+       return rp->msg_enable;
 }
 
 static void netdev_set_msglevel(struct net_device *dev, u32 value)
 {
-       debug = value;
+       struct rhine_private *rp = netdev_priv(dev);
+
+       rp->msg_enable = value;
 }
 
 static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -2119,10 +2196,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        if (!netif_running(dev))
                return -EINVAL;
 
-       spin_lock_irq(&rp->lock);
+       mutex_lock(&rp->task_lock);
        rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
-       spin_unlock_irq(&rp->lock);
        rhine_set_carrier(&rp->mii_if);
+       mutex_unlock(&rp->task_lock);
 
        return rc;
 }
@@ -2132,27 +2209,21 @@ static int rhine_close(struct net_device *dev)
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
 
+       rhine_task_disable(rp);
        napi_disable(&rp->napi);
-       cancel_work_sync(&rp->reset_task);
        netif_stop_queue(dev);
 
-       spin_lock_irq(&rp->lock);
-
-       if (debug > 1)
-               netdev_dbg(dev, "Shutting down ethercard, status was %04x\n",
-                          ioread16(ioaddr + ChipCmd));
+       netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n",
+                 ioread16(ioaddr + ChipCmd));
 
        /* Switch to loopback mode to avoid hardware races. */
        iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
 
-       /* Disable interrupts by clearing the interrupt mask. */
-       iowrite16(0x0000, ioaddr + IntrEnable);
+       rhine_irq_disable(rp);
 
        /* Stop the chip's Tx and Rx processes. */
        iowrite16(CmdStop, ioaddr + ChipCmd);
 
-       spin_unlock_irq(&rp->lock);
-
        free_irq(rp->pdev->irq, dev);
        free_rbufs(dev);
        free_tbufs(dev);
@@ -2192,6 +2263,8 @@ static void rhine_shutdown (struct pci_dev *pdev)
        if (rp->quirks & rq6patterns)
                iowrite8(0x04, ioaddr + WOLcgClr);
 
+       spin_lock(&rp->lock);
+
        if (rp->wolopts & WAKE_MAGIC) {
                iowrite8(WOLmagic, ioaddr + WOLcrSet);
                /*
@@ -2216,58 +2289,46 @@ static void rhine_shutdown (struct pci_dev *pdev)
                iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW);
        }
 
-       /* Hit power state D3 (sleep) */
-       if (!avoid_D3)
-               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
+       spin_unlock(&rp->lock);
 
-       /* TODO: Check use of pci_enable_wake() */
+       if (system_state == SYSTEM_POWER_OFF && !avoid_D3) {
+               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
 
+               pci_wake_from_d3(pdev, true);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 
-#ifdef CONFIG_PM
-static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int rhine_suspend(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
-       unsigned long flags;
 
        if (!netif_running(dev))
                return 0;
 
+       rhine_task_disable(rp);
+       rhine_irq_disable(rp);
        napi_disable(&rp->napi);
 
        netif_device_detach(dev);
-       pci_save_state(pdev);
 
-       spin_lock_irqsave(&rp->lock, flags);
        rhine_shutdown(pdev);
-       spin_unlock_irqrestore(&rp->lock, flags);
 
-       free_irq(dev->irq, dev);
        return 0;
 }
 
-static int rhine_resume(struct pci_dev *pdev)
+static int rhine_resume(struct device *device)
 {
+       struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rhine_private *rp = netdev_priv(dev);
-       unsigned long flags;
-       int ret;
 
        if (!netif_running(dev))
                return 0;
 
-       if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
-               netdev_err(dev, "request_irq failed\n");
-
-       ret = pci_set_power_state(pdev, PCI_D0);
-       if (debug > 1)
-               netdev_info(dev, "Entering power state D0 %s (%d)\n",
-                           ret ? "failed" : "succeeded", ret);
-
-       pci_restore_state(pdev);
-
-       spin_lock_irqsave(&rp->lock, flags);
 #ifdef USE_MMIO
        enable_mmio(rp->pioaddr, rp->quirks);
 #endif
@@ -2276,25 +2337,32 @@ static int rhine_resume(struct pci_dev *pdev)
        free_rbufs(dev);
        alloc_tbufs(dev);
        alloc_rbufs(dev);
+       rhine_task_enable(rp);
+       spin_lock_bh(&rp->lock);
        init_registers(dev);
-       spin_unlock_irqrestore(&rp->lock, flags);
+       spin_unlock_bh(&rp->lock);
 
        netif_device_attach(dev);
 
        return 0;
 }
-#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume);
+#define RHINE_PM_OPS   (&rhine_pm_ops)
+
+#else
+
+#define RHINE_PM_OPS   NULL
+
+#endif /* !CONFIG_PM_SLEEP */
 
 static struct pci_driver rhine_driver = {
        .name           = DRV_NAME,
        .id_table       = rhine_pci_tbl,
        .probe          = rhine_init_one,
        .remove         = __devexit_p(rhine_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = rhine_suspend,
-       .resume         = rhine_resume,
-#endif /* CONFIG_PM */
-       .shutdown =     rhine_shutdown,
+       .shutdown       = rhine_shutdown,
+       .driver.pm      = RHINE_PM_OPS,
 };
 
 static struct dmi_system_id __initdata rhine_dmi_table[] = {
index f45c85a8426125be667c80cd4e8408bb58fc7337..72a854f05bb8042cf8392c518377652e8af62daf 100644 (file)
@@ -529,7 +529,7 @@ static int ixp4xx_mdio_register(void)
        mdio_bus->name = "IXP4xx MII Bus";
        mdio_bus->read = &ixp4xx_mdio_read;
        mdio_bus->write = &ixp4xx_mdio_write;
-       strcpy(mdio_bus->id, "0");
+       snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "ixp4xx-eth-0");
 
        if ((err = mdiobus_register(mdio_bus)))
                mdiobus_free(mdio_bus);
index 9663e0ba60034d8edf1806c8bcd7eb928a7c4733..ba3c59147aa7eecda0e6cf1ff344caa498eb91fd 100644 (file)
@@ -1159,7 +1159,7 @@ static void rx_timestamp_work(struct work_struct *work)
                        }
                }
                spin_unlock_irqrestore(&dp83640->rx_lock, flags);
-               netif_rx(skb);
+               netif_rx_ni(skb);
        }
 
        /* Clear out expired time stamps. */
index 1fa4d73c3cca5e0d6ff4579abd986a910ab67305..633680d0828e64b2c96b2a335713eb17e62490bf 100644 (file)
@@ -220,7 +220,7 @@ static int __init fixed_mdio_bus_init(void)
                goto err_mdiobus_reg;
        }
 
-       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0");
+       snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
        fmb->mii_bus->name = "Fixed MDIO Bus";
        fmb->mii_bus->priv = fmb;
        fmb->mii_bus->parent = &pdev->dev;
index 89c5a3eccc12daa760fa0e1e6c73e392c0a81f3e..50e8e5e74465bc607dddda8126a8d960aa5268cb 100644 (file)
@@ -116,7 +116,7 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
                if (!new_bus->irq[i])
                        new_bus->irq[i] = PHY_POLL;
 
-       snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id);
+       snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
 
        if (gpio_request(bitbang->mdc, "mdc"))
                goto out_free_bus;
index bd12ba941be51b9bb9dc4ee20e3dfb48e8bfae78..826d961f39f74ff7bbd2a9c839f36f3c5b2ed851 100644 (file)
@@ -118,7 +118,8 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev)
        bus->mii_bus->priv = bus;
        bus->mii_bus->irq = bus->phy_irq;
        bus->mii_bus->name = "mdio-octeon";
-       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
+       snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+               bus->mii_bus->name, bus->unit);
        bus->mii_bus->parent = &pdev->dev;
 
        bus->mii_bus->read = octeon_mdiobus_read;
index 6c58da2b882c845e453ddd7b6bb0b544f4705b83..88cc5db9affd7a4923fe29de85c63cd98d80c3aa 100644 (file)
 #include <asm/uaccess.h>
 
 /**
- * mdiobus_alloc - allocate a mii_bus structure
+ * mdiobus_alloc_size - allocate a mii_bus structure
  *
  * Description: called by a bus driver to allocate an mii_bus
  * structure to fill in.
+ *
+ * 'size' is an an extra amount of memory to allocate for private storage.
+ * If non-zero, then bus->priv is points to that memory.
  */
-struct mii_bus *mdiobus_alloc(void)
+struct mii_bus *mdiobus_alloc_size(size_t size)
 {
        struct mii_bus *bus;
+       size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN);
+       size_t alloc_size;
+
+       /* If we alloc extra space, it should be aligned */
+       if (size)
+               alloc_size = aligned_size + size;
+       else
+               alloc_size = sizeof(*bus);
 
-       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
-       if (bus != NULL)
+       bus = kzalloc(alloc_size, GFP_KERNEL);
+       if (bus) {
                bus->state = MDIOBUS_ALLOCATED;
+               if (size)
+                       bus->priv = (void *)bus + aligned_size;
+       }
 
        return bus;
 }
-EXPORT_SYMBOL(mdiobus_alloc);
+EXPORT_SYMBOL(mdiobus_alloc_size);
 
 /**
  * mdiobus_release - mii_bus device release callback
index c1c9293c2bbf1eecd638d8d6e428777951cdff9d..df884dde2a511c27b95db1edef5848886b6c9abd 100644 (file)
@@ -585,8 +585,8 @@ static int pptp_create(struct net *net, struct socket *sock)
        po = pppox_sk(sk);
        opt = &po->proto.pptp;
 
-       opt->seq_sent = 0; opt->seq_recv = 0;
-       opt->ack_recv = 0; opt->ack_sent = 0;
+       opt->seq_sent = 0; opt->seq_recv = 0xffffffff;
+       opt->ack_recv = 0; opt->ack_sent = 0xffffffff;
 
        error = 0;
 out:
index d0937c4634c9ef584f73023f73a144c673e4514a..8e84f5bdd6ca581a3f6d26cfe9a06eb1b27771b2 100644 (file)
@@ -978,6 +978,7 @@ static int ax88772_link_reset(struct usbnet *dev)
 
 static int ax88772_reset(struct usbnet *dev)
 {
+       struct asix_data *data = (struct asix_data *)&dev->data;
        int ret, embd_phy;
        u16 rx_ctl;
 
@@ -1055,6 +1056,13 @@ static int ax88772_reset(struct usbnet *dev)
                goto out;
        }
 
+       /* Rewrite MAC address */
+       memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+       ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                                                       data->mac_addr);
+       if (ret < 0)
+               goto out;
+
        /* Set RX_CTL to default values with 2k buffer, and enable cactus */
        ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
        if (ret < 0)
@@ -1320,6 +1328,13 @@ static int ax88178_reset(struct usbnet *dev)
        if (ret < 0)
                return ret;
 
+       /* Rewrite MAC address */
+       memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+       ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                                                       data->mac_addr);
+       if (ret < 0)
+               return ret;
+
        ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
        if (ret < 0)
                return ret;
index 76fe14efb2b52910c3e113dd0f8917f22c9661b6..4880aa8b4c28b4662446e8e56b2acc98958645e4 100644 (file)
@@ -370,7 +370,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 
        skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
        if (err < 0)
                dev_kfree_skb(skb);
 
@@ -415,8 +415,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
 
        /* chain first in list head */
        first->private = (unsigned long)list;
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
-                                   first, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
+                               first, gfp);
        if (err < 0)
                give_pages(vi, first);
 
@@ -434,7 +434,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
 
        sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
 
-       err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
+       err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
        if (err < 0)
                give_pages(vi, page);
 
@@ -609,7 +609,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 
        hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
        return virtqueue_add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
-                                       0, skb);
+                                0, skb, GFP_ATOMIC);
 }
 
 static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -767,7 +767,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
                sg_set_buf(&sg[i + 1], sg_virt(s), s->length);
        sg_set_buf(&sg[out + in - 1], &status, sizeof(status));
 
-       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi) < 0);
+       BUG_ON(virtqueue_add_buf(vi->cvq, sg, out, in, vi, GFP_ATOMIC) < 0);
 
        virtqueue_kick(vi->cvq);
 
@@ -985,15 +985,38 @@ static void virtnet_config_changed(struct virtio_device *vdev)
        virtnet_update_status(vi);
 }
 
+static int init_vqs(struct virtnet_info *vi)
+{
+       struct virtqueue *vqs[3];
+       vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
+       const char *names[] = { "input", "output", "control" };
+       int nvqs, err;
+
+       /* We expect two virtqueues, receive then send,
+        * and optionally control. */
+       nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
+
+       err = vi->vdev->config->find_vqs(vi->vdev, nvqs, vqs, callbacks, names);
+       if (err)
+               return err;
+
+       vi->rvq = vqs[0];
+       vi->svq = vqs[1];
+
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
+               vi->cvq = vqs[2];
+
+               if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
+                       vi->dev->features |= NETIF_F_HW_VLAN_FILTER;
+       }
+       return 0;
+}
+
 static int virtnet_probe(struct virtio_device *vdev)
 {
        int err;
        struct net_device *dev;
        struct virtnet_info *vi;
-       struct virtqueue *vqs[3];
-       vq_callback_t *callbacks[] = { skb_recv_done, skb_xmit_done, NULL};
-       const char *names[] = { "input", "output", "control" };
-       int nvqs;
 
        /* Allocate ourselves a network device with room for our info */
        dev = alloc_etherdev(sizeof(struct virtnet_info));
@@ -1065,24 +1088,10 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
                vi->mergeable_rx_bufs = true;
 
-       /* We expect two virtqueues, receive then send,
-        * and optionally control. */
-       nvqs = virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ) ? 3 : 2;
-
-       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       err = init_vqs(vi);
        if (err)
                goto free_stats;
 
-       vi->rvq = vqs[0];
-       vi->svq = vqs[1];
-
-       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) {
-               vi->cvq = vqs[2];
-
-               if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
-                       dev->features |= NETIF_F_HW_VLAN_FILTER;
-       }
-
        err = register_netdev(dev);
        if (err) {
                pr_debug("virtio_net: registering device failed\n");
@@ -1144,27 +1153,73 @@ static void free_unused_bufs(struct virtnet_info *vi)
        BUG_ON(vi->num != 0);
 }
 
-static void __devexit virtnet_remove(struct virtio_device *vdev)
+static void remove_vq_common(struct virtnet_info *vi)
 {
-       struct virtnet_info *vi = vdev->priv;
-
-       /* Stop all the virtqueues. */
-       vdev->config->reset(vdev);
-
-       unregister_netdev(vi->dev);
+       vi->vdev->config->reset(vi->vdev);
 
        /* Free unused buffers in both send and recv, if any. */
        free_unused_bufs(vi);
 
-       vdev->config->del_vqs(vi->vdev);
+       vi->vdev->config->del_vqs(vi->vdev);
 
        while (vi->pages)
                __free_pages(get_a_page(vi, GFP_KERNEL), 0);
+}
+
+static void __devexit virtnet_remove(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+
+       unregister_netdev(vi->dev);
+
+       remove_vq_common(vi);
 
        free_percpu(vi->stats);
        free_netdev(vi->dev);
 }
 
+#ifdef CONFIG_PM
+static int virtnet_freeze(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+
+       virtqueue_disable_cb(vi->rvq);
+       virtqueue_disable_cb(vi->svq);
+       if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
+               virtqueue_disable_cb(vi->cvq);
+
+       netif_device_detach(vi->dev);
+       cancel_delayed_work_sync(&vi->refill);
+
+       if (netif_running(vi->dev))
+               napi_disable(&vi->napi);
+
+       remove_vq_common(vi);
+
+       return 0;
+}
+
+static int virtnet_restore(struct virtio_device *vdev)
+{
+       struct virtnet_info *vi = vdev->priv;
+       int err;
+
+       err = init_vqs(vi);
+       if (err)
+               return err;
+
+       if (netif_running(vi->dev))
+               virtnet_napi_enable(vi);
+
+       netif_device_attach(vi->dev);
+
+       if (!try_fill_recv(vi, GFP_KERNEL))
+               queue_delayed_work(system_nrt_wq, &vi->refill, 0);
+
+       return 0;
+}
+#endif
+
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -1189,6 +1244,10 @@ static struct virtio_driver virtio_net_driver = {
        .probe =        virtnet_probe,
        .remove =       __devexit_p(virtnet_remove),
        .config_changed = virtnet_config_changed,
+#ifdef CONFIG_PM
+       .freeze =       virtnet_freeze,
+       .restore =      virtnet_restore,
+#endif
 };
 
 static int __init init(void)
index 2589b38b689a82cdc3acbe7748ffa7bd33092906..2b0bfb8cca02d023da420b842f058b904807f646 100644 (file)
@@ -46,7 +46,7 @@ static const int m2ThreshExt_off = 127;
  * @chan:
  *
  * This is the function to change channel on single-chip devices, that is
- * all devices after ar9280.
+ * for AR9300 family of chipsets.
  *
  * This function takes the channel value in MHz and sets
  * hardware channel value. Assumes writes have been enabled to analog bus.
index b30e9fc6433f0b8c947ce4029ef7037d11fd7486..171ccf7c972ff1cc228dca2019122ff6e79bdc0c 100644 (file)
@@ -679,7 +679,6 @@ void ath9k_deinit_device(struct ath_softc *sc);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
 
-void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
 bool ath9k_uses_beacons(int type);
 
 #ifdef CONFIG_ATH9K_PCI
index 172e33db7f4c49d2e9447636a380c34e5c15f3f6..2f4b48e6fb036648af5eb1cdf35bd217b97dc67f 100644 (file)
@@ -400,6 +400,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
        ah->noise = ath9k_hw_getchan_noise(ah, chan);
        return true;
 }
+EXPORT_SYMBOL(ath9k_hw_getnf);
 
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
                                  struct ath9k_channel *chan)
index 05b9dbf818507535288360bfdff4379aa7bf9970..3b33996d97dfeb84c7ba71233ff2a214cec1585e 100644 (file)
@@ -19,7 +19,6 @@
 
 #include "hw.h"
 
-#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
 
 #define NUM_NF_READINGS       6
index e267c92dbfb8e22de58a0156771a461ccfada95a..4a00806e2852af4e88638076f8b60c85fb82426b 100644 (file)
@@ -1629,7 +1629,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                struct ieee80211_channel *curchan = hw->conf.channel;
-               struct ath9k_channel old_chan;
                int pos = curchan->hw_value;
                int old_pos = -1;
                unsigned long flags;
@@ -1654,11 +1653,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                 * Preserve the current channel values, before updating
                 * the same channel
                 */
-               if (old_pos == pos) {
-                       memcpy(&old_chan, &sc->sc_ah->channels[pos],
-                               sizeof(struct ath9k_channel));
-                       ah->curchan = &old_chan;
-               }
+               if (ah->curchan && (old_pos == pos))
+                       ath9k_hw_getnf(ah, ah->curchan);
 
                ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
                                          curchan, conf->channel_type);
index 5a002a21f108aa23895ee59139c8fcb6ac37e643..f7eeee1dcdb66a8b3a09c5534bb8f15a15f09e91 100644 (file)
@@ -3119,8 +3119,10 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
                /* Verify NVRAM bytes */
                brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
                nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
-               if (!nvram_ularray)
+               if (!nvram_ularray) {
+                       kfree(vbuffer);
                        return -ENOMEM;
+               }
 
                /* Upload image to verify downloaded contents. */
                memset(nvram_ularray, 0xaa, varsize);
index 61092156755e0a77984736df7a1ac524bb074ef5..5637436430381a12d6322fbac9e9be1ec27de276 100644 (file)
@@ -763,6 +763,22 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
        }
 }
 
+/*
+ * The crc check is done on a little-endian array, we need
+ * to switch the bytes around before checking crc (and
+ * then switch it back).
+ */
+static int do_crc_check(u16 *buf, unsigned nwords)
+{
+       u8 crc;
+
+       cpu_to_le16_buf(buf, nwords);
+       crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE);
+       le16_to_cpu_buf(buf, nwords);
+
+       return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table);
+}
+
 /*
  * Read in and validate sprom.
  * Return 0 on success, nonzero on error.
@@ -772,8 +788,6 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
 {
        int err = 0;
        uint i;
-       u8 *bbuf = (u8 *)buf; /* byte buffer */
-       uint nbytes = nwords << 1;
        struct bcma_device *core;
        uint sprom_offset;
 
@@ -786,9 +800,9 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
                sprom_offset = CHIPCREGOFFS(sromotp);
        }
 
-       /* read the sprom in bytes */
-       for (i = 0; i < nbytes; i++)
-               bbuf[i] = bcma_read8(core, sprom_offset+i);
+       /* read the sprom */
+       for (i = 0; i < nwords; i++)
+               buf[i] = bcma_read16(core, sprom_offset+i*2);
 
        if (buf[0] == 0xffff)
                /*
@@ -798,13 +812,8 @@ sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
                 */
                return -ENODATA;
 
-       if (check_crc &&
-           crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
-                CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+       if (check_crc && !do_crc_check(buf, nwords))
                err = -EIO;
-       else
-               /* now correct the endianness of the byte array */
-               le16_to_cpu_buf(buf, nwords);
 
        return err;
 }
index 6f91a148c2220ad2f4694c21a4f47e52822912e2..3fda6b1dcf465ee3fcda52a5807d78dedb50c760 100644 (file)
@@ -196,6 +196,8 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
                /* Allocate skb buffer to contain firmware */
                /* info and tx descriptor info. */
                skb = dev_alloc_skb(frag_length);
+               if (!skb)
+                       return false;
                skb_reserve(skb, extra_descoffset);
                seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
                                        extra_descoffset));
@@ -573,6 +575,8 @@ static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
 
        len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
        skb = dev_alloc_skb(len);
+       if (!skb)
+               return false;
        cb_desc = (struct rtl_tcb_desc *)(skb->cb);
        cb_desc->queue_index = TXCMD_QUEUE;
        cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
index 91a375fb6ae622181231fce19b1a5907e94c9f40..ea2bd1be26404092585dcb4d20b0ab113a808ab7 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/machdep.h>
 #endif /* CONFIG_PPC */
 
+#include <asm/setup.h>
 #include <asm/page.h>
 
 char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
index bcd5d54b7d4d2b3cfc938acf6141cc65bb4ec8ec..7ff10c1e8664806f941785619ed9fd8ed0582e71 100644 (file)
@@ -562,19 +562,6 @@ dino_fixup_bus(struct pci_bus *bus)
        /* Firmware doesn't set up card-mode dino, so we have to */
        if (is_card_dino(&dino_dev->hba.dev->id)) {
                dino_card_setup(bus, dino_dev->hba.base_addr);
-       } else if(bus->parent == NULL) {
-               /* must have a dino above it, reparent the resources
-                * into the dino window */
-               int i;
-               struct resource *res = &dino_dev->hba.lmmio_space;
-
-               bus->resource[0] = &(dino_dev->hba.io_space);
-               for(i = 0; i < DINO_MAX_LMMIO_RESOURCES; i++) {
-                       if(res[i].flags == 0)
-                               break;
-                       bus->resource[i+1] = &res[i];
-               }
-
        } else if (bus->parent) {
                int i;
 
@@ -927,6 +914,7 @@ static int __init dino_probe(struct parisc_device *dev)
        const char *version = "unknown";
        char *name;
        int is_cujo = 0;
+       LIST_HEAD(resources);
        struct pci_bus *bus;
        unsigned long hpa = dev->hpa.start;
 
@@ -1003,26 +991,37 @@ static int __init dino_probe(struct parisc_device *dev)
 
        dev->dev.platform_data = dino_dev;
 
+       pci_add_resource(&resources, &dino_dev->hba.io_space);
+       if (dino_dev->hba.lmmio_space.flags)
+               pci_add_resource(&resources, &dino_dev->hba.lmmio_space);
+       if (dino_dev->hba.elmmio_space.flags)
+               pci_add_resource(&resources, &dino_dev->hba.elmmio_space);
+       if (dino_dev->hba.gmmio_space.flags)
+               pci_add_resource(&resources, &dino_dev->hba.gmmio_space);
+
        /*
        ** It's not used to avoid chicken/egg problems
        ** with configuration accessor functions.
        */
-       dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
-                        dino_current_bus, &dino_cfg_ops, NULL);
-
-       if(bus) {
-               /* This code *depends* on scanning being single threaded
-                * if it isn't, this global bus number count will fail
-                */
-               dino_current_bus = bus->subordinate + 1;
-               pci_bus_assign_resources(bus);
-               pci_bus_add_devices(bus);
-       } else {
+       dino_dev->hba.hba_bus = bus = pci_create_root_bus(&dev->dev,
+                        dino_current_bus, &dino_cfg_ops, NULL, &resources);
+       if (!bus) {
                printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
                       dev_name(&dev->dev), dino_current_bus);
+               pci_free_resource_list(&resources);
                /* increment the bus number in case of duplicates */
                dino_current_bus++;
+               return 0;
        }
+
+       bus->subordinate = pci_scan_child_bus(bus);
+
+       /* This code *depends* on scanning being single threaded
+        * if it isn't, this global bus number count will fail
+        */
+       dino_current_bus = bus->subordinate + 1;
+       pci_bus_assign_resources(bus);
+       pci_bus_add_devices(bus);
        return 0;
 }
 
index 3aeb3279c92ab976d62fad84223442e441225963..d5f3d753a108693abae1143f3a6f51959a4f4139 100644 (file)
@@ -653,7 +653,7 @@ lba_fixup_bus(struct pci_bus *bus)
                }
        } else {
                /* Host-PCI Bridge */
-               int err, i;
+               int err;
 
                DBG("lba_fixup_bus() %s [%lx/%lx]/%lx\n",
                        ldev->hba.io_space.name,
@@ -669,9 +669,6 @@ lba_fixup_bus(struct pci_bus *bus)
                        lba_dump_res(&ioport_resource, 2);
                        BUG();
                }
-               /* advertize Host bridge resources to PCI bus */
-               bus->resource[0] = &(ldev->hba.io_space);
-               i = 1;
 
                if (ldev->hba.elmmio_space.start) {
                        err = request_resource(&iomem_resource,
@@ -685,35 +682,17 @@ lba_fixup_bus(struct pci_bus *bus)
 
                                /* lba_dump_res(&iomem_resource, 2); */
                                /* BUG(); */
-                       } else
-                               bus->resource[i++] = &(ldev->hba.elmmio_space);
+                       }
                }
 
-
-               /*   Overlaps with elmmio can (and should) fail here.
-                *   We will prune (or ignore) the distributed range.
-                *
-                *   FIXME: SBA code should register all elmmio ranges first.
-                *      that would take care of elmmio ranges routed
-                *      to a different rope (already discovered) from
-                *      getting registered *after* LBA code has already
-                *      registered it's distributed lmmio range.
-                */
-               if (truncate_pat_collision(&iomem_resource,
-                                       &(ldev->hba.lmmio_space))) {
-
-                       printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
-                                       (long)ldev->hba.lmmio_space.start,
-                                       (long)ldev->hba.lmmio_space.end);
-               } else {
+               if (ldev->hba.lmmio_space.flags) {
                        err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
                        if (err < 0) {
                                printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
                                        "lmmio_space [%lx/%lx]\n",
                                        (long)ldev->hba.lmmio_space.start,
                                        (long)ldev->hba.lmmio_space.end);
-                       } else
-                               bus->resource[i++] = &(ldev->hba.lmmio_space);
+                       }
                }
 
 #ifdef CONFIG_64BIT
@@ -728,7 +707,6 @@ lba_fixup_bus(struct pci_bus *bus)
                                lba_dump_res(&iomem_resource, 2);
                                BUG();
                        }
-                       bus->resource[i++] = &(ldev->hba.gmmio_space);
                }
 #endif
 
@@ -1404,6 +1382,7 @@ static int __init
 lba_driver_probe(struct parisc_device *dev)
 {
        struct lba_device *lba_dev;
+       LIST_HEAD(resources);
        struct pci_bus *lba_bus;
        struct pci_ops *cfg_ops;
        u32 func_class;
@@ -1518,10 +1497,41 @@ lba_driver_probe(struct parisc_device *dev)
        if (lba_dev->hba.bus_num.start < lba_next_bus)
                lba_dev->hba.bus_num.start = lba_next_bus;
 
+       /*   Overlaps with elmmio can (and should) fail here.
+        *   We will prune (or ignore) the distributed range.
+        *
+        *   FIXME: SBA code should register all elmmio ranges first.
+        *      that would take care of elmmio ranges routed
+        *      to a different rope (already discovered) from
+        *      getting registered *after* LBA code has already
+        *      registered it's distributed lmmio range.
+        */
+       if (truncate_pat_collision(&iomem_resource,
+                                  &(lba_dev->hba.lmmio_space))) {
+               printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
+                               (long)lba_dev->hba.lmmio_space.start,
+                               (long)lba_dev->hba.lmmio_space.end);
+               lba_dev->hba.lmmio_space.flags = 0;
+       }
+
+       pci_add_resource(&resources, &lba_dev->hba.io_space);
+       if (lba_dev->hba.elmmio_space.start)
+               pci_add_resource(&resources, &lba_dev->hba.elmmio_space);
+       if (lba_dev->hba.lmmio_space.flags)
+               pci_add_resource(&resources, &lba_dev->hba.lmmio_space);
+       if (lba_dev->hba.gmmio_space.flags)
+               pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
+
        dev->dev.platform_data = lba_dev;
        lba_bus = lba_dev->hba.hba_bus =
-               pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
-                               cfg_ops, NULL);
+               pci_create_root_bus(&dev->dev, lba_dev->hba.bus_num.start,
+                                   cfg_ops, NULL, &resources);
+       if (!lba_bus) {
+               pci_free_resource_list(&resources);
+               return 0;
+       }
+
+       lba_bus->subordinate = pci_scan_child_bus(lba_bus);
 
        /* This is in lieu of calling pci_assign_unassigned_resources() */
        if (is_pdc_pat()) {
@@ -1551,10 +1561,8 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
        }
 
-       if (lba_bus) {
-               lba_next_bus = lba_bus->subordinate + 1;
-               pci_bus_add_devices(lba_bus);
-       }
+       lba_next_bus = lba_bus->subordinate + 1;
+       pci_bus_add_devices(lba_bus);
 
        /* Whew! Finally done! Tell services we got this one covered. */
        return 0;
index d0b597b503983a68f655971970d7392876c3b224..0cb64f50cecde58fc62340e5e457bedf04471b19 100644 (file)
@@ -3404,8 +3404,8 @@ static int __init parport_init_mode_setup(char *str)
 #endif
 
 #ifdef MODULE
-static const char *irq[PARPORT_PC_MAX_PORTS];
-static const char *dma[PARPORT_PC_MAX_PORTS];
+static char *irq[PARPORT_PC_MAX_PORTS];
+static char *dma[PARPORT_PC_MAX_PORTS];
 
 MODULE_PARM_DESC(io, "Base I/O address (SPP regs)");
 module_param_array(io, int, NULL, 0);
index fdaa42aac7c6ecffb46955b27901f1bfa0658dd3..2a581642c237b74a4b71a70d04c86c8365f8aff8 100644 (file)
@@ -13,7 +13,7 @@
  * configuration space.
  */
 
-static DEFINE_RAW_SPINLOCK(pci_lock);
+DEFINE_RAW_SPINLOCK(pci_lock);
 
 /*
  *  Wrappers for all PCI configuration access functions.  They just check
@@ -127,20 +127,20 @@ EXPORT_SYMBOL(pci_write_vpd);
  * We have a bit per device to indicate it's blocked and a global wait queue
  * for callers to sleep on until devices are unblocked.
  */
-static DECLARE_WAIT_QUEUE_HEAD(pci_ucfg_wait);
+static DECLARE_WAIT_QUEUE_HEAD(pci_cfg_wait);
 
-static noinline void pci_wait_ucfg(struct pci_dev *dev)
+static noinline void pci_wait_cfg(struct pci_dev *dev)
 {
        DECLARE_WAITQUEUE(wait, current);
 
-       __add_wait_queue(&pci_ucfg_wait, &wait);
+       __add_wait_queue(&pci_cfg_wait, &wait);
        do {
                set_current_state(TASK_UNINTERRUPTIBLE);
                raw_spin_unlock_irq(&pci_lock);
                schedule();
                raw_spin_lock_irq(&pci_lock);
-       } while (dev->block_ucfg_access);
-       __remove_wait_queue(&pci_ucfg_wait, &wait);
+       } while (dev->block_cfg_access);
+       __remove_wait_queue(&pci_cfg_wait, &wait);
 }
 
 /* Returns 0 on success, negative values indicate error. */
@@ -153,7 +153,8 @@ int pci_user_read_config_##size                                             \
        if (PCI_##size##_BAD)                                           \
                return -EINVAL;                                         \
        raw_spin_lock_irq(&pci_lock);                           \
-       if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev);       \
+       if (unlikely(dev->block_cfg_access))                            \
+               pci_wait_cfg(dev);                                      \
        ret = dev->bus->ops->read(dev->bus, dev->devfn,                 \
                                        pos, sizeof(type), &data);      \
        raw_spin_unlock_irq(&pci_lock);                         \
@@ -172,7 +173,8 @@ int pci_user_write_config_##size                                    \
        if (PCI_##size##_BAD)                                           \
                return -EINVAL;                                         \
        raw_spin_lock_irq(&pci_lock);                           \
-       if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev);       \
+       if (unlikely(dev->block_cfg_access))                            \
+               pci_wait_cfg(dev);                                      \
        ret = dev->bus->ops->write(dev->bus, dev->devfn,                \
                                        pos, sizeof(type), val);        \
        raw_spin_unlock_irq(&pci_lock);                         \
@@ -401,36 +403,56 @@ int pci_vpd_truncate(struct pci_dev *dev, size_t size)
 EXPORT_SYMBOL(pci_vpd_truncate);
 
 /**
- * pci_block_user_cfg_access - Block userspace PCI config reads/writes
+ * pci_cfg_access_lock - Lock PCI config reads/writes
  * @dev:       pci device struct
  *
- * When user access is blocked, any reads or writes to config space will
- * sleep until access is unblocked again.  We don't allow nesting of
- * block/unblock calls.
+ * When access is locked, any userspace reads or writes to config
+ * space and concurrent lock requests will sleep until access is
+ * allowed via pci_cfg_access_unlocked again.
  */
-void pci_block_user_cfg_access(struct pci_dev *dev)
+void pci_cfg_access_lock(struct pci_dev *dev)
+{
+       might_sleep();
+
+       raw_spin_lock_irq(&pci_lock);
+       if (dev->block_cfg_access)
+               pci_wait_cfg(dev);
+       dev->block_cfg_access = 1;
+       raw_spin_unlock_irq(&pci_lock);
+}
+EXPORT_SYMBOL_GPL(pci_cfg_access_lock);
+
+/**
+ * pci_cfg_access_trylock - try to lock PCI config reads/writes
+ * @dev:       pci device struct
+ *
+ * Same as pci_cfg_access_lock, but will return 0 if access is
+ * already locked, 1 otherwise. This function can be used from
+ * atomic contexts.
+ */
+bool pci_cfg_access_trylock(struct pci_dev *dev)
 {
        unsigned long flags;
-       int was_blocked;
+       bool locked = true;
 
        raw_spin_lock_irqsave(&pci_lock, flags);
-       was_blocked = dev->block_ucfg_access;
-       dev->block_ucfg_access = 1;
+       if (dev->block_cfg_access)
+               locked = false;
+       else
+               dev->block_cfg_access = 1;
        raw_spin_unlock_irqrestore(&pci_lock, flags);
 
-       /* If we BUG() inside the pci_lock, we're guaranteed to hose
-        * the machine */
-       BUG_ON(was_blocked);
+       return locked;
 }
-EXPORT_SYMBOL_GPL(pci_block_user_cfg_access);
+EXPORT_SYMBOL_GPL(pci_cfg_access_trylock);
 
 /**
- * pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes
+ * pci_cfg_access_unlock - Unlock PCI config reads/writes
  * @dev:       pci device struct
  *
- * This function allows userspace PCI config accesses to resume.
+ * This function allows PCI config accesses to resume.
  */
-void pci_unblock_user_cfg_access(struct pci_dev *dev)
+void pci_cfg_access_unlock(struct pci_dev *dev)
 {
        unsigned long flags;
 
@@ -438,10 +460,10 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev)
 
        /* This indicates a problem in the caller, but we don't need
         * to kill them, unlike a double-block above. */
-       WARN_ON(!dev->block_ucfg_access);
+       WARN_ON(!dev->block_cfg_access);
 
-       dev->block_ucfg_access = 0;
-       wake_up_all(&pci_ucfg_wait);
+       dev->block_cfg_access = 0;
+       wake_up_all(&pci_cfg_wait);
        raw_spin_unlock_irqrestore(&pci_lock, flags);
 }
-EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access);
+EXPORT_SYMBOL_GPL(pci_cfg_access_unlock);
index 9dd90b30f91a23703c420f5b60cf1fc2d31f55cd..95655d7c0d0b1abdd7e2d4c584af7f0f4217d184 100644 (file)
@@ -128,6 +128,23 @@ void pci_disable_ats(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_disable_ats);
 
+void pci_restore_ats_state(struct pci_dev *dev)
+{
+       u16 ctrl;
+
+       if (!pci_ats_enabled(dev))
+               return;
+       if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS))
+               BUG();
+
+       ctrl = PCI_ATS_CTRL_ENABLE;
+       if (!dev->is_virtfn)
+               ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU);
+
+       pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
+}
+EXPORT_SYMBOL_GPL(pci_restore_ats_state);
+
 /**
  * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
  * @dev: the PCI device
index 1e2ad92a47525d009372b5a4724a1cc55b82d494..398f5d8597910c7a661525434e001fc6d42de259 100644 (file)
 
 #include "pci.h"
 
+void pci_add_resource(struct list_head *resources, struct resource *res)
+{
+       struct pci_bus_resource *bus_res;
+
+       bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
+       if (!bus_res) {
+               printk(KERN_ERR "PCI: can't add bus resource %pR\n", res);
+               return;
+       }
+
+       bus_res->res = res;
+       list_add_tail(&bus_res->list, resources);
+}
+EXPORT_SYMBOL(pci_add_resource);
+
+void pci_free_resource_list(struct list_head *resources)
+{
+       struct pci_bus_resource *bus_res, *tmp;
+
+       list_for_each_entry_safe(bus_res, tmp, resources, list) {
+               list_del(&bus_res->list);
+               kfree(bus_res);
+       }
+}
+EXPORT_SYMBOL(pci_free_resource_list);
+
 void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
                          unsigned int flags)
 {
@@ -52,16 +78,12 @@ EXPORT_SYMBOL_GPL(pci_bus_resource_n);
 
 void pci_bus_remove_resources(struct pci_bus *bus)
 {
-       struct pci_bus_resource *bus_res, *tmp;
        int i;
 
        for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
                bus->resource[i] = NULL;
 
-       list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
-               list_del(&bus_res->list);
-               kfree(bus_res);
-       }
+       pci_free_resource_list(&bus->resources);
 }
 
 /**
index 1969a3ee3058328e469a0fc6e529f9841f5708ab..0321fa3b42268841d9bc9909354a71f8a385dcc5 100644 (file)
@@ -347,11 +347,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
                        return rc;
        }
 
+       pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
+
        iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
-       pci_block_user_cfg_access(dev);
+       pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
        msleep(100);
-       pci_unblock_user_cfg_access(dev);
+       pci_cfg_access_unlock(dev);
 
        iov->initial = initial;
        if (nr_virtfn < initial)
@@ -379,10 +381,10 @@ failed:
                virtfn_remove(dev, j, 0);
 
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
-       pci_block_user_cfg_access(dev);
+       pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
        ssleep(1);
-       pci_unblock_user_cfg_access(dev);
+       pci_cfg_access_unlock(dev);
 
        if (iov->link != dev->devfn)
                sysfs_remove_link(&dev->dev.kobj, "dep_link");
@@ -405,10 +407,10 @@ static void sriov_disable(struct pci_dev *dev)
                virtfn_remove(dev, i, 0);
 
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
-       pci_block_user_cfg_access(dev);
+       pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
        ssleep(1);
-       pci_unblock_user_cfg_access(dev);
+       pci_cfg_access_unlock(dev);
 
        if (iov->link != dev->devfn)
                sysfs_remove_link(&dev->dev.kobj, "dep_link");
@@ -452,7 +454,6 @@ static int sriov_init(struct pci_dev *dev, int pos)
 
 found:
        pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
-       pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total);
        pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
        pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
        if (!offset || (total > 1 && !stride))
@@ -465,7 +466,6 @@ found:
                return -EIO;
 
        pgsz &= ~(pgsz - 1);
-       pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
 
        nres = 0;
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
index 337e16ab4a92ba3cde34b53b220b61d9191b4658..a825d78fd0aa7e50bfb50520d6af16604436890e 100644 (file)
@@ -86,6 +86,31 @@ void default_teardown_msi_irqs(struct pci_dev *dev)
 }
 #endif
 
+#ifndef arch_restore_msi_irqs
+# define arch_restore_msi_irqs default_restore_msi_irqs
+# define HAVE_DEFAULT_MSI_RESTORE_IRQS
+#endif
+
+#ifdef HAVE_DEFAULT_MSI_RESTORE_IRQS
+void default_restore_msi_irqs(struct pci_dev *dev, int irq)
+{
+       struct msi_desc *entry;
+
+       entry = NULL;
+       if (dev->msix_enabled) {
+               list_for_each_entry(entry, &dev->msi_list, list) {
+                       if (irq == entry->irq)
+                               break;
+               }
+       } else if (dev->msi_enabled)  {
+               entry = irq_get_msi_desc(irq);
+       }
+
+       if (entry)
+               write_msi_msg(irq, &entry->msg);
+}
+#endif
+
 static void msi_set_enable(struct pci_dev *dev, int pos, int enable)
 {
        u16 control;
@@ -323,8 +348,18 @@ static void free_msi_irqs(struct pci_dev *dev)
                        if (list_is_last(&entry->list, &dev->msi_list))
                                iounmap(entry->mask_base);
                }
-               kobject_del(&entry->kobj);
-               kobject_put(&entry->kobj);
+
+               /*
+                * Its possible that we get into this path
+                * When populate_msi_sysfs fails, which means the entries
+                * were not registered with sysfs.  In that case don't
+                * unregister them.
+                */
+               if (entry->kobj.parent) {
+                       kobject_del(&entry->kobj);
+                       kobject_put(&entry->kobj);
+               }
+
                list_del(&entry->list);
                kfree(entry);
        }
@@ -362,7 +397,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
 
        pci_intx_for_msi(dev, 0);
        msi_set_enable(dev, pos, 0);
-       write_msi_msg(dev->irq, &entry->msg);
+       arch_restore_msi_irqs(dev, dev->irq);
 
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
        msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
@@ -390,7 +425,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
-               write_msi_msg(entry->irq, &entry->msg);
+               arch_restore_msi_irqs(dev, entry->irq);
                msix_mask_irq(entry, entry->masked);
        }
 
index 12d1e81a8abecd2fc1a6bc7ab3946d53df05542a..3623d65f8b86ccb9d786085ec57592d2e890292c 100644 (file)
@@ -604,7 +604,8 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
         * supported as well.  Drivers are supposed to support either the
         * former, or the latter, but not both at the same time.
         */
-       WARN_ON(ret && drv->driver.pm);
+       WARN(ret && drv->driver.pm, "driver %s device %04x:%04x\n",
+               drv->name, pci_dev->vendor, pci_dev->device);
 
        return ret;
 }
index 6d4a5319148d7eb293eb499cb98cfc56e496f078..97fff785e97e7027f7d54563186db969075a2558 100644 (file)
@@ -88,6 +88,12 @@ enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
 u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2;
 u8 pci_cache_line_size;
 
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
 /**
  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
  * @bus: pointer to PCI bus structure to search
@@ -959,6 +965,7 @@ void pci_restore_state(struct pci_dev *dev)
 
        /* PCI Express register must be restored first */
        pci_restore_pcie_state(dev);
+       pci_restore_ats_state(dev);
 
        /*
         * The Base Address register should be programmed before the command
@@ -967,7 +974,7 @@ void pci_restore_state(struct pci_dev *dev)
        for (i = 15; i >= 0; i--) {
                pci_read_config_dword(dev, i * 4, &val);
                if (val != dev->saved_config_space[i]) {
-                       dev_printk(KERN_DEBUG, &dev->dev, "restoring config "
+                       dev_dbg(&dev->dev, "restoring config "
                                "space at offset %#x (was %#x, writing %#x)\n",
                                i, val, (int)dev->saved_config_space[i]);
                        pci_write_config_dword(dev,i * 4,
@@ -1536,8 +1543,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
        }
 
 out:
-       dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n",
-                       enable ? "enabled" : "disabled");
+       dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled");
 }
 
 /**
@@ -2595,6 +2601,33 @@ static void __pci_set_master(struct pci_dev *dev, bool enable)
        dev->is_busmaster = enable;
 }
 
+/**
+ * pcibios_set_master - enable PCI bus-mastering for device dev
+ * @dev: the PCI device to enable
+ *
+ * Enables PCI bus-mastering for the device.  This is the default
+ * implementation.  Architecture specific implementations can override
+ * this if necessary.
+ */
+void __weak pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+
+       /* The latency timer doesn't apply to PCIe (either Type 0 or Type 1) */
+       if (pci_is_pcie(dev))
+               return;
+
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       if (lat < 16)
+               lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+       else if (lat > pcibios_max_latency)
+               lat = pcibios_max_latency;
+       else
+               return;
+       dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
 /**
  * pci_set_master - enables bus-mastering for device dev
  * @dev: the PCI device to enable
@@ -2767,6 +2800,116 @@ pci_intx(struct pci_dev *pdev, int enable)
        }
 }
 
+/**
+ * pci_intx_mask_supported - probe for INTx masking support
+ * @pdev: the PCI device to operate on
+ *
+ * Check if the device dev support INTx masking via the config space
+ * command word.
+ */
+bool pci_intx_mask_supported(struct pci_dev *dev)
+{
+       bool mask_supported = false;
+       u16 orig, new;
+
+       pci_cfg_access_lock(dev);
+
+       pci_read_config_word(dev, PCI_COMMAND, &orig);
+       pci_write_config_word(dev, PCI_COMMAND,
+                             orig ^ PCI_COMMAND_INTX_DISABLE);
+       pci_read_config_word(dev, PCI_COMMAND, &new);
+
+       /*
+        * There's no way to protect against hardware bugs or detect them
+        * reliably, but as long as we know what the value should be, let's
+        * go ahead and check it.
+        */
+       if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) {
+               dev_err(&dev->dev, "Command register changed from "
+                       "0x%x to 0x%x: driver or hardware bug?\n", orig, new);
+       } else if ((new ^ orig) & PCI_COMMAND_INTX_DISABLE) {
+               mask_supported = true;
+               pci_write_config_word(dev, PCI_COMMAND, orig);
+       }
+
+       pci_cfg_access_unlock(dev);
+       return mask_supported;
+}
+EXPORT_SYMBOL_GPL(pci_intx_mask_supported);
+
+static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
+{
+       struct pci_bus *bus = dev->bus;
+       bool mask_updated = true;
+       u32 cmd_status_dword;
+       u16 origcmd, newcmd;
+       unsigned long flags;
+       bool irq_pending;
+
+       /*
+        * We do a single dword read to retrieve both command and status.
+        * Document assumptions that make this possible.
+        */
+       BUILD_BUG_ON(PCI_COMMAND % 4);
+       BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
+
+       raw_spin_lock_irqsave(&pci_lock, flags);
+
+       bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
+
+       irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
+
+       /*
+        * Check interrupt status register to see whether our device
+        * triggered the interrupt (when masking) or the next IRQ is
+        * already pending (when unmasking).
+        */
+       if (mask != irq_pending) {
+               mask_updated = false;
+               goto done;
+       }
+
+       origcmd = cmd_status_dword;
+       newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
+       if (mask)
+               newcmd |= PCI_COMMAND_INTX_DISABLE;
+       if (newcmd != origcmd)
+               bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
+
+done:
+       raw_spin_unlock_irqrestore(&pci_lock, flags);
+
+       return mask_updated;
+}
+
+/**
+ * pci_check_and_mask_intx - mask INTx on pending interrupt
+ * @pdev: the PCI device to operate on
+ *
+ * Check if the device dev has its INTx line asserted, mask it and
+ * return true in that case. False is returned if not interrupt was
+ * pending.
+ */
+bool pci_check_and_mask_intx(struct pci_dev *dev)
+{
+       return pci_check_and_set_intx_mask(dev, true);
+}
+EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
+
+/**
+ * pci_check_and_mask_intx - unmask INTx of no interrupt is pending
+ * @pdev: the PCI device to operate on
+ *
+ * Check if the device dev has its INTx line asserted, unmask it if not
+ * and return true. False is returned and the mask remains active if
+ * there was still an interrupt pending.
+ */
+bool pci_check_and_unmask_intx(struct pci_dev *dev)
+{
+       return pci_check_and_set_intx_mask(dev, false);
+}
+EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
+
 /**
  * pci_msi_off - disables any msi or msix capabilities
  * @dev: the PCI device to operate on
@@ -2965,7 +3108,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
        might_sleep();
 
        if (!probe) {
-               pci_block_user_cfg_access(dev);
+               pci_cfg_access_lock(dev);
                /* block PM suspend, driver probe, etc. */
                device_lock(&dev->dev);
        }
@@ -2990,7 +3133,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)
 done:
        if (!probe) {
                device_unlock(&dev->dev);
-               pci_unblock_user_cfg_access(dev);
+               pci_cfg_access_unlock(dev);
        }
 
        return rc;
index b74084e9ca12fa52e14f06e3b71d38aca4708b7d..1009a5e88e533f37736710895ffc6ba5194f0498 100644 (file)
@@ -136,6 +136,8 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
 /* Lock for read/write access to pci device and bus lists */
 extern struct rw_semaphore pci_bus_sem;
 
+extern raw_spinlock_t pci_lock;
+
 extern unsigned int pci_pm_d3_delay;
 
 #ifdef CONFIG_PCI_MSI
@@ -249,6 +251,14 @@ struct pci_sriov {
        u8 __iomem *mstate;     /* VF Migration State Array */
 };
 
+#ifdef CONFIG_PCI_ATS
+extern void pci_restore_ats_state(struct pci_dev *dev);
+#else
+static inline void pci_restore_ats_state(struct pci_dev *dev)
+{
+}
+#endif /* CONFIG_PCI_ATS */
+
 #ifdef CONFIG_PCI_IOV
 extern int pci_iov_init(struct pci_dev *dev);
 extern void pci_iov_release(struct pci_dev *dev);
index dc29348264c668e16c63a7909d59e82008a18109..72962cc92e0af46402c0c6c4d38a15d82666931d 100644 (file)
@@ -39,7 +39,7 @@ config PCIEASPM
          Power Management) and Clock Power Management. ASPM supports
          state L0/L0s/L1.
 
-         ASPM is initially set up the the firmware. With this option enabled,
+         ASPM is initially set up by the firmware. With this option enabled,
          Linux can modify this state in order to disable ASPM on known-bad
          hardware or configurations and enable it when known-safe.
 
index 04e74f4857146e4700669504de55a6ad632823a0..7cc9e2f0f47cab6c55a214af1d9134e77f1bd0a8 100644 (file)
@@ -1522,19 +1522,21 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
        return max;
 }
 
-struct pci_bus * pci_create_bus(struct device *parent,
-               int bus, struct pci_ops *ops, void *sysdata)
+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+               struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
-       int error;
+       int error, i;
        struct pci_bus *b, *b2;
        struct device *dev;
+       struct pci_bus_resource *bus_res, *n;
+       struct resource *res;
 
        b = pci_alloc_bus();
        if (!b)
                return NULL;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev){
+       if (!dev) {
                kfree(b);
                return NULL;
        }
@@ -1577,8 +1579,20 @@ struct pci_bus * pci_create_bus(struct device *parent,
        pci_create_legacy_files(b);
 
        b->number = b->secondary = bus;
-       b->resource[0] = &ioport_resource;
-       b->resource[1] = &iomem_resource;
+
+       /* Add initial resources to the bus */
+       list_for_each_entry_safe(bus_res, n, resources, list)
+               list_move_tail(&bus_res->list, &b->resources);
+
+       if (parent)
+               dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
+       else
+               printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
+
+       pci_bus_for_each_resource(b, res, i) {
+               if (res)
+                       dev_info(&b->dev, "root bus resource %pR\n", res);
+       }
 
        return b;
 
@@ -1594,18 +1608,58 @@ err_out:
        return NULL;
 }
 
+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
+               struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+       struct pci_bus *b;
+
+       b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
+       if (!b)
+               return NULL;
+
+       b->subordinate = pci_scan_child_bus(b);
+       pci_bus_add_devices(b);
+       return b;
+}
+EXPORT_SYMBOL(pci_scan_root_bus);
+
+/* Deprecated; use pci_scan_root_bus() instead */
 struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
                int bus, struct pci_ops *ops, void *sysdata)
 {
+       LIST_HEAD(resources);
        struct pci_bus *b;
 
-       b = pci_create_bus(parent, bus, ops, sysdata);
+       pci_add_resource(&resources, &ioport_resource);
+       pci_add_resource(&resources, &iomem_resource);
+       b = pci_create_root_bus(parent, bus, ops, sysdata, &resources);
        if (b)
                b->subordinate = pci_scan_child_bus(b);
+       else
+               pci_free_resource_list(&resources);
        return b;
 }
 EXPORT_SYMBOL(pci_scan_bus_parented);
 
+struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
+                                       void *sysdata)
+{
+       LIST_HEAD(resources);
+       struct pci_bus *b;
+
+       pci_add_resource(&resources, &ioport_resource);
+       pci_add_resource(&resources, &iomem_resource);
+       b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
+       if (b) {
+               b->subordinate = pci_scan_child_bus(b);
+               pci_bus_add_devices(b);
+       } else {
+               pci_free_resource_list(&resources);
+       }
+       return b;
+}
+EXPORT_SYMBOL(pci_scan_bus);
+
 #ifdef CONFIG_HOTPLUG
 /**
  * pci_rescan_bus - scan a PCI bus for devices.
index 7f87beed35ac1c9eddec522b4efa6400cc6598da..6def3624c688c64f26f1ce981ab9a58e9e235804 100644 (file)
@@ -89,9 +89,8 @@ EXPORT_SYMBOL(pci_remove_bus);
  * device lists, remove the /proc entry, and notify userspace
  * (/sbin/hotplug).
  */
-void pci_remove_bus_device(struct pci_dev *dev)
+static void __pci_remove_bus_device(struct pci_dev *dev)
 {
-       pci_stop_bus_device(dev);
        if (dev->subordinate) {
                struct pci_bus *b = dev->subordinate;
 
@@ -102,6 +101,11 @@ void pci_remove_bus_device(struct pci_dev *dev)
 
        pci_destroy_dev(dev);
 }
+void pci_remove_bus_device(struct pci_dev *dev)
+{
+       pci_stop_bus_device(dev);
+       __pci_remove_bus_device(dev);
+}
 
 /**
  * pci_remove_behind_bridge - remove all devices behind a PCI bridge
@@ -117,7 +121,7 @@ void pci_remove_behind_bridge(struct pci_dev *dev)
 
        if (dev->subordinate)
                list_for_each_safe(l, n, &dev->subordinate->devices)
-                       pci_remove_bus_device(pci_dev_b(l));
+                       __pci_remove_bus_device(pci_dev_b(l));
 }
 
 static void pci_stop_bus_devices(struct pci_bus *bus)
index 5717509becbea42ab3f0c8e44b9ae76893b2cd4c..b66bfdbd21f7aafa55f3ea9e6b4782bf29dc2f01 100644 (file)
@@ -85,9 +85,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                }
        }
        res->flags &= ~IORESOURCE_UNSET;
-       dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
-                resno, res, (unsigned long long)region.start,
-                (unsigned long long)region.end);
+       dev_dbg(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
+               resno, res, (unsigned long long)region.start,
+               (unsigned long long)region.end);
 }
 
 int pci_claim_resource(struct pci_dev *dev, int resource)
index 7f43cf86d77602675297aaea32932c9a176f4c07..f995e6e2f78c1d53a1a8c5843a77fe2c3684d620 100644 (file)
@@ -639,7 +639,7 @@ config ACPI_CMPC
 
 config INTEL_SCU_IPC
        bool "Intel SCU IPC Support"
-       depends on X86_MRST
+       depends on X86_INTEL_MID
        default y
        ---help---
          IPC is used to bridge the communications between kernel and SCU on
index dfbd5a6cc58becc8cca321e4c6c34a043aebe81f..258fef272ea7d6b61faa565260c8fc7b7a4f995d 100644 (file)
@@ -295,6 +295,45 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
        }
 }
 
+#ifdef CONFIG_AMD_NB
+
+#include <asm/amd_nb.h>
+
+static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
+{
+       resource_size_t start, end;
+       struct pnp_resource *pnp_res;
+       struct resource *res;
+       struct resource mmconfig_res, *mmconfig;
+
+       mmconfig = amd_get_mmconfig_range(&mmconfig_res);
+       if (!mmconfig)
+               return;
+
+       list_for_each_entry(pnp_res, &dev->resources, list) {
+               res = &pnp_res->res;
+               if (res->end < mmconfig->start || res->start > mmconfig->end ||
+                   (res->start == mmconfig->start && res->end == mmconfig->end))
+                       continue;
+
+               dev_info(&dev->dev, FW_BUG
+                        "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n",
+                        res, mmconfig);
+               if (mmconfig->start < res->start) {
+                       start = mmconfig->start;
+                       end = res->start - 1;
+                       pnp_add_mem_resource(dev, start, end, 0);
+               }
+               if (mmconfig->end > res->end) {
+                       start = res->end + 1;
+                       end = mmconfig->end;
+                       pnp_add_mem_resource(dev, start, end, 0);
+               }
+               break;
+       }
+}
+#endif
+
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -322,6 +361,9 @@ static struct pnp_fixup pnp_fixups[] = {
        /* PnP resources that might overlap PCI BARs */
        {"PNP0c01", quirk_system_pci_resources},
        {"PNP0c02", quirk_system_pci_resources},
+#ifdef CONFIG_AMD_NB
+       {"PNP0c01", quirk_amd_mmconfig_area},
+#endif
        {""}
 };
 
index 9f88641e67f9255e0219071eb5a702a1289bb066..3a8daf858742ca6ebfe535786ec12944369d6022 100644 (file)
@@ -116,12 +116,12 @@ config BATTERY_WM97XX
        help
          Say Y to enable support for battery measured by WM97xx aux port.
 
-config BATTERY_BQ20Z75
-        tristate "TI BQ20z75 gas gauge"
+config BATTERY_SBS
+        tristate "SBS Compliant gas gauge"
         depends on I2C
         help
-         Say Y to include support for TI BQ20z75 SBS-compliant
-         gas gauge and protection IC.
+         Say Y to include support for SBS battery driver for SBS-compliant
+         gas gauges.
 
 config BATTERY_BQ27x00
        tristate "BQ27x00 battery driver"
@@ -150,6 +150,14 @@ config BATTERY_DA9030
          Say Y here to enable support for batteries charger integrated into
          DA9030 PMIC.
 
+config BATTERY_DA9052
+       tristate "Dialog DA9052 Battery"
+       depends on PMIC_DA9052
+       depends on BROKEN
+       help
+         Say Y here to enable support for batteries charger integrated into
+         DA9052 PMIC.
+
 config BATTERY_MAX17040
        tristate "Maxim MAX17040 Fuel Gauge"
        depends on I2C
@@ -226,6 +234,12 @@ config CHARGER_TWL4030
        help
          Say Y here to enable support for TWL4030 Battery Charge Interface.
 
+config CHARGER_LP8727
+       tristate "National Semiconductor LP8727 charger driver"
+       depends on I2C
+       help
+         Say Y here to enable support for LP8727 Charger Driver.
+
 config CHARGER_GPIO
        tristate "GPIO charger"
        depends on GPIOLIB
@@ -236,6 +250,16 @@ config CHARGER_GPIO
          This driver can be build as a module. If so, the module will be
          called gpio-charger.
 
+config CHARGER_MANAGER
+       bool "Battery charger manager for multiple chargers"
+       depends on REGULATOR && RTC_CLASS
+       help
+          Say Y to enable charger-manager support, which allows multiple
+          chargers attached to a battery and multiple batteries attached to a
+          system. The charger-manager also can monitor charging status in
+          runtime and in suspend-to-RAM by waking up the system periodically
+          with help of suspend_again support.
+
 config CHARGER_MAX8997
        tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
        depends on MFD_MAX8997 && REGULATOR_MAX8997
index b4af13dd8b66a1b45a3ed1307c1d0c4b1b10e169..e429008eaf10da66a8904850c55ff60553ff6aca 100644 (file)
@@ -22,9 +22,10 @@ obj-$(CONFIG_BATTERY_OLPC)   += olpc_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
 obj-$(CONFIG_BATTERY_COLLIE)   += collie_battery.o
 obj-$(CONFIG_BATTERY_WM97XX)   += wm97xx_battery.o
-obj-$(CONFIG_BATTERY_BQ20Z75)  += bq20z75.o
+obj-$(CONFIG_BATTERY_SBS)      += sbs-battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)  += bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)   += da9030_battery.o
+obj-$(CONFIG_BATTERY_DA9052)   += da9052-battery.o
 obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
@@ -35,6 +36,8 @@ obj-$(CONFIG_BATTERY_INTEL_MID)       += intel_mid_battery.o
 obj-$(CONFIG_CHARGER_ISP1704)  += isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)  += max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
+obj-$(CONFIG_CHARGER_LP8727)   += lp8727_charger.o
 obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
+obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
 obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c
deleted file mode 100644 (file)
index 9c5e5be..0000000
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * Gas Gauge driver for TI's BQ20Z75
- *
- * Copyright (c) 2010, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/power_supply.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-
-#include <linux/power/bq20z75.h>
-
-enum {
-       REG_MANUFACTURER_DATA,
-       REG_TEMPERATURE,
-       REG_VOLTAGE,
-       REG_CURRENT,
-       REG_CAPACITY,
-       REG_TIME_TO_EMPTY,
-       REG_TIME_TO_FULL,
-       REG_STATUS,
-       REG_CYCLE_COUNT,
-       REG_SERIAL_NUMBER,
-       REG_REMAINING_CAPACITY,
-       REG_REMAINING_CAPACITY_CHARGE,
-       REG_FULL_CHARGE_CAPACITY,
-       REG_FULL_CHARGE_CAPACITY_CHARGE,
-       REG_DESIGN_CAPACITY,
-       REG_DESIGN_CAPACITY_CHARGE,
-       REG_DESIGN_VOLTAGE,
-};
-
-/* Battery Mode defines */
-#define BATTERY_MODE_OFFSET            0x03
-#define BATTERY_MODE_MASK              0x8000
-enum bq20z75_battery_mode {
-       BATTERY_MODE_AMPS,
-       BATTERY_MODE_WATTS
-};
-
-/* manufacturer access defines */
-#define MANUFACTURER_ACCESS_STATUS     0x0006
-#define MANUFACTURER_ACCESS_SLEEP      0x0011
-
-/* battery status value bits */
-#define BATTERY_DISCHARGING            0x40
-#define BATTERY_FULL_CHARGED           0x20
-#define BATTERY_FULL_DISCHARGED                0x10
-
-#define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \
-       .psp = _psp, \
-       .addr = _addr, \
-       .min_value = _min_value, \
-       .max_value = _max_value, \
-}
-
-static const struct bq20z75_device_data {
-       enum power_supply_property psp;
-       u8 addr;
-       int min_value;
-       int max_value;
-} bq20z75_data[] = {
-       [REG_MANUFACTURER_DATA] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
-       [REG_TEMPERATURE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
-       [REG_VOLTAGE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
-       [REG_CURRENT] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768,
-                       32767),
-       [REG_CAPACITY] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
-       [REG_REMAINING_CAPACITY] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
-       [REG_REMAINING_CAPACITY_CHARGE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
-       [REG_FULL_CHARGE_CAPACITY] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
-       [REG_FULL_CHARGE_CAPACITY_CHARGE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
-       [REG_TIME_TO_EMPTY] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0,
-                       65535),
-       [REG_TIME_TO_FULL] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0,
-                       65535),
-       [REG_STATUS] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
-       [REG_CYCLE_COUNT] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
-       [REG_DESIGN_CAPACITY] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0,
-                       65535),
-       [REG_DESIGN_CAPACITY_CHARGE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0,
-                       65535),
-       [REG_DESIGN_VOLTAGE] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0,
-                       65535),
-       [REG_SERIAL_NUMBER] =
-               BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
-};
-
-static enum power_supply_property bq20z75_properties[] = {
-       POWER_SUPPLY_PROP_STATUS,
-       POWER_SUPPLY_PROP_HEALTH,
-       POWER_SUPPLY_PROP_PRESENT,
-       POWER_SUPPLY_PROP_TECHNOLOGY,
-       POWER_SUPPLY_PROP_CYCLE_COUNT,
-       POWER_SUPPLY_PROP_VOLTAGE_NOW,
-       POWER_SUPPLY_PROP_CURRENT_NOW,
-       POWER_SUPPLY_PROP_CAPACITY,
-       POWER_SUPPLY_PROP_TEMP,
-       POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
-       POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
-       POWER_SUPPLY_PROP_SERIAL_NUMBER,
-       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-       POWER_SUPPLY_PROP_ENERGY_NOW,
-       POWER_SUPPLY_PROP_ENERGY_FULL,
-       POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
-       POWER_SUPPLY_PROP_CHARGE_NOW,
-       POWER_SUPPLY_PROP_CHARGE_FULL,
-       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-};
-
-struct bq20z75_info {
-       struct i2c_client               *client;
-       struct power_supply             power_supply;
-       struct bq20z75_platform_data    *pdata;
-       bool                            is_present;
-       bool                            gpio_detect;
-       bool                            enable_detection;
-       int                             irq;
-       int                             last_state;
-       int                             poll_time;
-       struct delayed_work             work;
-       int                             ignore_changes;
-};
-
-static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
-{
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-       s32 ret = 0;
-       int retries = 1;
-
-       if (bq20z75_device->pdata)
-               retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
-
-       while (retries > 0) {
-               ret = i2c_smbus_read_word_data(client, address);
-               if (ret >= 0)
-                       break;
-               retries--;
-       }
-
-       if (ret < 0) {
-               dev_dbg(&client->dev,
-                       "%s: i2c read at address 0x%x failed\n",
-                       __func__, address);
-               return ret;
-       }
-
-       return le16_to_cpu(ret);
-}
-
-static int bq20z75_write_word_data(struct i2c_client *client, u8 address,
-       u16 value)
-{
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-       s32 ret = 0;
-       int retries = 1;
-
-       if (bq20z75_device->pdata)
-               retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1);
-
-       while (retries > 0) {
-               ret = i2c_smbus_write_word_data(client, address,
-                       le16_to_cpu(value));
-               if (ret >= 0)
-                       break;
-               retries--;
-       }
-
-       if (ret < 0) {
-               dev_dbg(&client->dev,
-                       "%s: i2c write to address 0x%x failed\n",
-                       __func__, address);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int bq20z75_get_battery_presence_and_health(
-       struct i2c_client *client, enum power_supply_property psp,
-       union power_supply_propval *val)
-{
-       s32 ret;
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-
-       if (psp == POWER_SUPPLY_PROP_PRESENT &&
-               bq20z75_device->gpio_detect) {
-               ret = gpio_get_value(
-                       bq20z75_device->pdata->battery_detect);
-               if (ret == bq20z75_device->pdata->battery_detect_present)
-                       val->intval = 1;
-               else
-                       val->intval = 0;
-               bq20z75_device->is_present = val->intval;
-               return ret;
-       }
-
-       /* Write to ManufacturerAccess with
-        * ManufacturerAccess command and then
-        * read the status */
-       ret = bq20z75_write_word_data(client,
-               bq20z75_data[REG_MANUFACTURER_DATA].addr,
-               MANUFACTURER_ACCESS_STATUS);
-       if (ret < 0) {
-               if (psp == POWER_SUPPLY_PROP_PRESENT)
-                       val->intval = 0; /* battery removed */
-               return ret;
-       }
-
-       ret = bq20z75_read_word_data(client,
-               bq20z75_data[REG_MANUFACTURER_DATA].addr);
-       if (ret < 0)
-               return ret;
-
-       if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value ||
-           ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) {
-               val->intval = 0;
-               return 0;
-       }
-
-       /* Mask the upper nibble of 2nd byte and
-        * lower byte of response then
-        * shift the result by 8 to get status*/
-       ret &= 0x0F00;
-       ret >>= 8;
-       if (psp == POWER_SUPPLY_PROP_PRESENT) {
-               if (ret == 0x0F)
-                       /* battery removed */
-                       val->intval = 0;
-               else
-                       val->intval = 1;
-       } else if (psp == POWER_SUPPLY_PROP_HEALTH) {
-               if (ret == 0x09)
-                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
-               else if (ret == 0x0B)
-                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
-               else if (ret == 0x0C)
-                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
-               else
-                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
-       }
-
-       return 0;
-}
-
-static int bq20z75_get_battery_property(struct i2c_client *client,
-       int reg_offset, enum power_supply_property psp,
-       union power_supply_propval *val)
-{
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-       s32 ret;
-
-       ret = bq20z75_read_word_data(client,
-               bq20z75_data[reg_offset].addr);
-       if (ret < 0)
-               return ret;
-
-       /* returned values are 16 bit */
-       if (bq20z75_data[reg_offset].min_value < 0)
-               ret = (s16)ret;
-
-       if (ret >= bq20z75_data[reg_offset].min_value &&
-           ret <= bq20z75_data[reg_offset].max_value) {
-               val->intval = ret;
-               if (psp != POWER_SUPPLY_PROP_STATUS)
-                       return 0;
-
-               if (ret & BATTERY_FULL_CHARGED)
-                       val->intval = POWER_SUPPLY_STATUS_FULL;
-               else if (ret & BATTERY_FULL_DISCHARGED)
-                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               else if (ret & BATTERY_DISCHARGING)
-                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-               else
-                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
-
-               if (bq20z75_device->poll_time == 0)
-                       bq20z75_device->last_state = val->intval;
-               else if (bq20z75_device->last_state != val->intval) {
-                       cancel_delayed_work_sync(&bq20z75_device->work);
-                       power_supply_changed(&bq20z75_device->power_supply);
-                       bq20z75_device->poll_time = 0;
-               }
-       } else {
-               if (psp == POWER_SUPPLY_PROP_STATUS)
-                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-               else
-                       val->intval = 0;
-       }
-
-       return 0;
-}
-
-static void  bq20z75_unit_adjustment(struct i2c_client *client,
-       enum power_supply_property psp, union power_supply_propval *val)
-{
-#define BASE_UNIT_CONVERSION           1000
-#define BATTERY_MODE_CAP_MULT_WATT     (10 * BASE_UNIT_CONVERSION)
-#define TIME_UNIT_CONVERSION           60
-#define TEMP_KELVIN_TO_CELSIUS         2731
-       switch (psp) {
-       case POWER_SUPPLY_PROP_ENERGY_NOW:
-       case POWER_SUPPLY_PROP_ENERGY_FULL:
-       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-               /* bq20z75 provides energy in units of 10mWh.
-                * Convert to ÂµWh
-                */
-               val->intval *= BATTERY_MODE_CAP_MULT_WATT;
-               break;
-
-       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-       case POWER_SUPPLY_PROP_CURRENT_NOW:
-       case POWER_SUPPLY_PROP_CHARGE_NOW:
-       case POWER_SUPPLY_PROP_CHARGE_FULL:
-       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-               val->intval *= BASE_UNIT_CONVERSION;
-               break;
-
-       case POWER_SUPPLY_PROP_TEMP:
-               /* bq20z75 provides battery temperature in 0.1K
-                * so convert it to 0.1°C
-                */
-               val->intval -= TEMP_KELVIN_TO_CELSIUS;
-               break;
-
-       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
-       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
-               /* bq20z75 provides time to empty and time to full in minutes.
-                * Convert to seconds
-                */
-               val->intval *= TIME_UNIT_CONVERSION;
-               break;
-
-       default:
-               dev_dbg(&client->dev,
-                       "%s: no need for unit conversion %d\n", __func__, psp);
-       }
-}
-
-static enum bq20z75_battery_mode
-bq20z75_set_battery_mode(struct i2c_client *client,
-       enum bq20z75_battery_mode mode)
-{
-       int ret, original_val;
-
-       original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET);
-       if (original_val < 0)
-               return original_val;
-
-       if ((original_val & BATTERY_MODE_MASK) == mode)
-               return mode;
-
-       if (mode == BATTERY_MODE_AMPS)
-               ret = original_val & ~BATTERY_MODE_MASK;
-       else
-               ret = original_val | BATTERY_MODE_MASK;
-
-       ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret);
-       if (ret < 0)
-               return ret;
-
-       return original_val & BATTERY_MODE_MASK;
-}
-
-static int bq20z75_get_battery_capacity(struct i2c_client *client,
-       int reg_offset, enum power_supply_property psp,
-       union power_supply_propval *val)
-{
-       s32 ret;
-       enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS;
-
-       if (power_supply_is_amp_property(psp))
-               mode = BATTERY_MODE_AMPS;
-
-       mode = bq20z75_set_battery_mode(client, mode);
-       if (mode < 0)
-               return mode;
-
-       ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr);
-       if (ret < 0)
-               return ret;
-
-       if (psp == POWER_SUPPLY_PROP_CAPACITY) {
-               /* bq20z75 spec says that this can be >100 %
-               * even if max value is 100 % */
-               val->intval = min(ret, 100);
-       } else
-               val->intval = ret;
-
-       ret = bq20z75_set_battery_mode(client, mode);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static char bq20z75_serial[5];
-static int bq20z75_get_battery_serial_number(struct i2c_client *client,
-       union power_supply_propval *val)
-{
-       int ret;
-
-       ret = bq20z75_read_word_data(client,
-               bq20z75_data[REG_SERIAL_NUMBER].addr);
-       if (ret < 0)
-               return ret;
-
-       ret = sprintf(bq20z75_serial, "%04x", ret);
-       val->strval = bq20z75_serial;
-
-       return 0;
-}
-
-static int bq20z75_get_property_index(struct i2c_client *client,
-       enum power_supply_property psp)
-{
-       int count;
-       for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++)
-               if (psp == bq20z75_data[count].psp)
-                       return count;
-
-       dev_warn(&client->dev,
-               "%s: Invalid Property - %d\n", __func__, psp);
-
-       return -EINVAL;
-}
-
-static int bq20z75_get_property(struct power_supply *psy,
-       enum power_supply_property psp,
-       union power_supply_propval *val)
-{
-       int ret = 0;
-       struct bq20z75_info *bq20z75_device = container_of(psy,
-                               struct bq20z75_info, power_supply);
-       struct i2c_client *client = bq20z75_device->client;
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_PRESENT:
-       case POWER_SUPPLY_PROP_HEALTH:
-               ret = bq20z75_get_battery_presence_and_health(client, psp, val);
-               if (psp == POWER_SUPPLY_PROP_PRESENT)
-                       return 0;
-               break;
-
-       case POWER_SUPPLY_PROP_TECHNOLOGY:
-               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
-               break;
-
-       case POWER_SUPPLY_PROP_ENERGY_NOW:
-       case POWER_SUPPLY_PROP_ENERGY_FULL:
-       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-       case POWER_SUPPLY_PROP_CHARGE_NOW:
-       case POWER_SUPPLY_PROP_CHARGE_FULL:
-       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-       case POWER_SUPPLY_PROP_CAPACITY:
-               ret = bq20z75_get_property_index(client, psp);
-               if (ret < 0)
-                       break;
-
-               ret = bq20z75_get_battery_capacity(client, ret, psp, val);
-               break;
-
-       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
-               ret = bq20z75_get_battery_serial_number(client, val);
-               break;
-
-       case POWER_SUPPLY_PROP_STATUS:
-       case POWER_SUPPLY_PROP_CYCLE_COUNT:
-       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-       case POWER_SUPPLY_PROP_CURRENT_NOW:
-       case POWER_SUPPLY_PROP_TEMP:
-       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
-       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
-       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-               ret = bq20z75_get_property_index(client, psp);
-               if (ret < 0)
-                       break;
-
-               ret = bq20z75_get_battery_property(client, ret, psp, val);
-               break;
-
-       default:
-               dev_err(&client->dev,
-                       "%s: INVALID property\n", __func__);
-               return -EINVAL;
-       }
-
-       if (!bq20z75_device->enable_detection)
-               goto done;
-
-       if (!bq20z75_device->gpio_detect &&
-               bq20z75_device->is_present != (ret >= 0)) {
-               bq20z75_device->is_present = (ret >= 0);
-               power_supply_changed(&bq20z75_device->power_supply);
-       }
-
-done:
-       if (!ret) {
-               /* Convert units to match requirements for power supply class */
-               bq20z75_unit_adjustment(client, psp, val);
-       }
-
-       dev_dbg(&client->dev,
-               "%s: property = %d, value = %x\n", __func__, psp, val->intval);
-
-       if (ret && bq20z75_device->is_present)
-               return ret;
-
-       /* battery not present, so return NODATA for properties */
-       if (ret)
-               return -ENODATA;
-
-       return 0;
-}
-
-static irqreturn_t bq20z75_irq(int irq, void *devid)
-{
-       struct power_supply *battery = devid;
-
-       power_supply_changed(battery);
-
-       return IRQ_HANDLED;
-}
-
-static void bq20z75_external_power_changed(struct power_supply *psy)
-{
-       struct bq20z75_info *bq20z75_device;
-
-       bq20z75_device = container_of(psy, struct bq20z75_info, power_supply);
-
-       if (bq20z75_device->ignore_changes > 0) {
-               bq20z75_device->ignore_changes--;
-               return;
-       }
-
-       /* cancel outstanding work */
-       cancel_delayed_work_sync(&bq20z75_device->work);
-
-       schedule_delayed_work(&bq20z75_device->work, HZ);
-       bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count;
-}
-
-static void bq20z75_delayed_work(struct work_struct *work)
-{
-       struct bq20z75_info *bq20z75_device;
-       s32 ret;
-
-       bq20z75_device = container_of(work, struct bq20z75_info, work.work);
-
-       ret = bq20z75_read_word_data(bq20z75_device->client,
-                                    bq20z75_data[REG_STATUS].addr);
-       /* if the read failed, give up on this work */
-       if (ret < 0) {
-               bq20z75_device->poll_time = 0;
-               return;
-       }
-
-       if (ret & BATTERY_FULL_CHARGED)
-               ret = POWER_SUPPLY_STATUS_FULL;
-       else if (ret & BATTERY_FULL_DISCHARGED)
-               ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
-       else if (ret & BATTERY_DISCHARGING)
-               ret = POWER_SUPPLY_STATUS_DISCHARGING;
-       else
-               ret = POWER_SUPPLY_STATUS_CHARGING;
-
-       if (bq20z75_device->last_state != ret) {
-               bq20z75_device->poll_time = 0;
-               power_supply_changed(&bq20z75_device->power_supply);
-               return;
-       }
-       if (bq20z75_device->poll_time > 0) {
-               schedule_delayed_work(&bq20z75_device->work, HZ);
-               bq20z75_device->poll_time--;
-               return;
-       }
-}
-
-static int __devinit bq20z75_probe(struct i2c_client *client,
-       const struct i2c_device_id *id)
-{
-       struct bq20z75_info *bq20z75_device;
-       struct bq20z75_platform_data *pdata = client->dev.platform_data;
-       int rc;
-       int irq;
-
-       bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL);
-       if (!bq20z75_device)
-               return -ENOMEM;
-
-       bq20z75_device->client = client;
-       bq20z75_device->enable_detection = false;
-       bq20z75_device->gpio_detect = false;
-       bq20z75_device->power_supply.name = "battery";
-       bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
-       bq20z75_device->power_supply.properties = bq20z75_properties;
-       bq20z75_device->power_supply.num_properties =
-               ARRAY_SIZE(bq20z75_properties);
-       bq20z75_device->power_supply.get_property = bq20z75_get_property;
-       /* ignore first notification of external change, it is generated
-        * from the power_supply_register call back
-        */
-       bq20z75_device->ignore_changes = 1;
-       bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
-       bq20z75_device->power_supply.external_power_changed =
-               bq20z75_external_power_changed;
-
-       if (pdata) {
-               bq20z75_device->gpio_detect =
-                       gpio_is_valid(pdata->battery_detect);
-               bq20z75_device->pdata = pdata;
-       }
-
-       i2c_set_clientdata(client, bq20z75_device);
-
-       if (!bq20z75_device->gpio_detect)
-               goto skip_gpio;
-
-       rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
-       if (rc) {
-               dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
-               bq20z75_device->gpio_detect = false;
-               goto skip_gpio;
-       }
-
-       rc = gpio_direction_input(pdata->battery_detect);
-       if (rc) {
-               dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
-               gpio_free(pdata->battery_detect);
-               bq20z75_device->gpio_detect = false;
-               goto skip_gpio;
-       }
-
-       irq = gpio_to_irq(pdata->battery_detect);
-       if (irq <= 0) {
-               dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
-               gpio_free(pdata->battery_detect);
-               bq20z75_device->gpio_detect = false;
-               goto skip_gpio;
-       }
-
-       rc = request_irq(irq, bq20z75_irq,
-               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-               dev_name(&client->dev), &bq20z75_device->power_supply);
-       if (rc) {
-               dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
-               gpio_free(pdata->battery_detect);
-               bq20z75_device->gpio_detect = false;
-               goto skip_gpio;
-       }
-
-       bq20z75_device->irq = irq;
-
-skip_gpio:
-
-       rc = power_supply_register(&client->dev, &bq20z75_device->power_supply);
-       if (rc) {
-               dev_err(&client->dev,
-                       "%s: Failed to register power supply\n", __func__);
-               goto exit_psupply;
-       }
-
-       dev_info(&client->dev,
-               "%s: battery gas gauge device registered\n", client->name);
-
-       INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work);
-
-       bq20z75_device->enable_detection = true;
-
-       return 0;
-
-exit_psupply:
-       if (bq20z75_device->irq)
-               free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
-       if (bq20z75_device->gpio_detect)
-               gpio_free(pdata->battery_detect);
-
-       kfree(bq20z75_device);
-
-       return rc;
-}
-
-static int __devexit bq20z75_remove(struct i2c_client *client)
-{
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-
-       if (bq20z75_device->irq)
-               free_irq(bq20z75_device->irq, &bq20z75_device->power_supply);
-       if (bq20z75_device->gpio_detect)
-               gpio_free(bq20z75_device->pdata->battery_detect);
-
-       power_supply_unregister(&bq20z75_device->power_supply);
-
-       cancel_delayed_work_sync(&bq20z75_device->work);
-
-       kfree(bq20z75_device);
-       bq20z75_device = NULL;
-
-       return 0;
-}
-
-#if defined CONFIG_PM
-static int bq20z75_suspend(struct i2c_client *client,
-       pm_message_t state)
-{
-       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
-       s32 ret;
-
-       if (bq20z75_device->poll_time > 0)
-               cancel_delayed_work_sync(&bq20z75_device->work);
-
-       /* write to manufacturer access with sleep command */
-       ret = bq20z75_write_word_data(client,
-               bq20z75_data[REG_MANUFACTURER_DATA].addr,
-               MANUFACTURER_ACCESS_SLEEP);
-       if (bq20z75_device->is_present && ret < 0)
-               return ret;
-
-       return 0;
-}
-#else
-#define bq20z75_suspend                NULL
-#endif
-/* any smbus transaction will wake up bq20z75 */
-#define bq20z75_resume         NULL
-
-static const struct i2c_device_id bq20z75_id[] = {
-       { "bq20z75", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, bq20z75_id);
-
-static struct i2c_driver bq20z75_battery_driver = {
-       .probe          = bq20z75_probe,
-       .remove         = __devexit_p(bq20z75_remove),
-       .suspend        = bq20z75_suspend,
-       .resume         = bq20z75_resume,
-       .id_table       = bq20z75_id,
-       .driver = {
-               .name   = "bq20z75-battery",
-       },
-};
-
-static int __init bq20z75_battery_init(void)
-{
-       return i2c_add_driver(&bq20z75_battery_driver);
-}
-module_init(bq20z75_battery_init);
-
-static void __exit bq20z75_battery_exit(void)
-{
-       i2c_del_driver(&bq20z75_battery_driver);
-}
-module_exit(bq20z75_battery_exit);
-
-MODULE_DESCRIPTION("BQ20z75 battery monitor driver");
-MODULE_LICENSE("GPL");
index bb16f5b7e167490519d2793cbaa1546192e447f5..98bf5676318d4b7664870558b8f26eb35222fbe8 100644 (file)
 
 #define BQ27000_REG_RSOC               0x0B /* Relative State-of-Charge */
 #define BQ27000_REG_ILMD               0x76 /* Initial last measured discharge */
-#define BQ27000_FLAG_CHGS              BIT(7)
+#define BQ27000_FLAG_EDVF              BIT(0) /* Final End-of-Discharge-Voltage flag */
+#define BQ27000_FLAG_EDV1              BIT(1) /* First End-of-Discharge-Voltage flag */
+#define BQ27000_FLAG_CI                        BIT(4) /* Capacity Inaccurate flag */
 #define BQ27000_FLAG_FC                        BIT(5)
+#define BQ27000_FLAG_CHGS              BIT(7) /* Charge state flag */
 
 #define BQ27500_REG_SOC                        0x2C
 #define BQ27500_REG_DCAP               0x3C /* Design capacity */
-#define BQ27500_FLAG_DSC               BIT(0)
-#define BQ27500_FLAG_FC                        BIT(9)
+#define BQ27500_FLAG_DSG               BIT(0) /* Discharging */
+#define BQ27500_FLAG_SOCF              BIT(1) /* State-of-Charge threshold final */
+#define BQ27500_FLAG_SOC1              BIT(2) /* State-of-Charge threshold 1 */
+#define BQ27500_FLAG_CHG               BIT(8) /* Charging */
+#define BQ27500_FLAG_FC                        BIT(9) /* Fully charged */
 
 #define BQ27000_RS                     20 /* Resistor sense */
 
@@ -79,9 +85,8 @@ struct bq27x00_reg_cache {
        int charge_full;
        int cycle_count;
        int capacity;
+       int energy;
        int flags;
-
-       int current_now;
 };
 
 struct bq27x00_device_info {
@@ -108,6 +113,7 @@ static enum power_supply_property bq27x00_battery_props[] = {
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_CURRENT_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TEMP,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
@@ -149,7 +155,7 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di)
                rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
 
        if (rsoc < 0)
-               dev_err(di->dev, "error reading relative State-of-Charge\n");
+               dev_dbg(di->dev, "error reading relative State-of-Charge\n");
 
        return rsoc;
 }
@@ -164,7 +170,8 @@ static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg)
 
        charge = bq27x00_read(di, reg, false);
        if (charge < 0) {
-               dev_err(di->dev, "error reading nominal available capacity\n");
+               dev_dbg(di->dev, "error reading charge register %02x: %d\n",
+                       reg, charge);
                return charge;
        }
 
@@ -208,7 +215,7 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
                ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
 
        if (ilmd < 0) {
-               dev_err(di->dev, "error reading initial last measured discharge\n");
+               dev_dbg(di->dev, "error reading initial last measured discharge\n");
                return ilmd;
        }
 
@@ -220,6 +227,50 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
        return ilmd;
 }
 
+/*
+ * Return the battery Available energy in ÂµWh
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_read_energy(struct bq27x00_device_info *di)
+{
+       int ae;
+
+       ae = bq27x00_read(di, BQ27x00_REG_AE, false);
+       if (ae < 0) {
+               dev_dbg(di->dev, "error reading available energy\n");
+               return ae;
+       }
+
+       if (di->chip == BQ27500)
+               ae *= 1000;
+       else
+               ae = ae * 29200 / BQ27000_RS;
+
+       return ae;
+}
+
+/*
+ * Return the battery temperature in tenths of degree Celsius
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_read_temperature(struct bq27x00_device_info *di)
+{
+       int temp;
+
+       temp = bq27x00_read(di, BQ27x00_REG_TEMP, false);
+       if (temp < 0) {
+               dev_err(di->dev, "error reading temperature\n");
+               return temp;
+       }
+
+       if (di->chip == BQ27500)
+               temp -= 2731;
+       else
+               temp = ((temp * 5) - 5463) / 2;
+
+       return temp;
+}
+
 /*
  * Return the battery Cycle count total
  * Or < 0 if something fails.
@@ -245,7 +296,8 @@ static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg)
 
        tval = bq27x00_read(di, reg, false);
        if (tval < 0) {
-               dev_err(di->dev, "error reading register %02x: %d\n", reg, tval);
+               dev_dbg(di->dev, "error reading time register %02x: %d\n",
+                       reg, tval);
                return tval;
        }
 
@@ -262,25 +314,31 @@ static void bq27x00_update(struct bq27x00_device_info *di)
 
        cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500);
        if (cache.flags >= 0) {
-               cache.capacity = bq27x00_battery_read_rsoc(di);
-               cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false);
-               cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
-               cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
-               cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
-               cache.charge_full = bq27x00_battery_read_lmd(di);
+               if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) {
+                       dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
+                       cache.capacity = -ENODATA;
+                       cache.energy = -ENODATA;
+                       cache.time_to_empty = -ENODATA;
+                       cache.time_to_empty_avg = -ENODATA;
+                       cache.time_to_full = -ENODATA;
+                       cache.charge_full = -ENODATA;
+               } else {
+                       cache.capacity = bq27x00_battery_read_rsoc(di);
+                       cache.energy = bq27x00_battery_read_energy(di);
+                       cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE);
+                       cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
+                       cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
+                       cache.charge_full = bq27x00_battery_read_lmd(di);
+               }
+               cache.temperature = bq27x00_battery_read_temperature(di);
                cache.cycle_count = bq27x00_battery_read_cyct(di);
 
-               if (!is_bq27500)
-                       cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
-
                /* We only have to read charge design full once */
                if (di->charge_design_full <= 0)
                        di->charge_design_full = bq27x00_battery_read_ilmd(di);
        }
 
-       /* Ignore current_now which is a snapshot of the current battery state
-        * and is likely to be different even between two consecutive reads */
-       if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) {
+       if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
                di->cache = cache;
                power_supply_changed(&di->bat);
        }
@@ -302,25 +360,6 @@ static void bq27x00_battery_poll(struct work_struct *work)
        }
 }
 
-
-/*
- * Return the battery temperature in tenths of degree Celsius
- * Or < 0 if something fails.
- */
-static int bq27x00_battery_temperature(struct bq27x00_device_info *di,
-       union power_supply_propval *val)
-{
-       if (di->cache.temperature < 0)
-               return di->cache.temperature;
-
-       if (di->chip == BQ27500)
-               val->intval = di->cache.temperature - 2731;
-       else
-               val->intval = ((di->cache.temperature * 5) - 5463) / 2;
-
-       return 0;
-}
-
 /*
  * Return the battery average current in ÂµA
  * Note that current can be negative signed as well
@@ -330,20 +369,20 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di,
        union power_supply_propval *val)
 {
        int curr;
+       int flags;
 
-       if (di->chip == BQ27500)
-           curr = bq27x00_read(di, BQ27x00_REG_AI, false);
-       else
-           curr = di->cache.current_now;
-
-       if (curr < 0)
+       curr = bq27x00_read(di, BQ27x00_REG_AI, false);
+       if (curr < 0) {
+               dev_err(di->dev, "error reading current\n");
                return curr;
+       }
 
        if (di->chip == BQ27500) {
                /* bq27500 returns signed value */
                val->intval = (int)((s16)curr) * 1000;
        } else {
-               if (di->cache.flags & BQ27000_FLAG_CHGS) {
+               flags = bq27x00_read(di, BQ27x00_REG_FLAGS, false);
+               if (flags & BQ27000_FLAG_CHGS) {
                        dev_dbg(di->dev, "negative current!\n");
                        curr = -curr;
                }
@@ -362,10 +401,14 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
        if (di->chip == BQ27500) {
                if (di->cache.flags & BQ27500_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
-               else if (di->cache.flags & BQ27500_FLAG_DSC)
+               else if (di->cache.flags & BQ27500_FLAG_DSG)
                        status = POWER_SUPPLY_STATUS_DISCHARGING;
-               else
+               else if (di->cache.flags & BQ27500_FLAG_CHG)
                        status = POWER_SUPPLY_STATUS_CHARGING;
+               else if (power_supply_am_i_supplied(&di->bat))
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else
+                       status = POWER_SUPPLY_STATUS_UNKNOWN;
        } else {
                if (di->cache.flags & BQ27000_FLAG_FC)
                        status = POWER_SUPPLY_STATUS_FULL;
@@ -382,50 +425,56 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di,
        return 0;
 }
 
-/*
- * Return the battery Voltage in milivolts
- * Or < 0 if something fails.
- */
-static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
+static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
        union power_supply_propval *val)
 {
-       int volt;
+       int level;
 
-       volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
-       if (volt < 0)
-               return volt;
+       if (di->chip == BQ27500) {
+               if (di->cache.flags & BQ27500_FLAG_FC)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+               else if (di->cache.flags & BQ27500_FLAG_SOC1)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+               else if (di->cache.flags & BQ27500_FLAG_SOCF)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+               else
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+       } else {
+               if (di->cache.flags & BQ27000_FLAG_FC)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+               else if (di->cache.flags & BQ27000_FLAG_EDV1)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+               else if (di->cache.flags & BQ27000_FLAG_EDVF)
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+               else
+                       level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+       }
 
-       val->intval = volt * 1000;
+       val->intval = level;
 
        return 0;
 }
 
 /*
- * Return the battery Available energy in ÂµWh
+ * Return the battery Voltage in milivolts
  * Or < 0 if something fails.
  */
-static int bq27x00_battery_energy(struct bq27x00_device_info *di,
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
        union power_supply_propval *val)
 {
-       int ae;
+       int volt;
 
-       ae = bq27x00_read(di, BQ27x00_REG_AE, false);
-       if (ae < 0) {
-               dev_err(di->dev, "error reading available energy\n");
-               return ae;
+       volt = bq27x00_read(di, BQ27x00_REG_VOLT, false);
+       if (volt < 0) {
+               dev_err(di->dev, "error reading voltage\n");
+               return volt;
        }
 
-       if (di->chip == BQ27500)
-               ae *= 1000;
-       else
-               ae = ae * 29200 / BQ27000_RS;
-
-       val->intval = ae;
+       val->intval = volt * 1000;
 
        return 0;
 }
 
-
 static int bq27x00_simple_value(int value,
        union power_supply_propval *val)
 {
@@ -473,8 +522,11 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_CAPACITY:
                ret = bq27x00_simple_value(di->cache.capacity, val);
                break;
+       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+               ret = bq27x00_battery_capacity_level(di, val);
+               break;
        case POWER_SUPPLY_PROP_TEMP:
-               ret = bq27x00_battery_temperature(di, val);
+               ret = bq27x00_simple_value(di->cache.temperature, val);
                break;
        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
                ret = bq27x00_simple_value(di->cache.time_to_empty, val);
@@ -501,7 +553,7 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
                ret = bq27x00_simple_value(di->cache.cycle_count, val);
                break;
        case POWER_SUPPLY_PROP_ENERGY_NOW:
-               ret = bq27x00_battery_energy(di, val);
+               ret = bq27x00_simple_value(di->cache.energy, val);
                break;
        default:
                return -EINVAL;
@@ -546,6 +598,14 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
 
 static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
 {
+       /*
+        * power_supply_unregister call bq27x00_battery_get_property which
+        * call bq27x00_battery_poll.
+        * Make sure that bq27x00_battery_poll will not call
+        * schedule_delayed_work again after unregister (which cause OOPS).
+        */
+       poll_interval = 0;
+
        cancel_delayed_work_sync(&di->work);
 
        power_supply_unregister(&di->bat);
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
new file mode 100644 (file)
index 0000000..0378d01
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This driver enables to monitor battery health and control charger
+ * during suspend-to-mem.
+ * Charger manager depends on other devices. register this later than
+ * the depending devices.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+**/
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/power/charger-manager.h>
+#include <linux/regulator/consumer.h>
+
+/*
+ * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for
+ * delayed works so that we can run delayed works with CM_JIFFIES_SMALL
+ * without any delays.
+ */
+#define        CM_JIFFIES_SMALL        (2)
+
+/* If y is valid (> 0) and smaller than x, do x = y */
+#define CM_MIN_VALID(x, y)     x = (((y > 0) && ((x) > (y))) ? (y) : (x))
+
+/*
+ * Regard CM_RTC_SMALL (sec) is small enough to ignore error in invoking
+ * rtc alarm. It should be 2 or larger
+ */
+#define CM_RTC_SMALL           (2)
+
+#define UEVENT_BUF_SIZE                32
+
+static LIST_HEAD(cm_list);
+static DEFINE_MUTEX(cm_list_mtx);
+
+/* About in-suspend (suspend-again) monitoring */
+static struct rtc_device *rtc_dev;
+/*
+ * Backup RTC alarm
+ * Save the wakeup alarm before entering suspend-to-RAM
+ */
+static struct rtc_wkalrm rtc_wkalarm_save;
+/* Backup RTC alarm time in terms of seconds since 01-01-1970 00:00:00 */
+static unsigned long rtc_wkalarm_save_time;
+static bool cm_suspended;
+static bool cm_rtc_set;
+static unsigned long cm_suspend_duration_ms;
+
+/* Global charger-manager description */
+static struct charger_global_desc *g_desc; /* init with setup_charger_manager */
+
+/**
+ * is_batt_present - See if the battery presents in place.
+ * @cm: the Charger Manager representing the battery.
+ */
+static bool is_batt_present(struct charger_manager *cm)
+{
+       union power_supply_propval val;
+       bool present = false;
+       int i, ret;
+
+       switch (cm->desc->battery_present) {
+       case CM_FUEL_GAUGE:
+               ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                               POWER_SUPPLY_PROP_PRESENT, &val);
+               if (ret == 0 && val.intval)
+                       present = true;
+               break;
+       case CM_CHARGER_STAT:
+               for (i = 0; cm->charger_stat[i]; i++) {
+                       ret = cm->charger_stat[i]->get_property(
+                                       cm->charger_stat[i],
+                                       POWER_SUPPLY_PROP_PRESENT, &val);
+                       if (ret == 0 && val.intval) {
+                               present = true;
+                               break;
+                       }
+               }
+               break;
+       }
+
+       return present;
+}
+
+/**
+ * is_ext_pwr_online - See if an external power source is attached to charge
+ * @cm: the Charger Manager representing the battery.
+ *
+ * Returns true if at least one of the chargers of the battery has an external
+ * power source attached to charge the battery regardless of whether it is
+ * actually charging or not.
+ */
+static bool is_ext_pwr_online(struct charger_manager *cm)
+{
+       union power_supply_propval val;
+       bool online = false;
+       int i, ret;
+
+       /* If at least one of them has one, it's yes. */
+       for (i = 0; cm->charger_stat[i]; i++) {
+               ret = cm->charger_stat[i]->get_property(
+                               cm->charger_stat[i],
+                               POWER_SUPPLY_PROP_ONLINE, &val);
+               if (ret == 0 && val.intval) {
+                       online = true;
+                       break;
+               }
+       }
+
+       return online;
+}
+
+/**
+ * get_batt_uV - Get the voltage level of the battery
+ * @cm: the Charger Manager representing the battery.
+ * @uV: the voltage level returned.
+ *
+ * Returns 0 if there is no error.
+ * Returns a negative value on error.
+ */
+static int get_batt_uV(struct charger_manager *cm, int *uV)
+{
+       union power_supply_propval val;
+       int ret;
+
+       if (cm->fuel_gauge)
+               ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                               POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
+       else
+               return -ENODEV;
+
+       if (ret)
+               return ret;
+
+       *uV = val.intval;
+       return 0;
+}
+
+/**
+ * is_charging - Returns true if the battery is being charged.
+ * @cm: the Charger Manager representing the battery.
+ */
+static bool is_charging(struct charger_manager *cm)
+{
+       int i, ret;
+       bool charging = false;
+       union power_supply_propval val;
+
+       /* If there is no battery, it cannot be charged */
+       if (!is_batt_present(cm))
+               return false;
+
+       /* If at least one of the charger is charging, return yes */
+       for (i = 0; cm->charger_stat[i]; i++) {
+               /* 1. The charger sholuld not be DISABLED */
+               if (cm->emergency_stop)
+                       continue;
+               if (!cm->charger_enabled)
+                       continue;
+
+               /* 2. The charger should be online (ext-power) */
+               ret = cm->charger_stat[i]->get_property(
+                               cm->charger_stat[i],
+                               POWER_SUPPLY_PROP_ONLINE, &val);
+               if (ret) {
+                       dev_warn(cm->dev, "Cannot read ONLINE value from %s.\n",
+                                       cm->desc->psy_charger_stat[i]);
+                       continue;
+               }
+               if (val.intval == 0)
+                       continue;
+
+               /*
+                * 3. The charger should not be FULL, DISCHARGING,
+                * or NOT_CHARGING.
+                */
+               ret = cm->charger_stat[i]->get_property(
+                               cm->charger_stat[i],
+                               POWER_SUPPLY_PROP_STATUS, &val);
+               if (ret) {
+                       dev_warn(cm->dev, "Cannot read STATUS value from %s.\n",
+                                       cm->desc->psy_charger_stat[i]);
+                       continue;
+               }
+               if (val.intval == POWER_SUPPLY_STATUS_FULL ||
+                               val.intval == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               val.intval == POWER_SUPPLY_STATUS_NOT_CHARGING)
+                       continue;
+
+               /* Then, this is charging. */
+               charging = true;
+               break;
+       }
+
+       return charging;
+}
+
+/**
+ * is_polling_required - Return true if need to continue polling for this CM.
+ * @cm: the Charger Manager representing the battery.
+ */
+static bool is_polling_required(struct charger_manager *cm)
+{
+       switch (cm->desc->polling_mode) {
+       case CM_POLL_DISABLE:
+               return false;
+       case CM_POLL_ALWAYS:
+               return true;
+       case CM_POLL_EXTERNAL_POWER_ONLY:
+               return is_ext_pwr_online(cm);
+       case CM_POLL_CHARGING_ONLY:
+               return is_charging(cm);
+       default:
+               dev_warn(cm->dev, "Incorrect polling_mode (%d)\n",
+                       cm->desc->polling_mode);
+       }
+
+       return false;
+}
+
+/**
+ * try_charger_enable - Enable/Disable chargers altogether
+ * @cm: the Charger Manager representing the battery.
+ * @enable: true: enable / false: disable
+ *
+ * Note that Charger Manager keeps the charger enabled regardless whether
+ * the charger is charging or not (because battery is full or no external
+ * power source exists) except when CM needs to disable chargers forcibly
+ * bacause of emergency causes; when the battery is overheated or too cold.
+ */
+static int try_charger_enable(struct charger_manager *cm, bool enable)
+{
+       int err = 0, i;
+       struct charger_desc *desc = cm->desc;
+
+       /* Ignore if it's redundent command */
+       if (enable && cm->charger_enabled)
+               return 0;
+       if (!enable && !cm->charger_enabled)
+               return 0;
+
+       if (enable) {
+               if (cm->emergency_stop)
+                       return -EAGAIN;
+               err = regulator_bulk_enable(desc->num_charger_regulators,
+                                       desc->charger_regulators);
+       } else {
+               /*
+                * Abnormal battery state - Stop charging forcibly,
+                * even if charger was enabled at the other places
+                */
+               err = regulator_bulk_disable(desc->num_charger_regulators,
+                                       desc->charger_regulators);
+
+               for (i = 0; i < desc->num_charger_regulators; i++) {
+                       if (regulator_is_enabled(
+                                   desc->charger_regulators[i].consumer)) {
+                               regulator_force_disable(
+                                       desc->charger_regulators[i].consumer);
+                               dev_warn(cm->dev,
+                                       "Disable regulator(%s) forcibly.\n",
+                                       desc->charger_regulators[i].supply);
+                       }
+               }
+       }
+
+       if (!err)
+               cm->charger_enabled = enable;
+
+       return err;
+}
+
+/**
+ * uevent_notify - Let users know something has changed.
+ * @cm: the Charger Manager representing the battery.
+ * @event: the event string.
+ *
+ * If @event is null, it implies that uevent_notify is called
+ * by resume function. When called in the resume function, cm_suspended
+ * should be already reset to false in order to let uevent_notify
+ * notify the recent event during the suspend to users. While
+ * suspended, uevent_notify does not notify users, but tracks
+ * events so that uevent_notify can notify users later after resumed.
+ */
+static void uevent_notify(struct charger_manager *cm, const char *event)
+{
+       static char env_str[UEVENT_BUF_SIZE + 1] = "";
+       static char env_str_save[UEVENT_BUF_SIZE + 1] = "";
+
+       if (cm_suspended) {
+               /* Nothing in suspended-event buffer */
+               if (env_str_save[0] == 0) {
+                       if (!strncmp(env_str, event, UEVENT_BUF_SIZE))
+                               return; /* status not changed */
+                       strncpy(env_str_save, event, UEVENT_BUF_SIZE);
+                       return;
+               }
+
+               if (!strncmp(env_str_save, event, UEVENT_BUF_SIZE))
+                       return; /* Duplicated. */
+               else
+                       strncpy(env_str_save, event, UEVENT_BUF_SIZE);
+
+               return;
+       }
+
+       if (event == NULL) {
+               /* No messages pending */
+               if (!env_str_save[0])
+                       return;
+
+               strncpy(env_str, env_str_save, UEVENT_BUF_SIZE);
+               kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE);
+               env_str_save[0] = 0;
+
+               return;
+       }
+
+       /* status not changed */
+       if (!strncmp(env_str, event, UEVENT_BUF_SIZE))
+               return;
+
+       /* save the status and notify the update */
+       strncpy(env_str, event, UEVENT_BUF_SIZE);
+       kobject_uevent(&cm->dev->kobj, KOBJ_CHANGE);
+
+       dev_info(cm->dev, event);
+}
+
+/**
+ * _cm_monitor - Monitor the temperature and return true for exceptions.
+ * @cm: the Charger Manager representing the battery.
+ *
+ * Returns true if there is an event to notify for the battery.
+ * (True if the status of "emergency_stop" changes)
+ */
+static bool _cm_monitor(struct charger_manager *cm)
+{
+       struct charger_desc *desc = cm->desc;
+       int temp = desc->temperature_out_of_range(&cm->last_temp_mC);
+
+       dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n",
+               cm->last_temp_mC / 1000, cm->last_temp_mC % 1000);
+
+       /* It has been stopped or charging already */
+       if (!!temp == !!cm->emergency_stop)
+               return false;
+
+       if (temp) {
+               cm->emergency_stop = temp;
+               if (!try_charger_enable(cm, false)) {
+                       if (temp > 0)
+                               uevent_notify(cm, "OVERHEAT");
+                       else
+                               uevent_notify(cm, "COLD");
+               }
+       } else {
+               cm->emergency_stop = 0;
+               if (!try_charger_enable(cm, true))
+                       uevent_notify(cm, "CHARGING");
+       }
+
+       return true;
+}
+
+/**
+ * cm_monitor - Monitor every battery.
+ *
+ * Returns true if there is an event to notify from any of the batteries.
+ * (True if the status of "emergency_stop" changes)
+ */
+static bool cm_monitor(void)
+{
+       bool stop = false;
+       struct charger_manager *cm;
+
+       mutex_lock(&cm_list_mtx);
+
+       list_for_each_entry(cm, &cm_list, entry)
+               stop = stop || _cm_monitor(cm);
+
+       mutex_unlock(&cm_list_mtx);
+
+       return stop;
+}
+
+static int charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct charger_manager *cm = container_of(psy,
+                       struct charger_manager, charger_psy);
+       struct charger_desc *desc = cm->desc;
+       int i, ret = 0, uV;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               if (is_charging(cm))
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               else if (is_ext_pwr_online(cm))
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               if (cm->emergency_stop > 0)
+                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+               else if (cm->emergency_stop < 0)
+                       val->intval = POWER_SUPPLY_HEALTH_COLD;
+               else
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               if (is_batt_present(cm))
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               ret = get_batt_uV(cm, &i);
+               val->intval = i;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                               POWER_SUPPLY_PROP_CURRENT_NOW, val);
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               /* in thenth of centigrade */
+               if (cm->last_temp_mC == INT_MIN)
+                       desc->temperature_out_of_range(&cm->last_temp_mC);
+               val->intval = cm->last_temp_mC / 100;
+               if (!desc->measure_battery_temp)
+                       ret = -ENODEV;
+               break;
+       case POWER_SUPPLY_PROP_TEMP_AMBIENT:
+               /* in thenth of centigrade */
+               if (cm->last_temp_mC == INT_MIN)
+                       desc->temperature_out_of_range(&cm->last_temp_mC);
+               val->intval = cm->last_temp_mC / 100;
+               if (desc->measure_battery_temp)
+                       ret = -ENODEV;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               if (!cm->fuel_gauge) {
+                       ret = -ENODEV;
+                       break;
+               }
+
+               if (!is_batt_present(cm)) {
+                       /* There is no battery. Assume 100% */
+                       val->intval = 100;
+                       break;
+               }
+
+               ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                                       POWER_SUPPLY_PROP_CAPACITY, val);
+               if (ret)
+                       break;
+
+               if (val->intval > 100) {
+                       val->intval = 100;
+                       break;
+               }
+               if (val->intval < 0)
+                       val->intval = 0;
+
+               /* Do not adjust SOC when charging: voltage is overrated */
+               if (is_charging(cm))
+                       break;
+
+               /*
+                * If the capacity value is inconsistent, calibrate it base on
+                * the battery voltage values and the thresholds given as desc
+                */
+               ret = get_batt_uV(cm, &uV);
+               if (ret) {
+                       /* Voltage information not available. No calibration */
+                       ret = 0;
+                       break;
+               }
+
+               if (desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV &&
+                   !is_charging(cm)) {
+                       val->intval = 100;
+                       break;
+               }
+
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               if (is_ext_pwr_online(cm))
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               if (cm->fuel_gauge) {
+                       if (cm->fuel_gauge->get_property(cm->fuel_gauge,
+                           POWER_SUPPLY_PROP_CHARGE_FULL, val) == 0)
+                               break;
+               }
+
+               if (is_ext_pwr_online(cm)) {
+                       /* Not full if it's charging. */
+                       if (is_charging(cm)) {
+                               val->intval = 0;
+                               break;
+                       }
+                       /*
+                        * Full if it's powered but not charging andi
+                        * not forced stop by emergency
+                        */
+                       if (!cm->emergency_stop) {
+                               val->intval = 1;
+                               break;
+                       }
+               }
+
+               /* Full if it's over the fullbatt voltage */
+               ret = get_batt_uV(cm, &uV);
+               if (!ret && desc->fullbatt_uV > 0 && uV >= desc->fullbatt_uV &&
+                   !is_charging(cm)) {
+                       val->intval = 1;
+                       break;
+               }
+
+               /* Full if the cap is 100 */
+               if (cm->fuel_gauge) {
+                       ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                                       POWER_SUPPLY_PROP_CAPACITY, val);
+                       if (!ret && val->intval >= 100 && !is_charging(cm)) {
+                               val->intval = 1;
+                               break;
+                       }
+               }
+
+               val->intval = 0;
+               ret = 0;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               if (is_charging(cm)) {
+                       ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+                                               POWER_SUPPLY_PROP_CHARGE_NOW,
+                                               val);
+                       if (ret) {
+                               val->intval = 1;
+                               ret = 0;
+                       } else {
+                               /* If CHARGE_NOW is supplied, use it */
+                               val->intval = (val->intval > 0) ?
+                                               val->intval : 1;
+                       }
+               } else {
+                       val->intval = 0;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return ret;
+}
+
+#define NUM_CHARGER_PSY_OPTIONAL       (4)
+static enum power_supply_property default_charger_props[] = {
+       /* Guaranteed to provide */
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       /*
+        * Optional properties are:
+        * POWER_SUPPLY_PROP_CHARGE_NOW,
+        * POWER_SUPPLY_PROP_CURRENT_NOW,
+        * POWER_SUPPLY_PROP_TEMP, and
+        * POWER_SUPPLY_PROP_TEMP_AMBIENT,
+        */
+};
+
+static struct power_supply psy_default = {
+       .name = "battery",
+       .type = POWER_SUPPLY_TYPE_BATTERY,
+       .properties = default_charger_props,
+       .num_properties = ARRAY_SIZE(default_charger_props),
+       .get_property = charger_get_property,
+};
+
+/**
+ * cm_setup_timer - For in-suspend monitoring setup wakeup alarm
+ *                 for suspend_again.
+ *
+ * Returns true if the alarm is set for Charger Manager to use.
+ * Returns false if
+ *     cm_setup_timer fails to set an alarm,
+ *     cm_setup_timer does not need to set an alarm for Charger Manager,
+ *     or an alarm previously configured is to be used.
+ */
+static bool cm_setup_timer(void)
+{
+       struct charger_manager *cm;
+       unsigned int wakeup_ms = UINT_MAX;
+       bool ret = false;
+
+       mutex_lock(&cm_list_mtx);
+
+       list_for_each_entry(cm, &cm_list, entry) {
+               /* Skip if polling is not required for this CM */
+               if (!is_polling_required(cm) && !cm->emergency_stop)
+                       continue;
+               if (cm->desc->polling_interval_ms == 0)
+                       continue;
+               CM_MIN_VALID(wakeup_ms, cm->desc->polling_interval_ms);
+       }
+
+       mutex_unlock(&cm_list_mtx);
+
+       if (wakeup_ms < UINT_MAX && wakeup_ms > 0) {
+               pr_info("Charger Manager wakeup timer: %u ms.\n", wakeup_ms);
+               if (rtc_dev) {
+                       struct rtc_wkalrm tmp;
+                       unsigned long time, now;
+                       unsigned long add = DIV_ROUND_UP(wakeup_ms, 1000);
+
+                       /*
+                        * Set alarm with the polling interval (wakeup_ms)
+                        * except when rtc_wkalarm_save comes first.
+                        * However, the alarm time should be NOW +
+                        * CM_RTC_SMALL or later.
+                        */
+                       tmp.enabled = 1;
+                       rtc_read_time(rtc_dev, &tmp.time);
+                       rtc_tm_to_time(&tmp.time, &now);
+                       if (add < CM_RTC_SMALL)
+                               add = CM_RTC_SMALL;
+                       time = now + add;
+
+                       ret = true;
+
+                       if (rtc_wkalarm_save.enabled &&
+                           rtc_wkalarm_save_time &&
+                           rtc_wkalarm_save_time < time) {
+                               if (rtc_wkalarm_save_time < now + CM_RTC_SMALL)
+                                       time = now + CM_RTC_SMALL;
+                               else
+                                       time = rtc_wkalarm_save_time;
+
+                               /* The timer is not appointed by CM */
+                               ret = false;
+                       }
+
+                       pr_info("Waking up after %lu secs.\n",
+                                       time - now);
+
+                       rtc_time_to_tm(time, &tmp.time);
+                       rtc_set_alarm(rtc_dev, &tmp);
+                       cm_suspend_duration_ms += wakeup_ms;
+                       return ret;
+               }
+       }
+
+       if (rtc_dev)
+               rtc_set_alarm(rtc_dev, &rtc_wkalarm_save);
+       return false;
+}
+
+/**
+ * cm_suspend_again - Determine whether suspend again or not
+ *
+ * Returns true if the system should be suspended again
+ * Returns false if the system should be woken up
+ */
+bool cm_suspend_again(void)
+{
+       struct charger_manager *cm;
+       bool ret = false;
+
+       if (!g_desc || !g_desc->rtc_only_wakeup || !g_desc->rtc_only_wakeup() ||
+           !cm_rtc_set)
+               return false;
+
+       if (cm_monitor())
+               goto out;
+
+       ret = true;
+       mutex_lock(&cm_list_mtx);
+       list_for_each_entry(cm, &cm_list, entry) {
+               if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) ||
+                   cm->status_save_batt != is_batt_present(cm))
+                       ret = false;
+       }
+       mutex_unlock(&cm_list_mtx);
+
+       cm_rtc_set = cm_setup_timer();
+out:
+       /* It's about the time when the non-CM appointed timer goes off */
+       if (rtc_wkalarm_save.enabled) {
+               unsigned long now;
+               struct rtc_time tmp;
+
+               rtc_read_time(rtc_dev, &tmp);
+               rtc_tm_to_time(&tmp, &now);
+
+               if (rtc_wkalarm_save_time &&
+                   now + CM_RTC_SMALL >= rtc_wkalarm_save_time)
+                       return false;
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cm_suspend_again);
+
+/**
+ * setup_charger_manager - initialize charger_global_desc data
+ * @gd: pointer to instance of charger_global_desc
+ */
+int setup_charger_manager(struct charger_global_desc *gd)
+{
+       if (!gd)
+               return -EINVAL;
+
+       if (rtc_dev)
+               rtc_class_close(rtc_dev);
+       rtc_dev = NULL;
+       g_desc = NULL;
+
+       if (!gd->rtc_only_wakeup) {
+               pr_err("The callback rtc_only_wakeup is not given.\n");
+               return -EINVAL;
+       }
+
+       if (gd->rtc_name) {
+               rtc_dev = rtc_class_open(gd->rtc_name);
+               if (IS_ERR_OR_NULL(rtc_dev)) {
+                       rtc_dev = NULL;
+                       /* Retry at probe. RTC may be not registered yet */
+               }
+       } else {
+               pr_warn("No wakeup timer is given for charger manager."
+                       "In-suspend monitoring won't work.\n");
+       }
+
+       g_desc = gd;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(setup_charger_manager);
+
+static int charger_manager_probe(struct platform_device *pdev)
+{
+       struct charger_desc *desc = dev_get_platdata(&pdev->dev);
+       struct charger_manager *cm;
+       int ret = 0, i = 0;
+       union power_supply_propval val;
+
+       if (g_desc && !rtc_dev && g_desc->rtc_name) {
+               rtc_dev = rtc_class_open(g_desc->rtc_name);
+               if (IS_ERR_OR_NULL(rtc_dev)) {
+                       rtc_dev = NULL;
+                       dev_err(&pdev->dev, "Cannot get RTC %s.\n",
+                               g_desc->rtc_name);
+                       ret = -ENODEV;
+                       goto err_alloc;
+               }
+       }
+
+       if (!desc) {
+               dev_err(&pdev->dev, "No platform data (desc) found.\n");
+               ret = -ENODEV;
+               goto err_alloc;
+       }
+
+       cm = kzalloc(sizeof(struct charger_manager), GFP_KERNEL);
+       if (!cm) {
+               dev_err(&pdev->dev, "Cannot allocate memory.\n");
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       /* Basic Values. Unspecified are Null or 0 */
+       cm->dev = &pdev->dev;
+       cm->desc = kzalloc(sizeof(struct charger_desc), GFP_KERNEL);
+       if (!cm->desc) {
+               dev_err(&pdev->dev, "Cannot allocate memory.\n");
+               ret = -ENOMEM;
+               goto err_alloc_desc;
+       }
+       memcpy(cm->desc, desc, sizeof(struct charger_desc));
+       cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */
+
+       if (!desc->charger_regulators || desc->num_charger_regulators < 1) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "charger_regulators undefined.\n");
+               goto err_no_charger;
+       }
+
+       if (!desc->psy_charger_stat || !desc->psy_charger_stat[0]) {
+               dev_err(&pdev->dev, "No power supply defined.\n");
+               ret = -EINVAL;
+               goto err_no_charger_stat;
+       }
+
+       /* Counting index only */
+       while (desc->psy_charger_stat[i])
+               i++;
+
+       cm->charger_stat = kzalloc(sizeof(struct power_supply *) * (i + 1),
+                                  GFP_KERNEL);
+       if (!cm->charger_stat) {
+               ret = -ENOMEM;
+               goto err_no_charger_stat;
+       }
+
+       for (i = 0; desc->psy_charger_stat[i]; i++) {
+               cm->charger_stat[i] = power_supply_get_by_name(
+                                       desc->psy_charger_stat[i]);
+               if (!cm->charger_stat[i]) {
+                       dev_err(&pdev->dev, "Cannot find power supply "
+                                       "\"%s\"\n",
+                                       desc->psy_charger_stat[i]);
+                       ret = -ENODEV;
+                       goto err_chg_stat;
+               }
+       }
+
+       cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
+       if (!cm->fuel_gauge) {
+               dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
+                               desc->psy_fuel_gauge);
+               ret = -ENODEV;
+               goto err_chg_stat;
+       }
+
+       if (desc->polling_interval_ms == 0 ||
+           msecs_to_jiffies(desc->polling_interval_ms) <= CM_JIFFIES_SMALL) {
+               dev_err(&pdev->dev, "polling_interval_ms is too small\n");
+               ret = -EINVAL;
+               goto err_chg_stat;
+       }
+
+       if (!desc->temperature_out_of_range) {
+               dev_err(&pdev->dev, "there is no temperature_out_of_range\n");
+               ret = -EINVAL;
+               goto err_chg_stat;
+       }
+
+       platform_set_drvdata(pdev, cm);
+
+       memcpy(&cm->charger_psy, &psy_default,
+                               sizeof(psy_default));
+       if (!desc->psy_name) {
+               strncpy(cm->psy_name_buf, psy_default.name,
+                               PSY_NAME_MAX);
+       } else {
+               strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX);
+       }
+       cm->charger_psy.name = cm->psy_name_buf;
+
+       /* Allocate for psy properties because they may vary */
+       cm->charger_psy.properties = kzalloc(sizeof(enum power_supply_property)
+                               * (ARRAY_SIZE(default_charger_props) +
+                               NUM_CHARGER_PSY_OPTIONAL),
+                               GFP_KERNEL);
+       if (!cm->charger_psy.properties) {
+               dev_err(&pdev->dev, "Cannot allocate for psy properties.\n");
+               ret = -ENOMEM;
+               goto err_chg_stat;
+       }
+       memcpy(cm->charger_psy.properties, default_charger_props,
+               sizeof(enum power_supply_property) *
+               ARRAY_SIZE(default_charger_props));
+       cm->charger_psy.num_properties = psy_default.num_properties;
+
+       /* Find which optional psy-properties are available */
+       if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
+                                         POWER_SUPPLY_PROP_CHARGE_NOW, &val)) {
+               cm->charger_psy.properties[cm->charger_psy.num_properties] =
+                               POWER_SUPPLY_PROP_CHARGE_NOW;
+               cm->charger_psy.num_properties++;
+       }
+       if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
+                                         POWER_SUPPLY_PROP_CURRENT_NOW,
+                                         &val)) {
+               cm->charger_psy.properties[cm->charger_psy.num_properties] =
+                               POWER_SUPPLY_PROP_CURRENT_NOW;
+               cm->charger_psy.num_properties++;
+       }
+       if (!desc->measure_battery_temp) {
+               cm->charger_psy.properties[cm->charger_psy.num_properties] =
+                               POWER_SUPPLY_PROP_TEMP_AMBIENT;
+               cm->charger_psy.num_properties++;
+       }
+       if (desc->measure_battery_temp) {
+               cm->charger_psy.properties[cm->charger_psy.num_properties] =
+                               POWER_SUPPLY_PROP_TEMP;
+               cm->charger_psy.num_properties++;
+       }
+
+       ret = power_supply_register(NULL, &cm->charger_psy);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot register charger-manager with"
+                               " name \"%s\".\n", cm->charger_psy.name);
+               goto err_register;
+       }
+
+       ret = regulator_bulk_get(&pdev->dev, desc->num_charger_regulators,
+                                desc->charger_regulators);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot get charger regulators.\n");
+               goto err_bulk_get;
+       }
+
+       ret = try_charger_enable(cm, true);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot enable charger regulators\n");
+               goto err_chg_enable;
+       }
+
+       /* Add to the list */
+       mutex_lock(&cm_list_mtx);
+       list_add(&cm->entry, &cm_list);
+       mutex_unlock(&cm_list_mtx);
+
+       return 0;
+
+err_chg_enable:
+       if (desc->charger_regulators)
+               regulator_bulk_free(desc->num_charger_regulators,
+                                       desc->charger_regulators);
+err_bulk_get:
+       power_supply_unregister(&cm->charger_psy);
+err_register:
+       kfree(cm->charger_psy.properties);
+err_chg_stat:
+       kfree(cm->charger_stat);
+err_no_charger_stat:
+err_no_charger:
+       kfree(cm->desc);
+err_alloc_desc:
+       kfree(cm);
+err_alloc:
+       return ret;
+}
+
+static int __devexit charger_manager_remove(struct platform_device *pdev)
+{
+       struct charger_manager *cm = platform_get_drvdata(pdev);
+       struct charger_desc *desc = cm->desc;
+
+       /* Remove from the list */
+       mutex_lock(&cm_list_mtx);
+       list_del(&cm->entry);
+       mutex_unlock(&cm_list_mtx);
+
+       if (desc->charger_regulators)
+               regulator_bulk_free(desc->num_charger_regulators,
+                                       desc->charger_regulators);
+
+       power_supply_unregister(&cm->charger_psy);
+       kfree(cm->charger_psy.properties);
+       kfree(cm->charger_stat);
+       kfree(cm->desc);
+       kfree(cm);
+
+       return 0;
+}
+
+const struct platform_device_id charger_manager_id[] = {
+       { "charger-manager", 0 },
+       { },
+};
+
+static int cm_suspend_prepare(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct charger_manager *cm = platform_get_drvdata(pdev);
+
+       if (!cm_suspended) {
+               if (rtc_dev) {
+                       struct rtc_time tmp;
+                       unsigned long now;
+
+                       rtc_read_alarm(rtc_dev, &rtc_wkalarm_save);
+                       rtc_read_time(rtc_dev, &tmp);
+
+                       if (rtc_wkalarm_save.enabled) {
+                               rtc_tm_to_time(&rtc_wkalarm_save.time,
+                                              &rtc_wkalarm_save_time);
+                               rtc_tm_to_time(&tmp, &now);
+                               if (now > rtc_wkalarm_save_time)
+                                       rtc_wkalarm_save_time = 0;
+                       } else {
+                               rtc_wkalarm_save_time = 0;
+                       }
+               }
+               cm_suspended = true;
+       }
+
+       cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
+       cm->status_save_batt = is_batt_present(cm);
+
+       if (!cm_rtc_set) {
+               cm_suspend_duration_ms = 0;
+               cm_rtc_set = cm_setup_timer();
+       }
+
+       return 0;
+}
+
+static void cm_suspend_complete(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev, struct platform_device,
+                                                   dev);
+       struct charger_manager *cm = platform_get_drvdata(pdev);
+
+       if (cm_suspended) {
+               if (rtc_dev) {
+                       struct rtc_wkalrm tmp;
+
+                       rtc_read_alarm(rtc_dev, &tmp);
+                       rtc_wkalarm_save.pending = tmp.pending;
+                       rtc_set_alarm(rtc_dev, &rtc_wkalarm_save);
+               }
+               cm_suspended = false;
+               cm_rtc_set = false;
+       }
+
+       uevent_notify(cm, NULL);
+}
+
+static const struct dev_pm_ops charger_manager_pm = {
+       .prepare        = cm_suspend_prepare,
+       .complete       = cm_suspend_complete,
+};
+
+static struct platform_driver charger_manager_driver = {
+       .driver = {
+               .name = "charger-manager",
+               .owner = THIS_MODULE,
+               .pm = &charger_manager_pm,
+       },
+       .probe = charger_manager_probe,
+       .remove = __devexit_p(charger_manager_remove),
+       .id_table = charger_manager_id,
+};
+
+static int __init charger_manager_init(void)
+{
+       return platform_driver_register(&charger_manager_driver);
+}
+late_initcall(charger_manager_init);
+
+static void __exit charger_manager_cleanup(void)
+{
+       platform_driver_unregister(&charger_manager_driver);
+}
+module_exit(charger_manager_cleanup);
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("Charger Manager");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("charger-manager");
index 548d263b1ad0b1444cf65198c112e7c237b9f1bc..74c6b23aeabfc769c6e2892577669ab658a32ade 100644 (file)
@@ -146,7 +146,7 @@ static void collie_bat_external_power_changed(struct power_supply *psy)
 
 static irqreturn_t collie_bat_gpio_isr(int irq, void *data)
 {
-       pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+       pr_info("collie_bat_gpio irq\n");
        schedule_work(&bat_work);
        return IRQ_HANDLED;
 }
@@ -277,18 +277,13 @@ static struct collie_bat collie_bat_bu = {
        .adc_temp_divider = -1,
 };
 
-static struct {
-       int gpio;
-       char *name;
-       bool output;
-       int value;
-} gpios[] = {
-       { COLLIE_GPIO_CO,               "main battery full",    0, 0 },
-       { COLLIE_GPIO_MAIN_BAT_LOW,     "main battery low",     0, 0 },
-       { COLLIE_GPIO_CHARGE_ON,        "main charge on",       1, 0 },
-       { COLLIE_GPIO_MBAT_ON,          "main battery",         1, 0 },
-       { COLLIE_GPIO_TMP_ON,           "main battery temp",    1, 0 },
-       { COLLIE_GPIO_BBAT_ON,          "backup battery",       1, 0 },
+static struct gpio collie_batt_gpios[] = {
+       { COLLIE_GPIO_CO,           GPIOF_IN,           "main battery full" },
+       { COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN,           "main battery low" },
+       { COLLIE_GPIO_CHARGE_ON,    GPIOF_OUT_INIT_LOW, "main charge on" },
+       { COLLIE_GPIO_MBAT_ON,      GPIOF_OUT_INIT_LOW, "main battery" },
+       { COLLIE_GPIO_TMP_ON,       GPIOF_OUT_INIT_LOW, "main battery temp" },
+       { COLLIE_GPIO_BBAT_ON,      GPIOF_OUT_INIT_LOW, "backup battery" },
 };
 
 #ifdef CONFIG_PM
@@ -313,29 +308,16 @@ static int collie_bat_resume(struct ucb1x00_dev *dev)
 static int __devinit collie_bat_probe(struct ucb1x00_dev *dev)
 {
        int ret;
-       int i;
 
        if (!machine_is_collie())
                return -ENODEV;
 
        ucb = dev->ucb;
 
-       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
-               ret = gpio_request(gpios[i].gpio, gpios[i].name);
-               if (ret) {
-                       i--;
-                       goto err_gpio;
-               }
-
-               if (gpios[i].output)
-                       ret = gpio_direction_output(gpios[i].gpio,
-                                       gpios[i].value);
-               else
-                       ret = gpio_direction_input(gpios[i].gpio);
-
-               if (ret)
-                       goto err_gpio;
-       }
+       ret = gpio_request_array(collie_batt_gpios,
+                                ARRAY_SIZE(collie_batt_gpios));
+       if (ret)
+               return ret;
 
        mutex_init(&collie_bat_main.work_lock);
 
@@ -363,19 +345,12 @@ err_psy_reg_main:
 
        /* see comment in collie_bat_remove */
        cancel_work_sync(&bat_work);
-
-       i--;
-err_gpio:
-       for (; i >= 0; i--)
-               gpio_free(gpios[i].gpio);
-
+       gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
        return ret;
 }
 
 static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
 {
-       int i;
-
        free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
 
        power_supply_unregister(&collie_bat_bu.psy);
@@ -387,9 +362,7 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
         * unregistered now.
         */
        cancel_work_sync(&bat_work);
-
-       for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
-               gpio_free(gpios[i].gpio);
+       gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
 }
 
 static struct ucb1x00_driver collie_bat_driver = {
index d2c793cf676582516ef97af4bb4deae08750c728..3fd3e95d2b8517d101e7dbab63e0bafdb0c25513 100644 (file)
@@ -588,18 +588,7 @@ static struct platform_driver da903x_battery_driver = {
        .remove = da9030_battery_remove,
 };
 
-static int da903x_battery_init(void)
-{
-       return platform_driver_register(&da903x_battery_driver);
-}
-
-static void da903x_battery_exit(void)
-{
-       platform_driver_unregister(&da903x_battery_driver);
-}
-
-module_init(da903x_battery_init);
-module_exit(da903x_battery_exit);
+module_platform_driver(da903x_battery_driver);
 
 MODULE_DESCRIPTION("DA9030 battery charger driver");
 MODULE_AUTHOR("Mike Rapoport, CompuLab");
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
new file mode 100644 (file)
index 0000000..e8ea47a
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ * Batttery Driver for Dialog DA9052 PMICs
+ *
+ * Copyright(c) 2011 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/fs.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/pdata.h>
+#include <linux/mfd/da9052/reg.h>
+
+/* STATIC CONFIGURATION */
+#define DA9052_BAT_CUTOFF_VOLT         2800
+#define DA9052_BAT_TSH                 62000
+#define DA9052_BAT_LOW_CAP             4
+#define DA9052_AVG_SZ                  4
+#define DA9052_VC_TBL_SZ               68
+#define DA9052_VC_TBL_REF_SZ           3
+
+#define DA9052_ISET_USB_MASK           0x0F
+#define DA9052_CHG_USB_ILIM_MASK       0x40
+#define DA9052_CHG_LIM_COLS            16
+
+#define DA9052_MEAN(x, y)              ((x + y) / 2)
+
+enum charger_type_enum {
+       DA9052_NOCHARGER = 1,
+       DA9052_CHARGER,
+};
+
+static const u16 da9052_chg_current_lim[2][DA9052_CHG_LIM_COLS] = {
+       {70,  80,  90,  100, 110, 120, 400,  450,
+        500, 550, 600, 650, 700, 900, 1100, 1300},
+       {80,  90,  100, 110,  120,  400,  450,  500,
+        550, 600, 800, 1000, 1200, 1400, 1600, 1800},
+};
+
+static const u16 vc_tbl_ref[3] = {10, 25, 40};
+/* Lookup table for voltage vs capacity */
+static u32 const vc_tbl[3][68][2] = {
+       /* For temperature 10 degree Celsius */
+       {
+       {4082, 100}, {4036, 98},
+       {4020, 96}, {4008, 95},
+       {3997, 93}, {3983, 91},
+       {3964, 90}, {3943, 88},
+       {3926, 87}, {3912, 85},
+       {3900, 84}, {3890, 82},
+       {3881, 80}, {3873, 79},
+       {3865, 77}, {3857, 76},
+       {3848, 74}, {3839, 73},
+       {3829, 71}, {3820, 70},
+       {3811, 68}, {3802, 67},
+       {3794, 65}, {3785, 64},
+       {3778, 62}, {3770, 61},
+       {3763, 59}, {3756, 58},
+       {3750, 56}, {3744, 55},
+       {3738, 53}, {3732, 52},
+       {3727, 50}, {3722, 49},
+       {3717, 47}, {3712, 46},
+       {3708, 44}, {3703, 43},
+       {3700, 41}, {3696, 40},
+       {3693, 38}, {3691, 37},
+       {3688, 35}, {3686, 34},
+       {3683, 32}, {3681, 31},
+       {3678, 29}, {3675, 28},
+       {3672, 26}, {3669, 25},
+       {3665, 23}, {3661, 22},
+       {3656, 21}, {3651, 19},
+       {3645, 18}, {3639, 16},
+       {3631, 15}, {3622, 13},
+       {3611, 12}, {3600, 10},
+       {3587, 9}, {3572, 7},
+       {3548, 6}, {3503, 5},
+       {3420, 3}, {3268, 2},
+       {2992, 1}, {2746, 0}
+       },
+       /* For temperature 25 degree Celsius */
+       {
+       {4102, 100}, {4065, 98},
+       {4048, 96}, {4034, 95},
+       {4021, 93}, {4011, 92},
+       {4001, 90}, {3986, 88},
+       {3968, 87}, {3952, 85},
+       {3938, 84}, {3926, 82},
+       {3916, 81}, {3908, 79},
+       {3900, 77}, {3892, 76},
+       {3883, 74}, {3874, 73},
+       {3864, 71}, {3855, 70},
+       {3846, 68}, {3836, 67},
+       {3827, 65}, {3819, 64},
+       {3810, 62}, {3801, 61},
+       {3793, 59}, {3786, 58},
+       {3778, 56}, {3772, 55},
+       {3765, 53}, {3759, 52},
+       {3754, 50}, {3748, 49},
+       {3743, 47}, {3738, 46},
+       {3733, 44}, {3728, 43},
+       {3724, 41}, {3720, 40},
+       {3716, 38}, {3712, 37},
+       {3709, 35}, {3706, 34},
+       {3703, 33}, {3701, 31},
+       {3698, 30}, {3696, 28},
+       {3693, 27}, {3690, 25},
+       {3687, 24}, {3683, 22},
+       {3680, 21}, {3675, 19},
+       {3671, 18}, {3666, 17},
+       {3660, 15}, {3654, 14},
+       {3647, 12}, {3639, 11},
+       {3630, 9}, {3621, 8},
+       {3613, 6}, {3606, 5},
+       {3597, 4}, {3582, 2},
+       {3546, 1}, {2747, 0}
+       },
+       /* For temperature 40 degree Celsius */
+       {
+       {4114, 100}, {4081, 98},
+       {4065, 96}, {4050, 95},
+       {4036, 93}, {4024, 92},
+       {4013, 90}, {4002, 88},
+       {3990, 87}, {3976, 85},
+       {3962, 84}, {3950, 82},
+       {3939, 81}, {3930, 79},
+       {3921, 77}, {3912, 76},
+       {3902, 74}, {3893, 73},
+       {3883, 71}, {3874, 70},
+       {3865, 68}, {3856, 67},
+       {3847, 65}, {3838, 64},
+       {3829, 62}, {3820, 61},
+       {3812, 59}, {3803, 58},
+       {3795, 56}, {3787, 55},
+       {3780, 53}, {3773, 52},
+       {3767, 50}, {3761, 49},
+       {3756, 47}, {3751, 46},
+       {3746, 44}, {3741, 43},
+       {3736, 41}, {3732, 40},
+       {3728, 38}, {3724, 37},
+       {3720, 35}, {3716, 34},
+       {3713, 33}, {3710, 31},
+       {3707, 30}, {3704, 28},
+       {3701, 27}, {3698, 25},
+       {3695, 24}, {3691, 22},
+       {3686, 21}, {3681, 19},
+       {3676, 18}, {3671, 17},
+       {3666, 15}, {3661, 14},
+       {3655, 12}, {3648, 11},
+       {3640, 9}, {3632, 8},
+       {3622, 6}, {3616, 5},
+       {3611, 4}, {3604, 2},
+       {3594, 1}, {2747, 0}
+       }
+};
+
+struct da9052_battery {
+       struct da9052 *da9052;
+       struct power_supply psy;
+       struct notifier_block nb;
+       int charger_type;
+       int status;
+       int health;
+};
+
+static inline int volt_reg_to_mV(int value)
+{
+       return ((value * 1000) / 512) + 2500;
+}
+
+static inline int ichg_reg_to_mA(int value)
+{
+       return (value * 3900) / 1000;
+}
+
+static int da9052_read_chgend_current(struct da9052_battery *bat,
+                                      int *current_mA)
+{
+       int ret;
+
+       if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
+               return -EINVAL;
+
+       ret = da9052_reg_read(bat->da9052, DA9052_ICHG_END_REG);
+       if (ret < 0)
+               return ret;
+
+       *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGEND_ICHGEND);
+
+       return 0;
+}
+
+static int da9052_read_chg_current(struct da9052_battery *bat, int *current_mA)
+{
+       int ret;
+
+       if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
+               return -EINVAL;
+
+       ret = da9052_reg_read(bat->da9052, DA9052_ICHG_AV_REG);
+       if (ret < 0)
+               return ret;
+
+       *current_mA = ichg_reg_to_mA(ret & DA9052_ICHGAV_ICHGAV);
+
+       return 0;
+}
+
+static int da9052_bat_check_status(struct da9052_battery *bat, int *status)
+{
+       u8 v[2] = {0, 0};
+       u8 bat_status;
+       u8 chg_end;
+       int ret;
+       int chg_current;
+       int chg_end_current;
+       bool dcinsel;
+       bool dcindet;
+       bool vbussel;
+       bool vbusdet;
+       bool dc;
+       bool vbus;
+
+       ret = da9052_group_read(bat->da9052, DA9052_STATUS_A_REG, 2, v);
+       if (ret < 0)
+               return ret;
+
+       bat_status = v[0];
+       chg_end = v[1];
+
+       dcinsel = bat_status & DA9052_STATUSA_DCINSEL;
+       dcindet = bat_status & DA9052_STATUSA_DCINDET;
+       vbussel = bat_status & DA9052_STATUSA_VBUSSEL;
+       vbusdet = bat_status & DA9052_STATUSA_VBUSDET;
+       dc = dcinsel && dcindet;
+       vbus = vbussel && vbusdet;
+
+       /* Preference to WALL(DCIN) charger unit */
+       if (dc || vbus) {
+               bat->charger_type = DA9052_CHARGER;
+
+               /* If charging end flag is set and Charging current is greater
+                * than charging end limit then battery is charging
+               */
+               if ((chg_end & DA9052_STATUSB_CHGEND) != 0) {
+                       ret = da9052_read_chg_current(bat, &chg_current);
+                       if (ret < 0)
+                               return ret;
+                       ret = da9052_read_chgend_current(bat, &chg_end_current);
+                       if (ret < 0)
+                               return ret;
+
+                       if (chg_current >= chg_end_current)
+                               bat->status = POWER_SUPPLY_STATUS_CHARGING;
+                       else
+                               bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               } else {
+                       /* If Charging end flag is cleared then battery is
+                        * charging
+                       */
+                       bat->status = POWER_SUPPLY_STATUS_CHARGING;
+               }
+       } else if (dcindet || vbusdet) {
+                       bat->charger_type = DA9052_CHARGER;
+                       bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       } else {
+               bat->charger_type = DA9052_NOCHARGER;
+               bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+
+       if (status != NULL)
+               *status = bat->status;
+       return 0;
+}
+
+static int da9052_bat_read_volt(struct da9052_battery *bat, int *volt_mV)
+{
+       int volt;
+
+       volt = da9052_adc_manual_read(bat->da9052, DA9052_ADC_MAN_MUXSEL_VBAT);
+       if (volt < 0)
+               return volt;
+
+       *volt_mV = volt_reg_to_mV(volt);
+
+       return 0;
+}
+
+static int da9052_bat_check_presence(struct da9052_battery *bat, int *illegal)
+{
+       int bat_temp;
+
+       bat_temp = da9052_adc_read_temp(bat->da9052);
+       if (bat_temp < 0)
+               return bat_temp;
+
+       if (bat_temp > DA9052_BAT_TSH)
+               *illegal = 1;
+       else
+               *illegal = 0;
+
+       return 0;
+}
+
+static int da9052_bat_interpolate(int vbat_lower, int  vbat_upper,
+                                  int level_lower, int level_upper,
+                                  int bat_voltage)
+{
+       int tmp;
+
+       tmp = ((level_upper - level_lower) * 1000) / (vbat_upper - vbat_lower);
+       tmp = level_lower + (((bat_voltage - vbat_lower) * tmp) / 1000);
+
+       return tmp;
+}
+
+unsigned char da9052_determine_vc_tbl_index(unsigned char adc_temp)
+{
+       int i;
+
+       if (adc_temp <= vc_tbl_ref[0])
+               return 0;
+
+       if (adc_temp > vc_tbl_ref[DA9052_VC_TBL_REF_SZ - 1])
+               return DA9052_VC_TBL_REF_SZ - 1;
+
+       for (i = 0; i < DA9052_VC_TBL_REF_SZ; i++) {
+               if ((adc_temp > vc_tbl_ref[i]) &&
+                   (adc_temp <= DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1])))
+                               return i;
+               if ((adc_temp > DA9052_MEAN(vc_tbl_ref[i], vc_tbl_ref[i + 1]))
+                    && (adc_temp <= vc_tbl_ref[i]))
+                               return i + 1;
+       }
+}
+
+static int da9052_bat_read_capacity(struct da9052_battery *bat, int *capacity)
+{
+       int adc_temp;
+       int bat_voltage;
+       int vbat_lower;
+       int vbat_upper;
+       int level_upper;
+       int level_lower;
+       int ret;
+       int flag;
+       int i = 0;
+       int j;
+
+       ret = da9052_bat_read_volt(bat, &bat_voltage);
+       if (ret < 0)
+               return ret;
+
+       adc_temp = da9052_adc_read_temp(bat->da9052);
+       if (adc_temp < 0)
+               return adc_temp;
+
+       i = da9052_determine_vc_tbl_index(adc_temp);
+
+       if (bat_voltage >= vc_tbl[i][0][0]) {
+               *capacity = 100;
+               return 0;
+       }
+       if (bat_voltage <= vc_tbl[i][DA9052_VC_TBL_SZ - 1][0]) {
+               *capacity = 0;
+               return 0;
+       }
+       flag = 0;
+
+       for (j = 0; j < (DA9052_VC_TBL_SZ-1); j++) {
+               if ((bat_voltage <= vc_tbl[i][j][0]) &&
+                   (bat_voltage >= vc_tbl[i][j + 1][0])) {
+                       vbat_upper = vc_tbl[i][j][0];
+                       vbat_lower = vc_tbl[i][j + 1][0];
+                       level_upper = vc_tbl[i][j][1];
+                       level_lower = vc_tbl[i][j + 1][1];
+                       flag = 1;
+                       break;
+               }
+       }
+       if (!flag)
+               return -EIO;
+
+       *capacity = da9052_bat_interpolate(vbat_lower, vbat_upper, level_lower,
+                                          level_upper, bat_voltage);
+
+       return 0;
+}
+
+static int da9052_bat_check_health(struct da9052_battery *bat, int *health)
+{
+       int ret;
+       int bat_illegal;
+       int capacity;
+
+       ret = da9052_bat_check_presence(bat, &bat_illegal);
+       if (ret < 0)
+               return ret;
+
+       if (bat_illegal) {
+               bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
+               return 0;
+       }
+
+       if (bat->health != POWER_SUPPLY_HEALTH_OVERHEAT) {
+               ret = da9052_bat_read_capacity(bat, &capacity);
+               if (ret < 0)
+                       return ret;
+               if (capacity < DA9052_BAT_LOW_CAP)
+                       bat->health = POWER_SUPPLY_HEALTH_DEAD;
+               else
+                       bat->health = POWER_SUPPLY_HEALTH_GOOD;
+       }
+
+       *health = bat->health;
+
+       return 0;
+}
+
+static irqreturn_t da9052_bat_irq(int irq, void *data)
+{
+       struct da9052_battery *bat = data;
+
+       irq -= bat->da9052->irq_base;
+
+       if (irq == DA9052_IRQ_CHGEND)
+               bat->status = POWER_SUPPLY_STATUS_FULL;
+       else
+               da9052_bat_check_status(bat, NULL);
+
+       if (irq == DA9052_IRQ_CHGEND || irq == DA9052_IRQ_DCIN ||
+           irq == DA9052_IRQ_VBUS || irq == DA9052_IRQ_TBAT) {
+               power_supply_changed(&bat->psy);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int da9052_USB_current_notifier(struct notifier_block *nb,
+                                       unsigned long events, void *data)
+{
+       u8 row;
+       u8 col;
+       int *current_mA = data;
+       int ret;
+       struct da9052_battery *bat = container_of(nb, struct da9052_battery,
+                                                 nb);
+
+       if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING)
+               return -EPERM;
+
+       ret = da9052_reg_read(bat->da9052, DA9052_CHGBUCK_REG);
+       if (ret & DA9052_CHG_USB_ILIM_MASK)
+               return -EPERM;
+
+       if (bat->da9052->chip_id == DA9052)
+               row = 0;
+       else
+               row = 1;
+
+       if (*current_mA < da9052_chg_current_lim[row][0] ||
+           *current_mA > da9052_chg_current_lim[row][DA9052_CHG_LIM_COLS - 1])
+               return -EINVAL;
+
+       for (col = 0; col <= DA9052_CHG_LIM_COLS - 1 ; col++) {
+               if (*current_mA <= da9052_chg_current_lim[row][col])
+                       break;
+       }
+
+       return da9052_reg_update(bat->da9052, DA9052_ISET_REG,
+                                DA9052_ISET_USB_MASK, col);
+}
+
+static int da9052_bat_get_property(struct power_supply *psy,
+                                   enum power_supply_property psp,
+                                   union power_supply_propval *val)
+{
+       int ret;
+       int illegal;
+       struct da9052_battery *bat = container_of(psy, struct da9052_battery,
+                                                 psy);
+
+       ret = da9052_bat_check_presence(bat, &illegal);
+       if (ret < 0)
+               return ret;
+
+       if (illegal && psp != POWER_SUPPLY_PROP_PRESENT)
+               return -ENODEV;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = da9052_bat_check_status(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval =
+                       (bat->charger_type == DA9052_NOCHARGER) ? 0 : 1;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               ret = da9052_bat_check_presence(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = da9052_bat_check_health(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = DA9052_BAT_CUTOFF_VOLT * 1000;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+               ret = da9052_bat_read_volt(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               ret = da9052_read_chg_current(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               ret = da9052_bat_read_capacity(bat, &val->intval);
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = da9052_adc_read_temp(bat->da9052);
+               ret = val->intval;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return ret;
+}
+
+static enum power_supply_property da9052_bat_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_AVG,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+};
+
+static struct power_supply template_battery = {
+       .name           = "da9052-bat",
+       .type           = POWER_SUPPLY_TYPE_BATTERY,
+       .properties     = da9052_bat_props,
+       .num_properties = ARRAY_SIZE(da9052_bat_props),
+       .get_property   = da9052_bat_get_property,
+};
+
+static const char *const da9052_bat_irqs[] = {
+       "BATT TEMP",
+       "DCIN DET",
+       "DCIN REM",
+       "VBUS DET",
+       "VBUS REM",
+       "CHG END",
+};
+
+static s32 __devinit da9052_bat_probe(struct platform_device *pdev)
+{
+       struct da9052_pdata *pdata;
+       struct da9052_battery *bat;
+       int ret;
+       int irq;
+       int i;
+
+       bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL);
+       if (!bat)
+               return -ENOMEM;
+
+       bat->da9052 = dev_get_drvdata(pdev->dev.parent);
+       bat->psy = template_battery;
+       bat->charger_type = DA9052_NOCHARGER;
+       bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
+       bat->health = POWER_SUPPLY_HEALTH_UNKNOWN;
+       bat->nb.notifier_call = da9052_USB_current_notifier;
+
+       pdata = bat->da9052->dev->platform_data;
+       if (pdata != NULL && pdata->use_for_apm)
+               bat->psy.use_for_apm = pdata->use_for_apm;
+       else
+               bat->psy.use_for_apm = 1;
+
+       for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) {
+               irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
+               ret = request_threaded_irq(bat->da9052->irq_base + irq,
+                                          NULL, da9052_bat_irq,
+                                          IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                          da9052_bat_irqs[i], bat);
+               if (ret != 0) {
+                       dev_err(bat->da9052->dev,
+                               "DA9052 failed to request %s IRQ %d: %d\n",
+                               da9052_bat_irqs[i], irq, ret);
+                       goto err;
+               }
+       }
+
+       ret = power_supply_register(&pdev->dev, &bat->psy);
+        if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       for (; i >= 0; i--) {
+               irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
+               free_irq(bat->da9052->irq_base + irq, bat);
+       }
+       kfree(bat);
+       return ret;
+}
+static int __devexit da9052_bat_remove(struct platform_device *pdev)
+{
+       int i;
+       int irq;
+       struct da9052_battery *bat = platform_get_drvdata(pdev);
+
+       for (i = 0; i < ARRAY_SIZE(da9052_bat_irqs); i++) {
+               irq = platform_get_irq_byname(pdev, da9052_bat_irqs[i]);
+               free_irq(bat->da9052->irq_base + irq, bat);
+       }
+       power_supply_unregister(&bat->psy);
+
+       return 0;
+}
+
+static struct platform_driver da9052_bat_driver = {
+       .probe = da9052_bat_probe,
+       .remove = __devexit_p(da9052_bat_remove),
+       .driver = {
+               .name = "da9052-bat",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init da9052_bat_init(void)
+{
+       return platform_driver_register(&da9052_bat_driver);
+}
+module_init(da9052_bat_init);
+
+static void __exit da9052_bat_exit(void)
+{
+       platform_driver_unregister(&da9052_bat_driver);
+}
+module_exit(da9052_bat_exit);
+
+MODULE_DESCRIPTION("DA9052 BAT Device Driver");
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-bat");
index f2c9cc33c0f9f795a81125368c1dc758c2dd81c8..545874b1df9ebfa4d14bdb2b4b04f07f274cb77e 100644 (file)
@@ -95,7 +95,11 @@ static int rated_capacities[] = {
        2880,   /* Samsung */
        2880,   /* BYD */
        2880,   /* Lishen */
-       2880    /* NEC */
+       2880,   /* NEC */
+#ifdef CONFIG_MACH_H4700
+       0,
+       3600,   /* HP iPAQ hx4700 3.7V 3600mAh (359114-001) */
+#endif
 };
 
 /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C
@@ -637,18 +641,7 @@ static struct platform_driver ds2760_battery_driver = {
        .resume   = ds2760_battery_resume,
 };
 
-static int __init ds2760_battery_init(void)
-{
-       return platform_driver_register(&ds2760_battery_driver);
-}
-
-static void __exit ds2760_battery_exit(void)
-{
-       platform_driver_unregister(&ds2760_battery_driver);
-}
-
-module_init(ds2760_battery_init);
-module_exit(ds2760_battery_exit);
+module_platform_driver(ds2760_battery_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
index 91a783d72360b314094a134d5284a89e751b3ca9..de31cae1ba53cc4d2dbc6eb661b9d741be4bca19 100644 (file)
@@ -841,29 +841,17 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
        return 0;
 }
 
-MODULE_ALIAS("platform:ds2780-battery");
-
 static struct platform_driver ds2780_battery_driver = {
        .driver = {
                .name = "ds2780-battery",
        },
        .probe    = ds2780_battery_probe,
-       .remove   = ds2780_battery_remove,
+       .remove   = __devexit_p(ds2780_battery_remove),
 };
 
-static int __init ds2780_battery_init(void)
-{
-       return platform_driver_register(&ds2780_battery_driver);
-}
-
-static void __exit ds2780_battery_exit(void)
-{
-       platform_driver_unregister(&ds2780_battery_driver);
-}
-
-module_init(ds2780_battery_init);
-module_exit(ds2780_battery_exit);
+module_platform_driver(ds2780_battery_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
 MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver");
+MODULE_ALIAS("platform:ds2780-battery");
index a64b8854cfd59dcb640202e56044e77ff9e13605..8672c9177dd70f481937233fcd5fe0083bd8796c 100644 (file)
@@ -185,17 +185,7 @@ static struct platform_driver gpio_charger_driver = {
        },
 };
 
-static int __init gpio_charger_init(void)
-{
-       return platform_driver_register(&gpio_charger_driver);
-}
-module_init(gpio_charger_init);
-
-static void __exit gpio_charger_exit(void)
-{
-       platform_driver_unregister(&gpio_charger_driver);
-}
-module_exit(gpio_charger_exit);
+module_platform_driver(gpio_charger_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
index 01fa671ec97f6af9a31bf1a8c39ceef86691617b..d09649706bd33d7fd3cecf4c303a2c57c8661204 100644 (file)
@@ -779,18 +779,7 @@ static struct platform_driver platform_pmic_battery_driver = {
        .remove = __devexit_p(platform_pmic_battery_remove),
 };
 
-static int __init platform_pmic_battery_module_init(void)
-{
-       return platform_driver_register(&platform_pmic_battery_driver);
-}
-
-static void __exit platform_pmic_battery_module_exit(void)
-{
-       platform_driver_unregister(&platform_pmic_battery_driver);
-}
-
-module_init(platform_pmic_battery_module_init);
-module_exit(platform_pmic_battery_module_exit);
+module_platform_driver(platform_pmic_battery_driver);
 
 MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>");
 MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
index f6d72b402a8e3dc48d37319f6ebac236df71d60a..b806667b59ae68639a43b1a52ed95c0ad4fce638 100644 (file)
@@ -79,7 +79,7 @@ static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on)
 {
        struct isp1704_charger_data     *board = isp->dev->platform_data;
 
-       if (board->set_power)
+       if (board && board->set_power)
                board->set_power(on);
 }
 
@@ -494,17 +494,7 @@ static struct platform_driver isp1704_charger_driver = {
        .remove = __devexit_p(isp1704_charger_remove),
 };
 
-static int __init isp1704_charger_init(void)
-{
-       return platform_driver_register(&isp1704_charger_driver);
-}
-module_init(isp1704_charger_init);
-
-static void __exit isp1704_charger_exit(void)
-{
-       platform_driver_unregister(&isp1704_charger_driver);
-}
-module_exit(isp1704_charger_exit);
+module_platform_driver(isp1704_charger_driver);
 
 MODULE_ALIAS("platform:isp1704_charger");
 MODULE_AUTHOR("Nokia Corporation");
index 763f894ed18815d5e54f9cd1359d42eab03f44ea..8dbc7bfaab14d40422c8bb17db3a4c43cf695abe 100644 (file)
@@ -67,7 +67,7 @@ static irqreturn_t jz_battery_irq_handler(int irq, void *devid)
 
 static long jz_battery_read_voltage(struct jz_battery *battery)
 {
-       unsigned long t;
+       long t;
        unsigned long val;
        long voltage;
 
@@ -441,17 +441,7 @@ static struct platform_driver jz_battery_driver = {
        },
 };
 
-static int __init jz_battery_init(void)
-{
-       return platform_driver_register(&jz_battery_driver);
-}
-module_init(jz_battery_init);
-
-static void __exit jz_battery_exit(void)
-{
-       platform_driver_unregister(&jz_battery_driver);
-}
-module_exit(jz_battery_exit);
+module_platform_driver(jz_battery_driver);
 
 MODULE_ALIAS("platform:jz4740-battery");
 MODULE_LICENSE("GPL");
diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c
new file mode 100644 (file)
index 0000000..b15b575
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * Driver for LP8727 Micro/Mini USB IC with intergrated charger
+ *
+ *                     Copyright (C) 2011 National Semiconductor
+ *
+ * This program is free software; you can 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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/power_supply.h>
+#include <linux/lp8727.h>
+
+#define DEBOUNCE_MSEC  270
+
+/* Registers */
+#define CTRL1          0x1
+#define CTRL2          0x2
+#define        SWCTRL          0x3
+#define INT1           0x4
+#define INT2           0x5
+#define STATUS1                0x6
+#define STATUS2        0x7
+#define CHGCTRL2       0x9
+
+/* CTRL1 register */
+#define CP_EN          (1 << 0)
+#define ADC_EN         (1 << 1)
+#define ID200_EN       (1 << 4)
+
+/* CTRL2 register */
+#define CHGDET_EN      (1 << 1)
+#define INT_EN         (1 << 6)
+
+/* SWCTRL register */
+#define SW_DM1_DM      (0x0 << 0)
+#define SW_DM1_U1      (0x1 << 0)
+#define SW_DM1_HiZ     (0x7 << 0)
+#define SW_DP2_DP      (0x0 << 3)
+#define SW_DP2_U2      (0x1 << 3)
+#define SW_DP2_HiZ     (0x7 << 3)
+
+/* INT1 register */
+#define IDNO           (0xF << 0)
+#define VBUS           (1 << 4)
+
+/* STATUS1 register */
+#define CHGSTAT                (3 << 4)
+#define CHPORT         (1 << 6)
+#define DCPORT         (1 << 7)
+
+/* STATUS2 register */
+#define TEMP_STAT      (3 << 5)
+
+enum lp8727_dev_id {
+       ID_NONE,
+       ID_TA,
+       ID_DEDICATED_CHG,
+       ID_USB_CHG,
+       ID_USB_DS,
+       ID_MAX,
+};
+
+enum lp8727_chg_stat {
+       PRECHG,
+       CC,
+       CV,
+       EOC,
+};
+
+struct lp8727_psy {
+       struct power_supply ac;
+       struct power_supply usb;
+       struct power_supply batt;
+};
+
+struct lp8727_chg {
+       struct device *dev;
+       struct i2c_client *client;
+       struct mutex xfer_lock;
+       struct delayed_work work;
+       struct workqueue_struct *irqthread;
+       struct lp8727_platform_data *pdata;
+       struct lp8727_psy *psy;
+       struct lp8727_chg_param *chg_parm;
+       enum lp8727_dev_id devid;
+};
+
+static int lp8727_i2c_read(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
+{
+       s32 ret;
+
+       mutex_lock(&pchg->xfer_lock);
+       ret = i2c_smbus_read_i2c_block_data(pchg->client, reg, len, data);
+       mutex_unlock(&pchg->xfer_lock);
+
+       return (ret != len) ? -EIO : 0;
+}
+
+static int lp8727_i2c_write(struct lp8727_chg *pchg, u8 reg, u8 *data, u8 len)
+{
+       s32 ret;
+
+       mutex_lock(&pchg->xfer_lock);
+       ret = i2c_smbus_write_i2c_block_data(pchg->client, reg, len, data);
+       mutex_unlock(&pchg->xfer_lock);
+
+       return ret;
+}
+
+static inline int lp8727_i2c_read_byte(struct lp8727_chg *pchg, u8 reg,
+                                      u8 *data)
+{
+       return lp8727_i2c_read(pchg, reg, data, 1);
+}
+
+static inline int lp8727_i2c_write_byte(struct lp8727_chg *pchg, u8 reg,
+                                       u8 *data)
+{
+       return lp8727_i2c_write(pchg, reg, data, 1);
+}
+
+static int lp8727_is_charger_attached(const char *name, int id)
+{
+       if (name) {
+               if (!strcmp(name, "ac"))
+                       return (id == ID_TA || id == ID_DEDICATED_CHG) ? 1 : 0;
+               else if (!strcmp(name, "usb"))
+                       return (id == ID_USB_CHG) ? 1 : 0;
+       }
+
+       return (id >= ID_TA && id <= ID_USB_CHG) ? 1 : 0;
+}
+
+static void lp8727_init_device(struct lp8727_chg *pchg)
+{
+       u8 val;
+
+       val = ID200_EN | ADC_EN | CP_EN;
+       if (lp8727_i2c_write_byte(pchg, CTRL1, &val))
+               dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL1);
+
+       val = INT_EN | CHGDET_EN;
+       if (lp8727_i2c_write_byte(pchg, CTRL2, &val))
+               dev_err(pchg->dev, "i2c write err : addr=0x%.2x\n", CTRL2);
+}
+
+static int lp8727_is_dedicated_charger(struct lp8727_chg *pchg)
+{
+       u8 val;
+       lp8727_i2c_read_byte(pchg, STATUS1, &val);
+       return (val & DCPORT);
+}
+
+static int lp8727_is_usb_charger(struct lp8727_chg *pchg)
+{
+       u8 val;
+       lp8727_i2c_read_byte(pchg, STATUS1, &val);
+       return (val & CHPORT);
+}
+
+static void lp8727_ctrl_switch(struct lp8727_chg *pchg, u8 sw)
+{
+       u8 val = sw;
+       lp8727_i2c_write_byte(pchg, SWCTRL, &val);
+}
+
+static void lp8727_id_detection(struct lp8727_chg *pchg, u8 id, int vbusin)
+{
+       u8 devid = ID_NONE;
+       u8 swctrl = SW_DM1_HiZ | SW_DP2_HiZ;
+
+       switch (id) {
+       case 0x5:
+               devid = ID_TA;
+               pchg->chg_parm = &pchg->pdata->ac;
+               break;
+       case 0xB:
+               if (lp8727_is_dedicated_charger(pchg)) {
+                       pchg->chg_parm = &pchg->pdata->ac;
+                       devid = ID_DEDICATED_CHG;
+               } else if (lp8727_is_usb_charger(pchg)) {
+                       pchg->chg_parm = &pchg->pdata->usb;
+                       devid = ID_USB_CHG;
+                       swctrl = SW_DM1_DM | SW_DP2_DP;
+               } else if (vbusin) {
+                       devid = ID_USB_DS;
+                       swctrl = SW_DM1_DM | SW_DP2_DP;
+               }
+               break;
+       default:
+               devid = ID_NONE;
+               pchg->chg_parm = NULL;
+               break;
+       }
+
+       pchg->devid = devid;
+       lp8727_ctrl_switch(pchg, swctrl);
+}
+
+static void lp8727_enable_chgdet(struct lp8727_chg *pchg)
+{
+       u8 val;
+
+       lp8727_i2c_read_byte(pchg, CTRL2, &val);
+       val |= CHGDET_EN;
+       lp8727_i2c_write_byte(pchg, CTRL2, &val);
+}
+
+static void lp8727_delayed_func(struct work_struct *_work)
+{
+       u8 intstat[2], idno, vbus;
+       struct lp8727_chg *pchg =
+           container_of(_work, struct lp8727_chg, work.work);
+
+       if (lp8727_i2c_read(pchg, INT1, intstat, 2)) {
+               dev_err(pchg->dev, "can not read INT registers\n");
+               return;
+       }
+
+       idno = intstat[0] & IDNO;
+       vbus = intstat[0] & VBUS;
+
+       lp8727_id_detection(pchg, idno, vbus);
+       lp8727_enable_chgdet(pchg);
+
+       power_supply_changed(&pchg->psy->ac);
+       power_supply_changed(&pchg->psy->usb);
+       power_supply_changed(&pchg->psy->batt);
+}
+
+static irqreturn_t lp8727_isr_func(int irq, void *ptr)
+{
+       struct lp8727_chg *pchg = ptr;
+       unsigned long delay = msecs_to_jiffies(DEBOUNCE_MSEC);
+
+       queue_delayed_work(pchg->irqthread, &pchg->work, delay);
+
+       return IRQ_HANDLED;
+}
+
+static void lp8727_intr_config(struct lp8727_chg *pchg)
+{
+       INIT_DELAYED_WORK(&pchg->work, lp8727_delayed_func);
+
+       pchg->irqthread = create_singlethread_workqueue("lp8727-irqthd");
+       if (!pchg->irqthread)
+               dev_err(pchg->dev, "can not create thread for lp8727\n");
+
+       if (request_threaded_irq(pchg->client->irq,
+                                NULL,
+                                lp8727_isr_func,
+                                IRQF_TRIGGER_FALLING, "lp8727_irq", pchg)) {
+               dev_err(pchg->dev, "lp8727 irq can not be registered\n");
+       }
+}
+
+static enum power_supply_property lp8727_charger_prop[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property lp8727_battery_prop[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+};
+
+static char *battery_supplied_to[] = {
+       "main_batt",
+};
+
+static int lp8727_charger_get_property(struct power_supply *psy,
+                                      enum power_supply_property psp,
+                                      union power_supply_propval *val)
+{
+       struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
+
+       if (psp == POWER_SUPPLY_PROP_ONLINE)
+               val->intval = lp8727_is_charger_attached(psy->name,
+                                                        pchg->devid);
+
+       return 0;
+}
+
+static int lp8727_battery_get_property(struct power_supply *psy,
+                                      enum power_supply_property psp,
+                                      union power_supply_propval *val)
+{
+       struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
+       u8 read;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               if (lp8727_is_charger_attached(psy->name, pchg->devid)) {
+                       lp8727_i2c_read_byte(pchg, STATUS1, &read);
+                       if (((read & CHGSTAT) >> 4) == EOC)
+                               val->intval = POWER_SUPPLY_STATUS_FULL;
+                       else
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               } else {
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               }
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               lp8727_i2c_read_byte(pchg, STATUS2, &read);
+               read = (read & TEMP_STAT) >> 5;
+               if (read >= 0x1 && read <= 0x3)
+                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+               else
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               if (pchg->pdata->get_batt_present)
+                       val->intval = pchg->pdata->get_batt_present();
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               if (pchg->pdata->get_batt_level)
+                       val->intval = pchg->pdata->get_batt_level();
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               if (pchg->pdata->get_batt_capacity)
+                       val->intval = pchg->pdata->get_batt_capacity();
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               if (pchg->pdata->get_batt_temp)
+                       val->intval = pchg->pdata->get_batt_temp();
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void lp8727_charger_changed(struct power_supply *psy)
+{
+       struct lp8727_chg *pchg = dev_get_drvdata(psy->dev->parent);
+       u8 val;
+       u8 eoc_level, ichg;
+
+       if (lp8727_is_charger_attached(psy->name, pchg->devid)) {
+               if (pchg->chg_parm) {
+                       eoc_level = pchg->chg_parm->eoc_level;
+                       ichg = pchg->chg_parm->ichg;
+                       val = (ichg << 4) | eoc_level;
+                       lp8727_i2c_write_byte(pchg, CHGCTRL2, &val);
+               }
+       }
+}
+
+static int lp8727_register_psy(struct lp8727_chg *pchg)
+{
+       struct lp8727_psy *psy;
+
+       psy = kzalloc(sizeof(*psy), GFP_KERNEL);
+       if (!psy)
+               goto err_mem;
+
+       pchg->psy = psy;
+
+       psy->ac.name = "ac";
+       psy->ac.type = POWER_SUPPLY_TYPE_MAINS;
+       psy->ac.properties = lp8727_charger_prop;
+       psy->ac.num_properties = ARRAY_SIZE(lp8727_charger_prop);
+       psy->ac.get_property = lp8727_charger_get_property;
+       psy->ac.supplied_to = battery_supplied_to;
+       psy->ac.num_supplicants = ARRAY_SIZE(battery_supplied_to);
+
+       if (power_supply_register(pchg->dev, &psy->ac))
+               goto err_psy;
+
+       psy->usb.name = "usb";
+       psy->usb.type = POWER_SUPPLY_TYPE_USB;
+       psy->usb.properties = lp8727_charger_prop;
+       psy->usb.num_properties = ARRAY_SIZE(lp8727_charger_prop);
+       psy->usb.get_property = lp8727_charger_get_property;
+       psy->usb.supplied_to = battery_supplied_to;
+       psy->usb.num_supplicants = ARRAY_SIZE(battery_supplied_to);
+
+       if (power_supply_register(pchg->dev, &psy->usb))
+               goto err_psy;
+
+       psy->batt.name = "main_batt";
+       psy->batt.type = POWER_SUPPLY_TYPE_BATTERY;
+       psy->batt.properties = lp8727_battery_prop;
+       psy->batt.num_properties = ARRAY_SIZE(lp8727_battery_prop);
+       psy->batt.get_property = lp8727_battery_get_property;
+       psy->batt.external_power_changed = lp8727_charger_changed;
+
+       if (power_supply_register(pchg->dev, &psy->batt))
+               goto err_psy;
+
+       return 0;
+
+err_mem:
+       return -ENOMEM;
+err_psy:
+       kfree(psy);
+       return -EPERM;
+}
+
+static void lp8727_unregister_psy(struct lp8727_chg *pchg)
+{
+       struct lp8727_psy *psy = pchg->psy;
+
+       if (!psy)
+               return;
+
+       power_supply_unregister(&psy->ac);
+       power_supply_unregister(&psy->usb);
+       power_supply_unregister(&psy->batt);
+       kfree(psy);
+}
+
+static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+       struct lp8727_chg *pchg;
+       int ret;
+
+       if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+               return -EIO;
+
+       pchg = kzalloc(sizeof(*pchg), GFP_KERNEL);
+       if (!pchg)
+               return -ENOMEM;
+
+       pchg->client = cl;
+       pchg->dev = &cl->dev;
+       pchg->pdata = cl->dev.platform_data;
+       i2c_set_clientdata(cl, pchg);
+
+       mutex_init(&pchg->xfer_lock);
+
+       lp8727_init_device(pchg);
+       lp8727_intr_config(pchg);
+
+       ret = lp8727_register_psy(pchg);
+       if (ret)
+               dev_err(pchg->dev,
+                       "can not register power supplies. err=%d", ret);
+
+       return 0;
+}
+
+static int __devexit lp8727_remove(struct i2c_client *cl)
+{
+       struct lp8727_chg *pchg = i2c_get_clientdata(cl);
+
+       lp8727_unregister_psy(pchg);
+       free_irq(pchg->client->irq, pchg);
+       flush_workqueue(pchg->irqthread);
+       destroy_workqueue(pchg->irqthread);
+       kfree(pchg);
+       return 0;
+}
+
+static const struct i2c_device_id lp8727_ids[] = {
+       {"lp8727", 0},
+};
+
+static struct i2c_driver lp8727_driver = {
+       .driver = {
+                  .name = "lp8727",
+                  },
+       .probe = lp8727_probe,
+       .remove = __devexit_p(lp8727_remove),
+       .id_table = lp8727_ids,
+};
+
+static int __init lp8727_init(void)
+{
+       return i2c_add_driver(&lp8727_driver);
+}
+
+static void __exit lp8727_exit(void)
+{
+       i2c_del_driver(&lp8727_driver);
+}
+
+module_init(lp8727_init);
+module_exit(lp8727_exit);
+
+MODULE_DESCRIPTION("National Semiconductor LP8727 charger driver");
+MODULE_AUTHOR
+    ("Woogyom Kim <milo.kim@ti.com>, Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL");
index 9f0183c73076852b213b10ea2832bc7e9d74cd3e..86acee2f988917912919e710d4b62f1592b98397 100644 (file)
@@ -85,55 +85,79 @@ static int max17042_get_property(struct power_supply *psy,
 {
        struct max17042_chip *chip = container_of(psy,
                                struct max17042_chip, battery);
+       int ret;
 
        switch (psp) {
        case POWER_SUPPLY_PROP_PRESENT:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_STATUS);
-               if (val->intval & MAX17042_STATUS_BattAbsent)
+               ret = max17042_read_reg(chip->client, MAX17042_STATUS);
+               if (ret < 0)
+                       return ret;
+
+               if (ret & MAX17042_STATUS_BattAbsent)
                        val->intval = 0;
                else
                        val->intval = 1;
                break;
        case POWER_SUPPLY_PROP_CYCLE_COUNT:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_Cycles);
+               ret = max17042_read_reg(chip->client, MAX17042_Cycles);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MAX:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_MinMaxVolt);
-               val->intval >>= 8;
+               ret = max17042_read_reg(chip->client, MAX17042_MinMaxVolt);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret >> 8;
                val->intval *= 20000; /* Units of LSB = 20mV */
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_V_empty);
-               val->intval >>= 7;
+               ret = max17042_read_reg(chip->client, MAX17042_V_empty);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret >> 7;
                val->intval *= 10000; /* Units of LSB = 10mV */
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
+               ret = max17042_read_reg(chip->client, MAX17042_VCELL);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret * 625 / 8;
                break;
        case POWER_SUPPLY_PROP_VOLTAGE_AVG:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_AvgVCELL) * 83;
+               ret = max17042_read_reg(chip->client, MAX17042_AvgVCELL);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret * 625 / 8;
                break;
        case POWER_SUPPLY_PROP_CAPACITY:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_SOC) / 256;
+               ret = max17042_read_reg(chip->client, MAX17042_SOC);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret >> 8;
                break;
        case POWER_SUPPLY_PROP_CHARGE_FULL:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_RepSOC);
-               if ((val->intval / 256) >= MAX17042_BATTERY_FULL)
+               ret = max17042_read_reg(chip->client, MAX17042_RepSOC);
+               if (ret < 0)
+                       return ret;
+
+               if ((ret >> 8) >= MAX17042_BATTERY_FULL)
                        val->intval = 1;
-               else if (val->intval >= 0)
+               else if (ret >= 0)
                        val->intval = 0;
                break;
        case POWER_SUPPLY_PROP_TEMP:
-               val->intval = max17042_read_reg(chip->client,
-                               MAX17042_TEMP);
+               ret = max17042_read_reg(chip->client, MAX17042_TEMP);
+               if (ret < 0)
+                       return ret;
+
+               val->intval = ret;
                /* The value is signed. */
                if (val->intval & 0x8000) {
                        val->intval = (0x7fff & ~val->intval) + 1;
@@ -145,24 +169,30 @@ static int max17042_get_property(struct power_supply *psy,
                break;
        case POWER_SUPPLY_PROP_CURRENT_NOW:
                if (chip->pdata->enable_current_sense) {
-                       val->intval = max17042_read_reg(chip->client,
-                                       MAX17042_Current);
+                       ret = max17042_read_reg(chip->client, MAX17042_Current);
+                       if (ret < 0)
+                               return ret;
+
+                       val->intval = ret;
                        if (val->intval & 0x8000) {
                                /* Negative */
                                val->intval = ~val->intval & 0x7fff;
                                val->intval++;
                                val->intval *= -1;
                        }
-                       val->intval >>= 4;
-                       val->intval *= 1000000 * 25 / chip->pdata->r_sns;
+                       val->intval *= 1562500 / chip->pdata->r_sns;
                } else {
                        return -EINVAL;
                }
                break;
        case POWER_SUPPLY_PROP_CURRENT_AVG:
                if (chip->pdata->enable_current_sense) {
-                       val->intval = max17042_read_reg(chip->client,
-                                       MAX17042_AvgCurrent);
+                       ret = max17042_read_reg(chip->client,
+                                               MAX17042_AvgCurrent);
+                       if (ret < 0)
+                               return ret;
+
+                       val->intval = ret;
                        if (val->intval & 0x8000) {
                                /* Negative */
                                val->intval = ~val->intval & 0x7fff;
@@ -210,6 +240,9 @@ static int __devinit max17042_probe(struct i2c_client *client,
        if (!chip->pdata->enable_current_sense)
                chip->battery.num_properties -= 2;
 
+       if (chip->pdata->r_sns == 0)
+               chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
+
        ret = power_supply_register(&client->dev, &chip->battery);
        if (ret) {
                dev_err(&client->dev, "failed: power supply register\n");
@@ -226,9 +259,6 @@ static int __devinit max17042_probe(struct i2c_client *client,
                max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
                max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
                max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
-       } else {
-               if (chip->pdata->r_sns == 0)
-                       chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
        }
 
        return 0;
index 2595145f3bffad80d9cdfba4d50b83df3f41ffa6..3e23f43e98af5813462a83c06de11fefe9eaaef0 100644 (file)
@@ -374,19 +374,9 @@ static struct platform_driver max8903_driver = {
        },
 };
 
-static int __init max8903_init(void)
-{
-       return platform_driver_register(&max8903_driver);
-}
-module_init(max8903_init);
-
-static void __exit max8903_exit(void)
-{
-       platform_driver_unregister(&max8903_driver);
-}
-module_exit(max8903_exit);
+module_platform_driver(max8903_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MAX8903 Charger Driver");
 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
-MODULE_ALIAS("max8903-charger");
+MODULE_ALIAS("platform:max8903-charger");
index a70e16d3a3dc1d31942ccf6cf788d06b1c0ea3b1..daa333bd7ebb199f6c1325f214a6a7c074c0a061 100644 (file)
@@ -78,6 +78,8 @@ struct max8925_power_info {
        unsigned                batt_detect:1;  /* detecing MB by ID pin */
        unsigned                topoff_threshold:2;
        unsigned                fast_charge:3;
+       unsigned                no_temp_support:1;
+       unsigned                no_insert_detect:1;
 
        int (*set_charger) (int);
 };
@@ -116,17 +118,7 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
        case MAX8925_IRQ_VCHG_DC_F:
                info->ac_online = 0;
                __set_charger(info, 0);
-               dev_dbg(chip->dev, "Adapter is removal\n");
-               break;
-       case MAX8925_IRQ_VCHG_USB_R:
-               info->usb_online = 1;
-               __set_charger(info, 1);
-               dev_dbg(chip->dev, "USB inserted\n");
-               break;
-       case MAX8925_IRQ_VCHG_USB_F:
-               info->usb_online = 0;
-               __set_charger(info, 0);
-               dev_dbg(chip->dev, "USB is removal\n");
+               dev_dbg(chip->dev, "Adapter removed\n");
                break;
        case MAX8925_IRQ_VCHG_THM_OK_F:
                /* Battery is not ready yet */
@@ -168,27 +160,33 @@ static irqreturn_t max8925_charger_handler(int irq, void *data)
 static int start_measure(struct max8925_power_info *info, int type)
 {
        unsigned char buf[2] = {0, 0};
+       int meas_cmd;
        int meas_reg = 0, ret;
 
        switch (type) {
        case MEASURE_VCHG:
+               meas_cmd = MAX8925_CMD_VCHG;
                meas_reg = MAX8925_ADC_VCHG;
                break;
        case MEASURE_VBBATT:
+               meas_cmd = MAX8925_CMD_VBBATT;
                meas_reg = MAX8925_ADC_VBBATT;
                break;
        case MEASURE_VMBATT:
+               meas_cmd = MAX8925_CMD_VMBATT;
                meas_reg = MAX8925_ADC_VMBATT;
                break;
        case MEASURE_ISNS:
+               meas_cmd = MAX8925_CMD_ISNS;
                meas_reg = MAX8925_ADC_ISNS;
                break;
        default:
                return -EINVAL;
        }
 
+       max8925_reg_write(info->adc, meas_cmd, 0);
        max8925_bulk_read(info->adc, meas_reg, 2, buf);
-       ret = (buf[0] << 4) | (buf[1] >> 4);
+       ret = ((buf[0]<<8) | buf[1]) >> 4;
 
        return ret;
 }
@@ -208,7 +206,7 @@ static int max8925_ac_get_prop(struct power_supply *psy,
                if (info->ac_online) {
                        ret = start_measure(info, MEASURE_VCHG);
                        if (ret >= 0) {
-                               val->intval = ret << 1; /* unit is mV */
+                               val->intval = ret * 2000;       /* unit is uV */
                                goto out;
                        }
                }
@@ -242,7 +240,7 @@ static int max8925_usb_get_prop(struct power_supply *psy,
                if (info->usb_online) {
                        ret = start_measure(info, MEASURE_VCHG);
                        if (ret >= 0) {
-                               val->intval = ret << 1; /* unit is mV */
+                               val->intval = ret * 2000;       /* unit is uV */
                                goto out;
                        }
                }
@@ -266,7 +264,6 @@ static int max8925_bat_get_prop(struct power_supply *psy,
                                union power_supply_propval *val)
 {
        struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent);
-       long long int tmp = 0;
        int ret = 0;
 
        switch (psp) {
@@ -277,7 +274,7 @@ static int max8925_bat_get_prop(struct power_supply *psy,
                if (info->bat_online) {
                        ret = start_measure(info, MEASURE_VMBATT);
                        if (ret >= 0) {
-                               val->intval = ret << 1; /* unit is mV */
+                               val->intval = ret * 2000;       /* unit is uV */
                                ret = 0;
                                break;
                        }
@@ -288,8 +285,8 @@ static int max8925_bat_get_prop(struct power_supply *psy,
                if (info->bat_online) {
                        ret = start_measure(info, MEASURE_ISNS);
                        if (ret >= 0) {
-                               tmp = (long long int)ret * 6250 / 4096 - 3125;
-                               ret = (int)tmp;
+                               /* assume r_sns is 0.02 */
+                               ret = ((ret * 6250) - 3125) /* uA */;
                                val->intval = 0;
                                if (ret > 0)
                                        val->intval = ret; /* unit is mA */
@@ -365,13 +362,14 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip,
        int ret;
 
        REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
-       REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
+       if (!info->no_insert_detect) {
+               REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove");
+               REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert");
+       }
+       if (!info->no_temp_support) {
+               REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range");
+               REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range");
+       }
        REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high");
        REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low");
        REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset");
@@ -379,9 +377,15 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip,
        REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff");
        REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire");
 
-       info->ac_online = 0;
        info->usb_online = 0;
        info->bat_online = 0;
+
+       /* check for power - can miss interrupt at boot time */
+       if (start_measure(info, MEASURE_VCHG) * 2000 > 500000)
+               info->ac_online = 1;
+       else
+               info->ac_online = 0;
+
        ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS);
        if (ret >= 0) {
                /*
@@ -449,6 +453,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
        info->ac.properties = max8925_ac_props;
        info->ac.num_properties = ARRAY_SIZE(max8925_ac_props);
        info->ac.get_property = max8925_ac_get_prop;
+       info->ac.supplied_to = pdata->supplied_to;
+       info->ac.num_supplicants = pdata->num_supplicants;
        ret = power_supply_register(&pdev->dev, &info->ac);
        if (ret)
                goto out;
@@ -459,6 +465,9 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
        info->usb.properties = max8925_usb_props;
        info->usb.num_properties = ARRAY_SIZE(max8925_usb_props);
        info->usb.get_property = max8925_usb_get_prop;
+       info->usb.supplied_to = pdata->supplied_to;
+       info->usb.num_supplicants = pdata->num_supplicants;
+
        ret = power_supply_register(&pdev->dev, &info->usb);
        if (ret)
                goto out_usb;
@@ -478,6 +487,8 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
        info->topoff_threshold = pdata->topoff_threshold;
        info->fast_charge = pdata->fast_charge;
        info->set_charger = pdata->set_charger;
+       info->no_temp_support = pdata->no_temp_support;
+       info->no_insert_detect = pdata->no_insert_detect;
 
        max8925_init_charger(chip, info);
        return 0;
@@ -512,17 +523,7 @@ static struct platform_driver max8925_power_driver = {
        },
 };
 
-static int __init max8925_power_init(void)
-{
-       return platform_driver_register(&max8925_power_driver);
-}
-module_init(max8925_power_init);
-
-static void __exit max8925_power_exit(void)
-{
-       platform_driver_unregister(&max8925_power_driver);
-}
-module_exit(max8925_power_exit);
+module_platform_driver(max8925_power_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Power supply driver for MAX8925");
index a23317d75c5a80e65bec82fdf89bdb1f6499f0a1..6e88c5d026b93485a942c3102cf27971cd64df1f 100644 (file)
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -98,7 +97,7 @@ static __devinit int max8997_battery_probe(struct platform_device *pdev)
                return -EINVAL;
 
        if (pdata->eoc_mA) {
-               u8 val = (pdata->eoc_mA - 50) / 10;
+               int val = (pdata->eoc_mA - 50) / 10;
                if (val < 0)
                        val = 0;
                if (val > 0xf)
@@ -179,6 +178,7 @@ static int __devexit max8997_battery_remove(struct platform_device *pdev)
 
 static const struct platform_device_id max8997_battery_id[] = {
        { "max8997-battery", 0 },
+       { }
 };
 
 static struct platform_driver max8997_battery_driver = {
index 93e3bb47a3a817ac7d1fbf0aa712bb77b0c181fd..9b3f2bf56e706b1375caaa788446dfafde697ff5 100644 (file)
@@ -154,6 +154,7 @@ static __devinit int max8998_battery_probe(struct platform_device *pdev)
        case 0:
                dev_dbg(max8998->dev,
                        "Full Timeout not set: leave it unchanged.\n");
+               break;
        default:
                dev_err(max8998->dev, "Invalid Full Timeout value\n");
                ret = -EINVAL;
@@ -190,6 +191,7 @@ static int __devexit max8998_battery_remove(struct platform_device *pdev)
 
 static const struct platform_device_id max8998_battery_id[] = {
        { "max8998-battery", TYPE_MAX8998 },
+       { }
 };
 
 static struct platform_driver max8998_battery_driver = {
@@ -202,17 +204,7 @@ static struct platform_driver max8998_battery_driver = {
        .id_table = max8998_battery_id,
 };
 
-static int __init max8998_battery_init(void)
-{
-       return platform_driver_register(&max8998_battery_driver);
-}
-module_init(max8998_battery_init);
-
-static void __exit max8998_battery_cleanup(void)
-{
-       platform_driver_unregister(&max8998_battery_driver);
-}
-module_exit(max8998_battery_cleanup);
+module_platform_driver(max8998_battery_driver);
 
 MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
index 0b0ff3a936a61722be4fbb9a48d0a9de44626f1f..7385092f9bc8a98a8dc09155238d6ee924ab6034 100644 (file)
@@ -519,29 +519,35 @@ static struct device_attribute olpc_bat_error = {
  *             Initialisation
  *********************************************************************/
 
-static struct platform_device *bat_pdev;
-
 static struct power_supply olpc_bat = {
+       .name = "olpc-battery",
        .get_property = olpc_bat_get_property,
        .use_for_apm = 1,
 };
 
-void olpc_battery_trigger_uevent(unsigned long cause)
+static int olpc_battery_suspend(struct platform_device *pdev,
+                               pm_message_t state)
 {
-       if (cause & EC_SCI_SRC_ACPWR)
-               kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE);
-       if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY))
-               kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE);
+       if (device_may_wakeup(olpc_ac.dev))
+               olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);
+       else
+               olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);
+
+       if (device_may_wakeup(olpc_bat.dev))
+               olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
+                                  | EC_SCI_SRC_BATERR);
+       else
+               olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
+                                    | EC_SCI_SRC_BATERR);
+
+       return 0;
 }
 
-static int __init olpc_bat_init(void)
+static int __devinit olpc_battery_probe(struct platform_device *pdev)
 {
-       int ret = 0;
+       int ret;
        uint8_t status;
 
-       if (!olpc_platform_info.ecver)
-               return -ENXIO;
-
        /*
         * We've seen a number of EC protocol changes; this driver requires
         * the latest EC protocol, supported by 0x44 and above.
@@ -558,15 +564,10 @@ static int __init olpc_bat_init(void)
 
        /* Ignore the status. It doesn't actually matter */
 
-       bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
-       if (IS_ERR(bat_pdev))
-               return PTR_ERR(bat_pdev);
-
-       ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
+       ret = power_supply_register(&pdev->dev, &olpc_ac);
        if (ret)
-               goto ac_failed;
+               return ret;
 
-       olpc_bat.name = bat_pdev->name;
        if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
                olpc_bat.properties = olpc_xo15_bat_props;
                olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
@@ -575,7 +576,7 @@ static int __init olpc_bat_init(void)
                olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
        }
 
-       ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
+       ret = power_supply_register(&pdev->dev, &olpc_bat);
        if (ret)
                goto battery_failed;
 
@@ -587,7 +588,12 @@ static int __init olpc_bat_init(void)
        if (ret)
                goto error_failed;
 
-       goto success;
+       if (olpc_ec_wakeup_available()) {
+               device_set_wakeup_capable(olpc_ac.dev, true);
+               device_set_wakeup_capable(olpc_bat.dev, true);
+       }
+
+       return 0;
 
 error_failed:
        device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
@@ -595,23 +601,36 @@ eeprom_failed:
        power_supply_unregister(&olpc_bat);
 battery_failed:
        power_supply_unregister(&olpc_ac);
-ac_failed:
-       platform_device_unregister(bat_pdev);
-success:
        return ret;
 }
 
-static void __exit olpc_bat_exit(void)
+static int __devexit olpc_battery_remove(struct platform_device *pdev)
 {
        device_remove_file(olpc_bat.dev, &olpc_bat_error);
        device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
        power_supply_unregister(&olpc_bat);
        power_supply_unregister(&olpc_ac);
-       platform_device_unregister(bat_pdev);
+       return 0;
 }
 
-module_init(olpc_bat_init);
-module_exit(olpc_bat_exit);
+static const struct of_device_id olpc_battery_ids[] __devinitconst = {
+       { .compatible = "olpc,xo1-battery" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, olpc_battery_ids);
+
+static struct platform_driver olpc_battery_driver = {
+       .driver = {
+               .name = "olpc-battery",
+               .owner = THIS_MODULE,
+               .of_match_table = olpc_battery_ids,
+       },
+       .probe = olpc_battery_probe,
+       .remove = __devexit_p(olpc_battery_remove),
+       .suspend = olpc_battery_suspend,
+};
+
+module_platform_driver(olpc_battery_driver);
 
 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
 MODULE_LICENSE("GPL");
index 4fa52e1781a225e5bad152a6dd9a6c5e76752503..3d1e9efb6f53bfcd9dd03f675e1518e6ab7ffb5e 100644 (file)
@@ -474,17 +474,7 @@ static struct platform_driver pcf50633_mbc_driver = {
        .remove = __devexit_p(pcf50633_mbc_remove),
 };
 
-static int __init pcf50633_mbc_init(void)
-{
-       return platform_driver_register(&pcf50633_mbc_driver);
-}
-module_init(pcf50633_mbc_init);
-
-static void __exit pcf50633_mbc_exit(void)
-{
-       platform_driver_unregister(&pcf50633_mbc_driver);
-}
-module_exit(pcf50633_mbc_exit);
+module_platform_driver(pcf50633_mbc_driver);
 
 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
 MODULE_DESCRIPTION("PCF50633 mbc driver");
index 69f8aa3a6a4bda06b34ed6e7d147b09d723eaedc..fd49689738af92a8c03e65264410fcc5e313c276 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
+#include <linux/notifier.h>
 #include <linux/power_supply.h>
 #include <linux/pda_power.h>
 #include <linux/regulator/consumer.h>
@@ -40,7 +41,9 @@ static int polling;
 
 #ifdef CONFIG_USB_OTG_UTILS
 static struct otg_transceiver *transceiver;
+static struct notifier_block otg_nb;
 #endif
+
 static struct regulator *ac_draw;
 
 enum {
@@ -222,7 +225,42 @@ static void polling_timer_func(unsigned long unused)
 #ifdef CONFIG_USB_OTG_UTILS
 static int otg_is_usb_online(void)
 {
-       return (transceiver->state == OTG_STATE_B_PERIPHERAL);
+       return (transceiver->last_event == USB_EVENT_VBUS ||
+               transceiver->last_event == USB_EVENT_ENUMERATED);
+}
+
+static int otg_is_ac_online(void)
+{
+       return (transceiver->last_event == USB_EVENT_CHARGER);
+}
+
+static int otg_handle_notification(struct notifier_block *nb,
+               unsigned long event, void *unused)
+{
+       switch (event) {
+       case USB_EVENT_CHARGER:
+               ac_status = PDA_PSY_TO_CHANGE;
+               break;
+       case USB_EVENT_VBUS:
+       case USB_EVENT_ENUMERATED:
+               usb_status = PDA_PSY_TO_CHANGE;
+               break;
+       case USB_EVENT_NONE:
+               ac_status = PDA_PSY_TO_CHANGE;
+               usb_status = PDA_PSY_TO_CHANGE;
+               break;
+       default:
+               return NOTIFY_OK;
+       }
+
+       /*
+        * Wait a bit before reading ac/usb line status and setting charger,
+        * because ac/usb status readings may lag from irq.
+        */
+       mod_timer(&charger_timer,
+                 jiffies + msecs_to_jiffies(pdata->wait_for_status));
+
+       return NOTIFY_OK;
 }
 #endif
 
@@ -282,6 +320,16 @@ static int pda_power_probe(struct platform_device *pdev)
                ret = PTR_ERR(ac_draw);
        }
 
+#ifdef CONFIG_USB_OTG_UTILS
+       transceiver = otg_get_transceiver();
+       if (transceiver && !pdata->is_usb_online) {
+               pdata->is_usb_online = otg_is_usb_online;
+       }
+       if (transceiver && !pdata->is_ac_online) {
+               pdata->is_ac_online = otg_is_ac_online;
+       }
+#endif
+
        if (pdata->is_ac_online) {
                ret = power_supply_register(&pdev->dev, &pda_psy_ac);
                if (ret) {
@@ -303,13 +351,6 @@ static int pda_power_probe(struct platform_device *pdev)
                }
        }
 
-#ifdef CONFIG_USB_OTG_UTILS
-       transceiver = otg_get_transceiver();
-       if (transceiver && !pdata->is_usb_online) {
-               pdata->is_usb_online = otg_is_usb_online;
-       }
-#endif
-
        if (pdata->is_usb_online) {
                ret = power_supply_register(&pdev->dev, &pda_psy_usb);
                if (ret) {
@@ -331,6 +372,18 @@ static int pda_power_probe(struct platform_device *pdev)
                }
        }
 
+#ifdef CONFIG_USB_OTG_UTILS
+       if (transceiver && pdata->use_otg_notifier) {
+               otg_nb.notifier_call = otg_handle_notification;
+               ret = otg_register_notifier(transceiver, &otg_nb);
+               if (ret) {
+                       dev_err(dev, "failure to register otg notifier\n");
+                       goto otg_reg_notifier_failed;
+               }
+               polling = 0;
+       }
+#endif
+
        if (polling) {
                dev_dbg(dev, "will poll for status\n");
                setup_timer(&polling_timer, polling_timer_func, 0);
@@ -343,6 +396,11 @@ static int pda_power_probe(struct platform_device *pdev)
 
        return 0;
 
+#ifdef CONFIG_USB_OTG_UTILS
+otg_reg_notifier_failed:
+       if (pdata->is_usb_online && usb_irq)
+               free_irq(usb_irq->start, &pda_psy_usb);
+#endif
 usb_irq_failed:
        if (pdata->is_usb_online)
                power_supply_unregister(&pda_psy_usb);
@@ -440,8 +498,6 @@ static int pda_power_resume(struct platform_device *pdev)
 #define pda_power_resume NULL
 #endif /* CONFIG_PM */
 
-MODULE_ALIAS("platform:pda-power");
-
 static struct platform_driver pda_power_pdrv = {
        .driver = {
                .name = "pda-power",
@@ -452,17 +508,8 @@ static struct platform_driver pda_power_pdrv = {
        .resume = pda_power_resume,
 };
 
-static int __init pda_power_init(void)
-{
-       return platform_driver_register(&pda_power_pdrv);
-}
+module_platform_driver(pda_power_pdrv);
 
-static void __exit pda_power_exit(void)
-{
-       platform_driver_unregister(&pda_power_pdrv);
-}
-
-module_init(pda_power_init);
-module_exit(pda_power_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
+MODULE_ALIAS("platform:pda-power");
index 329b46b2327d4110eaea4438f87f2570f2587e88..6ad612726785f48cdd8dbcc2785de8e211aae873 100644 (file)
@@ -98,7 +98,9 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
 {
        union power_supply_propval ret = {0,};
        struct power_supply *psy = dev_get_drvdata(dev);
+       unsigned int *count = data;
 
+       (*count)++;
        if (psy->type != POWER_SUPPLY_TYPE_BATTERY) {
                if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
                        return 0;
@@ -111,10 +113,18 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data)
 int power_supply_is_system_supplied(void)
 {
        int error;
+       unsigned int count = 0;
 
-       error = class_for_each_device(power_supply_class, NULL, NULL,
+       error = class_for_each_device(power_supply_class, NULL, &count,
                                      __power_supply_is_system_supplied);
 
+       /*
+        * If no power class device was found at all, most probably we are
+        * running on a desktop system, so assume we are on mains power.
+        */
+       if (count == 0)
+               return 1;
+
        return error;
 }
 EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
@@ -147,6 +157,12 @@ struct power_supply *power_supply_get_by_name(char *name)
 }
 EXPORT_SYMBOL_GPL(power_supply_get_by_name);
 
+int power_supply_powers(struct power_supply *psy, struct device *dev)
+{
+       return sysfs_create_link(&psy->dev->kobj, &dev->kobj, "powers");
+}
+EXPORT_SYMBOL_GPL(power_supply_powers);
+
 static void power_supply_dev_release(struct device *dev)
 {
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
@@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
 void power_supply_unregister(struct power_supply *psy)
 {
        cancel_work_sync(&psy->changed_work);
+       sysfs_remove_link(&psy->dev->kobj, "powers");
        power_supply_remove_triggers(psy);
        device_unregister(psy->dev);
 }
index e95cd657dac2abb6d2ff3111a816fc313a69f55b..b52b57ca3084737fcced57eca769783bc435a3fd 100644 (file)
@@ -43,7 +43,7 @@ static ssize_t power_supply_show_property(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf) {
        static char *type_text[] = {
-               "Battery", "UPS", "Mains", "USB",
+               "Unknown", "Battery", "UPS", "Mains", "USB",
                "USB_DCP", "USB_CDP", "USB_ACA"
        };
        static char *status_text[] = {
@@ -63,6 +63,9 @@ static ssize_t power_supply_show_property(struct device *dev,
        static char *capacity_level_text[] = {
                "Unknown", "Critical", "Low", "Normal", "High", "Full"
        };
+       static char *scope_text[] = {
+               "Unknown", "System", "Device"
+       };
        ssize_t ret = 0;
        struct power_supply *psy = dev_get_drvdata(dev);
        const ptrdiff_t off = attr - power_supply_attrs;
@@ -78,8 +81,8 @@ static ssize_t power_supply_show_property(struct device *dev,
                        dev_dbg(dev, "driver has no data for `%s' property\n",
                                attr->attr.name);
                else if (ret != -ENODEV)
-                       dev_err(dev, "driver failed to report `%s' property\n",
-                               attr->attr.name);
+                       dev_err(dev, "driver failed to report `%s' property: %zd\n",
+                               attr->attr.name, ret);
                return ret;
        }
 
@@ -95,6 +98,8 @@ static ssize_t power_supply_show_property(struct device *dev,
                return sprintf(buf, "%s\n", capacity_level_text[value.intval]);
        else if (off == POWER_SUPPLY_PROP_TYPE)
                return sprintf(buf, "%s\n", type_text[value.intval]);
+       else if (off == POWER_SUPPLY_PROP_SCOPE)
+               return sprintf(buf, "%s\n", scope_text[value.intval]);
        else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
                return sprintf(buf, "%s\n", value.strval);
 
@@ -167,6 +172,7 @@ static struct device_attribute power_supply_attrs[] = {
        POWER_SUPPLY_ATTR(time_to_full_now),
        POWER_SUPPLY_ATTR(time_to_full_avg),
        POWER_SUPPLY_ATTR(type),
+       POWER_SUPPLY_ATTR(scope),
        /* Properties of type `const char *' */
        POWER_SUPPLY_ATTR(model_name),
        POWER_SUPPLY_ATTR(manufacturer),
index d32d0d70f9ba951c21204a6fccaf9a2d61951f67..8b804a566756a11c06ce08a8cdadc10828e6bcc0 100644 (file)
@@ -47,6 +47,22 @@ static void s3c_adc_bat_ext_power_changed(struct power_supply *psy)
                msecs_to_jiffies(JITTER_DELAY));
 }
 
+static int gather_samples(struct s3c_adc_client *client, int num, int channel)
+{
+       int value, i;
+
+       /* default to 1 if nothing is set */
+       if (num < 1)
+               num = 1;
+
+       value = 0;
+       for (i = 0; i < num; i++)
+               value += s3c_adc_read(client, channel);
+       value /= num;
+
+       return value;
+}
+
 static enum power_supply_property s3c_adc_backup_bat_props[] = {
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_MIN,
@@ -67,7 +83,8 @@ static int s3c_adc_backup_bat_get_property(struct power_supply *psy,
        if (bat->volt_value < 0 ||
                jiffies_to_msecs(jiffies - bat->timestamp) >
                        BAT_POLL_INTERVAL) {
-               bat->volt_value = s3c_adc_read(bat->client,
+               bat->volt_value = gather_samples(bat->client,
+                       bat->pdata->backup_volt_samples,
                        bat->pdata->backup_volt_channel);
                bat->volt_value *= bat->pdata->backup_volt_mult;
                bat->timestamp = jiffies;
@@ -139,9 +156,11 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
        if (bat->volt_value < 0 || bat->cur_value < 0 ||
                jiffies_to_msecs(jiffies - bat->timestamp) >
                        BAT_POLL_INTERVAL) {
-               bat->volt_value = s3c_adc_read(bat->client,
+               bat->volt_value = gather_samples(bat->client,
+                       bat->pdata->volt_samples,
                        bat->pdata->volt_channel) * bat->pdata->volt_mult;
-               bat->cur_value = s3c_adc_read(bat->client,
+               bat->cur_value = gather_samples(bat->client,
+                       bat->pdata->current_samples,
                        bat->pdata->current_channel) * bat->pdata->current_mult;
                bat->timestamp = jiffies;
        }
@@ -421,17 +440,7 @@ static struct platform_driver s3c_adc_bat_driver = {
        .resume         = s3c_adc_bat_resume,
 };
 
-static int __init s3c_adc_bat_init(void)
-{
-       return platform_driver_register(&s3c_adc_bat_driver);
-}
-module_init(s3c_adc_bat_init);
-
-static void __exit s3c_adc_bat_exit(void)
-{
-       platform_driver_unregister(&s3c_adc_bat_driver);
-}
-module_exit(s3c_adc_bat_exit);
+module_platform_driver(s3c_adc_bat_driver);
 
 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
 MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver");
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
new file mode 100644 (file)
index 0000000..9ff8af0
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Gas Gauge driver for SBS Compliant Batteries
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <linux/power/sbs-battery.h>
+
+enum {
+       REG_MANUFACTURER_DATA,
+       REG_TEMPERATURE,
+       REG_VOLTAGE,
+       REG_CURRENT,
+       REG_CAPACITY,
+       REG_TIME_TO_EMPTY,
+       REG_TIME_TO_FULL,
+       REG_STATUS,
+       REG_CYCLE_COUNT,
+       REG_SERIAL_NUMBER,
+       REG_REMAINING_CAPACITY,
+       REG_REMAINING_CAPACITY_CHARGE,
+       REG_FULL_CHARGE_CAPACITY,
+       REG_FULL_CHARGE_CAPACITY_CHARGE,
+       REG_DESIGN_CAPACITY,
+       REG_DESIGN_CAPACITY_CHARGE,
+       REG_DESIGN_VOLTAGE,
+};
+
+/* Battery Mode defines */
+#define BATTERY_MODE_OFFSET            0x03
+#define BATTERY_MODE_MASK              0x8000
+enum sbs_battery_mode {
+       BATTERY_MODE_AMPS,
+       BATTERY_MODE_WATTS
+};
+
+/* manufacturer access defines */
+#define MANUFACTURER_ACCESS_STATUS     0x0006
+#define MANUFACTURER_ACCESS_SLEEP      0x0011
+
+/* battery status value bits */
+#define BATTERY_DISCHARGING            0x40
+#define BATTERY_FULL_CHARGED           0x20
+#define BATTERY_FULL_DISCHARGED                0x10
+
+#define SBS_DATA(_psp, _addr, _min_value, _max_value) { \
+       .psp = _psp, \
+       .addr = _addr, \
+       .min_value = _min_value, \
+       .max_value = _max_value, \
+}
+
+static const struct chip_data {
+       enum power_supply_property psp;
+       u8 addr;
+       int min_value;
+       int max_value;
+} sbs_data[] = {
+       [REG_MANUFACTURER_DATA] =
+               SBS_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535),
+       [REG_TEMPERATURE] =
+               SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535),
+       [REG_VOLTAGE] =
+               SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000),
+       [REG_CURRENT] =
+               SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767),
+       [REG_CAPACITY] =
+               SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100),
+       [REG_REMAINING_CAPACITY] =
+               SBS_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535),
+       [REG_REMAINING_CAPACITY_CHARGE] =
+               SBS_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535),
+       [REG_FULL_CHARGE_CAPACITY] =
+               SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535),
+       [REG_FULL_CHARGE_CAPACITY_CHARGE] =
+               SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535),
+       [REG_TIME_TO_EMPTY] =
+               SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535),
+       [REG_TIME_TO_FULL] =
+               SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535),
+       [REG_STATUS] =
+               SBS_DATA(POWER_SUPPLY_PROP_STATUS, 0x16, 0, 65535),
+       [REG_CYCLE_COUNT] =
+               SBS_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT, 0x17, 0, 65535),
+       [REG_DESIGN_CAPACITY] =
+               SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 65535),
+       [REG_DESIGN_CAPACITY_CHARGE] =
+               SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, 65535),
+       [REG_DESIGN_VOLTAGE] =
+               SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535),
+       [REG_SERIAL_NUMBER] =
+               SBS_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER, 0x1C, 0, 65535),
+};
+
+static enum power_supply_property sbs_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_CYCLE_COUNT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+       POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_ENERGY_NOW,
+       POWER_SUPPLY_PROP_ENERGY_FULL,
+       POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+};
+
+struct sbs_info {
+       struct i2c_client               *client;
+       struct power_supply             power_supply;
+       struct sbs_platform_data        *pdata;
+       bool                            is_present;
+       bool                            gpio_detect;
+       bool                            enable_detection;
+       int                             irq;
+       int                             last_state;
+       int                             poll_time;
+       struct delayed_work             work;
+       int                             ignore_changes;
+};
+
+static int sbs_read_word_data(struct i2c_client *client, u8 address)
+{
+       struct sbs_info *chip = i2c_get_clientdata(client);
+       s32 ret = 0;
+       int retries = 1;
+
+       if (chip->pdata)
+               retries = max(chip->pdata->i2c_retry_count + 1, 1);
+
+       while (retries > 0) {
+               ret = i2c_smbus_read_word_data(client, address);
+               if (ret >= 0)
+                       break;
+               retries--;
+       }
+
+       if (ret < 0) {
+               dev_dbg(&client->dev,
+                       "%s: i2c read at address 0x%x failed\n",
+                       __func__, address);
+               return ret;
+       }
+
+       return le16_to_cpu(ret);
+}
+
+static int sbs_write_word_data(struct i2c_client *client, u8 address,
+       u16 value)
+{
+       struct sbs_info *chip = i2c_get_clientdata(client);
+       s32 ret = 0;
+       int retries = 1;
+
+       if (chip->pdata)
+               retries = max(chip->pdata->i2c_retry_count + 1, 1);
+
+       while (retries > 0) {
+               ret = i2c_smbus_write_word_data(client, address,
+                       le16_to_cpu(value));
+               if (ret >= 0)
+                       break;
+               retries--;
+       }
+
+       if (ret < 0) {
+               dev_dbg(&client->dev,
+                       "%s: i2c write to address 0x%x failed\n",
+                       __func__, address);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sbs_get_battery_presence_and_health(
+       struct i2c_client *client, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       s32 ret;
+       struct sbs_info *chip = i2c_get_clientdata(client);
+
+       if (psp == POWER_SUPPLY_PROP_PRESENT &&
+               chip->gpio_detect) {
+               ret = gpio_get_value(chip->pdata->battery_detect);
+               if (ret == chip->pdata->battery_detect_present)
+                       val->intval = 1;
+               else
+                       val->intval = 0;
+               chip->is_present = val->intval;
+               return ret;
+       }
+
+       /* Write to ManufacturerAccess with
+        * ManufacturerAccess command and then
+        * read the status */
+       ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
+                                       MANUFACTURER_ACCESS_STATUS);
+       if (ret < 0) {
+               if (psp == POWER_SUPPLY_PROP_PRESENT)
+                       val->intval = 0; /* battery removed */
+               return ret;
+       }
+
+       ret = sbs_read_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr);
+       if (ret < 0)
+               return ret;
+
+       if (ret < sbs_data[REG_MANUFACTURER_DATA].min_value ||
+           ret > sbs_data[REG_MANUFACTURER_DATA].max_value) {
+               val->intval = 0;
+               return 0;
+       }
+
+       /* Mask the upper nibble of 2nd byte and
+        * lower byte of response then
+        * shift the result by 8 to get status*/
+       ret &= 0x0F00;
+       ret >>= 8;
+       if (psp == POWER_SUPPLY_PROP_PRESENT) {
+               if (ret == 0x0F)
+                       /* battery removed */
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+       } else if (psp == POWER_SUPPLY_PROP_HEALTH) {
+               if (ret == 0x09)
+                       val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+               else if (ret == 0x0B)
+                       val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+               else if (ret == 0x0C)
+                       val->intval = POWER_SUPPLY_HEALTH_DEAD;
+               else
+                       val->intval = POWER_SUPPLY_HEALTH_GOOD;
+       }
+
+       return 0;
+}
+
+static int sbs_get_battery_property(struct i2c_client *client,
+       int reg_offset, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       struct sbs_info *chip = i2c_get_clientdata(client);
+       s32 ret;
+
+       ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
+       if (ret < 0)
+               return ret;
+
+       /* returned values are 16 bit */
+       if (sbs_data[reg_offset].min_value < 0)
+               ret = (s16)ret;
+
+       if (ret >= sbs_data[reg_offset].min_value &&
+           ret <= sbs_data[reg_offset].max_value) {
+               val->intval = ret;
+               if (psp != POWER_SUPPLY_PROP_STATUS)
+                       return 0;
+
+               if (ret & BATTERY_FULL_CHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+               else if (ret & BATTERY_FULL_DISCHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else if (ret & BATTERY_DISCHARGING)
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+
+               if (chip->poll_time == 0)
+                       chip->last_state = val->intval;
+               else if (chip->last_state != val->intval) {
+                       cancel_delayed_work_sync(&chip->work);
+                       power_supply_changed(&chip->power_supply);
+                       chip->poll_time = 0;
+               }
+       } else {
+               if (psp == POWER_SUPPLY_PROP_STATUS)
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+               else
+                       val->intval = 0;
+       }
+
+       return 0;
+}
+
+static void  sbs_unit_adjustment(struct i2c_client *client,
+       enum power_supply_property psp, union power_supply_propval *val)
+{
+#define BASE_UNIT_CONVERSION           1000
+#define BATTERY_MODE_CAP_MULT_WATT     (10 * BASE_UNIT_CONVERSION)
+#define TIME_UNIT_CONVERSION           60
+#define TEMP_KELVIN_TO_CELSIUS         2731
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+               /* sbs provides energy in units of 10mWh.
+                * Convert to ÂµWh
+                */
+               val->intval *= BATTERY_MODE_CAP_MULT_WATT;
+               break;
+
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+               val->intval *= BASE_UNIT_CONVERSION;
+               break;
+
+       case POWER_SUPPLY_PROP_TEMP:
+               /* sbs provides battery temperature in 0.1K
+                * so convert it to 0.1°C
+                */
+               val->intval -= TEMP_KELVIN_TO_CELSIUS;
+               break;
+
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+               /* sbs provides time to empty and time to full in minutes.
+                * Convert to seconds
+                */
+               val->intval *= TIME_UNIT_CONVERSION;
+               break;
+
+       default:
+               dev_dbg(&client->dev,
+                       "%s: no need for unit conversion %d\n", __func__, psp);
+       }
+}
+
+static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client,
+       enum sbs_battery_mode mode)
+{
+       int ret, original_val;
+
+       original_val = sbs_read_word_data(client, BATTERY_MODE_OFFSET);
+       if (original_val < 0)
+               return original_val;
+
+       if ((original_val & BATTERY_MODE_MASK) == mode)
+               return mode;
+
+       if (mode == BATTERY_MODE_AMPS)
+               ret = original_val & ~BATTERY_MODE_MASK;
+       else
+               ret = original_val | BATTERY_MODE_MASK;
+
+       ret = sbs_write_word_data(client, BATTERY_MODE_OFFSET, ret);
+       if (ret < 0)
+               return ret;
+
+       return original_val & BATTERY_MODE_MASK;
+}
+
+static int sbs_get_battery_capacity(struct i2c_client *client,
+       int reg_offset, enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       s32 ret;
+       enum sbs_battery_mode mode = BATTERY_MODE_WATTS;
+
+       if (power_supply_is_amp_property(psp))
+               mode = BATTERY_MODE_AMPS;
+
+       mode = sbs_set_battery_mode(client, mode);
+       if (mode < 0)
+               return mode;
+
+       ret = sbs_read_word_data(client, sbs_data[reg_offset].addr);
+       if (ret < 0)
+               return ret;
+
+       if (psp == POWER_SUPPLY_PROP_CAPACITY) {
+               /* sbs spec says that this can be >100 %
+               * even if max value is 100 % */
+               val->intval = min(ret, 100);
+       } else
+               val->intval = ret;
+
+       ret = sbs_set_battery_mode(client, mode);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static char sbs_serial[5];
+static int sbs_get_battery_serial_number(struct i2c_client *client,
+       union power_supply_propval *val)
+{
+       int ret;
+
+       ret = sbs_read_word_data(client, sbs_data[REG_SERIAL_NUMBER].addr);
+       if (ret < 0)
+               return ret;
+
+       ret = sprintf(sbs_serial, "%04x", ret);
+       val->strval = sbs_serial;
+
+       return 0;
+}
+
+static int sbs_get_property_index(struct i2c_client *client,
+       enum power_supply_property psp)
+{
+       int count;
+       for (count = 0; count < ARRAY_SIZE(sbs_data); count++)
+               if (psp == sbs_data[count].psp)
+                       return count;
+
+       dev_warn(&client->dev,
+               "%s: Invalid Property - %d\n", __func__, psp);
+
+       return -EINVAL;
+}
+
+static int sbs_get_property(struct power_supply *psy,
+       enum power_supply_property psp,
+       union power_supply_propval *val)
+{
+       int ret = 0;
+       struct sbs_info *chip = container_of(psy,
+                               struct sbs_info, power_supply);
+       struct i2c_client *client = chip->client;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = sbs_get_battery_presence_and_health(client, psp, val);
+               if (psp == POWER_SUPPLY_PROP_PRESENT)
+                       return 0;
+               break;
+
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+
+       case POWER_SUPPLY_PROP_ENERGY_NOW:
+       case POWER_SUPPLY_PROP_ENERGY_FULL:
+       case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+       case POWER_SUPPLY_PROP_CAPACITY:
+               ret = sbs_get_property_index(client, psp);
+               if (ret < 0)
+                       break;
+
+               ret = sbs_get_battery_capacity(client, ret, psp, val);
+               break;
+
+       case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+               ret = sbs_get_battery_serial_number(client, val);
+               break;
+
+       case POWER_SUPPLY_PROP_STATUS:
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+       case POWER_SUPPLY_PROP_TEMP:
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
+       case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               ret = sbs_get_property_index(client, psp);
+               if (ret < 0)
+                       break;
+
+               ret = sbs_get_battery_property(client, ret, psp, val);
+               break;
+
+       default:
+               dev_err(&client->dev,
+                       "%s: INVALID property\n", __func__);
+               return -EINVAL;
+       }
+
+       if (!chip->enable_detection)
+               goto done;
+
+       if (!chip->gpio_detect &&
+               chip->is_present != (ret >= 0)) {
+               chip->is_present = (ret >= 0);
+               power_supply_changed(&chip->power_supply);
+       }
+
+done:
+       if (!ret) {
+               /* Convert units to match requirements for power supply class */
+               sbs_unit_adjustment(client, psp, val);
+       }
+
+       dev_dbg(&client->dev,
+               "%s: property = %d, value = %x\n", __func__, psp, val->intval);
+
+       if (ret && chip->is_present)
+               return ret;
+
+       /* battery not present, so return NODATA for properties */
+       if (ret)
+               return -ENODATA;
+
+       return 0;
+}
+
+static irqreturn_t sbs_irq(int irq, void *devid)
+{
+       struct power_supply *battery = devid;
+
+       power_supply_changed(battery);
+
+       return IRQ_HANDLED;
+}
+
+static void sbs_external_power_changed(struct power_supply *psy)
+{
+       struct sbs_info *chip;
+
+       chip = container_of(psy, struct sbs_info, power_supply);
+
+       if (chip->ignore_changes > 0) {
+               chip->ignore_changes--;
+               return;
+       }
+
+       /* cancel outstanding work */
+       cancel_delayed_work_sync(&chip->work);
+
+       schedule_delayed_work(&chip->work, HZ);
+       chip->poll_time = chip->pdata->poll_retry_count;
+}
+
+static void sbs_delayed_work(struct work_struct *work)
+{
+       struct sbs_info *chip;
+       s32 ret;
+
+       chip = container_of(work, struct sbs_info, work.work);
+
+       ret = sbs_read_word_data(chip->client, sbs_data[REG_STATUS].addr);
+       /* if the read failed, give up on this work */
+       if (ret < 0) {
+               chip->poll_time = 0;
+               return;
+       }
+
+       if (ret & BATTERY_FULL_CHARGED)
+               ret = POWER_SUPPLY_STATUS_FULL;
+       else if (ret & BATTERY_FULL_DISCHARGED)
+               ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       else if (ret & BATTERY_DISCHARGING)
+               ret = POWER_SUPPLY_STATUS_DISCHARGING;
+       else
+               ret = POWER_SUPPLY_STATUS_CHARGING;
+
+       if (chip->last_state != ret) {
+               chip->poll_time = 0;
+               power_supply_changed(&chip->power_supply);
+               return;
+       }
+       if (chip->poll_time > 0) {
+               schedule_delayed_work(&chip->work, HZ);
+               chip->poll_time--;
+               return;
+       }
+}
+
+#if defined(CONFIG_OF)
+
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+static const struct of_device_id sbs_dt_ids[] = {
+       { .compatible = "sbs,sbs-battery" },
+       { .compatible = "ti,bq20z75" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sbs_dt_ids);
+
+static struct sbs_platform_data *sbs_of_populate_pdata(
+               struct i2c_client *client)
+{
+       struct device_node *of_node = client->dev.of_node;
+       struct sbs_platform_data *pdata = client->dev.platform_data;
+       enum of_gpio_flags gpio_flags;
+       int rc;
+       u32 prop;
+
+       /* verify this driver matches this device */
+       if (!of_node)
+               return NULL;
+
+       /* if platform data is set, honor it */
+       if (pdata)
+               return pdata;
+
+       /* first make sure at least one property is set, otherwise
+        * it won't change behavior from running without pdata.
+        */
+       if (!of_get_property(of_node, "sbs,i2c-retry-count", NULL) &&
+               !of_get_property(of_node, "sbs,poll-retry-count", NULL) &&
+               !of_get_property(of_node, "sbs,battery-detect-gpios", NULL))
+               goto of_out;
+
+       pdata = devm_kzalloc(&client->dev, sizeof(struct sbs_platform_data),
+                               GFP_KERNEL);
+       if (!pdata)
+               goto of_out;
+
+       rc = of_property_read_u32(of_node, "sbs,i2c-retry-count", &prop);
+       if (!rc)
+               pdata->i2c_retry_count = prop;
+
+       rc = of_property_read_u32(of_node, "sbs,poll-retry-count", &prop);
+       if (!rc)
+               pdata->poll_retry_count = prop;
+
+       if (!of_get_property(of_node, "sbs,battery-detect-gpios", NULL)) {
+               pdata->battery_detect = -1;
+               goto of_out;
+       }
+
+       pdata->battery_detect = of_get_named_gpio_flags(of_node,
+                       "sbs,battery-detect-gpios", 0, &gpio_flags);
+
+       if (gpio_flags & OF_GPIO_ACTIVE_LOW)
+               pdata->battery_detect_present = 0;
+       else
+               pdata->battery_detect_present = 1;
+
+of_out:
+       return pdata;
+}
+#else
+#define sbs_dt_ids NULL
+static struct sbs_platform_data *sbs_of_populate_pdata(
+       struct i2c_client *client)
+{
+       return client->dev.platform_data;
+}
+#endif
+
+static int __devinit sbs_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       struct sbs_info *chip;
+       struct sbs_platform_data *pdata = client->dev.platform_data;
+       int rc;
+       int irq;
+       char *name;
+
+       name = kasprintf(GFP_KERNEL, "sbs-%s", dev_name(&client->dev));
+       if (!name) {
+               dev_err(&client->dev, "Failed to allocate device name\n");
+               return -ENOMEM;
+       }
+
+       chip = kzalloc(sizeof(struct sbs_info), GFP_KERNEL);
+       if (!chip) {
+               rc = -ENOMEM;
+               goto exit_free_name;
+       }
+
+       chip->client = client;
+       chip->enable_detection = false;
+       chip->gpio_detect = false;
+       chip->power_supply.name = name;
+       chip->power_supply.type = POWER_SUPPLY_TYPE_BATTERY;
+       chip->power_supply.properties = sbs_properties;
+       chip->power_supply.num_properties = ARRAY_SIZE(sbs_properties);
+       chip->power_supply.get_property = sbs_get_property;
+       /* ignore first notification of external change, it is generated
+        * from the power_supply_register call back
+        */
+       chip->ignore_changes = 1;
+       chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+       chip->power_supply.external_power_changed = sbs_external_power_changed;
+
+       pdata = sbs_of_populate_pdata(client);
+
+       if (pdata) {
+               chip->gpio_detect = gpio_is_valid(pdata->battery_detect);
+               chip->pdata = pdata;
+       }
+
+       i2c_set_clientdata(client, chip);
+
+       if (!chip->gpio_detect)
+               goto skip_gpio;
+
+       rc = gpio_request(pdata->battery_detect, dev_name(&client->dev));
+       if (rc) {
+               dev_warn(&client->dev, "Failed to request gpio: %d\n", rc);
+               chip->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       rc = gpio_direction_input(pdata->battery_detect);
+       if (rc) {
+               dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc);
+               gpio_free(pdata->battery_detect);
+               chip->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       irq = gpio_to_irq(pdata->battery_detect);
+       if (irq <= 0) {
+               dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq);
+               gpio_free(pdata->battery_detect);
+               chip->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       rc = request_irq(irq, sbs_irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+               dev_name(&client->dev), &chip->power_supply);
+       if (rc) {
+               dev_warn(&client->dev, "Failed to request irq: %d\n", rc);
+               gpio_free(pdata->battery_detect);
+               chip->gpio_detect = false;
+               goto skip_gpio;
+       }
+
+       chip->irq = irq;
+
+skip_gpio:
+
+       rc = power_supply_register(&client->dev, &chip->power_supply);
+       if (rc) {
+               dev_err(&client->dev,
+                       "%s: Failed to register power supply\n", __func__);
+               goto exit_psupply;
+       }
+
+       dev_info(&client->dev,
+               "%s: battery gas gauge device registered\n", client->name);
+
+       INIT_DELAYED_WORK(&chip->work, sbs_delayed_work);
+
+       chip->enable_detection = true;
+
+       return 0;
+
+exit_psupply:
+       if (chip->irq)
+               free_irq(chip->irq, &chip->power_supply);
+       if (chip->gpio_detect)
+               gpio_free(pdata->battery_detect);
+
+       kfree(chip);
+
+exit_free_name:
+       kfree(name);
+
+       return rc;
+}
+
+static int __devexit sbs_remove(struct i2c_client *client)
+{
+       struct sbs_info *chip = i2c_get_clientdata(client);
+
+       if (chip->irq)
+               free_irq(chip->irq, &chip->power_supply);
+       if (chip->gpio_detect)
+               gpio_free(chip->pdata->battery_detect);
+
+       power_supply_unregister(&chip->power_supply);
+
+       cancel_delayed_work_sync(&chip->work);
+
+       kfree(chip->power_supply.name);
+       kfree(chip);
+       chip = NULL;
+
+       return 0;
+}
+
+#if defined CONFIG_PM
+static int sbs_suspend(struct i2c_client *client,
+       pm_message_t state)
+{
+       struct sbs_info *chip = i2c_get_clientdata(client);
+       s32 ret;
+
+       if (chip->poll_time > 0)
+               cancel_delayed_work_sync(&chip->work);
+
+       /* write to manufacturer access with sleep command */
+       ret = sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr,
+               MANUFACTURER_ACCESS_SLEEP);
+       if (chip->is_present && ret < 0)
+               return ret;
+
+       return 0;
+}
+#else
+#define sbs_suspend            NULL
+#endif
+/* any smbus transaction will wake up sbs */
+#define sbs_resume             NULL
+
+static const struct i2c_device_id sbs_id[] = {
+       { "bq20z75", 0 },
+       { "sbs-battery", 1 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, sbs_id);
+
+static struct i2c_driver sbs_battery_driver = {
+       .probe          = sbs_probe,
+       .remove         = __devexit_p(sbs_remove),
+       .suspend        = sbs_suspend,
+       .resume         = sbs_resume,
+       .id_table       = sbs_id,
+       .driver = {
+               .name   = "sbs-battery",
+               .of_match_table = sbs_dt_ids,
+       },
+};
+
+static int __init sbs_battery_init(void)
+{
+       return i2c_add_driver(&sbs_battery_driver);
+}
+module_init(sbs_battery_init);
+
+static void __exit sbs_battery_exit(void)
+{
+       i2c_del_driver(&sbs_battery_driver);
+}
+module_exit(sbs_battery_exit);
+
+MODULE_DESCRIPTION("SBS battery monitor driver");
+MODULE_LICENSE("GPL");
index 53f0d3524fcd58f483a0ebcda42ccc0a353726e8..28bbe7e094e36a7695ffaf4a81e3e3e50dbf5ca4 100644 (file)
@@ -307,25 +307,20 @@ static struct tosa_bat tosa_bat_bu = {
        .adc_temp_divider = -1,
 };
 
-static struct {
-       int gpio;
-       char *name;
-       bool output;
-       int value;
-} gpios[] = {
-       { TOSA_GPIO_CHARGE_OFF,         "main charge off",      1, 1 },
-       { TOSA_GPIO_CHARGE_OFF_JC,      "jacket charge off",    1, 1 },
-       { TOSA_GPIO_BAT_SW_ON,          "battery switch",       1, 0 },
-       { TOSA_GPIO_BAT0_V_ON,          "main battery",         1, 0 },
-       { TOSA_GPIO_BAT1_V_ON,          "jacket battery",       1, 0 },
-       { TOSA_GPIO_BAT1_TH_ON,         "main battery temp",    1, 0 },
-       { TOSA_GPIO_BAT0_TH_ON,         "jacket battery temp",  1, 0 },
-       { TOSA_GPIO_BU_CHRG_ON,         "backup battery",       1, 0 },
-       { TOSA_GPIO_BAT0_CRG,           "main battery full",    0, 0 },
-       { TOSA_GPIO_BAT1_CRG,           "jacket battery full",  0, 0 },
-       { TOSA_GPIO_BAT0_LOW,           "main battery low",     0, 0 },
-       { TOSA_GPIO_BAT1_LOW,           "jacket battery low",   0, 0 },
-       { TOSA_GPIO_JACKET_DETECT,      "jacket detect",        0, 0 },
+static struct gpio tosa_bat_gpios[] = {
+       { TOSA_GPIO_CHARGE_OFF,    GPIOF_OUT_INIT_HIGH, "main charge off" },
+       { TOSA_GPIO_CHARGE_OFF_JC, GPIOF_OUT_INIT_HIGH, "jacket charge off" },
+       { TOSA_GPIO_BAT_SW_ON,     GPIOF_OUT_INIT_LOW,  "battery switch" },
+       { TOSA_GPIO_BAT0_V_ON,     GPIOF_OUT_INIT_LOW,  "main battery" },
+       { TOSA_GPIO_BAT1_V_ON,     GPIOF_OUT_INIT_LOW,  "jacket battery" },
+       { TOSA_GPIO_BAT1_TH_ON,    GPIOF_OUT_INIT_LOW,  "main battery temp" },
+       { TOSA_GPIO_BAT0_TH_ON,    GPIOF_OUT_INIT_LOW,  "jacket battery temp" },
+       { TOSA_GPIO_BU_CHRG_ON,    GPIOF_OUT_INIT_LOW,  "backup battery" },
+       { TOSA_GPIO_BAT0_CRG,      GPIOF_IN,            "main battery full" },
+       { TOSA_GPIO_BAT1_CRG,      GPIOF_IN,            "jacket battery full" },
+       { TOSA_GPIO_BAT0_LOW,      GPIOF_IN,            "main battery low" },
+       { TOSA_GPIO_BAT1_LOW,      GPIOF_IN,            "jacket battery low" },
+       { TOSA_GPIO_JACKET_DETECT, GPIOF_IN,            "jacket detect" },
 };
 
 #ifdef CONFIG_PM
@@ -350,27 +345,13 @@ static int tosa_bat_resume(struct platform_device *dev)
 static int __devinit tosa_bat_probe(struct platform_device *dev)
 {
        int ret;
-       int i;
 
        if (!machine_is_tosa())
                return -ENODEV;
 
-       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
-               ret = gpio_request(gpios[i].gpio, gpios[i].name);
-               if (ret) {
-                       i--;
-                       goto err_gpio;
-               }
-
-               if (gpios[i].output)
-                       ret = gpio_direction_output(gpios[i].gpio,
-                                       gpios[i].value);
-               else
-                       ret = gpio_direction_input(gpios[i].gpio);
-
-               if (ret)
-                       goto err_gpio;
-       }
+       ret = gpio_request_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
+       if (ret)
+               return ret;
 
        mutex_init(&tosa_bat_main.work_lock);
        mutex_init(&tosa_bat_jacket.work_lock);
@@ -424,18 +405,12 @@ err_psy_reg_main:
        /* see comment in tosa_bat_remove */
        cancel_work_sync(&bat_work);
 
-       i--;
-err_gpio:
-       for (; i >= 0; i--)
-               gpio_free(gpios[i].gpio);
-
+       gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
        return ret;
 }
 
 static int __devexit tosa_bat_remove(struct platform_device *dev)
 {
-       int i;
-
        free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket);
        free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
        free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
@@ -450,10 +425,7 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
         * unregistered now.
         */
        cancel_work_sync(&bat_work);
-
-       for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
-               gpio_free(gpios[i].gpio);
-
+       gpio_free_array(tosa_bat_gpios, ARRAY_SIZE(tosa_bat_gpios));
        return 0;
 }
 
@@ -466,18 +438,7 @@ static struct platform_driver tosa_bat_driver = {
        .resume         = tosa_bat_resume,
 };
 
-static int __init tosa_bat_init(void)
-{
-       return platform_driver_register(&tosa_bat_driver);
-}
-
-static void __exit tosa_bat_exit(void)
-{
-       platform_driver_unregister(&tosa_bat_driver);
-}
-
-module_init(tosa_bat_init);
-module_exit(tosa_bat_exit);
+module_platform_driver(tosa_bat_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Dmitry Baryshkov");
index e648cbea1e6ac513349d31682114c5e56e4fcabd..6243e69751261e17fc2e89f5766bda8e52f32f01 100644 (file)
@@ -226,17 +226,7 @@ static struct platform_driver wm831x_backup_driver = {
        },
 };
 
-static int __init wm831x_backup_init(void)
-{
-       return platform_driver_register(&wm831x_backup_driver);
-}
-module_init(wm831x_backup_init);
-
-static void __exit wm831x_backup_exit(void)
-{
-       platform_driver_unregister(&wm831x_backup_driver);
-}
-module_exit(wm831x_backup_exit);
+module_platform_driver(wm831x_backup_driver);
 
 MODULE_DESCRIPTION("Backup battery charger driver for WM831x PMICs");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 6cc2ca6427f337460152ca9ab257d3575396e465..987332b71d8de3ddfbfab813800cac880e48e53d 100644 (file)
@@ -27,6 +27,7 @@ struct wm831x_power {
        char wall_name[20];
        char usb_name[20];
        char battery_name[20];
+       bool have_battery;
 };
 
 static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
@@ -449,7 +450,8 @@ static irqreturn_t wm831x_bat_irq(int irq, void *data)
 
        /* The battery charger is autonomous so we don't need to do
         * anything except kick user space */
-       power_supply_changed(&wm831x_power->battery);
+       if (wm831x_power->have_battery)
+               power_supply_changed(&wm831x_power->battery);
 
        return IRQ_HANDLED;
 }
@@ -479,7 +481,8 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
        dev_dbg(wm831x->dev, "Power source changed\n");
 
        /* Just notify for everything - little harm in overnotifying. */
-       power_supply_changed(&wm831x_power->battery);
+       if (wm831x_power->have_battery)
+               power_supply_changed(&wm831x_power->battery);
        power_supply_changed(&wm831x_power->usb);
        power_supply_changed(&wm831x_power->wall);
 
@@ -537,15 +540,6 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret)
                goto err_kmalloc;
 
-       battery->name = power->battery_name;
-       battery->properties = wm831x_bat_props;
-       battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
-       battery->get_property = wm831x_bat_get_prop;
-       battery->use_for_apm = 1;
-       ret = power_supply_register(&pdev->dev, battery);
-       if (ret)
-               goto err_wall;
-
        usb->name = power->usb_name,
        usb->type = POWER_SUPPLY_TYPE_USB;
        usb->properties = wm831x_usb_props;
@@ -553,7 +547,23 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        usb->get_property = wm831x_usb_get_prop;
        ret = power_supply_register(&pdev->dev, usb);
        if (ret)
-               goto err_battery;
+               goto err_wall;
+
+       ret = wm831x_reg_read(wm831x, WM831X_CHARGER_CONTROL_1);
+       if (ret < 0)
+               goto err_wall;
+       power->have_battery = ret & WM831X_CHG_ENA;
+
+       if (power->have_battery) {
+                   battery->name = power->battery_name;
+                   battery->properties = wm831x_bat_props;
+                   battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
+                   battery->get_property = wm831x_bat_get_prop;
+                   battery->use_for_apm = 1;
+                   ret = power_supply_register(&pdev->dev, battery);
+                   if (ret)
+                           goto err_usb;
+       }
 
        irq = platform_get_irq_byname(pdev, "SYSLO");
        ret = request_threaded_irq(irq, NULL, wm831x_syslo_irq,
@@ -562,7 +572,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request SYSLO IRQ %d: %d\n",
                        irq, ret);
-               goto err_usb;
+               goto err_battery;
        }
 
        irq = platform_get_irq_byname(pdev, "PWR SRC");
@@ -601,10 +611,11 @@ err_bat_irq:
 err_syslo:
        irq = platform_get_irq_byname(pdev, "SYSLO");
        free_irq(irq, power);
+err_battery:
+       if (power->have_battery)
+               power_supply_unregister(battery);
 err_usb:
        power_supply_unregister(usb);
-err_battery:
-       power_supply_unregister(battery);
 err_wall:
        power_supply_unregister(wall);
 err_kmalloc:
@@ -628,7 +639,8 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev)
        irq = platform_get_irq_byname(pdev, "SYSLO");
        free_irq(irq, wm831x_power);
 
-       power_supply_unregister(&wm831x_power->battery);
+       if (wm831x_power->have_battery)
+               power_supply_unregister(&wm831x_power->battery);
        power_supply_unregister(&wm831x_power->wall);
        power_supply_unregister(&wm831x_power->usb);
        kfree(wm831x_power);
@@ -643,17 +655,7 @@ static struct platform_driver wm831x_power_driver = {
        },
 };
 
-static int __init wm831x_power_init(void)
-{
-       return platform_driver_register(&wm831x_power_driver);
-}
-module_init(wm831x_power_init);
-
-static void __exit wm831x_power_exit(void)
-{
-       platform_driver_unregister(&wm831x_power_driver);
-}
-module_exit(wm831x_power_exit);
+module_platform_driver(wm831x_power_driver);
 
 MODULE_DESCRIPTION("Power supply driver for WM831x PMICs");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 0693902d6151a9aaba4e73bed6201ad11aeda590..fae04d3846570dd62d51d5baaa555437c5b42d76 100644 (file)
@@ -522,17 +522,7 @@ static struct platform_driver wm8350_power_driver = {
        },
 };
 
-static int __init wm8350_power_init(void)
-{
-       return platform_driver_register(&wm8350_power_driver);
-}
-module_init(wm8350_power_init);
-
-static void __exit wm8350_power_exit(void)
-{
-       platform_driver_unregister(&wm8350_power_driver);
-}
-module_exit(wm8350_power_exit);
+module_platform_driver(wm8350_power_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Power supply driver for WM8350");
index 156559e56fa5e808e48ce095efde1b3178767e91..d2d4c08c681cd99f1eef9b1a477830289b533f70 100644 (file)
@@ -25,9 +25,8 @@
 #include <linux/irq.h>
 #include <linux/slab.h>
 
-static DEFINE_MUTEX(bat_lock);
 static struct work_struct bat_work;
-static struct mutex work_lock;
+static DEFINE_MUTEX(work_lock);
 static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
 static enum power_supply_property *prop;
 
@@ -181,8 +180,6 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
        if (dev->id != -1)
                return -EINVAL;
 
-       mutex_init(&work_lock);
-
        if (!pdata) {
                dev_err(&dev->dev, "No platform_data supplied\n");
                return -EINVAL;
@@ -196,7 +193,7 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev)
                if (ret)
                        goto err2;
                ret = request_irq(gpio_to_irq(pdata->charge_gpio),
-                               wm97xx_chrg_irq, IRQF_DISABLED,
+                               wm97xx_chrg_irq, 0,
                                "AC Detect", dev);
                if (ret)
                        goto err2;
@@ -291,18 +288,7 @@ static struct platform_driver wm97xx_bat_driver = {
        .remove         = __devexit_p(wm97xx_bat_remove),
 };
 
-static int __init wm97xx_bat_init(void)
-{
-       return platform_driver_register(&wm97xx_bat_driver);
-}
-
-static void __exit wm97xx_bat_exit(void)
-{
-       platform_driver_unregister(&wm97xx_bat_driver);
-}
-
-module_init(wm97xx_bat_init);
-module_exit(wm97xx_bat_exit);
+module_platform_driver(wm97xx_bat_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
index d119c38b3ff632ef158f66a971799c522202c6a3..636ebb2a0e807bd44e28f902200cabdf16e399b9 100644 (file)
@@ -218,7 +218,7 @@ static int __devinit z2_batt_probe(struct i2c_client *client,
                irq_set_irq_type(gpio_to_irq(info->charge_gpio),
                                 IRQ_TYPE_EDGE_BOTH);
                ret = request_irq(gpio_to_irq(info->charge_gpio),
-                               z2_charge_switch_irq, IRQF_DISABLED,
+                               z2_charge_switch_irq, 0,
                                "AC Detect", charger);
                if (ret)
                        goto err3;
@@ -313,7 +313,7 @@ static struct i2c_driver z2_batt_driver = {
                .pm     = Z2_BATTERY_PM_OPS
        },
        .probe          = z2_batt_probe,
-       .remove         = z2_batt_remove,
+       .remove         = __devexit_p(z2_batt_remove),
        .id_table       = z2_batt_id,
 };
 
index e91b8ddc2793120b9e4e3697aa6912ab4358d2e2..c9b92531ae601a75e4dd54f9f206d00b6fd11e54 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
 #include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/ab8500.h>
index 877cf6fdcf24be411a0b8c081d5019b4ce3b7d77..e19a4031f45e9b3ad3e1e677afa2dffd271bb4fc 100644 (file)
@@ -498,9 +498,9 @@ config RTC_DRV_CMOS
          will be called rtc-cmos.
 
 config RTC_DRV_VRTC
-       tristate "Virtual RTC for Moorestown platforms"
-       depends on X86_MRST
-       default y if X86_MRST
+       tristate "Virtual RTC for Intel MID platforms"
+       depends on X86_INTEL_MID
+       default y if X86_INTEL_MID
 
        help
        Say "yes" here to get direct support for the real time clock
index 8e286259a007fbc5921b4c569cdb959f62762f7a..8a1c031391d66f00a2c276325841bea20546e3c4 100644 (file)
@@ -228,11 +228,11 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                alarm->time.tm_hour = now.tm_hour;
 
        /* For simplicity, only support date rollover for now */
-       if (alarm->time.tm_mday == -1) {
+       if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
                alarm->time.tm_mday = now.tm_mday;
                missing = day;
        }
-       if (alarm->time.tm_mon == -1) {
+       if ((unsigned)alarm->time.tm_mon >= 12) {
                alarm->time.tm_mon = now.tm_mon;
                if (missing == none)
                        missing = month;
index 64b847b7f9705e55e7471ce301bff5a4a3a7bd62..f04761e6622dddcc34a3e860b7559ea410a9d113 100644 (file)
@@ -410,17 +410,7 @@ static struct platform_driver pm860x_rtc_driver = {
        .remove         = __devexit_p(pm860x_rtc_remove),
 };
 
-static int __init pm860x_rtc_init(void)
-{
-       return platform_driver_register(&pm860x_rtc_driver);
-}
-module_init(pm860x_rtc_init);
-
-static void __exit pm860x_rtc_exit(void)
-{
-       platform_driver_unregister(&pm860x_rtc_driver);
-}
-module_exit(pm860x_rtc_exit);
+module_platform_driver(pm860x_rtc_driver);
 
 MODULE_DESCRIPTION("Marvell 88PM860x RTC driver");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index e346705aae92f1ebae4570f7f13adc77adc89fef..4bcf9ca2818ae740eadd016df48cc0461da23f6e 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 #include <linux/delay.h>
 
 #define AB8500_RTC_SOFF_STAT_REG       0x00
@@ -90,7 +90,7 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
        /* Early AB8500 chips will not clear the rtc read request bit */
        if (abx500_get_chip_id(dev) == 0) {
-               msleep(1);
+               usleep_range(1000, 1000);
        } else {
                /* Wait for some cycles after enabling the rtc read in ab8500 */
                while (time_before(jiffies, timeout)) {
@@ -102,7 +102,7 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
                        if (!(value & RTC_READ_REQUEST))
                                break;
 
-                       msleep(1);
+                       usleep_range(1000, 5000);
                }
        }
 
@@ -258,6 +258,109 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return ab8500_rtc_irq_enable(dev, alarm->enabled);
 }
 
+
+static int ab8500_rtc_set_calibration(struct device *dev, int calibration)
+{
+       int retval;
+       u8  rtccal = 0;
+
+       /*
+        * Check that the calibration value (which is in units of 0.5
+        * parts-per-million) is in the AB8500's range for RtcCalibration
+        * register. -128 (0x80) is not permitted because the AB8500 uses
+        * a sign-bit rather than two's complement, so 0x80 is just another
+        * representation of zero.
+        */
+       if ((calibration < -127) || (calibration > 127)) {
+               dev_err(dev, "RtcCalibration value outside permitted range\n");
+               return -EINVAL;
+       }
+
+       /*
+        * The AB8500 uses sign (in bit7) and magnitude (in bits0-7)
+        * so need to convert to this sort of representation before writing
+        * into RtcCalibration register...
+        */
+       if (calibration >= 0)
+               rtccal = 0x7F & calibration;
+       else
+               rtccal = ~(calibration - 1) | 0x80;
+
+       retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+                       AB8500_RTC_CALIB_REG, rtccal);
+
+       return retval;
+}
+
+static int ab8500_rtc_get_calibration(struct device *dev, int *calibration)
+{
+       int retval;
+       u8  rtccal = 0;
+
+       retval =  abx500_get_register_interruptible(dev, AB8500_RTC,
+                       AB8500_RTC_CALIB_REG, &rtccal);
+       if (retval >= 0) {
+               /*
+                * The AB8500 uses sign (in bit7) and magnitude (in bits0-7)
+                * so need to convert value from RtcCalibration register into
+                * a two's complement signed value...
+                */
+               if (rtccal & 0x80)
+                       *calibration = 0 - (rtccal & 0x7F);
+               else
+                       *calibration = 0x7F & rtccal;
+       }
+
+       return retval;
+}
+
+static ssize_t ab8500_sysfs_store_rtc_calibration(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int retval;
+       int calibration = 0;
+
+       if (sscanf(buf, " %i ", &calibration) != 1) {
+               dev_err(dev, "Failed to store RTC calibration attribute\n");
+               return -EINVAL;
+       }
+
+       retval = ab8500_rtc_set_calibration(dev, calibration);
+
+       return retval ? retval : count;
+}
+
+static ssize_t ab8500_sysfs_show_rtc_calibration(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       int  retval = 0;
+       int  calibration = 0;
+
+       retval = ab8500_rtc_get_calibration(dev, &calibration);
+       if (retval < 0) {
+               dev_err(dev, "Failed to read RTC calibration attribute\n");
+               sprintf(buf, "0\n");
+               return retval;
+       }
+
+       return sprintf(buf, "%d\n", calibration);
+}
+
+static DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR,
+                  ab8500_sysfs_show_rtc_calibration,
+                  ab8500_sysfs_store_rtc_calibration);
+
+static int ab8500_sysfs_rtc_register(struct device *dev)
+{
+       return device_create_file(dev, &dev_attr_rtc_calibration);
+}
+
+static void ab8500_sysfs_rtc_unregister(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_rtc_calibration);
+}
+
 static irqreturn_t rtc_alarm_handler(int irq, void *data)
 {
        struct rtc_device *rtc = data;
@@ -295,7 +398,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
                return err;
 
        /* Wait for reset by the PorRtc */
-       msleep(1);
+       usleep_range(1000, 5000);
 
        err = abx500_get_register_interruptible(&pdev->dev, AB8500_RTC,
                AB8500_RTC_STAT_REG, &rtc_ctrl);
@@ -308,6 +411,8 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       device_init_wakeup(&pdev->dev, true);
+
        rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
                        THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -316,8 +421,8 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
                return err;
        }
 
-       err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0,
-                                  "ab8500-rtc", rtc);
+       err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
+               IRQF_NO_SUSPEND, "ab8500-rtc", rtc);
        if (err < 0) {
                rtc_device_unregister(rtc);
                return err;
@@ -325,6 +430,13 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
+
+       err = ab8500_sysfs_rtc_register(&pdev->dev);
+       if (err) {
+               dev_err(&pdev->dev, "sysfs RTC failed to register\n");
+               return err;
+       }
+
        return 0;
 }
 
@@ -333,6 +445,8 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
        struct rtc_device *rtc = platform_get_drvdata(pdev);
        int irq = platform_get_irq_byname(pdev, "ALARM");
 
+       ab8500_sysfs_rtc_unregister(&pdev->dev);
+
        free_irq(irq, rtc);
        rtc_device_unregister(rtc);
        platform_set_drvdata(pdev, NULL);
@@ -349,18 +463,8 @@ static struct platform_driver ab8500_rtc_driver = {
        .remove = __devexit_p(ab8500_rtc_remove),
 };
 
-static int __init ab8500_rtc_init(void)
-{
-       return platform_driver_register(&ab8500_rtc_driver);
-}
-
-static void __exit ab8500_rtc_exit(void)
-{
-       platform_driver_unregister(&ab8500_rtc_driver);
-}
+module_platform_driver(ab8500_rtc_driver);
 
-module_init(ab8500_rtc_init);
-module_exit(ab8500_rtc_exit);
 MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>");
 MODULE_DESCRIPTION("AB8500 RTC Driver");
 MODULE_LICENSE("GPL v2");
index 90d866272c8ea5095981afaa62396f03d92343b6..abfc1a0c07d9cfb0c6e6f7c46249c1283d10afca 100644 (file)
@@ -456,18 +456,7 @@ static struct platform_driver bfin_rtc_driver = {
        .resume         = bfin_rtc_resume,
 };
 
-static int __init bfin_rtc_init(void)
-{
-       return platform_driver_register(&bfin_rtc_driver);
-}
-
-static void __exit bfin_rtc_exit(void)
-{
-       platform_driver_unregister(&bfin_rtc_driver);
-}
-
-module_init(bfin_rtc_init);
-module_exit(bfin_rtc_exit);
+module_platform_driver(bfin_rtc_driver);
 
 MODULE_DESCRIPTION("Blackfin On-Chip Real Time Clock Driver");
 MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
index 128270ce355d08f0689b8e0961d39bb565923bf5..bf612ef229417730a8146f62d3a9270daba67d28 100644 (file)
@@ -218,15 +218,4 @@ static struct platform_driver bq4802_driver = {
        .remove         = __devexit_p(bq4802_remove),
 };
 
-static int __init bq4802_init(void)
-{
-       return platform_driver_register(&bq4802_driver);
-}
-
-static void __exit bq4802_exit(void)
-{
-       platform_driver_unregister(&bq4802_driver);
-}
-
-module_init(bq4802_init);
-module_exit(bq4802_exit);
+module_platform_driver(bq4802_driver);
index 05beb6c1ca79c7a0e22793818debbfb774da4187..d7782aa099439575a1a4f1887190b70a1b5e6370 100644 (file)
@@ -164,7 +164,7 @@ static inline unsigned char cmos_read_bank2(unsigned char addr)
 static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
 {
        outb(addr, RTC_PORT(2));
-       outb(val, RTC_PORT(2));
+       outb(val, RTC_PORT(3));
 }
 
 #else
index 2322c43af201bd23d0725e184c9bb5cced228996..d4457afcba8910892f85e90fa72309104fd73db5 100644 (file)
@@ -161,16 +161,6 @@ static struct platform_driver rtc_dm355evm_driver = {
        },
 };
 
-static int __init dm355evm_rtc_init(void)
-{
-       return platform_driver_register(&rtc_dm355evm_driver);
-}
-module_init(dm355evm_rtc_init);
-
-static void __exit dm355evm_rtc_exit(void)
-{
-       platform_driver_unregister(&rtc_dm355evm_driver);
-}
-module_exit(dm355evm_rtc_exit);
+module_platform_driver(rtc_dm355evm_driver);
 
 MODULE_LICENSE("GPL");
index 68e6caf2549662a66a84b7f94196a2c20ac2f93b..990c3ff489bf1fff947c854d747121b16c0de36c 100644 (file)
@@ -396,21 +396,10 @@ static struct platform_driver ds1286_platform_driver = {
        .remove         = __devexit_p(ds1286_remove),
 };
 
-static int __init ds1286_init(void)
-{
-       return platform_driver_register(&ds1286_platform_driver);
-}
-
-static void __exit ds1286_exit(void)
-{
-       platform_driver_unregister(&ds1286_platform_driver);
-}
+module_platform_driver(ds1286_platform_driver);
 
 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
 MODULE_DESCRIPTION("DS1286 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:rtc-ds1286");
-
-module_init(ds1286_init);
-module_exit(ds1286_exit);
index 586c244a05d854ab593b8310bd9e8a66991def14..761f36bc83a95e6bbbfa7dfc7f87aad55057858e 100644 (file)
@@ -580,20 +580,7 @@ static struct platform_driver ds1511_rtc_driver = {
        },
 };
 
- static int __init
-ds1511_rtc_init(void)
-{
-       return platform_driver_register(&ds1511_rtc_driver);
-}
-
- static void __exit
-ds1511_rtc_exit(void)
-{
-       platform_driver_unregister(&ds1511_rtc_driver);
-}
-
-module_init(ds1511_rtc_init);
-module_exit(ds1511_rtc_exit);
+module_platform_driver(ds1511_rtc_driver);
 
 MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
 MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
index 1350029044e6247247c3220efa362dd3bb832e63..6f0a1b530f2e8bdf8fea8ef2de1f3965114d74ed 100644 (file)
@@ -361,18 +361,7 @@ static struct platform_driver ds1553_rtc_driver = {
        },
 };
 
-static __init int ds1553_init(void)
-{
-       return platform_driver_register(&ds1553_rtc_driver);
-}
-
-static __exit void ds1553_exit(void)
-{
-       platform_driver_unregister(&ds1553_rtc_driver);
-}
-
-module_init(ds1553_init);
-module_exit(ds1553_exit);
+module_platform_driver(ds1553_rtc_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
index e3e0f92b60f0d97012f723e3a11a56b9054568d3..76112667c5078103c8bc4f64dd1b30201a5f1fde 100644 (file)
@@ -240,18 +240,7 @@ static struct platform_driver ds1742_rtc_driver = {
        },
 };
 
-static __init int ds1742_init(void)
-{
-       return platform_driver_register(&ds1742_rtc_driver);
-}
-
-static __exit void ds1742_exit(void)
-{
-       platform_driver_unregister(&ds1742_rtc_driver);
-}
-
-module_init(ds1742_init);
-module_exit(ds1742_exit);
+module_platform_driver(ds1742_rtc_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
index b6473631d18213e80ba404ec93b4ffe13d83e92d..05ab227eeff725aaa11761990fc520de9b71ce07 100644 (file)
@@ -345,7 +345,7 @@ static const struct dev_pm_ops jz4740_pm_ops = {
 #define JZ4740_RTC_PM_OPS NULL
 #endif  /* CONFIG_PM */
 
-struct platform_driver jz4740_rtc_driver = {
+static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
        .remove  = __devexit_p(jz4740_rtc_remove),
        .driver  = {
@@ -355,17 +355,7 @@ struct platform_driver jz4740_rtc_driver = {
        },
 };
 
-static int __init jz4740_rtc_init(void)
-{
-       return platform_driver_register(&jz4740_rtc_driver);
-}
-module_init(jz4740_rtc_init);
-
-static void __exit jz4740_rtc_exit(void)
-{
-       platform_driver_unregister(&jz4740_rtc_driver);
-}
-module_exit(jz4740_rtc_exit);
+module_platform_driver(jz4740_rtc_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_LICENSE("GPL");
index ae16250c762f84ab7fd2958b0fa643fff1480c28..ecc1713b2b4f827f144e025d21ce8657d8a732d1 100644 (file)
@@ -396,17 +396,7 @@ static struct platform_driver lpc32xx_rtc_driver = {
        },
 };
 
-static int __init lpc32xx_rtc_init(void)
-{
-       return platform_driver_register(&lpc32xx_rtc_driver);
-}
-module_init(lpc32xx_rtc_init);
-
-static void __exit lpc32xx_rtc_exit(void)
-{
-       platform_driver_unregister(&lpc32xx_rtc_driver);
-}
-module_exit(lpc32xx_rtc_exit);
+module_platform_driver(lpc32xx_rtc_driver);
 
 MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
 MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
index 7317d3b9a3d54ffacdde1c40773eacf1309a075c..ef71132ff205fc1ef0faec00ba55cdea383622fa 100644 (file)
@@ -200,7 +200,6 @@ static int __devexit m41t93_remove(struct spi_device *spi)
 static struct spi_driver m41t93_driver = {
        .driver = {
                .name   = "rtc-m41t93",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = m41t93_probe,
index e259ed76ae856d5b2cc8f354522f39e70d5474dc..2a4721f617975bbb21db850418c5a41976fe5d89 100644 (file)
@@ -147,7 +147,6 @@ static int __devexit m41t94_remove(struct spi_device *spi)
 static struct spi_driver m41t94_driver = {
        .driver = {
                .name   = "rtc-m41t94",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = m41t94_probe,
index 8e2a24e33ed69f89530ab9996707c109c5d76816..f9e3b3583733a21a296a0a2ec32bbfe8daf4f699 100644 (file)
@@ -216,21 +216,10 @@ static struct platform_driver m48t35_platform_driver = {
        .remove         = __devexit_p(m48t35_remove),
 };
 
-static int __init m48t35_init(void)
-{
-       return platform_driver_register(&m48t35_platform_driver);
-}
-
-static void __exit m48t35_exit(void)
-{
-       platform_driver_unregister(&m48t35_platform_driver);
-}
+module_platform_driver(m48t35_platform_driver);
 
 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
 MODULE_DESCRIPTION("M48T35 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:rtc-m48t35");
-
-module_init(m48t35_init);
-module_exit(m48t35_exit);
index 28365388fb6c8665a96c9d7fb68638300d748dc0..30ebfec9fd2b84a6bdd819bc3a736bdea86218c7 100644 (file)
@@ -530,18 +530,7 @@ static struct platform_driver m48t59_rtc_driver = {
        .remove         = __devexit_p(m48t59_rtc_remove),
 };
 
-static int __init m48t59_rtc_init(void)
-{
-       return platform_driver_register(&m48t59_rtc_driver);
-}
-
-static void __exit m48t59_rtc_exit(void)
-{
-       platform_driver_unregister(&m48t59_rtc_driver);
-}
-
-module_init(m48t59_rtc_init);
-module_exit(m48t59_rtc_exit);
+module_platform_driver(m48t59_rtc_driver);
 
 MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
 MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
index f981287d582b76a4a68a11246451e37b9a60c352..863fb3363aa6da503a5e0d66f1b1e7e853a97dca 100644 (file)
@@ -185,21 +185,10 @@ static struct platform_driver m48t86_rtc_platform_driver = {
        .remove         = __devexit_p(m48t86_rtc_remove),
 };
 
-static int __init m48t86_rtc_init(void)
-{
-       return platform_driver_register(&m48t86_rtc_platform_driver);
-}
-
-static void __exit m48t86_rtc_exit(void)
-{
-       platform_driver_unregister(&m48t86_rtc_platform_driver);
-}
+module_platform_driver(m48t86_rtc_platform_driver);
 
 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_DESCRIPTION("M48T86 RTC driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:rtc-m48t86");
-
-module_init(m48t86_rtc_init);
-module_exit(m48t86_rtc_exit);
index 0ec3f588a255dc1abe0cff5bc900cded2bdc8b59..1f6b3cc58e8a3644e1412f77808464412540c37a 100644 (file)
@@ -154,7 +154,6 @@ static int __devexit max6902_remove(struct spi_device *spi)
 static struct spi_driver max6902_driver = {
        .driver = {
                .name   = "rtc-max6902",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = max6902_probe,
index 3bc046f427e04c373465a0ac25f9125d0e89043f..2d71943bc436ad9719d364d99361dd62f92268eb 100644 (file)
@@ -261,6 +261,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
        /* XXX - isn't this redundant? */
        platform_set_drvdata(pdev, info);
 
+       device_init_wakeup(&pdev->dev, 1);
+
        info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
                                        &max8925_rtc_ops, THIS_MODULE);
        ret = PTR_ERR(info->rtc_dev);
@@ -290,26 +292,40 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int max8925_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0;
+       return 0;
+}
+static int max8925_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+       if (device_may_wakeup(dev))
+               chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume);
+
 static struct platform_driver max8925_rtc_driver = {
        .driver         = {
                .name   = "max8925-rtc",
                .owner  = THIS_MODULE,
+               .pm     = &max8925_rtc_pm_ops,
        },
        .probe          = max8925_rtc_probe,
        .remove         = __devexit_p(max8925_rtc_remove),
 };
 
-static int __init max8925_rtc_init(void)
-{
-       return platform_driver_register(&max8925_rtc_driver);
-}
-module_init(max8925_rtc_init);
-
-static void __exit max8925_rtc_exit(void)
-{
-       platform_driver_unregister(&max8925_rtc_driver);
-}
-module_exit(max8925_rtc_exit);
+module_platform_driver(max8925_rtc_driver);
 
 MODULE_DESCRIPTION("Maxim MAX8925 RTC driver");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index 2e48aa604273ad8e93f737888de136ec549467b5..7196f438c0895707233a4e9b0814c680e7821722 100644 (file)
@@ -327,17 +327,7 @@ static struct platform_driver max8998_rtc_driver = {
        .id_table       = max8998_rtc_id,
 };
 
-static int __init max8998_rtc_init(void)
-{
-       return platform_driver_register(&max8998_rtc_driver);
-}
-module_init(max8998_rtc_init);
-
-static void __exit max8998_rtc_exit(void)
-{
-       platform_driver_unregister(&max8998_rtc_driver);
-}
-module_exit(max8998_rtc_exit);
+module_platform_driver(max8998_rtc_driver);
 
 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
index 9d0c3b478d558eb42279c6598e04f0d8e91a6695..546f6850bffbd9d0a9f884528b36d81296a08110 100644 (file)
@@ -399,7 +399,7 @@ static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
-const struct platform_device_id mc13xxx_rtc_idtable[] = {
+static const struct platform_device_id mc13xxx_rtc_idtable[] = {
        {
                .name = "mc13783-rtc",
        }, {
index da60915818b68cb526948e4e42111c89ded290ce..9d3caccfc250ff6c5dd8a89b5ee296457ec31bcb 100644 (file)
@@ -418,17 +418,7 @@ static struct platform_driver mpc5121_rtc_driver = {
        .remove = __devexit_p(mpc5121_rtc_remove),
 };
 
-static int __init mpc5121_rtc_init(void)
-{
-       return platform_driver_register(&mpc5121_rtc_driver);
-}
-module_init(mpc5121_rtc_init);
-
-static void __exit mpc5121_rtc_exit(void)
-{
-       platform_driver_unregister(&mpc5121_rtc_driver);
-}
-module_exit(mpc5121_rtc_exit);
+module_platform_driver(mpc5121_rtc_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
index bb21f443fb7038719458d03c97e4b4eb00a225a1..6cd6c7235344916c1c51eac091f2cd80194c5426 100644 (file)
@@ -537,18 +537,7 @@ static struct platform_driver vrtc_mrst_platform_driver = {
        }
 };
 
-static int __init vrtc_mrst_init(void)
-{
-       return platform_driver_register(&vrtc_mrst_platform_driver);
-}
-
-static void __exit vrtc_mrst_exit(void)
-{
-       platform_driver_unregister(&vrtc_mrst_platform_driver);
-}
-
-module_init(vrtc_mrst_init);
-module_exit(vrtc_mrst_exit);
+module_platform_driver(vrtc_mrst_platform_driver);
 
 MODULE_AUTHOR("Jacob Pan; Feng Tang");
 MODULE_DESCRIPTION("Driver for Moorestown virtual RTC");
index 39e41fbdf08ba6de6259347feb0cc5dee76803d7..5e1d64ee52289b9e7a47990f8c7de0b41c7fccaf 100644 (file)
@@ -155,7 +155,6 @@ static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
 {
        struct rtc_time alarm_tm, now_tm;
        unsigned long now, time;
-       int ret;
        struct platform_device *pdev = to_platform_device(dev);
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
        void __iomem *ioaddr = pdata->ioaddr;
@@ -168,21 +167,33 @@ static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
        alarm_tm.tm_hour = alrm->tm_hour;
        alarm_tm.tm_min = alrm->tm_min;
        alarm_tm.tm_sec = alrm->tm_sec;
-       rtc_tm_to_time(&now_tm, &now);
        rtc_tm_to_time(&alarm_tm, &time);
 
-       if (time < now) {
-               time += 60 * 60 * 24;
-               rtc_time_to_tm(time, &alarm_tm);
-       }
-
-       ret = rtc_tm_to_time(&alarm_tm, &time);
-
        /* clear all the interrupt status bits */
        writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR);
        set_alarm_or_time(dev, MXC_RTC_ALARM, time);
 
-       return ret;
+       return 0;
+}
+
+static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
+                               unsigned int enabled)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       void __iomem *ioaddr = pdata->ioaddr;
+       u32 reg;
+
+       spin_lock_irq(&pdata->rtc->irq_lock);
+       reg = readw(ioaddr + RTC_RTCIENR);
+
+       if (enabled)
+               reg |= bit;
+       else
+               reg &= ~bit;
+
+       writew(reg, ioaddr + RTC_RTCIENR);
+       spin_unlock_irq(&pdata->rtc->irq_lock);
 }
 
 /* This function is the RTC interrupt service routine. */
@@ -199,13 +210,12 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
        /* clear interrupt sources */
        writew(status, ioaddr + RTC_RTCISR);
 
-       /* clear alarm interrupt if it has occurred */
-       if (status & RTC_ALM_BIT)
-               status &= ~RTC_ALM_BIT;
-
        /* update irq data & counter */
-       if (status & RTC_ALM_BIT)
+       if (status & RTC_ALM_BIT) {
                events |= (RTC_AF | RTC_IRQF);
+               /* RTC alarm should be one-shot */
+               mxc_rtc_irq_enable(&pdev->dev, RTC_ALM_BIT, 0);
+       }
 
        if (status & RTC_1HZ_BIT)
                events |= (RTC_UF | RTC_IRQF);
@@ -213,9 +223,6 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
        if (status & PIT_ALL_ON)
                events |= (RTC_PF | RTC_IRQF);
 
-       if ((status & RTC_ALM_BIT) && rtc_valid_tm(&pdata->g_rtc_alarm))
-               rtc_update_alarm(&pdev->dev, &pdata->g_rtc_alarm);
-
        rtc_update_irq(pdata->rtc, 1, events);
        spin_unlock_irq(&pdata->rtc->irq_lock);
 
@@ -242,26 +249,6 @@ static void mxc_rtc_release(struct device *dev)
        spin_unlock_irq(&pdata->rtc->irq_lock);
 }
 
-static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
-                               unsigned int enabled)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-       void __iomem *ioaddr = pdata->ioaddr;
-       u32 reg;
-
-       spin_lock_irq(&pdata->rtc->irq_lock);
-       reg = readw(ioaddr + RTC_RTCIENR);
-
-       if (enabled)
-               reg |= bit;
-       else
-               reg &= ~bit;
-
-       writew(reg, ioaddr + RTC_RTCIENR);
-       spin_unlock_irq(&pdata->rtc->irq_lock);
-}
-
 static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        mxc_rtc_irq_enable(dev, RTC_ALM_BIT, enabled);
@@ -290,6 +277,17 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
  */
 static int mxc_rtc_set_mmss(struct device *dev, unsigned long time)
 {
+       /*
+        * TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only
+        */
+       if (cpu_is_mx1()) {
+               struct rtc_time tm;
+
+               rtc_time_to_tm(time, &tm);
+               tm.tm_year = 70;
+               rtc_tm_to_time(&tm, &time);
+       }
+
        /* Avoid roll-over from reading the different registers */
        do {
                set_alarm_or_time(dev, MXC_RTC_TIME, time);
@@ -324,21 +322,7 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
        int ret;
 
-       if (rtc_valid_tm(&alrm->time)) {
-               if (alrm->time.tm_sec > 59 ||
-                   alrm->time.tm_hour > 23 ||
-                   alrm->time.tm_min > 59)
-                       return -EINVAL;
-
-               ret = rtc_update_alarm(dev, &alrm->time);
-       } else {
-               ret = rtc_valid_tm(&alrm->time);
-               if (ret)
-                       return ret;
-
-               ret = rtc_update_alarm(dev, &alrm->time);
-       }
-
+       ret = rtc_update_alarm(dev, &alrm->time);
        if (ret)
                return ret;
 
@@ -424,6 +408,9 @@ static int __init mxc_rtc_probe(struct platform_device *pdev)
                pdata->irq = -1;
        }
 
+       if (pdata->irq >=0)
+               device_init_wakeup(&pdev->dev, 1);
+
        rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
                                  THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -459,9 +446,39 @@ static int __exit mxc_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int mxc_rtc_suspend(struct device *dev)
+{
+       struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(pdata->irq);
+
+       return 0;
+}
+
+static int mxc_rtc_resume(struct device *dev)
+{
+       struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(pdata->irq);
+
+       return 0;
+}
+
+static struct dev_pm_ops mxc_rtc_pm_ops = {
+       .suspend        = mxc_rtc_suspend,
+       .resume         = mxc_rtc_resume,
+};
+#endif
+
 static struct platform_driver mxc_rtc_driver = {
        .driver = {
                   .name        = "mxc_rtc",
+#ifdef CONFIG_PM
+                  .pm          = &mxc_rtc_pm_ops,
+#endif
                   .owner       = THIS_MODULE,
        },
        .remove         = __exit_p(mxc_rtc_remove),
index 2ee3bbf7e5ea03df488233c61b659c4909219335..b46c4004d8fe4e5728221857806c7878d14ba63c 100644 (file)
@@ -340,7 +340,6 @@ static int __devexit pcf2123_remove(struct spi_device *spi)
 static struct spi_driver pcf2123_driver = {
        .driver = {
                        .name   = "rtc-pcf2123",
-                       .bus    = &spi_bus_type,
                        .owner  = THIS_MODULE,
        },
        .probe  = pcf2123_probe,
index 0c423892923c99f7ed04a4d9a2d0e387de7e7b57..a20202f9ee577d5ec477630c4a8073b7ed8abee0 100644 (file)
@@ -294,17 +294,7 @@ static struct platform_driver pcf50633_rtc_driver = {
        .remove = __devexit_p(pcf50633_rtc_remove),
 };
 
-static int __init pcf50633_rtc_init(void)
-{
-       return platform_driver_register(&pcf50633_rtc_driver);
-}
-module_init(pcf50633_rtc_init);
-
-static void __exit pcf50633_rtc_exit(void)
-{
-       platform_driver_unregister(&pcf50633_rtc_driver);
-}
-module_exit(pcf50633_rtc_exit);
+module_platform_driver(pcf50633_rtc_driver);
 
 MODULE_DESCRIPTION("PCF50633 RTC driver");
 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
index d420e9d877e85e9cb7a6d3ccd3b7a5391ef1c69c..9f1d6bcbdf6cf0ffc9403be3ea380e9f58d14774 100644 (file)
@@ -532,17 +532,7 @@ static struct platform_driver pm8xxx_rtc_driver = {
        },
 };
 
-static int __init pm8xxx_rtc_init(void)
-{
-       return platform_driver_register(&pm8xxx_rtc_driver);
-}
-module_init(pm8xxx_rtc_init);
-
-static void __exit pm8xxx_rtc_exit(void)
-{
-       platform_driver_unregister(&pm8xxx_rtc_driver);
-}
-module_exit(pm8xxx_rtc_exit);
+module_platform_driver(pm8xxx_rtc_driver);
 
 MODULE_ALIAS("platform:rtc-pm8xxx");
 MODULE_DESCRIPTION("PMIC8xxx RTC driver");
index e4b6880aabd05492b2a08c0511f400340b9fc0fa..ab0acaeb23719bfc055fe97cfb1efe7a051df756 100644 (file)
@@ -164,7 +164,7 @@ static int puv3_rtc_open(struct device *dev)
        int ret;
 
        ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq,
-                         IRQF_DISABLED,  "pkunity-rtc alarm", rtc_dev);
+                       0, "pkunity-rtc alarm", rtc_dev);
 
        if (ret) {
                dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret);
@@ -172,7 +172,7 @@ static int puv3_rtc_open(struct device *dev)
        }
 
        ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq,
-                         IRQF_DISABLED,  "pkunity-rtc tick", rtc_dev);
+                       0, "pkunity-rtc tick", rtc_dev);
 
        if (ret) {
                dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret);
@@ -326,7 +326,7 @@ static int puv3_rtc_resume(struct platform_device *pdev)
 #define puv3_rtc_resume  NULL
 #endif
 
-static struct platform_driver puv3_rtcdrv = {
+static struct platform_driver puv3_rtc_driver = {
        .probe          = puv3_rtc_probe,
        .remove         = __devexit_p(puv3_rtc_remove),
        .suspend        = puv3_rtc_suspend,
@@ -337,21 +337,7 @@ static struct platform_driver puv3_rtcdrv = {
        }
 };
 
-static char __initdata banner[] = "PKUnity-v3 RTC, (c) 2009 PKUnity Co.\n";
-
-static int __init puv3_rtc_init(void)
-{
-       printk(banner);
-       return platform_driver_register(&puv3_rtcdrv);
-}
-
-static void __exit puv3_rtc_exit(void)
-{
-       platform_driver_unregister(&puv3_rtcdrv);
-}
-
-module_init(puv3_rtc_init);
-module_exit(puv3_rtc_exit);
+module_platform_driver(puv3_rtc_driver);
 
 MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip");
 MODULE_AUTHOR("Hu Dongliang");
index 971bc8e08da66008fecd1d16f29508bafc40d482..ce2ca8523ddd5d01146c1b17c64069e76dbc0229 100644 (file)
@@ -229,7 +229,6 @@ static int __devexit rs5c348_remove(struct spi_device *spi)
 static struct spi_driver rs5c348_driver = {
        .driver = {
                .name   = "rtc-rs5c348",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
        .probe  = rs5c348_probe,
index 175067a17c46f31ccc7af5382859f0cfa0ec9e64..aef40bd2957be7ccb2fd5adfebb6c6e13c3b6683 100644 (file)
@@ -673,21 +673,7 @@ static struct platform_driver s3c_rtc_driver = {
        },
 };
 
-static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
-
-static int __init s3c_rtc_init(void)
-{
-       printk(banner);
-       return platform_driver_register(&s3c_rtc_driver);
-}
-
-static void __exit s3c_rtc_exit(void)
-{
-       platform_driver_unregister(&s3c_rtc_driver);
-}
-
-module_init(s3c_rtc_init);
-module_exit(s3c_rtc_exit);
+module_platform_driver(s3c_rtc_driver);
 
 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
index fc1ffe97fca191c0952740aadd8e80b4f7a2ded9..4595d3e645a7358676b5409b8ced918f306e07c2 100644 (file)
@@ -435,18 +435,7 @@ static struct platform_driver sa1100_rtc_driver = {
        },
 };
 
-static int __init sa1100_rtc_init(void)
-{
-       return platform_driver_register(&sa1100_rtc_driver);
-}
-
-static void __exit sa1100_rtc_exit(void)
-{
-       platform_driver_unregister(&sa1100_rtc_driver);
-}
-
-module_init(sa1100_rtc_init);
-module_exit(sa1100_rtc_exit);
+module_platform_driver(sa1100_rtc_driver);
 
 MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
 MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
index 893bac2bb21b61b6f5b004a76e08316a2174366e..19a28a671a8e74f8abbd5ed149f4aebc4769b75d 100644 (file)
@@ -516,17 +516,7 @@ static struct platform_driver spear_rtc_driver = {
        },
 };
 
-static int __init rtc_init(void)
-{
-       return platform_driver_register(&spear_rtc_driver);
-}
-module_init(rtc_init);
-
-static void __exit rtc_exit(void)
-{
-       platform_driver_unregister(&spear_rtc_driver);
-}
-module_exit(rtc_exit);
+module_platform_driver(spear_rtc_driver);
 
 MODULE_ALIAS("platform:rtc-spear");
 MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
index ed3e9b5990315cc2389208768ab38b2332735fe1..7621116bd20d25680a266914c66ab7527bb27da1 100644 (file)
@@ -370,18 +370,7 @@ static struct platform_driver stk17ta8_rtc_driver = {
        },
 };
 
-static __init int stk17ta8_init(void)
-{
-       return platform_driver_register(&stk17ta8_rtc_driver);
-}
-
-static __exit void stk17ta8_exit(void)
-{
-       platform_driver_unregister(&stk17ta8_rtc_driver);
-}
-
-module_init(stk17ta8_init);
-module_exit(stk17ta8_exit);
+module_platform_driver(stk17ta8_rtc_driver);
 
 MODULE_AUTHOR("Thomas Hommel <thomas.hommel@ge.com>");
 MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
index 7315068daa59797b9372dbe871784ef12e5ea8c1..10287865e33012a154100b6b674f541273d132d3 100644 (file)
@@ -276,18 +276,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {
        },
 };
 
-static int __init stmp3xxx_rtc_init(void)
-{
-       return platform_driver_register(&stmp3xxx_rtcdrv);
-}
-
-static void __exit stmp3xxx_rtc_exit(void)
-{
-       platform_driver_unregister(&stmp3xxx_rtcdrv);
-}
-
-module_init(stmp3xxx_rtc_init);
-module_exit(stmp3xxx_rtc_exit);
+module_platform_driver(stmp3xxx_rtcdrv);
 
 MODULE_DESCRIPTION("STMP3xxx RTC Driver");
 MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com> and "
index 20687d55e7a72d5eb2871fd8504d6a2fa457e9e5..d43b4f6eb4e420c79327566e3444351cf86c8185 100644 (file)
@@ -550,6 +550,11 @@ static int twl_rtc_resume(struct platform_device *pdev)
 #define twl_rtc_resume  NULL
 #endif
 
+static const struct of_device_id twl_rtc_of_match[] = {
+       {.compatible = "ti,twl4030-rtc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
 MODULE_ALIAS("platform:twl_rtc");
 
 static struct platform_driver twl4030rtc_driver = {
@@ -559,8 +564,9 @@ static struct platform_driver twl4030rtc_driver = {
        .suspend        = twl_rtc_suspend,
        .resume         = twl_rtc_resume,
        .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "twl_rtc",
+               .owner          = THIS_MODULE,
+               .name           = "twl_rtc",
+               .of_match_table = twl_rtc_of_match,
        },
 };
 
index f71c3ce180369225938f8ba21a6960e605f9d251..bca5d677bc85385d31efcd5486a4f44ac08bed73 100644 (file)
@@ -393,18 +393,7 @@ static struct platform_driver rtc_device_driver = {
        },
 };
 
-static __init int v3020_init(void)
-{
-       return platform_driver_register(&rtc_device_driver);
-}
-
-static __exit void v3020_exit(void)
-{
-       platform_driver_unregister(&rtc_device_driver);
-}
-
-module_init(v3020_init);
-module_exit(v3020_exit);
+module_platform_driver(rtc_device_driver);
 
 MODULE_DESCRIPTION("V3020 RTC");
 MODULE_AUTHOR("Raphael Assenat");
index c5698cda366a910a6f16008248c3c78aac62823f..fcbfdda2993bea5e8dd2f2ca4a1dd74e3e5ff121 100644 (file)
@@ -405,15 +405,4 @@ static struct platform_driver rtc_platform_driver = {
        },
 };
 
-static int __init vr41xx_rtc_init(void)
-{
-       return platform_driver_register(&rtc_platform_driver);
-}
-
-static void __exit vr41xx_rtc_exit(void)
-{
-       platform_driver_unregister(&rtc_platform_driver);
-}
-
-module_init(vr41xx_rtc_init);
-module_exit(vr41xx_rtc_exit);
+module_platform_driver(rtc_platform_driver);
index f93f412423c6d4eaadcdfbe5412d4a65c80cc09e..9e94fb147c26afcffe92ad7175cb011051ca5fb8 100644 (file)
@@ -311,17 +311,7 @@ static struct platform_driver vt8500_rtc_driver = {
        },
 };
 
-static int __init vt8500_rtc_init(void)
-{
-       return platform_driver_register(&vt8500_rtc_driver);
-}
-module_init(vt8500_rtc_init);
-
-static void __exit vt8500_rtc_exit(void)
-{
-       platform_driver_unregister(&vt8500_rtc_driver);
-}
-module_exit(vt8500_rtc_exit);
+module_platform_driver(vt8500_rtc_driver);
 
 MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
 MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)");
index bdc909bd56da0f4c7c615349df6f43023bd52517..3b6e6a67e765b34e7efd7e5cb82eea63a930d31e 100644 (file)
@@ -324,15 +324,6 @@ static irqreturn_t wm831x_alm_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t wm831x_per_irq(int irq, void *data)
-{
-       struct wm831x_rtc *wm831x_rtc = data;
-
-       rtc_update_irq(wm831x_rtc->rtc, 1, RTC_IRQF | RTC_UF);
-
-       return IRQ_HANDLED;
-}
-
 static const struct rtc_class_ops wm831x_rtc_ops = {
        .read_time = wm831x_rtc_readtime,
        .set_mmss = wm831x_rtc_set_mmss,
@@ -405,11 +396,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
        struct wm831x_rtc *wm831x_rtc;
-       int per_irq = platform_get_irq_byname(pdev, "PER");
        int alm_irq = platform_get_irq_byname(pdev, "ALM");
        int ret = 0;
 
-       wm831x_rtc = kzalloc(sizeof(*wm831x_rtc), GFP_KERNEL);
+       wm831x_rtc = devm_kzalloc(&pdev->dev, sizeof(*wm831x_rtc), GFP_KERNEL);
        if (wm831x_rtc == NULL)
                return -ENOMEM;
 
@@ -433,14 +423,6 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
                goto err;
        }
 
-       ret = request_threaded_irq(per_irq, NULL, wm831x_per_irq,
-                                  IRQF_TRIGGER_RISING, "RTC period",
-                                  wm831x_rtc);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
-                       per_irq, ret);
-       }
-
        ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
                                   IRQF_TRIGGER_RISING, "RTC alarm",
                                   wm831x_rtc);
@@ -452,20 +434,16 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
        return 0;
 
 err:
-       kfree(wm831x_rtc);
        return ret;
 }
 
 static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
 {
        struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev);
-       int per_irq = platform_get_irq_byname(pdev, "PER");
        int alm_irq = platform_get_irq_byname(pdev, "ALM");
 
        free_irq(alm_irq, wm831x_rtc);
-       free_irq(per_irq, wm831x_rtc);
        rtc_device_unregister(wm831x_rtc->rtc);
-       kfree(wm831x_rtc);
 
        return 0;
 }
@@ -490,17 +468,7 @@ static struct platform_driver wm831x_rtc_driver = {
        },
 };
 
-static int __init wm831x_rtc_init(void)
-{
-       return platform_driver_register(&wm831x_rtc_driver);
-}
-module_init(wm831x_rtc_init);
-
-static void __exit wm831x_rtc_exit(void)
-{
-       platform_driver_unregister(&wm831x_rtc_driver);
-}
-module_exit(wm831x_rtc_exit);
+module_platform_driver(wm831x_rtc_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("RTC driver for the WM831x series PMICs");
index 66421426e404521c5ecafda56c49e0e34df594f9..c2e52d15abb295f0de5b0ae08afebf62c77ad009 100644 (file)
@@ -486,17 +486,7 @@ static struct platform_driver wm8350_rtc_driver = {
        },
 };
 
-static int __init wm8350_rtc_init(void)
-{
-       return platform_driver_register(&wm8350_rtc_driver);
-}
-module_init(wm8350_rtc_init);
-
-static void __exit wm8350_rtc_exit(void)
-{
-       platform_driver_unregister(&wm8350_rtc_driver);
-}
-module_exit(wm8350_rtc_exit);
+module_platform_driver(wm8350_rtc_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("RTC driver for the WM8350");
index 8af868bab20b52f9e2c11d4266a977c79ff99c01..7bc1955337ead5eecac17adc14021f9f5f843cd6 100644 (file)
@@ -198,7 +198,7 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
                goto out;
 
        vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
-                                vdev, (void *) config->address,
+                                vdev, true, (void *) config->address,
                                 kvm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
index fd860d952b288f3cacf6066253f4d75936e0c53e..67b169b7a5be505e5e5935db55552d2bba13e7a0 100644 (file)
@@ -7638,8 +7638,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
  **/
 static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd)
 {
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
        ENTER;
-       pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
+       if (ioa_cfg->cfg_locked)
+               pci_cfg_access_unlock(ioa_cfg->pdev);
+       ioa_cfg->cfg_locked = 0;
        ipr_cmd->job_step = ipr_reset_restore_cfg_space;
        LEAVE;
        return IPR_RC_JOB_CONTINUE;
@@ -7660,8 +7664,6 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
        int rc = PCIBIOS_SUCCESSFUL;
 
        ENTER;
-       pci_block_user_cfg_access(ioa_cfg->pdev);
-
        if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO)
                writel(IPR_UPROCI_SIS64_START_BIST,
                       ioa_cfg->regs.set_uproc_interrupt_reg32);
@@ -7673,7 +7675,9 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
                ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
                rc = IPR_RC_JOB_RETURN;
        } else {
-               pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
+               if (ioa_cfg->cfg_locked)
+                       pci_cfg_access_unlock(ipr_cmd->ioa_cfg->pdev);
+               ioa_cfg->cfg_locked = 0;
                ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
                rc = IPR_RC_JOB_CONTINUE;
        }
@@ -7716,7 +7720,6 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
        struct pci_dev *pdev = ioa_cfg->pdev;
 
        ENTER;
-       pci_block_user_cfg_access(pdev);
        pci_set_pcie_reset_state(pdev, pcie_warm_reset);
        ipr_cmd->job_step = ipr_reset_slot_reset_done;
        ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
@@ -7724,6 +7727,56 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
        return IPR_RC_JOB_RETURN;
 }
 
+/**
+ * ipr_reset_block_config_access_wait - Wait for permission to block config access
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This attempts to block config access to the IOA.
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_block_config_access_wait(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       int rc = IPR_RC_JOB_CONTINUE;
+
+       if (pci_cfg_access_trylock(ioa_cfg->pdev)) {
+               ioa_cfg->cfg_locked = 1;
+               ipr_cmd->job_step = ioa_cfg->reset;
+       } else {
+               if (ipr_cmd->u.time_left) {
+                       rc = IPR_RC_JOB_RETURN;
+                       ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
+                       ipr_reset_start_timer(ipr_cmd,
+                                             IPR_CHECK_FOR_RESET_TIMEOUT);
+               } else {
+                       ipr_cmd->job_step = ioa_cfg->reset;
+                       dev_err(&ioa_cfg->pdev->dev,
+                               "Timed out waiting to lock config access. Resetting anyway.\n");
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * ipr_reset_block_config_access - Block config access to the IOA
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This attempts to block config access to the IOA
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE
+ **/
+static int ipr_reset_block_config_access(struct ipr_cmnd *ipr_cmd)
+{
+       ipr_cmd->ioa_cfg->cfg_locked = 0;
+       ipr_cmd->job_step = ipr_reset_block_config_access_wait;
+       ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
+       return IPR_RC_JOB_CONTINUE;
+}
+
 /**
  * ipr_reset_allowed - Query whether or not IOA can be reset
  * @ioa_cfg:   ioa config struct
@@ -7763,7 +7816,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
                ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
                ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
        } else {
-               ipr_cmd->job_step = ioa_cfg->reset;
+               ipr_cmd->job_step = ipr_reset_block_config_access;
                rc = IPR_RC_JOB_CONTINUE;
        }
 
@@ -7796,7 +7849,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
                writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32);
                ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
        } else {
-               ipr_cmd->job_step = ioa_cfg->reset;
+               ipr_cmd->job_step = ipr_reset_block_config_access;
        }
 
        ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
index ac84736c1b9c414530d358fe4fda9235d00ac235..b13f9cc12279657c97d7be7456f3238376b874c2 100644 (file)
@@ -1387,6 +1387,7 @@ struct ipr_ioa_cfg {
        u8 msi_received:1;
        u8 sis64:1;
        u8 dump_timeout:1;
+       u8 cfg_locked:1;
 
        u8 revid;
 
index 67e272ab162310645f0c3339c7cd29987f3b4dd8..7139ad2f20864d61c53eeebaec5c3a0f935222c7 100644 (file)
@@ -7,11 +7,4 @@ obj-$(CONFIG_HAVE_CLK)         += clk/
 obj-$(CONFIG_MAPLE)            += maple/
 obj-$(CONFIG_SUPERHYWAY)       += superhyway/
 obj-$(CONFIG_GENERIC_GPIO)     += pfc.o
-
-#
-# For the moment we only use this framework for ARM-based SH/R-Mobile
-# platforms and generic SH. SH-based SH-Mobile platforms are still using
-# an older framework that is pending up-porting, at which point this
-# special casing can go away.
-#
-obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE)    += pm_runtime.o
+obj-y                          += pm_runtime.o
index db257a35e71a545aa724b97d40dbdd6dbf1fe7f2..7715de2629c104de4e98a87836ea2ef308a743c4 100644 (file)
@@ -355,7 +355,7 @@ static int clk_establish_mapping(struct clk *clk)
                 */
                if (!clk->parent) {
                        clk->mapping = &dummy_mapping;
-                       return 0;
+                       goto out;
                }
 
                /*
@@ -384,6 +384,9 @@ static int clk_establish_mapping(struct clk *clk)
        }
 
        clk->mapping = mapping;
+out:
+       clk->mapped_reg = clk->mapping->base;
+       clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys;
        return 0;
 }
 
@@ -402,10 +405,12 @@ static void clk_teardown_mapping(struct clk *clk)
 
        /* Nothing to do */
        if (mapping == &dummy_mapping)
-               return;
+               goto out;
 
        kref_put(&mapping->ref, clk_destroy_mapping);
        clk->mapping = NULL;
+out:
+       clk->mapped_reg = NULL;
 }
 
 int clk_register(struct clk *clk)
index 82dd6fb178386a31ef29ee4adc1dcd96ccf221c5..45fee368b0925bec46312dbbe7569c8b5ca2dfc2 100644 (file)
 
 static int sh_clk_mstp32_enable(struct clk *clk)
 {
-       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
-                    clk->enable_reg);
+       iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
+                 clk->mapped_reg);
        return 0;
 }
 
 static void sh_clk_mstp32_disable(struct clk *clk)
 {
-       __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
-                    clk->enable_reg);
+       iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
+                 clk->mapped_reg);
 }
 
 static struct clk_ops sh_clk_mstp32_clk_ops = {
@@ -72,7 +72,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
                             table, NULL);
 
-       idx = __raw_readl(clk->enable_reg) & 0x003f;
+       idx = ioread32(clk->mapped_reg) & 0x003f;
 
        return clk->freq_table[idx].frequency;
 }
@@ -98,10 +98,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
        if (ret < 0)
                return ret;
 
-       value = __raw_readl(clk->enable_reg) &
+       value = ioread32(clk->mapped_reg) &
                ~(((1 << clk->src_width) - 1) << clk->src_shift);
 
-       __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
+       iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
 
        /* Rebuild the frequency table */
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +119,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
        if (idx < 0)
                return idx;
 
-       value = __raw_readl(clk->enable_reg);
+       value = ioread32(clk->mapped_reg);
        value &= ~0x3f;
        value |= idx;
-       __raw_writel(value, clk->enable_reg);
+       iowrite32(value, clk->mapped_reg);
        return 0;
 }
 
@@ -133,9 +133,9 @@ static int sh_clk_div6_enable(struct clk *clk)
 
        ret = sh_clk_div6_set_rate(clk, clk->rate);
        if (ret == 0) {
-               value = __raw_readl(clk->enable_reg);
+               value = ioread32(clk->mapped_reg);
                value &= ~0x100; /* clear stop bit to enable clock */
-               __raw_writel(value, clk->enable_reg);
+               iowrite32(value, clk->mapped_reg);
        }
        return ret;
 }
@@ -144,10 +144,10 @@ static void sh_clk_div6_disable(struct clk *clk)
 {
        unsigned long value;
 
-       value = __raw_readl(clk->enable_reg);
+       value = ioread32(clk->mapped_reg);
        value |= 0x100; /* stop clock */
        value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
-       __raw_writel(value, clk->enable_reg);
+       iowrite32(value, clk->mapped_reg);
 }
 
 static struct clk_ops sh_clk_div6_clk_ops = {
@@ -167,6 +167,38 @@ static struct clk_ops sh_clk_div6_reparent_clk_ops = {
        .set_parent     = sh_clk_div6_set_parent,
 };
 
+static int __init sh_clk_init_parent(struct clk *clk)
+{
+       u32 val;
+
+       if (clk->parent)
+               return 0;
+
+       if (!clk->parent_table || !clk->parent_num)
+               return 0;
+
+       if (!clk->src_width) {
+               pr_err("sh_clk_init_parent: cannot select parent clock\n");
+               return -EINVAL;
+       }
+
+       val  = (ioread32(clk->mapped_reg) >> clk->src_shift);
+       val &= (1 << clk->src_width) - 1;
+
+       if (val >= clk->parent_num) {
+               pr_err("sh_clk_init_parent: parent table size failed\n");
+               return -EINVAL;
+       }
+
+       clk->parent = clk->parent_table[val];
+       if (!clk->parent) {
+               pr_err("sh_clk_init_parent: unable to set parent");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
                                           struct clk_ops *ops)
 {
@@ -190,8 +222,11 @@ static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
                clkp->ops = ops;
                clkp->freq_table = freq_table + (k * freq_table_size);
                clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
-
                ret = clk_register(clkp);
+               if (ret < 0)
+                       break;
+
+               ret = sh_clk_init_parent(clkp);
        }
 
        return ret;
@@ -217,7 +252,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
                             table, &clk->arch_flags);
 
-       idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
+       idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
 
        return clk->freq_table[idx].frequency;
 }
@@ -235,15 +270,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
         */
 
        if (parent->flags & CLK_ENABLE_ON_INIT)
-               value = __raw_readl(clk->enable_reg) & ~(1 << 7);
+               value = ioread32(clk->mapped_reg) & ~(1 << 7);
        else
-               value = __raw_readl(clk->enable_reg) | (1 << 7);
+               value = ioread32(clk->mapped_reg) | (1 << 7);
 
        ret = clk_reparent(clk, parent);
        if (ret < 0)
                return ret;
 
-       __raw_writel(value, clk->enable_reg);
+       iowrite32(value, clk->mapped_reg);
 
        /* Rebiuld the frequency table */
        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -260,10 +295,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
        if (idx < 0)
                return idx;
 
-       value = __raw_readl(clk->enable_reg);
+       value = ioread32(clk->mapped_reg);
        value &= ~(0xf << clk->enable_bit);
        value |= (idx << clk->enable_bit);
-       __raw_writel(value, clk->enable_reg);
+       iowrite32(value, clk->mapped_reg);
 
        if (d4t->kick)
                d4t->kick(clk);
@@ -273,13 +308,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
 
 static int sh_clk_div4_enable(struct clk *clk)
 {
-       __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
+       iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
        return 0;
 }
 
 static void sh_clk_div4_disable(struct clk *clk)
 {
-       __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
+       iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
 }
 
 static struct clk_ops sh_clk_div4_clk_ops = {
index e67fe170d8d5e8bef9c7683f6490bf1a7be9dbc6..522c6c46d1be83a5f95527d509cf12142a52e523 100644 (file)
 #include <linux/irq.h>
 #include <linux/bitops.h>
 #include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+
+static void pfc_iounmap(struct pinmux_info *pip)
+{
+       int k;
+
+       for (k = 0; k < pip->num_resources; k++)
+               if (pip->window[k].virt)
+                       iounmap(pip->window[k].virt);
+
+       kfree(pip->window);
+       pip->window = NULL;
+}
+
+static int pfc_ioremap(struct pinmux_info *pip)
+{
+       struct resource *res;
+       int k;
+
+       if (!pip->num_resources)
+               return 0;
+
+       pip->window = kzalloc(pip->num_resources * sizeof(*pip->window),
+                             GFP_NOWAIT);
+       if (!pip->window)
+               goto err1;
+
+       for (k = 0; k < pip->num_resources; k++) {
+               res = pip->resource + k;
+               WARN_ON(resource_type(res) != IORESOURCE_MEM);
+               pip->window[k].phys = res->start;
+               pip->window[k].size = resource_size(res);
+               pip->window[k].virt = ioremap_nocache(res->start,
+                                                        resource_size(res));
+               if (!pip->window[k].virt)
+                       goto err2;
+       }
+
+       return 0;
+
+err2:
+       pfc_iounmap(pip);
+err1:
+       return -1;
+}
+
+static void __iomem *pfc_phys_to_virt(struct pinmux_info *pip,
+                                     unsigned long address)
+{
+       struct pfc_window *window;
+       int k;
+
+       /* scan through physical windows and convert address */
+       for (k = 0; k < pip->num_resources; k++) {
+               window = pip->window + k;
+
+               if (address < window->phys)
+                       continue;
+
+               if (address >= (window->phys + window->size))
+                       continue;
+
+               return window->virt + (address - window->phys);
+       }
+
+       /* no windows defined, register must be 1:1 mapped virt:phys */
+       return (void __iomem *)address;
+}
 
 static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
 {
@@ -31,41 +100,54 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
        return 1;
 }
 
-static unsigned long gpio_read_raw_reg(unsigned long reg,
+static unsigned long gpio_read_raw_reg(void __iomem *mapped_reg,
                                       unsigned long reg_width)
 {
        switch (reg_width) {
        case 8:
-               return __raw_readb(reg);
+               return ioread8(mapped_reg);
        case 16:
-               return __raw_readw(reg);
+               return ioread16(mapped_reg);
        case 32:
-               return __raw_readl(reg);
+               return ioread32(mapped_reg);
        }
 
        BUG();
        return 0;
 }
 
-static void gpio_write_raw_reg(unsigned long reg,
+static void gpio_write_raw_reg(void __iomem *mapped_reg,
                               unsigned long reg_width,
                               unsigned long data)
 {
        switch (reg_width) {
        case 8:
-               __raw_writeb(data, reg);
+               iowrite8(data, mapped_reg);
                return;
        case 16:
-               __raw_writew(data, reg);
+               iowrite16(data, mapped_reg);
                return;
        case 32:
-               __raw_writel(data, reg);
+               iowrite32(data, mapped_reg);
                return;
        }
 
        BUG();
 }
 
+static int gpio_read_bit(struct pinmux_data_reg *dr,
+                        unsigned long in_pos)
+{
+       unsigned long pos;
+
+       pos = dr->reg_width - (in_pos + 1);
+
+       pr_debug("read_bit: addr = %lx, pos = %ld, "
+                "r_width = %ld\n", dr->reg, pos, dr->reg_width);
+
+       return (gpio_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1;
+}
+
 static void gpio_write_bit(struct pinmux_data_reg *dr,
                           unsigned long in_pos, unsigned long value)
 {
@@ -82,53 +164,72 @@ static void gpio_write_bit(struct pinmux_data_reg *dr,
        else
                clear_bit(pos, &dr->reg_shadow);
 
-       gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
+       gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
 }
 
-static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
-                        unsigned long field_width, unsigned long in_pos)
+static void config_reg_helper(struct pinmux_info *gpioc,
+                             struct pinmux_cfg_reg *crp,
+                             unsigned long in_pos,
+                             void __iomem **mapped_regp,
+                             unsigned long *maskp,
+                             unsigned long *posp)
 {
-       unsigned long data, mask, pos;
+       int k;
+
+       *mapped_regp = pfc_phys_to_virt(gpioc, crp->reg);
 
-       data = 0;
-       mask = (1 << field_width) - 1;
-       pos = reg_width - ((in_pos + 1) * field_width);
+       if (crp->field_width) {
+               *maskp = (1 << crp->field_width) - 1;
+               *posp = crp->reg_width - ((in_pos + 1) * crp->field_width);
+       } else {
+               *maskp = (1 << crp->var_field_width[in_pos]) - 1;
+               *posp = crp->reg_width;
+               for (k = 0; k <= in_pos; k++)
+                       *posp -= crp->var_field_width[k];
+       }
+}
 
-       pr_debug("read_reg: addr = %lx, pos = %ld, "
+static int read_config_reg(struct pinmux_info *gpioc,
+                          struct pinmux_cfg_reg *crp,
+                          unsigned long field)
+{
+       void __iomem *mapped_reg;
+       unsigned long mask, pos;
+
+       config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
+
+       pr_debug("read_reg: addr = %lx, field = %ld, "
                 "r_width = %ld, f_width = %ld\n",
-                reg, pos, reg_width, field_width);
+                crp->reg, field, crp->reg_width, crp->field_width);
 
-       data = gpio_read_raw_reg(reg, reg_width);
-       return (data >> pos) & mask;
+       return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
 }
 
-static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
-                          unsigned long field_width, unsigned long in_pos,
-                          unsigned long value)
+static void write_config_reg(struct pinmux_info *gpioc,
+                            struct pinmux_cfg_reg *crp,
+                            unsigned long field, unsigned long value)
 {
-       unsigned long mask, pos;
+       void __iomem *mapped_reg;
+       unsigned long mask, pos, data;
 
-       mask = (1 << field_width) - 1;
-       pos = reg_width - ((in_pos + 1) * field_width);
+       config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
 
-       pr_debug("write_reg addr = %lx, value = %ld, pos = %ld, "
+       pr_debug("write_reg addr = %lx, value = %ld, field = %ld, "
                 "r_width = %ld, f_width = %ld\n",
-                reg, value, pos, reg_width, field_width);
+                crp->reg, value, field, crp->reg_width, crp->field_width);
 
        mask = ~(mask << pos);
        value = value << pos;
 
-       switch (reg_width) {
-       case 8:
-               __raw_writeb((__raw_readb(reg) & mask) | value, reg);
-               break;
-       case 16:
-               __raw_writew((__raw_readw(reg) & mask) | value, reg);
-               break;
-       case 32:
-               __raw_writel((__raw_readl(reg) & mask) | value, reg);
-               break;
-       }
+       data = gpio_read_raw_reg(mapped_reg, crp->reg_width);
+       data &= mask;
+       data |= value;
+
+       if (gpioc->unlock_reg)
+               gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg),
+                                  32, ~data);
+
+       gpio_write_raw_reg(mapped_reg, crp->reg_width, data);
 }
 
 static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
@@ -147,6 +248,8 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
                if (!data_reg->reg_width)
                        break;
 
+               data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
+
                for (n = 0; n < data_reg->reg_width; n++) {
                        if (data_reg->enum_ids[n] == gpiop->enum_id) {
                                gpiop->flags &= ~PINMUX_FLAG_DREG;
@@ -179,7 +282,8 @@ static void setup_data_regs(struct pinmux_info *gpioc)
                if (!drp->reg_width)
                        break;
 
-               drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
+               drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
+                                                   drp->reg_width);
                k++;
        }
 }
@@ -201,12 +305,13 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
 }
 
 static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
-                         struct pinmux_cfg_reg **crp, int *indexp,
+                         struct pinmux_cfg_reg **crp,
+                         int *fieldp, int *valuep,
                          unsigned long **cntp)
 {
        struct pinmux_cfg_reg *config_reg;
-       unsigned long r_width, f_width;
-       int k, n;
+       unsigned long r_width, f_width, curr_width, ncomb;
+       int k, m, n, pos, bit_pos;
 
        k = 0;
        while (1) {
@@ -217,13 +322,27 @@ static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
 
                if (!r_width)
                        break;
-               for (n = 0; n < (r_width / f_width) * (1 << f_width); n++) {
-                       if (config_reg->enum_ids[n] == enum_id) {
-                               *crp = config_reg;
-                               *indexp = n;
-                               *cntp = &config_reg->cnt[n / (1 << f_width)];
-                               return 0;
+
+               pos = 0;
+               m = 0;
+               for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) {
+                       if (f_width)
+                               curr_width = f_width;
+                       else
+                               curr_width = config_reg->var_field_width[m];
+
+                       ncomb = 1 << curr_width;
+                       for (n = 0; n < ncomb; n++) {
+                               if (config_reg->enum_ids[pos + n] == enum_id) {
+                                       *crp = config_reg;
+                                       *fieldp = m;
+                                       *valuep = n;
+                                       *cntp = &config_reg->cnt[m];
+                                       return 0;
+                               }
                        }
+                       pos += ncomb;
+                       m++;
                }
                k++;
        }
@@ -261,36 +380,6 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
        return -1;
 }
 
-static void write_config_reg(struct pinmux_info *gpioc,
-                            struct pinmux_cfg_reg *crp,
-                            int index)
-{
-       unsigned long ncomb, pos, value;
-
-       ncomb = 1 << crp->field_width;
-       pos = index / ncomb;
-       value = index % ncomb;
-
-       gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
-}
-
-static int check_config_reg(struct pinmux_info *gpioc,
-                           struct pinmux_cfg_reg *crp,
-                           int index)
-{
-       unsigned long ncomb, pos, value;
-
-       ncomb = 1 << crp->field_width;
-       pos = index / ncomb;
-       value = index % ncomb;
-
-       if (gpio_read_reg(crp->reg, crp->reg_width,
-                         crp->field_width, pos) == value)
-               return 0;
-
-       return -1;
-}
-
 enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
 
 static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
@@ -299,7 +388,7 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
        struct pinmux_cfg_reg *cr = NULL;
        pinmux_enum_t enum_id;
        struct pinmux_range *range;
-       int in_range, pos, index;
+       int in_range, pos, field, value;
        unsigned long *cntp;
 
        switch (pinmux_type) {
@@ -330,7 +419,8 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 
        pos = 0;
        enum_id = 0;
-       index = 0;
+       field = 0;
+       value = 0;
        while (1) {
                pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id);
                if (pos <= 0)
@@ -377,17 +467,19 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
                if (!in_range)
                        continue;
 
-               if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0)
+               if (get_config_reg(gpioc, enum_id, &cr,
+                                  &field, &value, &cntp) != 0)
                        goto out_err;
 
                switch (cfg_mode) {
                case GPIO_CFG_DRYRUN:
-                       if (!*cntp || !check_config_reg(gpioc, cr, index))
+                       if (!*cntp ||
+                           (read_config_reg(gpioc, cr, field) != value))
                                continue;
                        break;
 
                case GPIO_CFG_REQ:
-                       write_config_reg(gpioc, cr, index);
+                       write_config_reg(gpioc, cr, field, value);
                        *cntp = *cntp + 1;
                        break;
 
@@ -564,7 +656,7 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
        if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
                return -EINVAL;
 
-       return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
+       return gpio_read_bit(dr, bit);
 }
 
 static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -606,10 +698,15 @@ static int sh_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 int register_pinmux(struct pinmux_info *pip)
 {
        struct gpio_chip *chip = &pip->chip;
+       int ret;
 
        pr_info("%s handling gpio %d -> %d\n",
                pip->name, pip->first_gpio, pip->last_gpio);
 
+       ret = pfc_ioremap(pip);
+       if (ret < 0)
+               return ret;
+
        setup_data_regs(pip);
 
        chip->request = sh_gpio_request;
@@ -627,12 +724,16 @@ int register_pinmux(struct pinmux_info *pip)
        chip->base = pip->first_gpio;
        chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
 
-       return gpiochip_add(chip);
+       ret = gpiochip_add(chip);
+       if (ret < 0)
+               pfc_iounmap(pip);
+
+       return ret;
 }
 
 int unregister_pinmux(struct pinmux_info *pip)
 {
        pr_info("%s deregistering\n", pip->name);
-
+       pfc_iounmap(pip);
        return gpiochip_remove(&pip->chip);
 }
index aff9d612dff02a46b38d6b4133d0283dbc3f8468..9e62349b3d9f22cfeb59d2fcea49da4b068aac34 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
@@ -73,6 +74,7 @@ struct sci_port {
        struct clk              *fclk;
 
        char                    *irqstr[SCIx_NR_IRQS];
+       char                    *gpiostr[SCIx_NR_FNS];
 
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
@@ -474,8 +476,15 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
        if (!reg->size)
                return;
 
-       if (!(cflag & CRTSCTS))
-               sci_out(port, SCSPTR, 0x0080); /* Set RTS = 1 */
+       if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) &&
+           ((!(cflag & CRTSCTS)))) {
+               unsigned short status;
+
+               status = sci_in(port, SCSPTR);
+               status &= ~SCSPTR_CTSIO;
+               status |= SCSPTR_RTSIO;
+               sci_out(port, SCSPTR, status); /* Set RTS = 1 */
+       }
 }
 
 static int sci_txfill(struct uart_port *port)
@@ -621,6 +630,7 @@ static void sci_receive_chars(struct uart_port *port)
                } else {
                        for (i = 0; i < count; i++) {
                                char c = sci_in(port, SCxRDR);
+
                                status = sci_in(port, SCxSR);
 #if defined(CONFIG_CPU_SH3)
                                /* Skip "chars" during break */
@@ -649,9 +659,11 @@ static void sci_receive_chars(struct uart_port *port)
                                /* Store data and status */
                                if (status & SCxSR_FER(port)) {
                                        flag = TTY_FRAME;
+                                       port->icount.frame++;
                                        dev_notice(port->dev, "frame error\n");
                                } else if (status & SCxSR_PER(port)) {
                                        flag = TTY_PARITY;
+                                       port->icount.parity++;
                                        dev_notice(port->dev, "parity error\n");
                                } else
                                        flag = TTY_NORMAL;
@@ -723,6 +735,8 @@ static int sci_handle_errors(struct uart_port *port)
         */
        if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) {
                if (status & (1 << s->cfg->overrun_bit)) {
+                       port->icount.overrun++;
+
                        /* overrun error */
                        if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
                                copied++;
@@ -737,6 +751,8 @@ static int sci_handle_errors(struct uart_port *port)
                        struct sci_port *sci_port = to_sci_port(port);
 
                        if (!sci_port->break_flag) {
+                               port->icount.brk++;
+
                                sci_port->break_flag = 1;
                                sci_schedule_break_timer(sci_port);
 
@@ -752,6 +768,8 @@ static int sci_handle_errors(struct uart_port *port)
 
                } else {
                        /* frame error */
+                       port->icount.frame++;
+
                        if (tty_insert_flip_char(tty, 0, TTY_FRAME))
                                copied++;
 
@@ -761,6 +779,8 @@ static int sci_handle_errors(struct uart_port *port)
 
        if (status & SCxSR_PER(port)) {
                /* parity error */
+               port->icount.parity++;
+
                if (tty_insert_flip_char(tty, 0, TTY_PARITY))
                        copied++;
 
@@ -787,6 +807,8 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
        if ((sci_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) {
                sci_out(port, SCLSR, 0);
 
+               port->icount.overrun++;
+
                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                tty_flip_buffer_push(tty);
 
@@ -812,6 +834,9 @@ static int sci_handle_breaks(struct uart_port *port)
                /* Debounce break */
                s->break_flag = 1;
 #endif
+
+               port->icount.brk++;
+
                /* Notify of BREAK */
                if (tty_insert_flip_char(tty, 0, TTY_BREAK))
                        copied++;
@@ -1082,6 +1107,67 @@ static void sci_free_irq(struct sci_port *port)
        }
 }
 
+static const char *sci_gpio_names[SCIx_NR_FNS] = {
+       "sck", "rxd", "txd", "cts", "rts",
+};
+
+static const char *sci_gpio_str(unsigned int index)
+{
+       return sci_gpio_names[index];
+}
+
+static void __devinit sci_init_gpios(struct sci_port *port)
+{
+       struct uart_port *up = &port->port;
+       int i;
+
+       if (!port->cfg)
+               return;
+
+       for (i = 0; i < SCIx_NR_FNS; i++) {
+               const char *desc;
+               int ret;
+
+               if (!port->cfg->gpios[i])
+                       continue;
+
+               desc = sci_gpio_str(i);
+
+               port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s",
+                                            dev_name(up->dev), desc);
+
+               /*
+                * If we've failed the allocation, we can still continue
+                * on with a NULL string.
+                */
+               if (!port->gpiostr[i])
+                       dev_notice(up->dev, "%s string allocation failure\n",
+                                  desc);
+
+               ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]);
+               if (unlikely(ret != 0)) {
+                       dev_notice(up->dev, "failed %s gpio request\n", desc);
+
+                       /*
+                        * If we can't get the GPIO for whatever reason,
+                        * no point in keeping the verbose string around.
+                        */
+                       kfree(port->gpiostr[i]);
+               }
+       }
+}
+
+static void sci_free_gpios(struct sci_port *port)
+{
+       int i;
+
+       for (i = 0; i < SCIx_NR_FNS; i++)
+               if (port->cfg->gpios[i]) {
+                       gpio_free(port->cfg->gpios[i]);
+                       kfree(port->gpiostr[i]);
+               }
+}
+
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
        unsigned short status = sci_in(port, SCxSR);
@@ -1090,19 +1176,39 @@ static unsigned int sci_tx_empty(struct uart_port *port)
        return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
 }
 
+/*
+ * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
+ * CTS/RTS is supported in hardware by at least one port and controlled
+ * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
+ * handled via the ->init_pins() op, which is a bit of a one-way street,
+ * lacking any ability to defer pin control -- this will later be
+ * converted over to the GPIO framework).
+ *
+ * Other modes (such as loopback) are supported generically on certain
+ * port types, but not others. For these it's sufficient to test for the
+ * existence of the support register and simply ignore the port type.
+ */
 static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
-       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
-       /* If you have signals for DTR and DCD, please implement here. */
+       if (mctrl & TIOCM_LOOP) {
+               struct plat_sci_reg *reg;
+
+               /*
+                * Standard loopback mode for SCFCR ports.
+                */
+               reg = sci_getreg(port, SCFCR);
+               if (reg->size)
+                       sci_out(port, SCFCR, sci_in(port, SCFCR) | 1);
+       }
 }
 
 static unsigned int sci_get_mctrl(struct uart_port *port)
 {
-       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
-          and CTS/RTS */
-
-       return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
+       /*
+        * CTS/RTS is handled in hardware when supported, while nothing
+        * else is wired up. Keep it simple and simply assert DSR/CAR.
+        */
+       return TIOCM_DSR | TIOCM_CAR;
 }
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1449,12 +1555,17 @@ static void sci_stop_rx(struct uart_port *port)
 
 static void sci_enable_ms(struct uart_port *port)
 {
-       /* Nothing here yet .. */
+       /*
+        * Not supported by hardware, always a nop.
+        */
 }
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
 {
-       /* Nothing here yet .. */
+       /*
+        * Not supported by hardware. Most parts couple break and rx
+        * interrupts together, with break detection always enabled.
+        */
 }
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1652,6 +1763,7 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
 
 static void sci_reset(struct uart_port *port)
 {
+       struct plat_sci_reg *reg;
        unsigned int status;
 
        do {
@@ -1660,7 +1772,8 @@ static void sci_reset(struct uart_port *port)
 
        sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
 
-       if (port->type != PORT_SCI)
+       reg = sci_getreg(port, SCFCR);
+       if (reg->size)
                sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
 }
 
@@ -1668,9 +1781,9 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
        struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg;
        unsigned int baud, smr_val, max_baud;
        int t = -1;
-       u16 scfcr = 0;
 
        /*
         * earlyprintk comes here early on with port->uartclk set to zero.
@@ -1720,7 +1833,27 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        }
 
        sci_init_pins(port, termios->c_cflag);
-       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
+
+       reg = sci_getreg(port, SCFCR);
+       if (reg->size) {
+               unsigned short ctrl = sci_in(port, SCFCR);
+
+               if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) {
+                       if (termios->c_cflag & CRTSCTS)
+                               ctrl |= SCFCR_MCE;
+                       else
+                               ctrl &= ~SCFCR_MCE;
+               }
+
+               /*
+                * As we've done a sci_reset() above, ensure we don't
+                * interfere with the FIFOs while toggling MCE. As the
+                * reset values could still be set, simply mask them out.
+                */
+               ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
+
+               sci_out(port, SCFCR, ctrl);
+       }
 
        sci_out(port, SCSCR, s->cfg->scscr);
 
@@ -1892,6 +2025,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
        struct uart_port *port = &sci_port->port;
        int ret;
 
+       sci_port->cfg   = p;
+
        port->ops       = &sci_uart_ops;
        port->iotype    = UPIO_MEM;
        port->line      = index;
@@ -1937,6 +2072,8 @@ static int __devinit sci_init_single(struct platform_device *dev,
 
                port->dev = &dev->dev;
 
+               sci_init_gpios(sci_port);
+
                pm_runtime_irq_safe(&dev->dev);
                pm_runtime_enable(&dev->dev);
        }
@@ -1971,8 +2108,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
                p->error_mask |= (1 << p->overrun_bit);
        }
 
-       sci_port->cfg           = p;
-
        port->mapbase           = p->mapbase;
        port->type              = p->type;
        port->flags             = p->flags;
@@ -2113,9 +2248,16 @@ static int sci_runtime_suspend(struct device *dev)
        struct uart_port *port = &sci_port->port;
 
        if (uart_console(port)) {
+               struct plat_sci_reg *reg;
+
                sci_port->saved_smr = sci_in(port, SCSMR);
                sci_port->saved_brr = sci_in(port, SCBRR);
-               sci_port->saved_fcr = sci_in(port, SCFCR);
+
+               reg = sci_getreg(port, SCFCR);
+               if (reg->size)
+                       sci_port->saved_fcr = sci_in(port, SCFCR);
+               else
+                       sci_port->saved_fcr = 0;
        }
        return 0;
 }
@@ -2129,7 +2271,10 @@ static int sci_runtime_resume(struct device *dev)
                sci_reset(port);
                sci_out(port, SCSMR, sci_port->saved_smr);
                sci_out(port, SCBRR, sci_port->saved_brr);
-               sci_out(port, SCFCR, sci_port->saved_fcr);
+
+               if (sci_port->saved_fcr)
+                       sci_out(port, SCFCR, sci_port->saved_fcr);
+
                sci_out(port, SCSCR, sci_port->cfg->scscr);
        }
        return 0;
@@ -2169,6 +2314,8 @@ static int sci_remove(struct platform_device *dev)
        cpufreq_unregister_notifier(&port->freq_transition,
                                    CPUFREQ_TRANSITION_NOTIFIER);
 
+       sci_free_gpios(port);
+
        uart_remove_one_port(&sci_uart_driver, &port->port);
 
        clk_put(port->iclk);
index e9bed038aa1fc11e3c3b2f0ef3c01e967118b846..a1a2d364f92b6a5fa92e865e4fd91954ce6119dc 100644 (file)
@@ -17,7 +17,9 @@
     defined(CONFIG_ARCH_SH73A0) || \
     defined(CONFIG_ARCH_SH7367) || \
     defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
+    defined(CONFIG_ARCH_SH7372) || \
+    defined(CONFIG_ARCH_R8A7740)
+
 # define SCxSR_RDxF_CLEAR(port)         (sci_in(port, SCxSR) & 0xfffc)
 # define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
 # define SCxSR_TDxE_CLEAR(port)         (sci_in(port, SCxSR) & 0xffdf)
index 02bd47bdee1c504727d29903ccb8d19bf6867829..0bd08ef2b39407cda69cfd1b32fea1808fd31176 100644 (file)
@@ -45,77 +45,12 @@ to_uio_pci_generic_dev(struct uio_info *info)
 static irqreturn_t irqhandler(int irq, struct uio_info *info)
 {
        struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info);
-       struct pci_dev *pdev = gdev->pdev;
-       irqreturn_t ret = IRQ_NONE;
-       u32 cmd_status_dword;
-       u16 origcmd, newcmd, status;
-
-       /* We do a single dword read to retrieve both command and status.
-        * Document assumptions that make this possible. */
-       BUILD_BUG_ON(PCI_COMMAND % 4);
-       BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
-
-       pci_block_user_cfg_access(pdev);
-
-       /* Read both command and status registers in a single 32-bit operation.
-        * Note: we could cache the value for command and move the status read
-        * out of the lock if there was a way to get notified of user changes
-        * to command register through sysfs. Should be good for shared irqs. */
-       pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword);
-       origcmd = cmd_status_dword;
-       status = cmd_status_dword >> 16;
-
-       /* Check interrupt status register to see whether our device
-        * triggered the interrupt. */
-       if (!(status & PCI_STATUS_INTERRUPT))
-               goto done;
-
-       /* We triggered the interrupt, disable it. */
-       newcmd = origcmd | PCI_COMMAND_INTX_DISABLE;
-       if (newcmd != origcmd)
-               pci_write_config_word(pdev, PCI_COMMAND, newcmd);
 
-       /* UIO core will signal the user process. */
-       ret = IRQ_HANDLED;
-done:
-
-       pci_unblock_user_cfg_access(pdev);
-       return ret;
-}
+       if (!pci_check_and_mask_intx(gdev->pdev))
+               return IRQ_NONE;
 
-/* Verify that the device supports Interrupt Disable bit in command register,
- * per PCI 2.3, by flipping this bit and reading it back: this bit was readonly
- * in PCI 2.2. */
-static int __devinit verify_pci_2_3(struct pci_dev *pdev)
-{
-       u16 orig, new;
-       int err = 0;
-
-       pci_block_user_cfg_access(pdev);
-       pci_read_config_word(pdev, PCI_COMMAND, &orig);
-       pci_write_config_word(pdev, PCI_COMMAND,
-                             orig ^ PCI_COMMAND_INTX_DISABLE);
-       pci_read_config_word(pdev, PCI_COMMAND, &new);
-       /* There's no way to protect against
-        * hardware bugs or detect them reliably, but as long as we know
-        * what the value should be, let's go ahead and check it. */
-       if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) {
-               err = -EBUSY;
-               dev_err(&pdev->dev, "Command changed from 0x%x to 0x%x: "
-                       "driver or HW bug?\n", orig, new);
-               goto err;
-       }
-       if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) {
-               dev_warn(&pdev->dev, "Device does not support "
-                        "disabling interrupts: unable to bind.\n");
-               err = -ENODEV;
-               goto err;
-       }
-       /* Now restore the original value. */
-       pci_write_config_word(pdev, PCI_COMMAND, orig);
-err:
-       pci_unblock_user_cfg_access(pdev);
-       return err;
+       /* UIO core will signal the user process. */
+       return IRQ_HANDLED;
 }
 
 static int __devinit probe(struct pci_dev *pdev,
@@ -138,9 +73,10 @@ static int __devinit probe(struct pci_dev *pdev,
                return -ENODEV;
        }
 
-       err = verify_pci_2_3(pdev);
-       if (err)
+       if (!pci_intx_mask_supported(pdev)) {
+               err = -ENODEV;
                goto err_verify;
+       }
 
        gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL);
        if (!gdev) {
index 07ccea9ada408e30734f797d9aa81df6b610ee79..74fe6e62e0f7c6a18552d3958c3f6ad6580b80c5 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
 
 #define AB8500_MAIN_WD_CTRL_REG 0x01
 #define AB8500_USB_LINE_STAT_REG 0x80
index 1105fa1ed7f4a47faf5e26e0796588d4dcaef585..a1376dc73d71cd79492c388afc340d7fba229545 100644 (file)
@@ -270,17 +270,7 @@ static struct platform_driver pm860x_backlight_driver = {
        .remove         = pm860x_backlight_remove,
 };
 
-static int __init pm860x_backlight_init(void)
-{
-       return platform_driver_register(&pm860x_backlight_driver);
-}
-module_init(pm860x_backlight_init);
-
-static void __exit pm860x_backlight_exit(void)
-{
-       platform_driver_unregister(&pm860x_backlight_driver);
-}
-module_exit(pm860x_backlight_exit);
+module_platform_driver(pm860x_backlight_driver);
 
 MODULE_DESCRIPTION("Backlight Driver for Marvell Semiconductor 88PM8606");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index 278aeaa925059673fdcefa7b1c243f5a92b41837..681b36929fe406642756ca6bcd8614422a16aa0c 100644 (file)
@@ -280,14 +280,6 @@ config BACKLIGHT_WM831X
          If you have a backlight driven by the ISINK and DCDC of a
          WM831x PMIC say y to enable the backlight driver for it.
 
-config BACKLIGHT_ADX
-       tristate "Avionic Design Xanthos Backlight Driver"
-       depends on ARCH_PXA_ADX
-       default y
-       help
-         Say Y to enable the backlight driver on Avionic Design Xanthos-based
-         boards.
-
 config BACKLIGHT_ADP5520
        tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
        depends on PMIC_ADP5520
index fdd1fc4b277062333846f4f9cd3ba75855d394a7..af5cf654ec7c5c4dba3a632f0d4fc2867a681112 100644 (file)
@@ -32,7 +32,6 @@ obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o
 obj-$(CONFIG_BACKLIGHT_TOSA)   += tosa_bl.o
 obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
-obj-$(CONFIG_BACKLIGHT_ADX)    += adx_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP5520)        += adp5520_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8860)        += adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8870)        += adp8870_bl.o
index dfb763e9147ff923676e9ff2778116e3677f61ea..2e630bf1164cab84c771da9accb52109b6b69ff7 100644 (file)
@@ -384,17 +384,7 @@ static struct platform_driver adp5520_bl_driver = {
        .resume         = adp5520_bl_resume,
 };
 
-static int __init adp5520_bl_init(void)
-{
-       return platform_driver_register(&adp5520_bl_driver);
-}
-module_init(adp5520_bl_init);
-
-static void __exit adp5520_bl_exit(void)
-{
-       platform_driver_unregister(&adp5520_bl_driver);
-}
-module_exit(adp5520_bl_exit);
+module_platform_driver(adp5520_bl_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("ADP5520(01) Backlight Driver");
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
deleted file mode 100644 (file)
index c861c41..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * linux/drivers/video/backlight/adx.c
- *
- * Copyright (C) 2009 Avionic Design GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Written by Thierry Reding <thierry.reding@avionic-design.de>
- */
-
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <linux/gfp.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-/* register definitions */
-#define ADX_BACKLIGHT_CONTROL          0x00
-#define ADX_BACKLIGHT_CONTROL_ENABLE   (1 << 0)
-#define ADX_BACKLIGHT_BRIGHTNESS       0x08
-#define ADX_BACKLIGHT_STATUS           0x10
-#define ADX_BACKLIGHT_ERROR            0x18
-
-struct adxbl {
-       void __iomem *base;
-};
-
-static int adx_backlight_update_status(struct backlight_device *bldev)
-{
-       struct adxbl *bl = bl_get_data(bldev);
-       u32 value;
-
-       value = bldev->props.brightness;
-       writel(value, bl->base + ADX_BACKLIGHT_BRIGHTNESS);
-
-       value = readl(bl->base + ADX_BACKLIGHT_CONTROL);
-
-       if (bldev->props.state & BL_CORE_FBBLANK)
-               value &= ~ADX_BACKLIGHT_CONTROL_ENABLE;
-       else
-               value |= ADX_BACKLIGHT_CONTROL_ENABLE;
-
-       writel(value, bl->base + ADX_BACKLIGHT_CONTROL);
-
-       return 0;
-}
-
-static int adx_backlight_get_brightness(struct backlight_device *bldev)
-{
-       struct adxbl *bl = bl_get_data(bldev);
-       u32 brightness;
-
-       brightness = readl(bl->base + ADX_BACKLIGHT_BRIGHTNESS);
-       return brightness & 0xff;
-}
-
-static int adx_backlight_check_fb(struct backlight_device *bldev, struct fb_info *fb)
-{
-       return 1;
-}
-
-static const struct backlight_ops adx_backlight_ops = {
-       .options = 0,
-       .update_status = adx_backlight_update_status,
-       .get_brightness = adx_backlight_get_brightness,
-       .check_fb = adx_backlight_check_fb,
-};
-
-static int __devinit adx_backlight_probe(struct platform_device *pdev)
-{
-       struct backlight_properties props;
-       struct backlight_device *bldev;
-       struct resource *res;
-       struct adxbl *bl;
-       int ret = 0;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       res = devm_request_mem_region(&pdev->dev, res->start,
-                       resource_size(res), res->name);
-       if (!res) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL);
-       if (!bl) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       bl->base = devm_ioremap_nocache(&pdev->dev, res->start,
-                       resource_size(res));
-       if (!bl->base) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.type = BACKLIGHT_RAW;
-       props.max_brightness = 0xff;
-       bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
-                                         bl, &adx_backlight_ops, &props);
-       if (IS_ERR(bldev)) {
-               ret = PTR_ERR(bldev);
-               goto out;
-       }
-
-       bldev->props.brightness = 0xff;
-       bldev->props.power = FB_BLANK_UNBLANK;
-
-       platform_set_drvdata(pdev, bldev);
-
-out:
-       return ret;
-}
-
-static int __devexit adx_backlight_remove(struct platform_device *pdev)
-{
-       struct backlight_device *bldev;
-       int ret = 0;
-
-       bldev = platform_get_drvdata(pdev);
-       bldev->props.power = FB_BLANK_UNBLANK;
-       bldev->props.brightness = 0xff;
-       backlight_update_status(bldev);
-       backlight_device_unregister(bldev);
-       platform_set_drvdata(pdev, NULL);
-
-       return ret;
-}
-
-#ifdef CONFIG_PM
-static int adx_backlight_suspend(struct platform_device *pdev,
-               pm_message_t state)
-{
-       return 0;
-}
-
-static int adx_backlight_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-#else
-#define adx_backlight_suspend NULL
-#define adx_backlight_resume NULL
-#endif
-
-static struct platform_driver adx_backlight_driver = {
-       .probe = adx_backlight_probe,
-       .remove = __devexit_p(adx_backlight_remove),
-       .suspend = adx_backlight_suspend,
-       .resume = adx_backlight_resume,
-       .driver = {
-               .name = "adx-backlight",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init adx_backlight_init(void)
-{
-       return platform_driver_register(&adx_backlight_driver);
-}
-
-static void __exit adx_backlight_exit(void)
-{
-       platform_driver_unregister(&adx_backlight_driver);
-}
-
-module_init(adx_backlight_init);
-module_exit(adx_backlight_exit);
-
-MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
-MODULE_DESCRIPTION("Avionic Design Xanthos Backlight Driver");
-MODULE_LICENSE("GPL v2");
index 7363c1b169e8f5719e5ba9bc1dee3542de468169..bf5b1ece71605d701516f599af7ef1ce18751a11 100644 (file)
@@ -102,7 +102,7 @@ static void backlight_generate_event(struct backlight_device *bd,
 }
 
 static ssize_t backlight_show_power(struct device *dev,
-               struct device_attribute *attr,char *buf)
+               struct device_attribute *attr, char *buf)
 {
        struct backlight_device *bd = to_backlight_device(dev);
 
@@ -116,7 +116,7 @@ static ssize_t backlight_store_power(struct device *dev,
        struct backlight_device *bd = to_backlight_device(dev);
        unsigned long power;
 
-       rc = strict_strtoul(buf, 0, &power);
+       rc = kstrtoul(buf, 0, &power);
        if (rc)
                return rc;
 
@@ -150,7 +150,7 @@ static ssize_t backlight_store_brightness(struct device *dev,
        struct backlight_device *bd = to_backlight_device(dev);
        unsigned long brightness;
 
-       rc = strict_strtoul(buf, 0, &brightness);
+       rc = kstrtoul(buf, 0, &brightness);
        if (rc)
                return rc;
 
index d68f14bbb687d8391b60f72f8949c3d2c396fbcf..abb4a06268f1831e57815475338447fb83822543 100644 (file)
@@ -199,17 +199,7 @@ static struct platform_driver da903x_backlight_driver = {
        .remove         = da903x_backlight_remove,
 };
 
-static int __init da903x_backlight_init(void)
-{
-       return platform_driver_register(&da903x_backlight_driver);
-}
-module_init(da903x_backlight_init);
-
-static void __exit da903x_backlight_exit(void)
-{
-       platform_driver_unregister(&da903x_backlight_driver);
-}
-module_exit(da903x_backlight_exit);
+module_platform_driver(da903x_backlight_driver);
 
 MODULE_DESCRIPTION("Backlight Driver for Dialog Semiconductor DA9030/DA9034");
 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
index c74a6f4baa127a313ea8eea5bf16adde62856b2a..b62b8b9063b53beeacffa86c8259d971372e3ec9 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/module.h>
 #include <linux/io.h>
 #include <linux/fb.h>
 #include <linux/backlight.h>
@@ -144,17 +143,7 @@ static struct platform_driver ep93xxbl_driver = {
        .resume         = ep93xxbl_resume,
 };
 
-static int __init ep93xxbl_init(void)
-{
-       return platform_driver_register(&ep93xxbl_driver);
-}
-module_init(ep93xxbl_init);
-
-static void __exit ep93xxbl_exit(void)
-{
-       platform_driver_unregister(&ep93xxbl_driver);
-}
-module_exit(ep93xxbl_exit);
+module_platform_driver(ep93xxbl_driver);
 
 MODULE_DESCRIPTION("EP93xx Backlight Driver");
 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
index adb191466d646355fdfcb5193c80b864631c3919..9ce6170c186079414dcb62123100e7786b032721 100644 (file)
@@ -132,18 +132,7 @@ static struct platform_driver genericbl_driver = {
        },
 };
 
-static int __init genericbl_init(void)
-{
-       return platform_driver_register(&genericbl_driver);
-}
-
-static void __exit genericbl_exit(void)
-{
-       platform_driver_unregister(&genericbl_driver);
-}
-
-module_init(genericbl_init);
-module_exit(genericbl_exit);
+module_platform_driver(genericbl_driver);
 
 MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
 MODULE_DESCRIPTION("Generic Backlight Driver");
index de65d80159beed3b90b21313070538b42c3ee4aa..2f8af5d786abbb5971aed6cad8c153229a4b4b84 100644 (file)
@@ -147,19 +147,8 @@ static struct platform_driver jornada_bl_driver = {
        },
 };
 
-static int __init jornada_bl_init(void)
-{
-       return platform_driver_register(&jornada_bl_driver);
-}
-
-static void __exit jornada_bl_exit(void)
-{
-       platform_driver_unregister(&jornada_bl_driver);
-}
+module_platform_driver(jornada_bl_driver);
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver");
 MODULE_LICENSE("GPL");
-
-module_init(jornada_bl_init);
-module_exit(jornada_bl_exit);
index d2ff658b4144f91cf6d10a6e04f5178822db26f8..22d231a17e3c4649652ec1992567111e5b70cd6c 100644 (file)
@@ -135,19 +135,8 @@ static struct platform_driver jornada_lcd_driver = {
        },
 };
 
-static int __init jornada_lcd_init(void)
-{
-       return platform_driver_register(&jornada_lcd_driver);
-}
-
-static void __exit jornada_lcd_exit(void)
-{
-       platform_driver_unregister(&jornada_lcd_driver);
-}
+module_platform_driver(jornada_lcd_driver);
 
 MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
 MODULE_DESCRIPTION("HP Jornada 710/720/728 LCD driver");
 MODULE_LICENSE("GPL");
-
-module_init(jornada_lcd_init);
-module_exit(jornada_lcd_exit);
index 71a11cadffc48134b3ab164cb798f7278be6f802..79c1b0d609a809e189f43515ee20f648a7d2e8fa 100644 (file)
@@ -97,19 +97,16 @@ static ssize_t lcd_store_power(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
-       char *endp;
        struct lcd_device *ld = to_lcd_device(dev);
-       int power = simple_strtoul(buf, &endp, 0);
-       size_t size = endp - buf;
+       unsigned long power;
 
-       if (isspace(*endp))
-               size++;
-       if (size != count)
-               return -EINVAL;
+       rc = kstrtoul(buf, 0, &power);
+       if (rc)
+               return rc;
 
        mutex_lock(&ld->ops_lock);
        if (ld->ops && ld->ops->set_power) {
-               pr_debug("lcd: set power to %d\n", power);
+               pr_debug("lcd: set power to %lu\n", power);
                ld->ops->set_power(ld, power);
                rc = count;
        }
@@ -136,19 +133,16 @@ static ssize_t lcd_store_contrast(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        int rc = -ENXIO;
-       char *endp;
        struct lcd_device *ld = to_lcd_device(dev);
-       int contrast = simple_strtoul(buf, &endp, 0);
-       size_t size = endp - buf;
+       unsigned long contrast;
 
-       if (isspace(*endp))
-               size++;
-       if (size != count)
-               return -EINVAL;
+       rc = kstrtoul(buf, 0, &contrast);
+       if (rc)
+               return rc;
 
        mutex_lock(&ld->ops_lock);
        if (ld->ops && ld->ops->set_contrast) {
-               pr_debug("lcd: set contrast to %d\n", contrast);
+               pr_debug("lcd: set contrast to %lu\n", contrast);
                ld->ops->set_contrast(ld, contrast);
                rc = count;
        }
index da9a5ce0ccb8463dcb85b18c708738b483383352..78dafc0c8fc5a1ec4830d04660d5914441e4fe09 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/lcd.h>
 #include <linux/backlight.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 
 #include "ld9040_gamma.h"
 
@@ -53,8 +54,51 @@ struct ld9040 {
        struct lcd_device               *ld;
        struct backlight_device         *bd;
        struct lcd_platform_data        *lcd_pd;
+
+       struct mutex                    lock;
+       bool  enabled;
+};
+
+static struct regulator_bulk_data supplies[] = {
+       { .supply = "vdd3", },
+       { .supply = "vci", },
 };
 
+static void ld9040_regulator_enable(struct ld9040 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd = NULL;
+
+       pd = lcd->lcd_pd;
+       mutex_lock(&lcd->lock);
+       if (!lcd->enabled) {
+               ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+               if (ret)
+                       goto out;
+
+               lcd->enabled = true;
+       }
+       mdelay(pd->power_on_delay);
+out:
+       mutex_unlock(&lcd->lock);
+}
+
+static void ld9040_regulator_disable(struct ld9040 *lcd)
+{
+       int ret = 0;
+
+       mutex_lock(&lcd->lock);
+       if (lcd->enabled) {
+               ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+               if (ret)
+                       goto out;
+
+               lcd->enabled = false;
+       }
+out:
+       mutex_unlock(&lcd->lock);
+}
+
 static const unsigned short seq_swreset[] = {
        0x01, COMMAND_ONLY,
        ENDDEF, 0x00
@@ -532,13 +576,8 @@ static int ld9040_power_on(struct ld9040 *lcd)
                return -EFAULT;
        }
 
-       if (!pd->power_on) {
-               dev_err(lcd->dev, "power_on is NULL.\n");
-               return -EFAULT;
-       } else {
-               pd->power_on(lcd->ld, 1);
-               mdelay(pd->power_on_delay);
-       }
+       /* lcd power on */
+       ld9040_regulator_enable(lcd);
 
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
@@ -582,11 +621,8 @@ static int ld9040_power_off(struct ld9040 *lcd)
 
        mdelay(pd->power_off_delay);
 
-       if (!pd->power_on) {
-               dev_err(lcd->dev, "power_on is NULL.\n");
-               return -EFAULT;
-       } else
-               pd->power_on(lcd->ld, 0);
+       /* lcd power off */
+       ld9040_regulator_disable(lcd);
 
        return 0;
 }
@@ -693,6 +729,14 @@ static int ld9040_probe(struct spi_device *spi)
                goto out_free_lcd;
        }
 
+       mutex_init(&lcd->lock);
+
+       ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+       if (ret) {
+               dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
+               goto out_free_lcd;
+       }
+
        ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
        if (IS_ERR(ld)) {
                ret = PTR_ERR(ld);
@@ -739,6 +783,8 @@ static int ld9040_probe(struct spi_device *spi)
 out_unregister_lcd:
        lcd_device_unregister(lcd->ld);
 out_free_lcd:
+       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+
        kfree(lcd);
        return ret;
 }
@@ -750,6 +796,7 @@ static int __devexit ld9040_remove(struct spi_device *spi)
        ld9040_power(lcd, FB_BLANK_POWERDOWN);
        backlight_device_unregister(lcd->bd);
        lcd_device_unregister(lcd->ld);
+       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
        kfree(lcd);
 
        return 0;
index 7bbc802560ea0473229e74ce89b2da299e140fce..c915e3b5388698b2c8c8007167ed531ad5e38580 100644 (file)
@@ -188,17 +188,7 @@ static struct platform_driver max8925_backlight_driver = {
        .remove         = __devexit_p(max8925_backlight_remove),
 };
 
-static int __init max8925_backlight_init(void)
-{
-       return platform_driver_register(&max8925_backlight_driver);
-}
-module_init(max8925_backlight_init);
-
-static void __exit max8925_backlight_exit(void)
-{
-       platform_driver_unregister(&max8925_backlight_driver);
-};
-module_exit(max8925_backlight_exit);
+module_platform_driver(max8925_backlight_driver);
 
 MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index 08d26a72394c8e9920cc23e115802c642902305d..d8cde277ec83a691c658b9e0afef6c3aef63ffb4 100644 (file)
@@ -195,18 +195,7 @@ static struct platform_driver omapbl_driver = {
        },
 };
 
-static int __init omapbl_init(void)
-{
-       return platform_driver_register(&omapbl_driver);
-}
-
-static void __exit omapbl_exit(void)
-{
-       platform_driver_unregister(&omapbl_driver);
-}
-
-module_init(omapbl_init);
-module_exit(omapbl_exit);
+module_platform_driver(omapbl_driver);
 
 MODULE_AUTHOR("Andrzej Zaborowski <balrog@zabor.org>");
 MODULE_DESCRIPTION("OMAP LCD Backlight driver");
index ef5628d60563841aceab7bca62191c0faf57f763..13e88b71daecc42b5e833c252fd1305a19cc5ed0 100644 (file)
@@ -173,17 +173,7 @@ static struct platform_driver pcf50633_bl_driver = {
        },
 };
 
-static int __init pcf50633_bl_init(void)
-{
-       return platform_driver_register(&pcf50633_bl_driver);
-}
-module_init(pcf50633_bl_init);
-
-static void __exit pcf50633_bl_exit(void)
-{
-       platform_driver_unregister(&pcf50633_bl_driver);
-}
-module_exit(pcf50633_bl_exit);
+module_platform_driver(pcf50633_bl_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("PCF50633 backlight driver");
index 302330acf6284e0b22e7dc77a6ea055603aa5358..f0bf491ed087a57d86fade373ad326fb6c68300d 100644 (file)
@@ -85,7 +85,8 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       plcd = kzalloc(sizeof(struct platform_lcd), GFP_KERNEL);
+       plcd = devm_kzalloc(&pdev->dev, sizeof(struct platform_lcd),
+                           GFP_KERNEL);
        if (!plcd) {
                dev_err(dev, "no memory for state\n");
                return -ENOMEM;
@@ -98,7 +99,7 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev)
        if (IS_ERR(plcd->lcd)) {
                dev_err(dev, "cannot register lcd device\n");
                err = PTR_ERR(plcd->lcd);
-               goto err_mem;
+               goto err;
        }
 
        platform_set_drvdata(pdev, plcd);
@@ -106,8 +107,7 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev)
 
        return 0;
 
- err_mem:
-       kfree(plcd);
+ err:
        return err;
 }
 
@@ -116,7 +116,6 @@ static int __devexit platform_lcd_remove(struct platform_device *pdev)
        struct platform_lcd *plcd = platform_get_drvdata(pdev);
 
        lcd_device_unregister(plcd->lcd);
-       kfree(plcd);
 
        return 0;
 }
@@ -157,18 +156,7 @@ static struct platform_driver platform_lcd_driver = {
        .resume         = platform_lcd_resume,
 };
 
-static int __init platform_lcd_init(void)
-{
-       return platform_driver_register(&platform_lcd_driver);
-}
-
-static void __exit platform_lcd_cleanup(void)
-{
-       platform_driver_unregister(&platform_lcd_driver);
-}
-
-module_init(platform_lcd_init);
-module_exit(platform_lcd_cleanup);
+module_platform_driver(platform_lcd_driver);
 
 MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>");
 MODULE_LICENSE("GPL v2");
index 8b5b2a4124c7980129be8146f881772f5c33fa97..7496d04e1d3c1fcda109ae04d12e79c24edacc0e 100644 (file)
@@ -169,10 +169,9 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int pwm_backlight_suspend(struct platform_device *pdev,
-                                pm_message_t state)
+static int pwm_backlight_suspend(struct device *dev)
 {
-       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct backlight_device *bl = dev_get_drvdata(dev);
        struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 
        if (pb->notify)
@@ -184,40 +183,32 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
        return 0;
 }
 
-static int pwm_backlight_resume(struct platform_device *pdev)
+static int pwm_backlight_resume(struct device *dev)
 {
-       struct backlight_device *bl = platform_get_drvdata(pdev);
+       struct backlight_device *bl = dev_get_drvdata(dev);
 
        backlight_update_status(bl);
        return 0;
 }
-#else
-#define pwm_backlight_suspend  NULL
-#define pwm_backlight_resume   NULL
+
+static SIMPLE_DEV_PM_OPS(pwm_backlight_pm_ops, pwm_backlight_suspend,
+                        pwm_backlight_resume);
+
 #endif
 
 static struct platform_driver pwm_backlight_driver = {
        .driver         = {
                .name   = "pwm-backlight",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &pwm_backlight_pm_ops,
+#endif
        },
        .probe          = pwm_backlight_probe,
        .remove         = pwm_backlight_remove,
-       .suspend        = pwm_backlight_suspend,
-       .resume         = pwm_backlight_resume,
 };
 
-static int __init pwm_backlight_init(void)
-{
-       return platform_driver_register(&pwm_backlight_driver);
-}
-module_init(pwm_backlight_init);
-
-static void __exit pwm_backlight_exit(void)
-{
-       platform_driver_unregister(&pwm_backlight_driver);
-}
-module_exit(pwm_backlight_exit);
+module_platform_driver(pwm_backlight_driver);
 
 MODULE_DESCRIPTION("PWM based Backlight Driver");
 MODULE_LICENSE("GPL");
index fbe9e9316f3b51a09e5de299a9a544d878bf5b33..4e915f5eca99b43697e195207150a00bae631f22 100644 (file)
@@ -236,17 +236,7 @@ static struct platform_driver wm831x_backlight_driver = {
        .remove         = wm831x_backlight_remove,
 };
 
-static int __init wm831x_backlight_init(void)
-{
-       return platform_driver_register(&wm831x_backlight_driver);
-}
-module_init(wm831x_backlight_init);
-
-static void __exit wm831x_backlight_exit(void)
-{
-       platform_driver_unregister(&wm831x_backlight_driver);
-}
-module_exit(wm831x_backlight_exit);
+module_platform_driver(wm831x_backlight_driver);
 
 MODULE_DESCRIPTION("Backlight Driver for WM831x PMICs");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com");
index 081dc47452742a769235d74c18cf49545efe72fd..fe13ac567d545b9408bc6e00bb108cf7b0c0d69f 100644 (file)
@@ -81,7 +81,7 @@ static int vram __devinitdata = 0;
 static int bpp __devinitdata = 8;
 static int reverse_i2c __devinitdata;
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata = 0;
+static bool nomtrr __devinitdata = false;
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 static int backlight __devinitdata = 1;
@@ -1509,7 +1509,7 @@ static int __devinit nvidiafb_setup(char *options)
                        backlight = simple_strtoul(this_opt+10, NULL, 0);
 #ifdef CONFIG_MTRR
                } else if (!strncmp(this_opt, "nomtrr", 6)) {
-                       nomtrr = 1;
+                       nomtrr = true;
 #endif
                } else if (!strncmp(this_opt, "fpdither:", 9)) {
                        fpdither = simple_strtol(this_opt+9, NULL, 0);
@@ -1599,7 +1599,7 @@ MODULE_PARM_DESC(bpp, "pixel width in bits"
 module_param(reverse_i2c, int, 0);
 MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus");
 #ifdef CONFIG_MTRR
-module_param(nomtrr, bool, 0);
+module_param(nomtrr, bool, false);
 MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
                 "(default=0)");
 #endif
index 94fd738a7741d046c76f53477d2487e94cde97ff..95aeedf198f8c9b6ee08fa59b8767d66f3ec0cc6 100644 (file)
@@ -1,4 +1,5 @@
-/* Virtio balloon implementation, inspired by Dor Loar and Marcelo
+/*
+ * Virtio balloon implementation, inspired by Dor Laor and Marcelo
  * Tosatti's implementations.
  *
  *  Copyright 2008 Rusty Russell IBM Corporation
@@ -17,7 +18,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-//#define DEBUG
+
 #include <linux/virtio.h>
 #include <linux/virtio_balloon.h>
 #include <linux/swap.h>
@@ -87,7 +88,7 @@ static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
        init_completion(&vb->acked);
 
        /* We should always be able to add one buffer to an empty queue. */
-       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
        virtqueue_kick(vq);
 
@@ -149,7 +150,6 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages--;
        }
 
-
        /*
         * Note that if
         * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
@@ -220,7 +220,7 @@ static void stats_handle_request(struct virtio_balloon *vb)
 
        vq = vb->stats_vq;
        sg_init_one(&sg, vb->stats, sizeof(vb->stats));
-       if (virtqueue_add_buf(vq, &sg, 1, 0, vb) < 0)
+       if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
        virtqueue_kick(vq);
 }
@@ -275,32 +275,21 @@ static int balloon(void *_vballoon)
        return 0;
 }
 
-static int virtballoon_probe(struct virtio_device *vdev)
+static int init_vqs(struct virtio_balloon *vb)
 {
-       struct virtio_balloon *vb;
        struct virtqueue *vqs[3];
        vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
        const char *names[] = { "inflate", "deflate", "stats" };
        int err, nvqs;
 
-       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
-       if (!vb) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       INIT_LIST_HEAD(&vb->pages);
-       vb->num_pages = 0;
-       init_waitqueue_head(&vb->config_change);
-       vb->vdev = vdev;
-       vb->need_stats_update = 0;
-
-       /* We expect two virtqueues: inflate and deflate,
-        * and optionally stat. */
+       /*
+        * We expect two virtqueues: inflate and deflate, and
+        * optionally stat.
+        */
        nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
-       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
+       err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names);
        if (err)
-               goto out_free_vb;
+               return err;
 
        vb->inflate_vq = vqs[0];
        vb->deflate_vq = vqs[1];
@@ -313,10 +302,34 @@ static int virtballoon_probe(struct virtio_device *vdev)
                 * use it to signal us later.
                 */
                sg_init_one(&sg, vb->stats, sizeof vb->stats);
-               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb) < 0)
+               if (virtqueue_add_buf(vb->stats_vq, &sg, 1, 0, vb, GFP_KERNEL)
+                   < 0)
                        BUG();
                virtqueue_kick(vb->stats_vq);
        }
+       return 0;
+}
+
+static int virtballoon_probe(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb;
+       int err;
+
+       vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
+       if (!vb) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&vb->pages);
+       vb->num_pages = 0;
+       init_waitqueue_head(&vb->config_change);
+       vb->vdev = vdev;
+       vb->need_stats_update = 0;
+
+       err = init_vqs(vb);
+       if (err)
+               goto out_free_vb;
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
@@ -351,6 +364,48 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
        kfree(vb);
 }
 
+#ifdef CONFIG_PM
+static int virtballoon_freeze(struct virtio_device *vdev)
+{
+       /*
+        * The kthread is already frozen by the PM core before this
+        * function is called.
+        */
+
+       /* Ensure we don't get any more requests from the host */
+       vdev->config->reset(vdev);
+       vdev->config->del_vqs(vdev);
+       return 0;
+}
+
+static int virtballoon_thaw(struct virtio_device *vdev)
+{
+       return init_vqs(vdev->priv);
+}
+
+static int virtballoon_restore(struct virtio_device *vdev)
+{
+       struct virtio_balloon *vb = vdev->priv;
+       struct page *page, *page2;
+
+       /* We're starting from a clean slate */
+       vb->num_pages = 0;
+
+       /*
+        * If a request wasn't complete at the time of freezing, this
+        * could have been set.
+        */
+       vb->need_stats_update = 0;
+
+       /* We don't have these pages in the balloon anymore! */
+       list_for_each_entry_safe(page, page2, &vb->pages, lru) {
+               list_del(&page->lru);
+               totalram_pages++;
+       }
+       return init_vqs(vdev->priv);
+}
+#endif
+
 static unsigned int features[] = {
        VIRTIO_BALLOON_F_MUST_TELL_HOST,
        VIRTIO_BALLOON_F_STATS_VQ,
@@ -365,6 +420,11 @@ static struct virtio_driver virtio_balloon_driver = {
        .probe =        virtballoon_probe,
        .remove =       __devexit_p(virtballoon_remove),
        .config_changed = virtballoon_changed,
+#ifdef CONFIG_PM
+       .freeze =       virtballoon_freeze,
+       .restore =      virtballoon_restore,
+       .thaw =         virtballoon_thaw,
+#endif
 };
 
 static int __init init(void)
index 0269717436af03f5d502be98629927e7591e5cc4..01d6dc250d5c50a8c01ea22d34818721d8c845d5 100644 (file)
@@ -310,8 +310,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
                        vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
 
        /* Create the vring */
-       vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN,
-                                vdev, info->queue, vm_notify, callback, name);
+       vq = vring_new_virtqueue(info->num, VIRTIO_MMIO_VRING_ALIGN, vdev,
+                                true, info->queue, vm_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto error_new_virtqueue;
index baabb7937ec2c338fc813fb91cfaac21b0c94484..635e1efb3792689b6e283766a64af11be6dc8dc6 100644 (file)
@@ -55,6 +55,10 @@ struct virtio_pci_device
        unsigned msix_vectors;
        /* Vectors allocated, excluding per-vq vectors if any */
        unsigned msix_used_vectors;
+
+       /* Status saved during hibernate/restore */
+       u8 saved_status;
+
        /* Whether we have vector per vq */
        bool per_vq_vectors;
 };
@@ -414,8 +418,8 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index,
                  vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
        /* create the vring */
-       vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
-                                vdev, info->queue, vp_notify, callback, name);
+       vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, vdev,
+                                true, info->queue, vp_notify, callback, name);
        if (!vq) {
                err = -ENOMEM;
                goto out_activate_queue;
@@ -716,19 +720,114 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
 }
 
 #ifdef CONFIG_PM
-static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+static int virtio_pci_suspend(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+
        pci_save_state(pci_dev);
        pci_set_power_state(pci_dev, PCI_D3hot);
        return 0;
 }
 
-static int virtio_pci_resume(struct pci_dev *pci_dev)
+static int virtio_pci_resume(struct device *dev)
 {
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+
        pci_restore_state(pci_dev);
        pci_set_power_state(pci_dev, PCI_D0);
        return 0;
 }
+
+static int virtio_pci_freeze(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       ret = 0;
+       vp_dev->saved_status = vp_get_status(&vp_dev->vdev);
+       if (drv && drv->freeze)
+               ret = drv->freeze(&vp_dev->vdev);
+
+       if (!ret)
+               pci_disable_device(pci_dev);
+       return ret;
+}
+
+static int restore_common(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       int ret;
+
+       ret = pci_enable_device(pci_dev);
+       if (ret)
+               return ret;
+       pci_set_master(pci_dev);
+       vp_finalize_features(&vp_dev->vdev);
+
+       return ret;
+}
+
+static int virtio_pci_thaw(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       ret = restore_common(dev);
+       if (ret)
+               return ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       if (drv && drv->thaw)
+               ret = drv->thaw(&vp_dev->vdev);
+       else if (drv && drv->restore)
+               ret = drv->restore(&vp_dev->vdev);
+
+       /* Finally, tell the device we're all set */
+       if (!ret)
+               vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
+
+       return ret;
+}
+
+static int virtio_pci_restore(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+       struct virtio_driver *drv;
+       int ret;
+
+       drv = container_of(vp_dev->vdev.dev.driver,
+                          struct virtio_driver, driver);
+
+       ret = restore_common(dev);
+       if (!ret && drv && drv->restore)
+               ret = drv->restore(&vp_dev->vdev);
+
+       /* Finally, tell the device we're all set */
+       if (!ret)
+               vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
+
+       return ret;
+}
+
+static const struct dev_pm_ops virtio_pci_pm_ops = {
+       .suspend        = virtio_pci_suspend,
+       .resume         = virtio_pci_resume,
+       .freeze         = virtio_pci_freeze,
+       .thaw           = virtio_pci_thaw,
+       .restore        = virtio_pci_restore,
+       .poweroff       = virtio_pci_suspend,
+};
 #endif
 
 static struct pci_driver virtio_pci_driver = {
@@ -737,8 +836,7 @@ static struct pci_driver virtio_pci_driver = {
        .probe          = virtio_pci_probe,
        .remove         = __devexit_p(virtio_pci_remove),
 #ifdef CONFIG_PM
-       .suspend        = virtio_pci_suspend,
-       .resume         = virtio_pci_resume,
+       .driver.pm      = &virtio_pci_pm_ops,
 #endif
 };
 
index c7a2c208f6eaded137c1f0d9ea73ea0a14100e65..79e1b292c0309b8175a84d7e4353ff94b8e13eb0 100644 (file)
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/hrtimer.h>
 
 /* virtio guest is communicating with a virtual "device" that actually runs on
  * a host processor.  Memory barriers are used to control SMP effects. */
 #ifdef CONFIG_SMP
 /* Where possible, use SMP barriers which are more lightweight than mandatory
  * barriers, because mandatory barriers control MMIO effects on accesses
- * through relaxed memory I/O windows (which virtio does not use). */
-#define virtio_mb() smp_mb()
-#define virtio_rmb() smp_rmb()
-#define virtio_wmb() smp_wmb()
+ * through relaxed memory I/O windows (which virtio-pci does not use). */
+#define virtio_mb(vq) \
+       do { if ((vq)->weak_barriers) smp_mb(); else mb(); } while(0)
+#define virtio_rmb(vq) \
+       do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0)
+#define virtio_wmb(vq) \
+       do { if ((vq)->weak_barriers) smp_rmb(); else rmb(); } while(0)
 #else
 /* We must force memory ordering even if guest is UP since host could be
  * running on another CPU, but SMP barriers are defined to barrier() in that
  * configuration. So fall back to mandatory barriers instead. */
-#define virtio_mb() mb()
-#define virtio_rmb() rmb()
-#define virtio_wmb() wmb()
+#define virtio_mb(vq) mb()
+#define virtio_rmb(vq) rmb()
+#define virtio_wmb(vq) wmb()
 #endif
 
 #ifdef DEBUG
@@ -77,6 +81,9 @@ struct vring_virtqueue
        /* Actual memory layout for this queue */
        struct vring vring;
 
+       /* Can we use weak barriers? */
+       bool weak_barriers;
+
        /* Other side has made a mess, don't try any more. */
        bool broken;
 
@@ -102,6 +109,10 @@ struct vring_virtqueue
 #ifdef DEBUG
        /* They're supposed to lock for us. */
        unsigned int in_use;
+
+       /* Figure out if their kicks are too delayed. */
+       bool last_add_time_valid;
+       ktime_t last_add_time;
 #endif
 
        /* Tokens for callbacks. */
@@ -160,12 +171,29 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        return head;
 }
 
-int virtqueue_add_buf_gfp(struct virtqueue *_vq,
-                         struct scatterlist sg[],
-                         unsigned int out,
-                         unsigned int in,
-                         void *data,
-                         gfp_t gfp)
+/**
+ * virtqueue_add_buf - expose buffer to other end
+ * @vq: the struct virtqueue we're talking about.
+ * @sg: the description of the buffer(s).
+ * @out_num: the number of sg readable by other side
+ * @in_num: the number of sg which are writable (after readable ones)
+ * @data: the token identifying the buffer.
+ * @gfp: how to do memory allocations (if necessary).
+ *
+ * Caller must ensure we don't call this with other virtqueue operations
+ * at the same time (except where noted).
+ *
+ * Returns remaining capacity of queue or a negative error
+ * (ie. ENOSPC).  Note that it only really makes sense to treat all
+ * positive return values as "available": indirect buffers mean that
+ * we can put an entire sg[] array inside a single queue entry.
+ */
+int virtqueue_add_buf(struct virtqueue *_vq,
+                     struct scatterlist sg[],
+                     unsigned int out,
+                     unsigned int in,
+                     void *data,
+                     gfp_t gfp)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        unsigned int i, avail, uninitialized_var(prev);
@@ -175,6 +203,19 @@ int virtqueue_add_buf_gfp(struct virtqueue *_vq,
 
        BUG_ON(data == NULL);
 
+#ifdef DEBUG
+       {
+               ktime_t now = ktime_get();
+
+               /* No kick or get, with .1 second between?  Warn. */
+               if (vq->last_add_time_valid)
+                       WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time))
+                                           > 100);
+               vq->last_add_time = now;
+               vq->last_add_time_valid = true;
+       }
+#endif
+
        /* If the host supports indirect descriptor tables, and we have multiple
         * buffers, then go indirect. FIXME: tune this threshold */
        if (vq->indirect && (out + in) > 1 && vq->num_free) {
@@ -227,40 +268,102 @@ add_head:
        vq->data[head] = data;
 
        /* Put entry in available array (but don't update avail->idx until they
-        * do sync).  FIXME: avoid modulus here? */
-       avail = (vq->vring.avail->idx + vq->num_added++) % vq->vring.num;
+        * do sync). */
+       avail = (vq->vring.avail->idx & (vq->vring.num-1));
        vq->vring.avail->ring[avail] = head;
 
+       /* Descriptors and available array need to be set before we expose the
+        * new available array entries. */
+       virtio_wmb(vq);
+       vq->vring.avail->idx++;
+       vq->num_added++;
+
+       /* This is very unlikely, but theoretically possible.  Kick
+        * just in case. */
+       if (unlikely(vq->num_added == (1 << 16) - 1))
+               virtqueue_kick(_vq);
+
        pr_debug("Added buffer head %i to %p\n", head, vq);
        END_USE(vq);
 
        return vq->num_free;
 }
-EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
+EXPORT_SYMBOL_GPL(virtqueue_add_buf);
 
-void virtqueue_kick(struct virtqueue *_vq)
+/**
+ * virtqueue_kick_prepare - first half of split virtqueue_kick call.
+ * @vq: the struct virtqueue
+ *
+ * Instead of virtqueue_kick(), you can do:
+ *     if (virtqueue_kick_prepare(vq))
+ *             virtqueue_notify(vq);
+ *
+ * This is sometimes useful because the virtqueue_kick_prepare() needs
+ * to be serialized, but the actual virtqueue_notify() call does not.
+ */
+bool virtqueue_kick_prepare(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        u16 new, old;
+       bool needs_kick;
+
        START_USE(vq);
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
-       virtio_wmb();
+       virtio_wmb(vq);
 
-       old = vq->vring.avail->idx;
-       new = vq->vring.avail->idx = old + vq->num_added;
+       old = vq->vring.avail->idx - vq->num_added;
+       new = vq->vring.avail->idx;
        vq->num_added = 0;
 
-       /* Need to update avail index before checking if we should notify */
-       virtio_mb();
-
-       if (vq->event ?
-           vring_need_event(vring_avail_event(&vq->vring), new, old) :
-           !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
-               /* Prod other side to tell it about changes. */
-               vq->notify(&vq->vq);
+#ifdef DEBUG
+       if (vq->last_add_time_valid) {
+               WARN_ON(ktime_to_ms(ktime_sub(ktime_get(),
+                                             vq->last_add_time)) > 100);
+       }
+       vq->last_add_time_valid = false;
+#endif
 
+       if (vq->event) {
+               needs_kick = vring_need_event(vring_avail_event(&vq->vring),
+                                             new, old);
+       } else {
+               needs_kick = !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
+       }
        END_USE(vq);
+       return needs_kick;
+}
+EXPORT_SYMBOL_GPL(virtqueue_kick_prepare);
+
+/**
+ * virtqueue_notify - second half of split virtqueue_kick call.
+ * @vq: the struct virtqueue
+ *
+ * This does not need to be serialized.
+ */
+void virtqueue_notify(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+
+       /* Prod other side to tell it about changes. */
+       vq->notify(_vq);
+}
+EXPORT_SYMBOL_GPL(virtqueue_notify);
+
+/**
+ * virtqueue_kick - update after add_buf
+ * @vq: the struct virtqueue
+ *
+ * After one or more virtqueue_add_buf calls, invoke this to kick
+ * the other side.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
+void virtqueue_kick(struct virtqueue *vq)
+{
+       if (virtqueue_kick_prepare(vq))
+               virtqueue_notify(vq);
 }
 EXPORT_SYMBOL_GPL(virtqueue_kick);
 
@@ -294,11 +397,28 @@ static inline bool more_used(const struct vring_virtqueue *vq)
        return vq->last_used_idx != vq->vring.used->idx;
 }
 
+/**
+ * virtqueue_get_buf - get the next used buffer
+ * @vq: the struct virtqueue we're talking about.
+ * @len: the length written into the buffer
+ *
+ * If the driver wrote data into the buffer, @len will be set to the
+ * amount written.  This means you don't need to clear the buffer
+ * beforehand to ensure there's no data leakage in the case of short
+ * writes.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ *
+ * Returns NULL if there are no used buffers, or the "data" token
+ * handed to virtqueue_add_buf().
+ */
 void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
        void *ret;
        unsigned int i;
+       u16 last_used;
 
        START_USE(vq);
 
@@ -314,10 +434,11 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
        }
 
        /* Only get used array entries after they have been exposed by host. */
-       virtio_rmb();
+       virtio_rmb(vq);
 
-       i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
-       *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
+       last_used = (vq->last_used_idx & (vq->vring.num - 1));
+       i = vq->vring.used->ring[last_used].id;
+       *len = vq->vring.used->ring[last_used].len;
 
        if (unlikely(i >= vq->vring.num)) {
                BAD_RING(vq, "id %u out of range\n", i);
@@ -337,14 +458,27 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
         * the read in the next get_buf call. */
        if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
                vring_used_event(&vq->vring) = vq->last_used_idx;
-               virtio_mb();
+               virtio_mb(vq);
        }
 
+#ifdef DEBUG
+       vq->last_add_time_valid = false;
+#endif
+
        END_USE(vq);
        return ret;
 }
 EXPORT_SYMBOL_GPL(virtqueue_get_buf);
 
+/**
+ * virtqueue_disable_cb - disable callbacks
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * Note that this is not necessarily synchronous, hence unreliable and only
+ * useful as an optimization.
+ *
+ * Unlike other operations, this need not be serialized.
+ */
 void virtqueue_disable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -353,6 +487,17 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
 
+/**
+ * virtqueue_enable_cb - restart callbacks after disable_cb.
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * This re-enables callbacks; it returns "false" if there are pending
+ * buffers in the queue, to detect a possible race between the driver
+ * checking for more work, and enabling callbacks.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
 bool virtqueue_enable_cb(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -366,7 +511,7 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
         * entry. Always do both to keep code simple. */
        vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
        vring_used_event(&vq->vring) = vq->last_used_idx;
-       virtio_mb();
+       virtio_mb(vq);
        if (unlikely(more_used(vq))) {
                END_USE(vq);
                return false;
@@ -377,6 +522,19 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
+/**
+ * virtqueue_enable_cb_delayed - restart callbacks after disable_cb.
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * This re-enables callbacks but hints to the other side to delay
+ * interrupts until most of the available buffers have been processed;
+ * it returns "false" if there are many pending buffers in the queue,
+ * to detect a possible race between the driver checking for more work,
+ * and enabling callbacks.
+ *
+ * Caller must ensure we don't call this with other virtqueue
+ * operations at the same time (except where noted).
+ */
 bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -393,7 +551,7 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
        /* TODO: tune this threshold */
        bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4;
        vring_used_event(&vq->vring) = vq->last_used_idx + bufs;
-       virtio_mb();
+       virtio_mb(vq);
        if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) {
                END_USE(vq);
                return false;
@@ -404,6 +562,14 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
 
+/**
+ * virtqueue_detach_unused_buf - detach first unused buffer
+ * @vq: the struct virtqueue we're talking about.
+ *
+ * Returns NULL or the "data" token handed to virtqueue_add_buf().
+ * This is not valid on an active queue; it is useful only for device
+ * shutdown.
+ */
 void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -453,6 +619,7 @@ EXPORT_SYMBOL_GPL(vring_interrupt);
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *),
                                      void (*callback)(struct virtqueue *),
@@ -476,12 +643,14 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        vq->vq.vdev = vdev;
        vq->vq.name = name;
        vq->notify = notify;
+       vq->weak_barriers = weak_barriers;
        vq->broken = false;
        vq->last_used_idx = 0;
        vq->num_added = 0;
        list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
        vq->in_use = false;
+       vq->last_add_time_valid = false;
 #endif
 
        vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
@@ -530,7 +699,13 @@ void vring_transport_features(struct virtio_device *vdev)
 }
 EXPORT_SYMBOL_GPL(vring_transport_features);
 
-/* return the size of the vring within the virtqueue */
+/**
+ * virtqueue_get_vring_size - return the size of the virtqueue's vring
+ * @vq: the struct virtqueue containing the vring of interest.
+ *
+ * Returns the size of the vring.  This is mainly used for boasting to
+ * userspace.  Unlike other operations, this need not be serialized.
+ */
 unsigned int virtqueue_get_vring_size(struct virtqueue *_vq)
 {
 
index 945aa5f02f9beb9786d8033b3d79d141071cdca0..a9ea73d6dcf311b7703af1225fb71698da2a4fc3 100644 (file)
@@ -62,8 +62,8 @@ static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
        uint16_t klen = 0;
 
        v9ses = (struct v9fs_session_info *)cookie_netfs_data;
-       P9_DPRINTK(P9_DEBUG_FSC, "session %p buf %p size %u", v9ses,
-                  buffer, bufmax);
+       p9_debug(P9_DEBUG_FSC, "session %p buf %p size %u\n",
+                v9ses, buffer, bufmax);
 
        if (v9ses->cachetag)
                klen = strlen(v9ses->cachetag);
@@ -72,7 +72,7 @@ static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
                return 0;
 
        memcpy(buffer, v9ses->cachetag, klen);
-       P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
+       p9_debug(P9_DEBUG_FSC, "cache session tag %s\n", v9ses->cachetag);
        return klen;
 }
 
@@ -91,14 +91,14 @@ void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
        v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
                                                &v9fs_cache_session_index_def,
                                                v9ses);
-       P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses,
-                  v9ses->fscache);
+       p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n",
+                v9ses, v9ses->fscache);
 }
 
 void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
 {
-       P9_DPRINTK(P9_DEBUG_FSC, "session %p put cookie %p", v9ses,
-                  v9ses->fscache);
+       p9_debug(P9_DEBUG_FSC, "session %p put cookie %p\n",
+                v9ses, v9ses->fscache);
        fscache_relinquish_cookie(v9ses->fscache, 0);
        v9ses->fscache = NULL;
 }
@@ -109,8 +109,8 @@ static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
 {
        const struct v9fs_inode *v9inode = cookie_netfs_data;
        memcpy(buffer, &v9inode->qid.path, sizeof(v9inode->qid.path));
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode,
-                  v9inode->qid.path);
+       p9_debug(P9_DEBUG_FSC, "inode %p get key %llu\n",
+                &v9inode->vfs_inode, v9inode->qid.path);
        return sizeof(v9inode->qid.path);
 }
 
@@ -120,8 +120,8 @@ static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
        const struct v9fs_inode *v9inode = cookie_netfs_data;
        *size = i_size_read(&v9inode->vfs_inode);
 
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &v9inode->vfs_inode,
-                  *size);
+       p9_debug(P9_DEBUG_FSC, "inode %p get attr %llu\n",
+                &v9inode->vfs_inode, *size);
 }
 
 static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
@@ -129,8 +129,8 @@ static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
 {
        const struct v9fs_inode *v9inode = cookie_netfs_data;
        memcpy(buffer, &v9inode->qid.version, sizeof(v9inode->qid.version));
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode,
-                  v9inode->qid.version);
+       p9_debug(P9_DEBUG_FSC, "inode %p get aux %u\n",
+                &v9inode->vfs_inode, v9inode->qid.version);
        return sizeof(v9inode->qid.version);
 }
 
@@ -206,8 +206,8 @@ void v9fs_cache_inode_get_cookie(struct inode *inode)
                                                  &v9fs_cache_inode_index_def,
                                                  v9inode);
 
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
-                  v9inode->fscache);
+       p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n",
+                inode, v9inode->fscache);
 }
 
 void v9fs_cache_inode_put_cookie(struct inode *inode)
@@ -216,8 +216,8 @@ void v9fs_cache_inode_put_cookie(struct inode *inode)
 
        if (!v9inode->fscache)
                return;
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
-                  v9inode->fscache);
+       p9_debug(P9_DEBUG_FSC, "inode %p put cookie %p\n",
+                inode, v9inode->fscache);
 
        fscache_relinquish_cookie(v9inode->fscache, 0);
        v9inode->fscache = NULL;
@@ -229,8 +229,8 @@ void v9fs_cache_inode_flush_cookie(struct inode *inode)
 
        if (!v9inode->fscache)
                return;
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
-                  v9inode->fscache);
+       p9_debug(P9_DEBUG_FSC, "inode %p flush cookie %p\n",
+                inode, v9inode->fscache);
 
        fscache_relinquish_cookie(v9inode->fscache, 1);
        v9inode->fscache = NULL;
@@ -272,8 +272,8 @@ void v9fs_cache_inode_reset_cookie(struct inode *inode)
        v9inode->fscache = fscache_acquire_cookie(v9ses->fscache,
                                                  &v9fs_cache_inode_index_def,
                                                  v9inode);
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
-                  inode, old, v9inode->fscache);
+       p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n",
+                inode, old, v9inode->fscache);
 
        spin_unlock(&v9inode->fscache_lock);
 }
@@ -323,7 +323,7 @@ int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
        int ret;
        const struct v9fs_inode *v9inode = V9FS_I(inode);
 
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
+       p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
        if (!v9inode->fscache)
                return -ENOBUFS;
 
@@ -335,13 +335,13 @@ int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
        switch (ret) {
        case -ENOBUFS:
        case -ENODATA:
-               P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret);
+               p9_debug(P9_DEBUG_FSC, "page/inode not in cache %d\n", ret);
                return 1;
        case 0:
-               P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
+               p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
                return ret;
        default:
-               P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
+               p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
                return ret;
        }
 }
@@ -361,7 +361,7 @@ int __v9fs_readpages_from_fscache(struct inode *inode,
        int ret;
        const struct v9fs_inode *v9inode = V9FS_I(inode);
 
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
+       p9_debug(P9_DEBUG_FSC, "inode %p pages %u\n", inode, *nr_pages);
        if (!v9inode->fscache)
                return -ENOBUFS;
 
@@ -373,15 +373,15 @@ int __v9fs_readpages_from_fscache(struct inode *inode,
        switch (ret) {
        case -ENOBUFS:
        case -ENODATA:
-               P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret);
+               p9_debug(P9_DEBUG_FSC, "pages/inodes not in cache %d\n", ret);
                return 1;
        case 0:
                BUG_ON(!list_empty(pages));
                BUG_ON(*nr_pages != 0);
-               P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
+               p9_debug(P9_DEBUG_FSC, "BIO submitted\n");
                return ret;
        default:
-               P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
+               p9_debug(P9_DEBUG_FSC, "ret %d\n", ret);
                return ret;
        }
 }
@@ -396,9 +396,9 @@ void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
        int ret;
        const struct v9fs_inode *v9inode = V9FS_I(inode);
 
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
+       p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
        ret = fscache_write_page(v9inode->fscache, page, GFP_KERNEL);
-       P9_DPRINTK(P9_DEBUG_FSC, "ret =  %d", ret);
+       p9_debug(P9_DEBUG_FSC, "ret =  %d\n", ret);
        if (ret != 0)
                v9fs_uncache_page(inode, page);
 }
@@ -409,7 +409,7 @@ void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
 void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
 {
        const struct v9fs_inode *v9inode = V9FS_I(inode);
-       P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
+       p9_debug(P9_DEBUG_FSC, "inode %p page %p\n", inode, page);
        if (PageFsCache(page))
                fscache_wait_on_page_write(v9inode->fscache, page);
 }
index 85b67ffa2a43eb184250b1a167eae215deaa0399..da8eefbe830d9a5beb7304109cf4b254a089c555 100644 (file)
@@ -45,8 +45,8 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
 {
        struct v9fs_dentry *dent;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
-                                       fid->fid, dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "fid %d dentry %s\n",
+                fid->fid, dentry->d_name.name);
 
        dent = dentry->d_fsdata;
        if (!dent) {
@@ -79,8 +79,8 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
        struct v9fs_dentry *dent;
        struct p9_fid *fid, *ret;
 
-       P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
-               dentry->d_name.name, dentry, uid, any);
+       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
+                dentry->d_name.name, dentry, uid, any);
        dent = (struct v9fs_dentry *) dentry->d_fsdata;
        ret = NULL;
        if (dent) {
index 2b78014a124a2522007d11e97eda94b3d82ab8af..1964f98e74bedf861d12950dda7f9382ec3f8093 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -85,15 +87,15 @@ static int get_cache_mode(char *s)
 
        if (!strcmp(s, "loose")) {
                version = CACHE_LOOSE;
-               P9_DPRINTK(P9_DEBUG_9P, "Cache mode: loose\n");
+               p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
        } else if (!strcmp(s, "fscache")) {
                version = CACHE_FSCACHE;
-               P9_DPRINTK(P9_DEBUG_9P, "Cache mode: fscache\n");
+               p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
        } else if (!strcmp(s, "none")) {
                version = CACHE_NONE;
-               P9_DPRINTK(P9_DEBUG_9P, "Cache mode: none\n");
+               p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
        } else
-               printk(KERN_INFO "9p: Unknown Cache mode %s.\n", s);
+               pr_info("Unknown Cache mode %s\n", s);
        return version;
 }
 
@@ -140,8 +142,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                case Opt_debug:
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                          "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                ret = r;
                                continue;
                        }
@@ -154,8 +156,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                case Opt_dfltuid:
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                          "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                ret = r;
                                continue;
                        }
@@ -164,8 +166,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                case Opt_dfltgid:
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                          "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                ret = r;
                                continue;
                        }
@@ -174,8 +176,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                case Opt_afid:
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                          "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                ret = r;
                                continue;
                        }
@@ -205,8 +207,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                        s = match_strdup(&args[0]);
                        if (!s) {
                                ret = -ENOMEM;
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                 "problem allocating copy of cache arg\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "problem allocating copy of cache arg\n");
                                goto free_and_return;
                        }
                        ret = get_cache_mode(s);
@@ -223,8 +225,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                        s = match_strdup(&args[0]);
                        if (!s) {
                                ret = -ENOMEM;
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                 "problem allocating copy of access arg\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "problem allocating copy of access arg\n");
                                goto free_and_return;
                        }
 
@@ -240,8 +242,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
                                v9ses->uid = simple_strtoul(s, &e, 10);
                                if (*e != '\0') {
                                        ret = -EINVAL;
-                                       printk(KERN_INFO "9p: Unknown access "
-                                                       "argument %s.\n", s);
+                                       pr_info("Unknown access argument %s\n",
+                                               s);
                                        kfree(s);
                                        goto free_and_return;
                                }
@@ -254,9 +256,8 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
 #ifdef CONFIG_9P_FS_POSIX_ACL
                        v9ses->flags |= V9FS_POSIX_ACL;
 #else
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                       "Not defined CONFIG_9P_FS_POSIX_ACL. "
-                                       "Ignoring posixacl option\n");
+                       p9_debug(P9_DEBUG_ERROR,
+                                "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
 #endif
                        break;
 
@@ -318,7 +319,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        if (IS_ERR(v9ses->clnt)) {
                retval = PTR_ERR(v9ses->clnt);
                v9ses->clnt = NULL;
-               P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n");
+               p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
                goto error;
        }
 
@@ -371,7 +372,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
        if (IS_ERR(fid)) {
                retval = PTR_ERR(fid);
                fid = NULL;
-               P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n");
+               p9_debug(P9_DEBUG_ERROR, "cannot attach\n");
                goto error;
        }
 
@@ -429,7 +430,7 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
  */
 
 void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
-       P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
+       p9_debug(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
        p9_client_disconnect(v9ses->clnt);
 }
 
@@ -442,7 +443,7 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
 
 void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses)
 {
-       P9_DPRINTK(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
+       p9_debug(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses);
        p9_client_begin_disconnect(v9ses->clnt);
 }
 
@@ -591,23 +592,23 @@ static void v9fs_cache_unregister(void)
 static int __init init_v9fs(void)
 {
        int err;
-       printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
+       pr_info("Installing v9fs 9p2000 file system support\n");
        /* TODO: Setup list of registered trasnport modules */
        err = register_filesystem(&v9fs_fs_type);
        if (err < 0) {
-               printk(KERN_ERR "Failed to register filesystem\n");
+               pr_err("Failed to register filesystem\n");
                return err;
        }
 
        err = v9fs_cache_register();
        if (err < 0) {
-               printk(KERN_ERR "Failed to register v9fs for caching\n");
+               pr_err("Failed to register v9fs for caching\n");
                goto out_fs_unreg;
        }
 
        err = v9fs_sysfs_init();
        if (err < 0) {
-               printk(KERN_ERR "Failed to register with sysfs\n");
+               pr_err("Failed to register with sysfs\n");
                goto out_sysfs_cleanup;
        }
 
index 2524e4cbb8ea0801b88b63d315b921dfc9d442c1..0ad61c6a65a5b1964b373432f5e9bf9b031f6d38 100644 (file)
@@ -56,7 +56,7 @@ static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
        struct inode *inode;
 
        inode = page->mapping->host;
-       P9_DPRINTK(P9_DEBUG_VFS, "\n");
+       p9_debug(P9_DEBUG_VFS, "\n");
 
        BUG_ON(!PageLocked(page));
 
@@ -116,14 +116,14 @@ static int v9fs_vfs_readpages(struct file *filp, struct address_space *mapping,
        struct inode *inode;
 
        inode = mapping->host;
-       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, filp);
+       p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, filp);
 
        ret = v9fs_readpages_from_fscache(inode, mapping, pages, &nr_pages);
        if (ret == 0)
                return ret;
 
        ret = read_cache_pages(mapping, pages, (void *)v9fs_vfs_readpage, filp);
-       P9_DPRINTK(P9_DEBUG_VFS, "  = %d\n", ret);
+       p9_debug(P9_DEBUG_VFS, "  = %d\n", ret);
        return ret;
 }
 
@@ -263,10 +263,9 @@ v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
         * Now that we do caching with cache mode enabled, We need
         * to support direct IO
         */
-       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) "
-                       "off/no(%lld/%lu) EINVAL\n",
-                       iocb->ki_filp->f_path.dentry->d_name.name,
-                       (long long) pos, nr_segs);
+       p9_debug(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) off/no(%lld/%lu) EINVAL\n",
+                iocb->ki_filp->f_path.dentry->d_name.name,
+                (long long)pos, nr_segs);
 
        return -EINVAL;
 }
index e022890c6f403283b4da166b7c56e4a27e14b975..d529437ff44269f79cb707592a8e504bf4744cea 100644 (file)
@@ -53,8 +53,8 @@
 
 static int v9fs_dentry_delete(const struct dentry *dentry)
 {
-       P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
-                                                                       dentry);
+       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n",
+                dentry->d_name.name, dentry);
 
        return 1;
 }
@@ -66,8 +66,8 @@ static int v9fs_dentry_delete(const struct dentry *dentry)
  */
 static int v9fs_cached_dentry_delete(const struct dentry *dentry)
 {
-       P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n",
-                  dentry->d_name.name, dentry);
+       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n",
+                dentry->d_name.name, dentry);
 
        /* Don't cache negative dentries */
        if (!dentry->d_inode)
@@ -86,8 +86,8 @@ static void v9fs_dentry_release(struct dentry *dentry)
        struct v9fs_dentry *dent;
        struct p9_fid *temp, *current_fid;
 
-       P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
-                                                                       dentry);
+       p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n",
+                dentry->d_name.name, dentry);
        dent = dentry->d_fsdata;
        if (dent) {
                list_for_each_entry_safe(current_fid, temp, &dent->fidlist,
index 598fff1a54e59f7eafedc2b7c87e77300228b9d6..ff911e779651bcf5726c08ea412bceebd1f9b79b 100644 (file)
@@ -140,7 +140,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
        int reclen = 0;
        struct p9_rdir *rdir;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
        fid = filp->private_data;
 
        buflen = fid->clnt->msize - P9_IOHDRSZ;
@@ -168,7 +168,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
                                          rdir->tail - rdir->head, &st);
                        if (err) {
-                               P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
+                               p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
                                err = -EIO;
                                p9stat_free(&st);
                                goto unlock_and_exit;
@@ -213,7 +213,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
        struct p9_dirent curdirent;
        u64 oldoffset = 0;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
        fid = filp->private_data;
 
        buflen = fid->clnt->msize - P9_READDIRHDRSZ;
@@ -244,7 +244,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
                                            rdir->tail - rdir->head,
                                            &curdirent);
                        if (err < 0) {
-                               P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
+                               p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
                                err = -EIO;
                                goto unlock_and_exit;
                        }
@@ -290,9 +290,8 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
        struct p9_fid *fid;
 
        fid = filp->private_data;
-       P9_DPRINTK(P9_DEBUG_VFS,
-                       "v9fs_dir_release: inode: %p filp: %p fid: %d\n",
-                       inode, filp, fid ? fid->fid : -1);
+       p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
+                inode, filp, fid ? fid->fid : -1);
        if (fid)
                p9_client_clunk(fid);
        return 0;
index 62857a810a79d00332a150c6a02a433e638d72b8..fc06fd27065eb3cade2f5e5f60f7155d3487ae80 100644 (file)
@@ -61,7 +61,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
        struct p9_fid *fid;
        int omode;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
+       p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
        v9inode = V9FS_I(inode);
        v9ses = v9fs_inode2v9ses(inode);
        if (v9fs_proto_dotl(v9ses))
@@ -135,7 +135,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
        int res = 0;
        struct inode *inode = filp->f_path.dentry->d_inode;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
+       p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
 
        /* No mandatory locks */
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
@@ -204,7 +204,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
                        break;
                if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
                        break;
-               schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
+               if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0)
+                       break;
        }
 
        /* map 9p status to VFS status */
@@ -304,8 +305,8 @@ static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
        struct inode *inode = filp->f_path.dentry->d_inode;
        int ret = -ENOLCK;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
-                               cmd, fl, filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
+                filp, cmd, fl, filp->f_path.dentry->d_name.name);
 
        /* No mandatory locks */
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
@@ -340,8 +341,8 @@ static int v9fs_file_flock_dotl(struct file *filp, int cmd,
        struct inode *inode = filp->f_path.dentry->d_inode;
        int ret = -ENOLCK;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
-                               cmd, fl, filp->f_path.dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
+                filp, cmd, fl, filp->f_path.dentry->d_name.name);
 
        /* No mandatory locks */
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
@@ -384,8 +385,8 @@ v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count,
 {
        int n, total, size;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
-                  (long long unsigned) offset, count);
+       p9_debug(P9_DEBUG_VFS, "fid %d offset %llu count %d\n",
+                fid->fid, (long long unsigned)offset, count);
        n = 0;
        total = 0;
        size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
@@ -443,7 +444,7 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count,
        struct p9_fid *fid;
        size_t size;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
+       p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
        fid = filp->private_data;
 
        size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
@@ -470,8 +471,8 @@ v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
        loff_t origin = *offset;
        unsigned long pg_start, pg_end;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
-               (int)count, (int)*offset);
+       p9_debug(P9_DEBUG_VFS, "data %p count %d offset %x\n",
+                data, (int)count, (int)*offset);
 
        clnt = fid->clnt;
        do {
@@ -552,7 +553,7 @@ static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
                return retval;
 
        mutex_lock(&inode->i_mutex);
-       P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
+       p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 
        fid = filp->private_data;
        v9fs_blank_wstat(&wstat);
@@ -575,8 +576,7 @@ int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
                return retval;
 
        mutex_lock(&inode->i_mutex);
-       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
-                       filp, datasync);
+       p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 
        fid = filp->private_data;
 
@@ -607,8 +607,8 @@ v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct inode *inode = filp->f_path.dentry->d_inode;
 
 
-       P9_DPRINTK(P9_DEBUG_VFS, "page %p fid %lx\n",
-                  page, (unsigned long)filp->private_data);
+       p9_debug(P9_DEBUG_VFS, "page %p fid %lx\n",
+                page, (unsigned long)filp->private_data);
 
        v9inode = V9FS_I(inode);
        /* make sure the cache has finished storing the page */
index e0f20de6aa2bc53f2a6b47b7f9926696f301e389..014c8dd62962c02a8acfb17f6a771bc76de1a73a 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -87,6 +89,32 @@ static u32 unixmode2p9mode(struct v9fs_session_info *v9ses, umode_t mode)
        return res;
 }
 
+/**
+ * p9mode2perm- convert plan9 mode bits to unix permission bits
+ * @v9ses: v9fs session information
+ * @stat: p9_wstat from which mode need to be derived
+ *
+ */
+static int p9mode2perm(struct v9fs_session_info *v9ses,
+                      struct p9_wstat *stat)
+{
+       int res;
+       int mode = stat->mode;
+
+       res = mode & S_IALLUGO;
+       if (v9fs_proto_dotu(v9ses)) {
+               if ((mode & P9_DMSETUID) == P9_DMSETUID)
+                       res |= S_ISUID;
+
+               if ((mode & P9_DMSETGID) == P9_DMSETGID)
+                       res |= S_ISGID;
+
+               if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
+                       res |= S_ISVTX;
+       }
+       return res;
+}
+
 /**
  * p9mode2unixmode- convert plan9 mode bits to unix mode bits
  * @v9ses: v9fs session information
@@ -100,8 +128,8 @@ static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,
        int res;
        u32 mode = stat->mode;
 
-       res = mode & S_IALLUGO;
        *rdev = 0;
+       res = p9mode2perm(v9ses, stat);
 
        if ((mode & P9_DMDIR) == P9_DMDIR)
                res |= S_IFDIR;
@@ -128,24 +156,13 @@ static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,
                        res |= S_IFBLK;
                        break;
                default:
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                               "Unknown special type %c %s\n", type,
-                               stat->extension);
+                       p9_debug(P9_DEBUG_ERROR, "Unknown special type %c %s\n",
+                                type, stat->extension);
                };
                *rdev = MKDEV(major, minor);
        } else
                res |= S_IFREG;
 
-       if (v9fs_proto_dotu(v9ses)) {
-               if ((mode & P9_DMSETUID) == P9_DMSETUID)
-                       res |= S_ISUID;
-
-               if ((mode & P9_DMSETGID) == P9_DMSETGID)
-                       res |= S_ISGID;
-
-               if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
-                       res |= S_ISVTX;
-       }
        return res;
 }
 
@@ -275,8 +292,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
                } else if (v9fs_proto_dotu(v9ses)) {
                        inode->i_op = &v9fs_file_inode_operations;
                } else {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                  "special files without extended mode\n");
+                       p9_debug(P9_DEBUG_ERROR,
+                                "special files without extended mode\n");
                        err = -EINVAL;
                        goto error;
                }
@@ -301,8 +318,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
                break;
        case S_IFLNK:
                if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
-                       P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with "
-                                               "legacy protocol.\n");
+                       p9_debug(P9_DEBUG_ERROR,
+                                "extended modes used with legacy protocol\n");
                        err = -EINVAL;
                        goto error;
                }
@@ -329,8 +346,8 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
 
                break;
        default:
-               P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%hx S_IFMT 0x%x\n",
-                          mode, mode & S_IFMT);
+               p9_debug(P9_DEBUG_ERROR, "BAD mode 0x%hx S_IFMT 0x%x\n",
+                        mode, mode & S_IFMT);
                err = -EINVAL;
                goto error;
        }
@@ -352,11 +369,12 @@ struct inode *v9fs_get_inode(struct super_block *sb, umode_t mode, dev_t rdev)
        struct inode *inode;
        struct v9fs_session_info *v9ses = sb->s_fs_info;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %ho\n", sb, mode);
+       p9_debug(P9_DEBUG_VFS, "super block: %p mode: %ho\n", sb, mode);
 
        inode = new_inode(sb);
        if (!inode) {
-               P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
+               pr_warn("%s (%d): Problem allocating inode\n",
+                       __func__, task_pid_nr(current));
                return ERR_PTR(-ENOMEM);
        }
        err = v9fs_init_inode(v9ses, inode, mode, rdev);
@@ -573,15 +591,15 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
        struct p9_fid *v9fid, *dfid;
        struct v9fs_session_info *v9ses;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",
-                  dir, dentry, flags);
+       p9_debug(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",
+                dir, dentry, flags);
 
        v9ses = v9fs_inode2v9ses(dir);
        inode = dentry->d_inode;
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
                retval = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
                return retval;
        }
        if (v9fs_proto_dotl(v9ses))
@@ -630,7 +648,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        struct p9_fid *dfid, *ofid, *fid;
        struct inode *inode;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
 
        err = 0;
        ofid = NULL;
@@ -639,7 +657,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
                return ERR_PTR(err);
        }
 
@@ -647,36 +665,41 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
        ofid = p9_client_walk(dfid, 0, NULL, 1);
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
                return ERR_PTR(err);
        }
 
        err = p9_client_fcreate(ofid, name, perm, mode, extension);
        if (err < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
-               goto error;
-       }
-
-       /* now walk from the parent so we can get unopened fid */
-       fid = p9_client_walk(dfid, 1, &name, 1);
-       if (IS_ERR(fid)) {
-               err = PTR_ERR(fid);
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
-               fid = NULL;
+               p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
                goto error;
        }
 
-       /* instantiate inode and assign the unopened fid to the dentry */
-       inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
-               goto error;
+       if (!(perm & P9_DMLINK)) {
+               /* now walk from the parent so we can get unopened fid */
+               fid = p9_client_walk(dfid, 1, &name, 1);
+               if (IS_ERR(fid)) {
+                       err = PTR_ERR(fid);
+                       p9_debug(P9_DEBUG_VFS,
+                                  "p9_client_walk failed %d\n", err);
+                       fid = NULL;
+                       goto error;
+               }
+               /*
+                * instantiate inode and assign the unopened fid to the dentry
+                */
+               inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
+               if (IS_ERR(inode)) {
+                       err = PTR_ERR(inode);
+                       p9_debug(P9_DEBUG_VFS,
+                                  "inode creation failed %d\n", err);
+                       goto error;
+               }
+               err = v9fs_fid_add(dentry, fid);
+               if (err < 0)
+                       goto error;
+               d_instantiate(dentry, inode);
        }
-       err = v9fs_fid_add(dentry, fid);
-       if (err < 0)
-               goto error;
-       d_instantiate(dentry, inode);
        return ofid;
 error:
        if (ofid)
@@ -788,7 +811,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        struct p9_fid *fid;
        struct v9fs_session_info *v9ses;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
        err = 0;
        v9ses = v9fs_inode2v9ses(dir);
        perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
@@ -826,8 +849,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        char *name;
        int result = 0;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
-               dir, dentry->d_name.name, dentry, nameidata);
+       p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
+                dir, dentry->d_name.name, dentry, nameidata);
 
        if (dentry->d_name.len > NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
@@ -933,7 +956,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct p9_fid *newdirfid;
        struct p9_wstat wstat;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "\n");
+       p9_debug(P9_DEBUG_VFS, "\n");
        retval = 0;
        old_inode = old_dentry->d_inode;
        new_inode = new_dentry->d_inode;
@@ -969,8 +992,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 * 9P .u can only handle file rename in the same directory
                 */
 
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "old dir and new dir are different\n");
+               p9_debug(P9_DEBUG_ERROR, "old dir and new dir are different\n");
                retval = -EXDEV;
                goto clunk_newdir;
        }
@@ -1026,7 +1048,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        struct p9_fid *fid;
        struct p9_wstat *st;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+       p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
        err = -EPERM;
        v9ses = v9fs_dentry2v9ses(dentry);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
@@ -1063,7 +1085,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
        struct p9_fid *fid;
        struct p9_wstat wstat;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "\n");
+       p9_debug(P9_DEBUG_VFS, "\n");
        retval = inode_change_ok(dentry->d_inode, iattr);
        if (retval)
                return retval;
@@ -1162,7 +1184,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
                                set_nlink(inode, i_nlink);
                }
        }
-       mode = stat->mode & S_IALLUGO;
+       mode = p9mode2perm(v9ses, stat);
        mode |= inode->i_mode & ~S_IALLUGO;
        inode->i_mode = mode;
        i_size_write(inode, stat->length);
@@ -1208,7 +1230,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        struct p9_fid *fid;
        struct p9_wstat *st;
 
-       P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
        retval = -EPERM;
        v9ses = v9fs_dentry2v9ses(dentry);
        fid = v9fs_fid_lookup(dentry);
@@ -1230,8 +1252,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
        /* copy extension buffer into buffer */
        strncpy(buffer, st->extension, buflen);
 
-       P9_DPRINTK(P9_DEBUG_VFS,
-               "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer);
+       p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n",
+                dentry->d_name.name, st->extension, buffer);
 
        retval = strnlen(buffer, buflen);
 done:
@@ -1252,7 +1274,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
        int len = 0;
        char *link = __getname();
 
-       P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
 
        if (!link)
                link = ERR_PTR(-ENOMEM);
@@ -1283,8 +1305,8 @@ v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
 {
        char *s = nd_get_link(nd);
 
-       P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name,
-               IS_ERR(s) ? "<error>" : s);
+       p9_debug(P9_DEBUG_VFS, " %s %s\n",
+                dentry->d_name.name, IS_ERR(s) ? "<error>" : s);
        if (!IS_ERR(s))
                __putname(s);
 }
@@ -1306,7 +1328,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
 
        v9ses = v9fs_inode2v9ses(dir);
        if (!v9fs_proto_dotu(v9ses)) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
+               p9_debug(P9_DEBUG_ERROR, "not extended\n");
                return -EPERM;
        }
 
@@ -1333,8 +1355,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
 static int
 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-       P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino,
-                                       dentry->d_name.name, symname);
+       p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
+                dir->i_ino, dentry->d_name.name, symname);
 
        return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);
 }
@@ -1355,9 +1377,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
        char *name;
        struct p9_fid *oldfid;
 
-       P9_DPRINTK(P9_DEBUG_VFS,
-               " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
-               old_dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
+                dir->i_ino, dentry->d_name.name, old_dentry->d_name.name);
 
        oldfid = v9fs_fid_clone(old_dentry);
        if (IS_ERR(oldfid))
@@ -1398,9 +1419,9 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
        char *name;
        u32 perm;
 
-       P9_DPRINTK(P9_DEBUG_VFS,
-               " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n", dir->i_ino,
-               dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
+       p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
+                dir->i_ino, dentry->d_name.name, mode,
+                MAJOR(rdev), MINOR(rdev));
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
index 8ef152ac6a16003bb5b39e947577d22cf4e667cd..a1e6c990cd410efded55c826f03bc5db13839d75 100644 (file)
@@ -283,13 +283,13 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        }
 
        name = (char *) dentry->d_name.name;
-       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
-                       "mode:0x%hx\n", name, flags, omode);
+       p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
+                name, flags, omode);
 
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
                return err;
        }
 
@@ -297,7 +297,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        ofid = p9_client_walk(dfid, 0, NULL, 1);
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
                return err;
        }
 
@@ -307,16 +307,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        /* Update mode based on ACL value */
        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_VFS,
-                          "Failed to get acl values in creat %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
+                        err);
                goto error;
        }
        err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
                                    mode, gid, &qid);
        if (err < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS,
-                               "p9_client_open_dotl failed in creat %d\n",
-                               err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
+                        err);
                goto error;
        }
        v9fs_invalidate_inode_attr(dir);
@@ -325,14 +324,14 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        fid = p9_client_walk(dfid, 1, &name, 1);
        if (IS_ERR(fid)) {
                err = PTR_ERR(fid);
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
                fid = NULL;
                goto error;
        }
        inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
-               P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
                goto error;
        }
        err = v9fs_fid_add(dentry, fid);
@@ -408,7 +407,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
        err = 0;
        v9ses = v9fs_inode2v9ses(dir);
 
@@ -420,7 +419,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        dfid = v9fs_fid_lookup(dir_dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
                dfid = NULL;
                goto error;
        }
@@ -430,8 +429,8 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
        /* Update mode based on ACL value */
        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_VFS,
-                          "Failed to get acl values in mkdir %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n",
+                        err);
                goto error;
        }
        name = (char *) dentry->d_name.name;
@@ -444,8 +443,8 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
                fid = p9_client_walk(dfid, 1, &name, 1);
                if (IS_ERR(fid)) {
                        err = PTR_ERR(fid);
-                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
-                               err);
+                       p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                                err);
                        fid = NULL;
                        goto error;
                }
@@ -453,8 +452,8 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
-                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
-                               err);
+                       p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
+                                err);
                        goto error;
                }
                err = v9fs_fid_add(dentry, fid);
@@ -495,7 +494,7 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
        struct p9_fid *fid;
        struct p9_stat_dotl *st;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+       p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
        err = -EPERM;
        v9ses = v9fs_dentry2v9ses(dentry);
        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
@@ -523,6 +522,46 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
        return 0;
 }
 
+/*
+ * Attribute flags.
+ */
+#define P9_ATTR_MODE           (1 << 0)
+#define P9_ATTR_UID            (1 << 1)
+#define P9_ATTR_GID            (1 << 2)
+#define P9_ATTR_SIZE           (1 << 3)
+#define P9_ATTR_ATIME          (1 << 4)
+#define P9_ATTR_MTIME          (1 << 5)
+#define P9_ATTR_CTIME          (1 << 6)
+#define P9_ATTR_ATIME_SET      (1 << 7)
+#define P9_ATTR_MTIME_SET      (1 << 8)
+
+struct dotl_iattr_map {
+       int iattr_valid;
+       int p9_iattr_valid;
+};
+
+static int v9fs_mapped_iattr_valid(int iattr_valid)
+{
+       int i;
+       int p9_iattr_valid = 0;
+       struct dotl_iattr_map dotl_iattr_map[] = {
+               { ATTR_MODE,            P9_ATTR_MODE },
+               { ATTR_UID,             P9_ATTR_UID },
+               { ATTR_GID,             P9_ATTR_GID },
+               { ATTR_SIZE,            P9_ATTR_SIZE },
+               { ATTR_ATIME,           P9_ATTR_ATIME },
+               { ATTR_MTIME,           P9_ATTR_MTIME },
+               { ATTR_CTIME,           P9_ATTR_CTIME },
+               { ATTR_ATIME_SET,       P9_ATTR_ATIME_SET },
+               { ATTR_MTIME_SET,       P9_ATTR_MTIME_SET },
+       };
+       for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) {
+               if (iattr_valid & dotl_iattr_map[i].iattr_valid)
+                       p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid;
+       }
+       return p9_iattr_valid;
+}
+
 /**
  * v9fs_vfs_setattr_dotl - set file metadata
  * @dentry: file whose metadata to set
@@ -537,13 +576,13 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
        struct p9_fid *fid;
        struct p9_iattr_dotl p9attr;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "\n");
+       p9_debug(P9_DEBUG_VFS, "\n");
 
        retval = inode_change_ok(dentry->d_inode, iattr);
        if (retval)
                return retval;
 
-       p9attr.valid = iattr->ia_valid;
+       p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid);
        p9attr.mode = iattr->ia_mode;
        p9attr.uid = iattr->ia_uid;
        p9attr.gid = iattr->ia_gid;
@@ -670,14 +709,13 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
        struct v9fs_session_info *v9ses;
 
        name = (char *) dentry->d_name.name;
-       P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
-                       dir->i_ino, name, symname);
+       p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
        v9ses = v9fs_inode2v9ses(dir);
 
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
                return err;
        }
 
@@ -687,7 +725,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
        err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
 
        if (err < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
                goto error;
        }
 
@@ -697,8 +735,8 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
                fid = p9_client_walk(dfid, 1, &name, 1);
                if (IS_ERR(fid)) {
                        err = PTR_ERR(fid);
-                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
-                                       err);
+                       p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                                err);
                        fid = NULL;
                        goto error;
                }
@@ -707,8 +745,8 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
-                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
-                                       err);
+                       p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
+                                err);
                        goto error;
                }
                err = v9fs_fid_add(dentry, fid);
@@ -751,9 +789,8 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
        struct p9_fid *dfid, *oldfid;
        struct v9fs_session_info *v9ses;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
-                       dir->i_ino, old_dentry->d_name.name,
-                       dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
+                dir->i_ino, old_dentry->d_name.name, dentry->d_name.name);
 
        v9ses = v9fs_inode2v9ses(dir);
        dir_dentry = v9fs_dentry_from_dir_inode(dir);
@@ -770,7 +807,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
        err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);
 
        if (err < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
                return err;
        }
 
@@ -813,9 +850,9 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        struct dentry *dir_dentry;
        struct posix_acl *dacl = NULL, *pacl = NULL;
 
-       P9_DPRINTK(P9_DEBUG_VFS,
-               " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n", dir->i_ino,
-               dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev));
+       p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
+                dir->i_ino, dentry->d_name.name, omode,
+                MAJOR(rdev), MINOR(rdev));
 
        if (!new_valid_dev(rdev))
                return -EINVAL;
@@ -825,7 +862,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        dfid = v9fs_fid_lookup(dir_dentry);
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
-               P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
                dfid = NULL;
                goto error;
        }
@@ -835,8 +872,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        /* Update mode based on ACL value */
        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_VFS,
-                          "Failed to get acl values in mknod %d\n", err);
+               p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n",
+                        err);
                goto error;
        }
        name = (char *) dentry->d_name.name;
@@ -851,8 +888,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
                fid = p9_client_walk(dfid, 1, &name, 1);
                if (IS_ERR(fid)) {
                        err = PTR_ERR(fid);
-                       P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
-                               err);
+                       p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
+                                err);
                        fid = NULL;
                        goto error;
                }
@@ -860,8 +897,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
-                       P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
-                               err);
+                       p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
+                                err);
                        goto error;
                }
                err = v9fs_fid_add(dentry, fid);
@@ -905,7 +942,7 @@ v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
        char *link = __getname();
        char *target;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
+       p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
 
        if (!link) {
                link = ERR_PTR(-ENOMEM);
index f68ff65a32a526cbb5bae7f7b31feec512560bc0..7b0cd87b07c20772b79395bb03afdb2bc5ebf414 100644 (file)
@@ -121,7 +121,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
        struct p9_fid *fid;
        int retval = 0;
 
-       P9_DPRINTK(P9_DEBUG_VFS, " \n");
+       p9_debug(P9_DEBUG_VFS, "\n");
 
        v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
        if (!v9ses)
@@ -191,7 +191,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                goto release_sb;
        v9fs_fid_add(root, fid);
 
-       P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
+       p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
        return dget(sb->s_root);
 
 clunk_fid:
@@ -223,7 +223,7 @@ static void v9fs_kill_super(struct super_block *s)
 {
        struct v9fs_session_info *v9ses = s->s_fs_info;
 
-       P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
+       p9_debug(P9_DEBUG_VFS, " %p\n", s);
 
        kill_anon_super(s);
 
@@ -231,7 +231,7 @@ static void v9fs_kill_super(struct super_block *s)
        v9fs_session_close(v9ses);
        kfree(v9ses);
        s->s_fs_info = NULL;
-       P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
+       p9_debug(P9_DEBUG_VFS, "exiting kill_super\n");
 }
 
 static void
@@ -303,7 +303,7 @@ static int v9fs_write_inode(struct inode *inode,
         * send an fsync request to server irrespective of
         * wbc->sync_mode.
         */
-       P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
+       p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
        v9inode = V9FS_I(inode);
        if (!v9inode->writeback_fid)
                return 0;
@@ -326,7 +326,7 @@ static int v9fs_write_inode_dotl(struct inode *inode,
         * send an fsync request to server irrespective of
         * wbc->sync_mode.
         */
-       P9_DPRINTK(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
+       p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
        v9inode = V9FS_I(inode);
        if (!v9inode->writeback_fid)
                return 0;
index d288773871b3aa9c1816096cdd59bc43520d64eb..29653b70a9c345b3d8b0ac8162ade170550c4083 100644 (file)
@@ -32,8 +32,8 @@ ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
        attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
        if (IS_ERR(attr_fid)) {
                retval = PTR_ERR(attr_fid);
-               P9_DPRINTK(P9_DEBUG_VFS,
-                       "p9_client_attrwalk failed %zd\n", retval);
+               p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n",
+                        retval);
                attr_fid = NULL;
                goto error;
        }
@@ -87,8 +87,8 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
 {
        struct p9_fid *fid;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
-               __func__, name, buffer_size);
+       p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu\n",
+                name, buffer_size);
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
                return PTR_ERR(fid);
@@ -115,8 +115,8 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
        int retval, msize, write_count;
        struct p9_fid *fid = NULL;
 
-       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
-               __func__, name, value_len, flags);
+       p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
+                name, value_len, flags);
 
        fid = v9fs_fid_clone(dentry);
        if (IS_ERR(fid)) {
@@ -129,8 +129,8 @@ int v9fs_xattr_set(struct dentry *dentry, const char *name,
         */
        retval = p9_client_xattrcreate(fid, name, value_len, flags);
        if (retval < 0) {
-               P9_DPRINTK(P9_DEBUG_VFS,
-                       "p9_client_xattrcreate failed %d\n", retval);
+               p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n",
+                        retval);
                goto error;
        }
        msize = fid->clnt->msize;
index 79e2ca7973b7a2b503a7f7fc168f716a5f6c0284..e95d1b64082cae708f3213a453ea3275f6afbb57 100644 (file)
@@ -27,6 +27,9 @@ config COMPAT_BINFMT_ELF
        bool
        depends on COMPAT && BINFMT_ELF
 
+config ARCH_BINFMT_ELF_RANDOMIZE_PIE
+       bool
+
 config BINFMT_ELF_FDPIC
        bool "Kernel support for FDPIC ELF binaries"
        default y
index 78c514cfd212d66b8e6311d4a25435be6493c26d..969beb0e22311a4f7e7f4155524709d5dd8269bf 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -476,14 +476,21 @@ static void kiocb_batch_init(struct kiocb_batch *batch, long total)
        batch->count = total;
 }
 
-static void kiocb_batch_free(struct kiocb_batch *batch)
+static void kiocb_batch_free(struct kioctx *ctx, struct kiocb_batch *batch)
 {
        struct kiocb *req, *n;
 
+       if (list_empty(&batch->head))
+               return;
+
+       spin_lock_irq(&ctx->ctx_lock);
        list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
                list_del(&req->ki_batch);
+               list_del(&req->ki_list);
                kmem_cache_free(kiocb_cachep, req);
+               ctx->reqs_active--;
        }
+       spin_unlock_irq(&ctx->ctx_lock);
 }
 
 /*
@@ -1742,7 +1749,7 @@ long do_io_submit(aio_context_t ctx_id, long nr,
        }
        blk_finish_plug(&plug);
 
-       kiocb_batch_free(&batch);
+       kiocb_batch_free(ctx, &batch);
        put_ioctx(ctx);
        return i ? i : ret;
 }
index 5869d4e974a94569b5457e0e7d7cf5b68f03ca5a..d8d8e7ba6a1e1bf52c367a73514aeaa202b8fcea 100644 (file)
@@ -116,6 +116,7 @@ struct autofs_sb_info {
        int needs_reghost;
        struct super_block *sb;
        struct mutex wq_mutex;
+       struct mutex pipe_mutex;
        spinlock_t fs_lock;
        struct autofs_wait_queue *queues; /* Wait queue pointer */
        spinlock_t lookup_lock;
index 2ba44c79d5486f7d39b999d0666eda0ddc3425b3..e16980b00b8d7315dda8d7b92d93fdaf7062e843 100644 (file)
@@ -225,6 +225,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        sbi->min_proto = 0;
        sbi->max_proto = 0;
        mutex_init(&sbi->wq_mutex);
+       mutex_init(&sbi->pipe_mutex);
        spin_lock_init(&sbi->fs_lock);
        sbi->queues = NULL;
        spin_lock_init(&sbi->lookup_lock);
index e1fbdeef85db2e4b73e78eaf6266d2784e2385b0..da8876d38a7b7e3a50101f02817cbbbc460cec20 100644 (file)
@@ -56,26 +56,27 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
        mutex_unlock(&sbi->wq_mutex);
 }
 
-static int autofs4_write(struct file *file, const void *addr, int bytes)
+static int autofs4_write(struct autofs_sb_info *sbi,
+                        struct file *file, const void *addr, int bytes)
 {
        unsigned long sigpipe, flags;
        mm_segment_t fs;
        const char *data = (const char *)addr;
        ssize_t wr = 0;
 
-       /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
-
        sigpipe = sigismember(&current->pending.signal, SIGPIPE);
 
        /* Save pointer to user space and point back to kernel space */
        fs = get_fs();
        set_fs(KERNEL_DS);
 
+       mutex_lock(&sbi->pipe_mutex);
        while (bytes &&
               (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
                data += wr;
                bytes -= wr;
        }
+       mutex_unlock(&sbi->pipe_mutex);
 
        set_fs(fs);
 
@@ -110,6 +111,13 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
 
        pkt.hdr.proto_version = sbi->version;
        pkt.hdr.type = type;
+       mutex_lock(&sbi->wq_mutex);
+
+       /* Check if we have become catatonic */
+       if (sbi->catatonic) {
+               mutex_unlock(&sbi->wq_mutex);
+               return;
+       }
        switch (type) {
        /* Kernel protocol v4 missing and expire packets */
        case autofs_ptype_missing:
@@ -163,22 +171,18 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        }
        default:
                printk("autofs4_notify_daemon: bad type %d!\n", type);
+               mutex_unlock(&sbi->wq_mutex);
                return;
        }
 
-       /* Check if we have become catatonic */
-       mutex_lock(&sbi->wq_mutex);
-       if (!sbi->catatonic) {
-               pipe = sbi->pipe;
-               get_file(pipe);
-       }
+       pipe = sbi->pipe;
+       get_file(pipe);
+
        mutex_unlock(&sbi->wq_mutex);
 
-       if (pipe) {
-               if (autofs4_write(pipe, &pkt, pktsz))
-                       autofs4_catatonic_mode(sbi);
-               fput(pipe);
-       }
+       if (autofs4_write(sbi, pipe, &pkt, pktsz))
+               autofs4_catatonic_mode(sbi);
+       fput(pipe);
 }
 
 static int autofs4_getpath(struct autofs_sb_info *sbi,
@@ -257,6 +261,9 @@ static int validate_request(struct autofs_wait_queue **wait,
        struct autofs_wait_queue *wq;
        struct autofs_info *ino;
 
+       if (sbi->catatonic)
+               return -ENOENT;
+
        /* Wait in progress, continue; */
        wq = autofs4_find_wait(sbi, qstr);
        if (wq) {
@@ -289,6 +296,9 @@ static int validate_request(struct autofs_wait_queue **wait,
                        if (mutex_lock_interruptible(&sbi->wq_mutex))
                                return -EINTR;
 
+                       if (sbi->catatonic)
+                               return -ENOENT;
+
                        wq = autofs4_find_wait(sbi, qstr);
                        if (wq) {
                                *wait = wq;
@@ -389,7 +399,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        ret = validate_request(&wq, sbi, &qstr, dentry, notify);
        if (ret <= 0) {
-               if (ret == 0)
+               if (ret != -EINTR)
                        mutex_unlock(&sbi->wq_mutex);
                kfree(qstr.name);
                return ret;
index 21ac5ee4b43f3e767b56aff2f54c6018175bc6af..bcb884e2d613e76d94570dd81b99ba27e3906a66 100644 (file)
@@ -794,7 +794,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                         * default mmap base, as well as whatever program they
                         * might try to exec.  This is because the brk will
                         * follow the loader, and is not movable.  */
-#if defined(CONFIG_X86) || defined(CONFIG_ARM)
+#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
                        /* Memory randomization might have been switched off
                         * in runtime via sysctl.
                         * If that is the case, retain the original non-zero
index 69a5b6fbee2bd9a000a92b34afe4e8338ae989ab..0e575d1304b461e67bfbbba6ef234c53838b8998 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/uio.h>
 #include <linux/namei.h>
 #include <linux/log2.h>
-#include <linux/kmemleak.h>
 #include <linux/cleancache.h>
 #include <asm/uaccess.h>
 #include "internal.h"
@@ -521,7 +520,7 @@ static struct super_block *blockdev_superblock __read_mostly;
 void __init bdev_cache_init(void)
 {
        int err;
-       struct vfsmount *bd_mnt;
+       static struct vfsmount *bd_mnt;
 
        bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
                        0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -533,12 +532,7 @@ void __init bdev_cache_init(void)
        bd_mnt = kern_mount(&bd_type);
        if (IS_ERR(bd_mnt))
                panic("Cannot create bdev pseudo-fs");
-       /*
-        * This vfsmount structure is only used to obtain the
-        * blockdev_superblock, so tell kmemleak not to report it.
-        */
-       kmemleak_not_leak(bd_mnt);
-       blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
+       blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
 }
 
 /*
@@ -1145,6 +1139,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        mutex_lock_nested(&bdev->bd_mutex, for_part);
        if (!bdev->bd_openers) {
                bdev->bd_disk = disk;
+               bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
                if (!partno) {
                        struct backing_dev_info *bdi;
@@ -1165,6 +1160,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                        disk_put_part(bdev->bd_part);
                                        bdev->bd_part = NULL;
                                        bdev->bd_disk = NULL;
+                                       bdev->bd_queue = NULL;
                                        mutex_unlock(&bdev->bd_mutex);
                                        disk_unblock_events(disk);
                                        put_disk(disk);
@@ -1238,6 +1234,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        disk_put_part(bdev->bd_part);
        bdev->bd_disk = NULL;
        bdev->bd_part = NULL;
+       bdev->bd_queue = NULL;
        bdev_inode_switch_bdi(bdev->bd_inode, &default_backing_dev_info);
        if (bdev != bdev->bd_contains)
                __blkdev_put(bdev->bd_contains, mode, 1);
index f99a099a7747fd4ff2b0584a3f689d33a52136ab..d8525662ca7a721b18e197191816ea16b095eb19 100644 (file)
@@ -872,7 +872,8 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 
 #ifdef CONFIG_MIGRATION
 static int btree_migratepage(struct address_space *mapping,
-                       struct page *newpage, struct page *page)
+                       struct page *newpage, struct page *page,
+                       enum migrate_mode mode)
 {
        /*
         * we can't safely write a btree page from here,
@@ -887,7 +888,7 @@ static int btree_migratepage(struct address_space *mapping,
        if (page_has_private(page) &&
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 #endif
 
index 97fbe939c050dc7d523baeaed960741c053cbf0d..034d985032296cd4dfbc80e4d6717ac8b4ea77c4 100644 (file)
@@ -1081,7 +1081,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
 again:
        for (i = 0; i < num_pages; i++) {
                pages[i] = find_or_create_page(inode->i_mapping, index + i,
-                                              mask);
+                                              mask | __GFP_WRITE);
                if (!pages[i]) {
                        faili = i - 1;
                        err = -ENOMEM;
@@ -1136,7 +1136,8 @@ again:
                                     GFP_NOFS);
        }
        for (i = 0; i < num_pages; i++) {
-               clear_page_dirty_for_io(pages[i]);
+               if (clear_page_dirty_for_io(pages[i]))
+                       account_page_redirty(pages[i]);
                set_page_extent_mapped(pages[i]);
                WARN_ON(!PageLocked(pages[i]));
        }
index 74fd74719dc2c5769b0c2982dab7d2b968bf25d5..618246bc2196eee020f6c53ccf789d784603e090 100644 (file)
@@ -973,7 +973,7 @@ static int dentry_lease_is_valid(struct dentry *dentry)
 
        spin_lock(&dentry->d_lock);
        di = ceph_dentry(dentry);
-       if (di && di->lease_session) {
+       if (di->lease_session) {
                s = di->lease_session;
                spin_lock(&s->s_cap_lock);
                gen = s->s_cap_gen;
@@ -1072,13 +1072,11 @@ static void ceph_d_release(struct dentry *dentry)
        struct ceph_dentry_info *di = ceph_dentry(dentry);
 
        dout("d_release %p\n", dentry);
-       if (di) {
-               ceph_dentry_lru_del(dentry);
-               if (di->lease_session)
-                       ceph_put_mds_session(di->lease_session);
-               kmem_cache_free(ceph_dentry_cachep, di);
-               dentry->d_fsdata = NULL;
-       }
+       ceph_dentry_lru_del(dentry);
+       if (di->lease_session)
+               ceph_put_mds_session(di->lease_session);
+       kmem_cache_free(ceph_dentry_cachep, di);
+       dentry->d_fsdata = NULL;
 }
 
 static int ceph_snapdir_d_revalidate(struct dentry *dentry,
@@ -1096,17 +1094,36 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry,
  */
 void ceph_dir_set_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+       
+       if (dentry && ceph_dentry(dentry) &&
+           ceph_test_mount_opt(ceph_sb_to_client(dentry->d_sb), DCACHE)) {
+               dout(" marking %p (%p) complete\n", inode, dentry);
+               set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
 }
 
 void ceph_dir_clear_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+
+       if (dentry && ceph_dentry(dentry)) {
+               dout(" marking %p (%p) complete\n", inode, dentry);
+               set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
 }
 
 bool ceph_dir_test_complete(struct inode *inode)
 {
-       /* not yet implemented */
+       struct dentry *dentry = d_find_any_alias(inode);
+
+       if (dentry && ceph_dentry(dentry)) {
+               dout(" marking %p (%p) NOT complete\n", inode, dentry);
+               clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags);
+       }
+       dput(dentry);
        return false;
 }
 
@@ -1220,6 +1237,7 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
        do {
                ceph_mdsc_get_request(req);
                spin_unlock(&ci->i_unsafe_lock);
+
                dout("dir_fsync %p wait on tid %llu (until %llu)\n",
                     inode, req->r_tid, last_tid);
                if (req->r_timeout) {
@@ -1232,9 +1250,9 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
                } else {
                        wait_for_completion(&req->r_safe_completion);
                }
-               spin_lock(&ci->i_unsafe_lock);
                ceph_mdsc_put_request(req);
 
+               spin_lock(&ci->i_unsafe_lock);
                if (ret || list_empty(head))
                        break;
                req = list_entry(head->next,
@@ -1259,13 +1277,11 @@ void ceph_dentry_lru_add(struct dentry *dn)
 
        dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_add_tail(&di->lru, &mdsc->dentry_lru);
-               mdsc->num_dentry++;
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_add_tail(&di->lru, &mdsc->dentry_lru);
+       mdsc->num_dentry++;
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 void ceph_dentry_lru_touch(struct dentry *dn)
@@ -1275,12 +1291,10 @@ void ceph_dentry_lru_touch(struct dentry *dn)
 
        dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
             dn->d_name.len, dn->d_name.name, di->offset);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_move_tail(&di->lru, &mdsc->dentry_lru);
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_move_tail(&di->lru, &mdsc->dentry_lru);
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 void ceph_dentry_lru_del(struct dentry *dn)
@@ -1290,13 +1304,11 @@ void ceph_dentry_lru_del(struct dentry *dn)
 
        dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
-       if (di) {
-               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
-               spin_lock(&mdsc->dentry_lru_lock);
-               list_del_init(&di->lru);
-               mdsc->num_dentry--;
-               spin_unlock(&mdsc->dentry_lru_lock);
-       }
+       mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
+       spin_lock(&mdsc->dentry_lru_lock);
+       list_del_init(&di->lru);
+       mdsc->num_dentry--;
+       spin_unlock(&mdsc->dentry_lru_lock);
 }
 
 /*
index 9fbcdecaaccdc1ef2edfa9a8578b60c6a9b64118..fbb2a643ef10a1f75c4918f165c9e3a22a603a86 100644 (file)
@@ -56,9 +56,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
                return -EINVAL;
 
        spin_lock(&dentry->d_lock);
-       parent = dget(dentry->d_parent);
-       spin_unlock(&dentry->d_lock);
-
+       parent = dentry->d_parent;
        if (*max_len >= connected_handle_length) {
                dout("encode_fh %p connectable\n", dentry);
                cfh->ino = ceph_ino(dentry->d_inode);
@@ -81,7 +79,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
                *max_len = handle_length;
                type = 255;
        }
-       dput(parent);
+       spin_unlock(&dentry->d_lock);
        return type;
 }
 
index 25283e7a37f81ecf8ba3606a957a1efc7481afa3..2c489378b4cd6b470d06ecc9f3c60fc67ea6e1cf 100644 (file)
@@ -850,11 +850,12 @@ static void ceph_set_dentry_offset(struct dentry *dn)
 {
        struct dentry *dir = dn->d_parent;
        struct inode *inode = dir->d_inode;
-       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_inode_info *ci;
        struct ceph_dentry_info *di;
 
        BUG_ON(!inode);
 
+       ci = ceph_inode(inode);
        di = ceph_dentry(dn);
 
        spin_lock(&ci->i_ceph_lock);
index 6203d805eb45061d20b5d8e08222f97aae6cd0a6..23ab6a3f1825e85cb839f508535a56cdc0cc55fe 100644 (file)
@@ -2772,7 +2772,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
        di = ceph_dentry(dentry);
        switch (h->action) {
        case CEPH_MDS_LEASE_REVOKE:
-               if (di && di->lease_session == session) {
+               if (di->lease_session == session) {
                        if (ceph_seq_cmp(di->lease_seq, seq) > 0)
                                h->seq = cpu_to_le32(di->lease_seq);
                        __ceph_mdsc_drop_dentry_lease(dentry);
@@ -2781,7 +2781,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                break;
 
        case CEPH_MDS_LEASE_RENEW:
-               if (di && di->lease_session == session &&
+               if (di->lease_session == session &&
                    di->lease_gen == session->s_cap_gen &&
                    di->lease_renew_from &&
                    di->lease_renew_after == 0) {
index 48f61a12af66eecdd57f792c2b5da44d5c86468f..00de2c9568cd89b13af544b87bc2f43acefa8b30 100644 (file)
@@ -131,6 +131,8 @@ enum {
        Opt_rbytes,
        Opt_norbytes,
        Opt_noasyncreaddir,
+       Opt_dcache,
+       Opt_nodcache,
        Opt_ino32,
 };
 
@@ -152,6 +154,8 @@ static match_table_t fsopt_tokens = {
        {Opt_rbytes, "rbytes"},
        {Opt_norbytes, "norbytes"},
        {Opt_noasyncreaddir, "noasyncreaddir"},
+       {Opt_dcache, "dcache"},
+       {Opt_nodcache, "nodcache"},
        {Opt_ino32, "ino32"},
        {-1, NULL}
 };
@@ -231,6 +235,12 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_noasyncreaddir:
                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
                break;
+       case Opt_dcache:
+               fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
+               break;
+       case Opt_nodcache:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
+               break;
        case Opt_ino32:
                fsopt->flags |= CEPH_MOUNT_OPT_INO32;
                break;
@@ -377,6 +387,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",norbytes");
        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
                seq_puts(m, ",noasyncreaddir");
+       if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE)
+               seq_puts(m, ",dcache");
+       else
+               seq_puts(m, ",nodcache");
 
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
@@ -647,10 +661,10 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                                root = ERR_PTR(-ENOMEM);
                                goto out;
                        }
-                       ceph_init_dentry(root);
                } else {
                        root = d_obtain_alias(inode);
                }
+               ceph_init_dentry(root);
                dout("open_root_inode success, root dentry is %p\n", root);
        } else {
                root = ERR_PTR(err);
index cb3652b37271fbc383f784ff35c48bb48c17ff32..1421f3d875a22e34e1449bde4d46327678d114fe 100644 (file)
@@ -28,6 +28,7 @@
 #define CEPH_MOUNT_OPT_RBYTES          (1<<5) /* dir st_bytes = rbytes */
 #define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
 #define CEPH_MOUNT_OPT_INO32           (1<<8) /* 32 bit inos */
+#define CEPH_MOUNT_OPT_DCACHE          (1<<9) /* use dcache for readdir etc */
 
 #define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES)
 
index a5e36e4488a7d6e9f6dc0b9a5b9d440b4229e9c1..857214ae8c0893181c85c6fb081ef13ae171f0e7 100644 (file)
@@ -818,6 +818,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
        int issued;
        int err;
+       int required_blob_size;
        int dirty;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
@@ -833,14 +834,34 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
                        return -EOPNOTSUPP;
        }
 
+       err = -ENOMEM;
        spin_lock(&ci->i_ceph_lock);
        __build_xattrs(inode);
+retry:
        issued = __ceph_caps_issued(ci, NULL);
        dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
 
        if (!(issued & CEPH_CAP_XATTR_EXCL))
                goto do_sync;
 
+       required_blob_size = __get_required_blob_size(ci, 0, 0);
+
+       if (!ci->i_xattrs.prealloc_blob ||
+           required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
+               struct ceph_buffer *blob;
+
+               spin_unlock(&ci->i_ceph_lock);
+               dout(" preaallocating new blob size=%d\n", required_blob_size);
+               blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
+               if (!blob)
+                       goto out;
+               spin_lock(&ci->i_ceph_lock);
+               if (ci->i_xattrs.prealloc_blob)
+                       ceph_buffer_put(ci->i_xattrs.prealloc_blob);
+               ci->i_xattrs.prealloc_blob = blob;
+               goto retry;
+       }
+
        err = __remove_xattr_by_name(ceph_inode(inode), name);
        dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
        ci->i_xattrs.dirty = true;
@@ -853,6 +874,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
 do_sync:
        spin_unlock(&ci->i_ceph_lock);
        err = ceph_send_removexattr(dentry, name);
+out:
        return err;
 }
 
index 6475877b07632cda1af59664e629aa5ab92d958b..911cf30d057d21b3e7608a0b3f5f1855dacaf584 100644 (file)
@@ -88,24 +88,21 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
    - link the two up if this is needed
    - fill in the attributes
 */
-int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb)
+struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb)
 {
         struct coda_vattr attr;
+       struct inode *inode;
         int error;
         
        /* We get inode numbers from Venus -- see venus source */
        error = venus_getattr(sb, fid, &attr);
-       if ( error ) {
-           *inode = NULL;
-           return error;
-       } 
+       if (error)
+               return ERR_PTR(error);
 
-       *inode = coda_iget(sb, fid, &attr);
-       if ( IS_ERR(*inode) ) {
+       inode = coda_iget(sb, fid, &attr);
+       if (IS_ERR(inode))
                printk("coda_cnode_make: coda_iget failed\n");
-                return PTR_ERR(*inode);
-        }
-       return 0;
+       return inode;
 }
 
 
@@ -156,19 +153,16 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
 }
 
 /* the CONTROL inode is made without asking attributes from Venus */
-int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
+struct inode *coda_cnode_makectl(struct super_block *sb)
 {
-       int error = -ENOMEM;
-
-       *inode = new_inode(sb);
-       if (*inode) {
-               (*inode)->i_ino = CTL_INO;
-               (*inode)->i_op = &coda_ioctl_inode_operations;
-               (*inode)->i_fop = &coda_ioctl_operations;
-               (*inode)->i_mode = 0444;
-               error = 0;
+       struct inode *inode = new_inode(sb);
+       if (inode) {
+               inode->i_ino = CTL_INO;
+               inode->i_op = &coda_ioctl_inode_operations;
+               inode->i_fop = &coda_ioctl_operations;
+               inode->i_mode = 0444;
+               return inode;
        }
-
-       return error;
+       return ERR_PTR(-ENOMEM);
 }
 
index e35071b1de0e26a3d8f5e1ee27c1da3d3667a4ad..b24fdfd8a3f097a091fe5b04362cd437b96ba0f7 100644 (file)
@@ -49,9 +49,9 @@ struct coda_file_info {
 #define C_DYING       0x4   /* from venus (which died) */
 #define C_PURGE       0x8
 
-int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *);
+struct inode *coda_cnode_make(struct CodaFid *, struct super_block *);
 struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr);
-int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
+struct inode *coda_cnode_makectl(struct super_block *sb);
 struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb);
 void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *);
 
index 83d2fd8ec24b2cac427be38610f36ea076a71eac..177515829062d82aed7dcdce9bda390535804614 100644 (file)
@@ -96,12 +96,11 @@ const struct file_operations coda_dir_operations = {
 /* access routines: lookup, readlink, permission */
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
 {
-       struct inode *inode = NULL;
-       struct CodaFid resfid = { { 0, } };
-       int type = 0;
-       int error = 0;
+       struct super_block *sb = dir->i_sb;
        const char *name = entry->d_name.name;
        size_t length = entry->d_name.len;
+       struct inode *inode;
+       int type = 0;
 
        if (length > CODA_MAXNAMLEN) {
                printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
@@ -111,23 +110,21 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
 
        /* control object, create inode on the fly */
        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
-               error = coda_cnode_makectl(&inode, dir->i_sb);
+               inode = coda_cnode_makectl(sb);
                type = CODA_NOCACHE;
-               goto exit;
+       } else {
+               struct CodaFid fid = { { 0, } };
+               int error = venus_lookup(sb, coda_i2f(dir), name, length,
+                                    &type, &fid);
+               inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
        }
 
-       error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
-                            &type, &resfid);
-       if (!error)
-               error = coda_cnode_make(&inode, &resfid, dir->i_sb);
-
-       if (error && error != -ENOENT)
-               return ERR_PTR(error);
-
-exit:
-       if (inode && (type & CODA_NOCACHE))
+       if (!IS_ERR(inode) && (type & CODA_NOCACHE))
                coda_flag_inode(inode, C_VATTR | C_PURGE);
 
+       if (inode == ERR_PTR(-ENOENT))
+               inode = NULL;
+
        return d_splice_alias(inode, entry);
 }
 
index 1c08a8cd673a917d1e73f68a31ef3bd675c3acd1..5e2e1b3f068d432ab082c43f97b0cb00d3d86000 100644 (file)
@@ -204,10 +204,12 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
        printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
        
        /* make root inode */
-        error = coda_cnode_make(&root, &fid, sb);
-        if ( error || !root ) {
-           printk("Failure of coda_cnode_make for root: error %d\n", error);
-           goto error;
+        root = coda_cnode_make(&fid, sb);
+        if (IS_ERR(root)) {
+               error = PTR_ERR(root);
+               printk("Failure of coda_cnode_make for root: error %d\n", error);
+               root = NULL;
+               goto error;
        } 
 
        printk("coda_read_super: rootinode is %ld dev %s\n", 
index 3c6d3113a255c7af1519fdb6aa1c211ec092e992..16a53cc2cc02e079554742bfcd95c1f92d3608d4 100644 (file)
@@ -243,6 +243,7 @@ static void dentry_lru_add(struct dentry *dentry)
 static void __dentry_lru_del(struct dentry *dentry)
 {
        list_del_init(&dentry->d_lru);
+       dentry->d_flags &= ~DCACHE_SHRINK_LIST;
        dentry->d_sb->s_nr_dentry_unused--;
        dentry_stat.nr_unused--;
 }
@@ -806,6 +807,7 @@ relock:
                        spin_unlock(&dentry->d_lock);
                } else {
                        list_move_tail(&dentry->d_lru, &tmp);
+                       dentry->d_flags |= DCACHE_SHRINK_LIST;
                        spin_unlock(&dentry->d_lock);
                        if (!--count)
                                break;
@@ -1097,14 +1099,19 @@ resume:
 
                /*
                 * move only zero ref count dentries to the dispose list.
+                *
+                * Those which are presently on the shrink list, being processed
+                * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
+                * loop in shrink_dcache_parent() might not make any progress
+                * and loop forever.
                 */
-               if (!dentry->d_count) {
+               if (dentry->d_count) {
+                       dentry_lru_del(dentry);
+               } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
                        dentry_lru_move_list(dentry, dispose);
+                       dentry->d_flags |= DCACHE_SHRINK_LIST;
                        found++;
-               } else {
-                       dentry_lru_del(dentry);
                }
-
                /*
                 * We can return to the caller if we have found some (this
                 * ensures forward progress). We'll be coming back to find
@@ -1468,7 +1475,14 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
        return alias;
 }
 
-static struct dentry * d_find_any_alias(struct inode *inode)
+/**
+ * d_find_any_alias - find any alias for a given inode
+ * @inode: inode to find an alias for
+ *
+ * If any aliases exist for the given inode, take and return a
+ * reference for one of them.  If no aliases exist, return %NULL.
+ */
+struct dentry *d_find_any_alias(struct inode *inode)
 {
        struct dentry *de;
 
@@ -1477,7 +1491,7 @@ static struct dentry * d_find_any_alias(struct inode *inode)
        spin_unlock(&inode->i_lock);
        return de;
 }
-
+EXPORT_SYMBOL(d_find_any_alias);
 
 /**
  * d_obtain_alias - find or allocate a dentry for a given inode
index d740ab67ff6e1bd581218fb149eb7a58c40fa3f3..4a588dbd11bfa57926b647e1e66bdd35a446cad4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/rwsem.h>
 #include <linux/uio.h>
 #include <linux/atomic.h>
+#include <linux/prefetch.h>
 
 /*
  * How many user pages to map in one call to get_user_pages().  This determines
@@ -580,9 +581,8 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
 {
        int ret;
        sector_t fs_startblk;   /* Into file, in filesystem-sized blocks */
+       sector_t fs_endblk;     /* Into file, in filesystem-sized blocks */
        unsigned long fs_count; /* Number of filesystem-sized blocks */
-       unsigned long dio_count;/* Number of dio_block-sized blocks */
-       unsigned long blkmask;
        int create;
 
        /*
@@ -593,11 +593,9 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
        if (ret == 0) {
                BUG_ON(sdio->block_in_file >= sdio->final_block_in_request);
                fs_startblk = sdio->block_in_file >> sdio->blkfactor;
-               dio_count = sdio->final_block_in_request - sdio->block_in_file;
-               fs_count = dio_count >> sdio->blkfactor;
-               blkmask = (1 << sdio->blkfactor) - 1;
-               if (dio_count & blkmask)        
-                       fs_count++;
+               fs_endblk = (sdio->final_block_in_request - 1) >>
+                                       sdio->blkfactor;
+               fs_count = fs_endblk - fs_startblk + 1;
 
                map_bh->b_state = 0;
                map_bh->b_size = fs_count << dio->inode->i_blkbits;
@@ -1090,8 +1088,8 @@ static inline int drop_refcount(struct dio *dio)
  * individual fields and will generate much worse code. This is important
  * for the whole file.
  */
-ssize_t
-__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+static inline ssize_t
+do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        struct block_device *bdev, const struct iovec *iov, loff_t offset, 
        unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
        dio_submit_t submit_io, int flags)
@@ -1100,7 +1098,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        size_t size;
        unsigned long addr;
        unsigned blkbits = inode->i_blkbits;
-       unsigned bdev_blkbits = 0;
        unsigned blocksize_mask = (1 << blkbits) - 1;
        ssize_t retval = -EINVAL;
        loff_t end = offset;
@@ -1113,12 +1110,14 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (rw & WRITE)
                rw = WRITE_ODIRECT;
 
-       if (bdev)
-               bdev_blkbits = blksize_bits(bdev_logical_block_size(bdev));
+       /*
+        * Avoid references to bdev if not absolutely needed to give
+        * the early prefetch in the caller enough time.
+        */
 
        if (offset & blocksize_mask) {
                if (bdev)
-                        blkbits = bdev_blkbits;
+                       blkbits = blksize_bits(bdev_logical_block_size(bdev));
                blocksize_mask = (1 << blkbits) - 1;
                if (offset & blocksize_mask)
                        goto out;
@@ -1129,11 +1128,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                addr = (unsigned long)iov[seg].iov_base;
                size = iov[seg].iov_len;
                end += size;
-               if ((addr & blocksize_mask) || (size & blocksize_mask))  {
+               if (unlikely((addr & blocksize_mask) ||
+                            (size & blocksize_mask))) {
                        if (bdev)
-                                blkbits = bdev_blkbits;
+                               blkbits = blksize_bits(
+                                        bdev_logical_block_size(bdev));
                        blocksize_mask = (1 << blkbits) - 1;
-                       if ((addr & blocksize_mask) || (size & blocksize_mask))  
+                       if ((addr & blocksize_mask) || (size & blocksize_mask))
                                goto out;
                }
        }
@@ -1316,6 +1317,30 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
 out:
        return retval;
 }
+
+ssize_t
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset,
+       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       dio_submit_t submit_io, int flags)
+{
+       /*
+        * The block device state is needed in the end to finally
+        * submit everything.  Since it's likely to be cache cold
+        * prefetch it here as first thing to hide some of the
+        * latency.
+        *
+        * Attempt to prefetch the pieces we likely need later.
+        */
+       prefetch(&bdev->bd_disk->part_tbl);
+       prefetch(bdev->bd_queue);
+       prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES);
+
+       return do_blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+                                    nr_segs, get_block, end_io,
+                                    submit_io, flags);
+}
+
 EXPORT_SYMBOL(__blockdev_direct_IO);
 
 static __init int dio_init(void)
index 6cf72fcc0d0c48bfab133529b6405912ed63d745..e7e327d43fa59482f5a247b3b904a076bbfe840f 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/dlmconstants.h>
 #include <net/ipv6.h>
 #include <net/sock.h>
 
@@ -36,6 +37,7 @@
 static struct config_group *space_list;
 static struct config_group *comm_list;
 static struct dlm_comm *local_comm;
+static uint32_t dlm_comm_count;
 
 struct dlm_clusters;
 struct dlm_cluster;
@@ -103,6 +105,8 @@ struct dlm_cluster {
        unsigned int cl_timewarn_cs;
        unsigned int cl_waitwarn_us;
        unsigned int cl_new_rsb_count;
+       unsigned int cl_recover_callbacks;
+       char cl_cluster_name[DLM_LOCKSPACE_LEN];
 };
 
 enum {
@@ -118,6 +122,8 @@ enum {
        CLUSTER_ATTR_TIMEWARN_CS,
        CLUSTER_ATTR_WAITWARN_US,
        CLUSTER_ATTR_NEW_RSB_COUNT,
+       CLUSTER_ATTR_RECOVER_CALLBACKS,
+       CLUSTER_ATTR_CLUSTER_NAME,
 };
 
 struct cluster_attribute {
@@ -126,6 +132,27 @@ struct cluster_attribute {
        ssize_t (*store)(struct dlm_cluster *, const char *, size_t);
 };
 
+static ssize_t cluster_cluster_name_read(struct dlm_cluster *cl, char *buf)
+{
+       return sprintf(buf, "%s\n", cl->cl_cluster_name);
+}
+
+static ssize_t cluster_cluster_name_write(struct dlm_cluster *cl,
+                                         const char *buf, size_t len)
+{
+       strncpy(dlm_config.ci_cluster_name, buf, DLM_LOCKSPACE_LEN);
+       strncpy(cl->cl_cluster_name, buf, DLM_LOCKSPACE_LEN);
+       return len;
+}
+
+static struct cluster_attribute cluster_attr_cluster_name = {
+       .attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "cluster_name",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+       .show   = cluster_cluster_name_read,
+       .store  = cluster_cluster_name_write,
+};
+
 static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
                           int *info_field, int check_zero,
                           const char *buf, size_t len)
@@ -171,6 +198,7 @@ CLUSTER_ATTR(protocol, 0);
 CLUSTER_ATTR(timewarn_cs, 1);
 CLUSTER_ATTR(waitwarn_us, 0);
 CLUSTER_ATTR(new_rsb_count, 0);
+CLUSTER_ATTR(recover_callbacks, 0);
 
 static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -185,6 +213,8 @@ static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
        [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us.attr,
        [CLUSTER_ATTR_NEW_RSB_COUNT] = &cluster_attr_new_rsb_count.attr,
+       [CLUSTER_ATTR_RECOVER_CALLBACKS] = &cluster_attr_recover_callbacks.attr,
+       [CLUSTER_ATTR_CLUSTER_NAME] = &cluster_attr_cluster_name.attr,
        NULL,
 };
 
@@ -293,6 +323,7 @@ struct dlm_comms {
 
 struct dlm_comm {
        struct config_item item;
+       int seq;
        int nodeid;
        int local;
        int addr_count;
@@ -309,6 +340,7 @@ struct dlm_node {
        int nodeid;
        int weight;
        int new;
+       int comm_seq; /* copy of cm->seq when nd->nodeid is set */
 };
 
 static struct configfs_group_operations clusters_ops = {
@@ -455,6 +487,9 @@ static struct config_group *make_cluster(struct config_group *g,
        cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs;
        cl->cl_waitwarn_us = dlm_config.ci_waitwarn_us;
        cl->cl_new_rsb_count = dlm_config.ci_new_rsb_count;
+       cl->cl_recover_callbacks = dlm_config.ci_recover_callbacks;
+       memcpy(cl->cl_cluster_name, dlm_config.ci_cluster_name,
+              DLM_LOCKSPACE_LEN);
 
        space_list = &sps->ss_group;
        comm_list = &cms->cs_group;
@@ -558,6 +593,11 @@ static struct config_item *make_comm(struct config_group *g, const char *name)
                return ERR_PTR(-ENOMEM);
 
        config_item_init_type_name(&cm->item, name, &comm_type);
+
+       cm->seq = dlm_comm_count++;
+       if (!cm->seq)
+               cm->seq = dlm_comm_count++;
+
        cm->nodeid = -1;
        cm->local = 0;
        cm->addr_count = 0;
@@ -801,7 +841,10 @@ static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf)
 static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,
                                 size_t len)
 {
+       uint32_t seq = 0;
        nd->nodeid = simple_strtol(buf, NULL, 0);
+       dlm_comm_seq(nd->nodeid, &seq);
+       nd->comm_seq = seq;
        return len;
 }
 
@@ -908,13 +951,13 @@ static void put_comm(struct dlm_comm *cm)
 }
 
 /* caller must free mem */
-int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
-                   int **new_out, int *new_count_out)
+int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
+                    int *count_out)
 {
        struct dlm_space *sp;
        struct dlm_node *nd;
-       int i = 0, rv = 0, ids_count = 0, new_count = 0;
-       int *ids, *new;
+       struct dlm_config_node *nodes, *node;
+       int rv, count;
 
        sp = get_space(lsname);
        if (!sp)
@@ -927,73 +970,42 @@ int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
                goto out;
        }
 
-       ids_count = sp->members_count;
+       count = sp->members_count;
 
-       ids = kcalloc(ids_count, sizeof(int), GFP_NOFS);
-       if (!ids) {
+       nodes = kcalloc(count, sizeof(struct dlm_config_node), GFP_NOFS);
+       if (!nodes) {
                rv = -ENOMEM;
                goto out;
        }
 
+       node = nodes;
        list_for_each_entry(nd, &sp->members, list) {
-               ids[i++] = nd->nodeid;
-               if (nd->new)
-                       new_count++;
-       }
-
-       if (ids_count != i)
-               printk(KERN_ERR "dlm: bad nodeid count %d %d\n", ids_count, i);
-
-       if (!new_count)
-               goto out_ids;
+               node->nodeid = nd->nodeid;
+               node->weight = nd->weight;
+               node->new = nd->new;
+               node->comm_seq = nd->comm_seq;
+               node++;
 
-       new = kcalloc(new_count, sizeof(int), GFP_NOFS);
-       if (!new) {
-               kfree(ids);
-               rv = -ENOMEM;
-               goto out;
+               nd->new = 0;
        }
 
-       i = 0;
-       list_for_each_entry(nd, &sp->members, list) {
-               if (nd->new) {
-                       new[i++] = nd->nodeid;
-                       nd->new = 0;
-               }
-       }
-       *new_count_out = new_count;
-       *new_out = new;
-
- out_ids:
-       *ids_count_out = ids_count;
-       *ids_out = ids;
+       *count_out = count;
+       *nodes_out = nodes;
+       rv = 0;
  out:
        mutex_unlock(&sp->members_lock);
        put_space(sp);
        return rv;
 }
 
-int dlm_node_weight(char *lsname, int nodeid)
+int dlm_comm_seq(int nodeid, uint32_t *seq)
 {
-       struct dlm_space *sp;
-       struct dlm_node *nd;
-       int w = -EEXIST;
-
-       sp = get_space(lsname);
-       if (!sp)
-               goto out;
-
-       mutex_lock(&sp->members_lock);
-       list_for_each_entry(nd, &sp->members, list) {
-               if (nd->nodeid != nodeid)
-                       continue;
-               w = nd->weight;
-               break;
-       }
-       mutex_unlock(&sp->members_lock);
-       put_space(sp);
- out:
-       return w;
+       struct dlm_comm *cm = get_comm(nodeid, NULL);
+       if (!cm)
+               return -EEXIST;
+       *seq = cm->seq;
+       put_comm(cm);
+       return 0;
 }
 
 int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
@@ -1047,6 +1059,8 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */
 #define DEFAULT_WAITWARN_US       0
 #define DEFAULT_NEW_RSB_COUNT    128
+#define DEFAULT_RECOVER_CALLBACKS  0
+#define DEFAULT_CLUSTER_NAME      ""
 
 struct dlm_config_info dlm_config = {
        .ci_tcp_port = DEFAULT_TCP_PORT,
@@ -1060,6 +1074,8 @@ struct dlm_config_info dlm_config = {
        .ci_protocol = DEFAULT_PROTOCOL,
        .ci_timewarn_cs = DEFAULT_TIMEWARN_CS,
        .ci_waitwarn_us = DEFAULT_WAITWARN_US,
-       .ci_new_rsb_count = DEFAULT_NEW_RSB_COUNT
+       .ci_new_rsb_count = DEFAULT_NEW_RSB_COUNT,
+       .ci_recover_callbacks = DEFAULT_RECOVER_CALLBACKS,
+       .ci_cluster_name = DEFAULT_CLUSTER_NAME
 };
 
index 3099d0dd26c0a00265972bafb7408709c9588cbc..9f5e3663bb0c9e9509f4614f54cad427b4a02485 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 #ifndef __CONFIG_DOT_H__
 #define __CONFIG_DOT_H__
 
+struct dlm_config_node {
+       int nodeid;
+       int weight;
+       int new;
+       uint32_t comm_seq;
+};
+
 #define DLM_MAX_ADDR_COUNT 3
 
 struct dlm_config_info {
@@ -29,15 +36,17 @@ struct dlm_config_info {
        int ci_timewarn_cs;
        int ci_waitwarn_us;
        int ci_new_rsb_count;
+       int ci_recover_callbacks;
+       char ci_cluster_name[DLM_LOCKSPACE_LEN];
 };
 
 extern struct dlm_config_info dlm_config;
 
 int dlm_config_init(void);
 void dlm_config_exit(void);
-int dlm_node_weight(char *lsname, int nodeid);
-int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
-                   int **new_out, int *new_count_out);
+int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
+                    int *count_out);
+int dlm_comm_seq(int nodeid, uint32_t *seq);
 int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
 int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
 int dlm_our_nodeid(void);
index 59779237e2b40d4af09fa17ad35dab3138feee52..3dca2b39e83fa9c8b5025f0e3aefa94252ed0a41 100644 (file)
@@ -393,6 +393,7 @@ static const struct seq_operations format3_seq_ops;
 
 static void *table_seq_start(struct seq_file *seq, loff_t *pos)
 {
+       struct rb_node *node;
        struct dlm_ls *ls = seq->private;
        struct rsbtbl_iter *ri;
        struct dlm_rsb *r;
@@ -418,9 +419,10 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos)
                ri->format = 3;
 
        spin_lock(&ls->ls_rsbtbl[bucket].lock);
-       if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
-               list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list,
-                                   res_hashchain) {
+       if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
+               for (node = rb_first(&ls->ls_rsbtbl[bucket].keep); node;
+                    node = rb_next(node)) {
+                       r = rb_entry(node, struct dlm_rsb, res_hashnode);
                        if (!entry--) {
                                dlm_hold_rsb(r);
                                ri->rsb = r;
@@ -449,9 +451,9 @@ static void *table_seq_start(struct seq_file *seq, loff_t *pos)
                }
 
                spin_lock(&ls->ls_rsbtbl[bucket].lock);
-               if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
-                       r = list_first_entry(&ls->ls_rsbtbl[bucket].list,
-                                            struct dlm_rsb, res_hashchain);
+               if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
+                       node = rb_first(&ls->ls_rsbtbl[bucket].keep);
+                       r = rb_entry(node, struct dlm_rsb, res_hashnode);
                        dlm_hold_rsb(r);
                        ri->rsb = r;
                        ri->bucket = bucket;
@@ -467,7 +469,7 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
 {
        struct dlm_ls *ls = seq->private;
        struct rsbtbl_iter *ri = iter_ptr;
-       struct list_head *next;
+       struct rb_node *next;
        struct dlm_rsb *r, *rp;
        loff_t n = *pos;
        unsigned bucket;
@@ -480,10 +482,10 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
 
        spin_lock(&ls->ls_rsbtbl[bucket].lock);
        rp = ri->rsb;
-       next = rp->res_hashchain.next;
+       next = rb_next(&rp->res_hashnode);
 
-       if (next != &ls->ls_rsbtbl[bucket].list) {
-               r = list_entry(next, struct dlm_rsb, res_hashchain);
+       if (next) {
+               r = rb_entry(next, struct dlm_rsb, res_hashnode);
                dlm_hold_rsb(r);
                ri->rsb = r;
                spin_unlock(&ls->ls_rsbtbl[bucket].lock);
@@ -511,9 +513,9 @@ static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
                }
 
                spin_lock(&ls->ls_rsbtbl[bucket].lock);
-               if (!list_empty(&ls->ls_rsbtbl[bucket].list)) {
-                       r = list_first_entry(&ls->ls_rsbtbl[bucket].list,
-                                            struct dlm_rsb, res_hashchain);
+               if (!RB_EMPTY_ROOT(&ls->ls_rsbtbl[bucket].keep)) {
+                       next = rb_first(&ls->ls_rsbtbl[bucket].keep);
+                       r = rb_entry(next, struct dlm_rsb, res_hashnode);
                        dlm_hold_rsb(r);
                        ri->rsb = r;
                        ri->bucket = bucket;
index 7b84c1dbc82ebeaec0a42846537524c73d1db13f..83641574b0168f6753e340cac3962fa390ae621d 100644 (file)
@@ -290,7 +290,6 @@ int dlm_recover_directory(struct dlm_ls *ls)
 
  out_status:
        error = 0;
-       dlm_set_recover_status(ls, DLM_RS_DIR);
        log_debug(ls, "dlm_recover_directory %d entries", count);
  out_free:
        kfree(last_name);
index fe2860c024495d4ca270f75a453caf1c8148bf58..3a564d197e99f2e822f16a6730425575c661248a 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2010 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -103,8 +103,8 @@ struct dlm_dirtable {
 };
 
 struct dlm_rsbtable {
-       struct list_head        list;
-       struct list_head        toss;
+       struct rb_root          keep;
+       struct rb_root          toss;
        spinlock_t              lock;
 };
 
@@ -117,6 +117,10 @@ struct dlm_member {
        struct list_head        list;
        int                     nodeid;
        int                     weight;
+       int                     slot;
+       int                     slot_prev;
+       int                     comm_seq;
+       uint32_t                generation;
 };
 
 /*
@@ -125,10 +129,8 @@ struct dlm_member {
 
 struct dlm_recover {
        struct list_head        list;
-       int                     *nodeids;   /* nodeids of all members */
-       int                     node_count;
-       int                     *new;       /* nodeids of new members */
-       int                     new_count;
+       struct dlm_config_node  *nodes;
+       int                     nodes_count;
        uint64_t                seq;
 };
 
@@ -285,7 +287,10 @@ struct dlm_rsb {
        unsigned long           res_toss_time;
        uint32_t                res_first_lkid;
        struct list_head        res_lookup;     /* lkbs waiting on first */
-       struct list_head        res_hashchain;  /* rsbtbl */
+       union {
+               struct list_head        res_hashchain;
+               struct rb_node          res_hashnode;   /* rsbtbl */
+       };
        struct list_head        res_grantqueue;
        struct list_head        res_convertqueue;
        struct list_head        res_waitqueue;
@@ -334,7 +339,9 @@ static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
 /* dlm_header is first element of all structs sent between nodes */
 
 #define DLM_HEADER_MAJOR       0x00030000
-#define DLM_HEADER_MINOR       0x00000000
+#define DLM_HEADER_MINOR       0x00000001
+
+#define DLM_HEADER_SLOTS       0x00000001
 
 #define DLM_MSG                        1
 #define DLM_RCOM               2
@@ -422,10 +429,34 @@ union dlm_packet {
        struct dlm_rcom         rcom;
 };
 
+#define DLM_RSF_NEED_SLOTS     0x00000001
+
+/* RCOM_STATUS data */
+struct rcom_status {
+       __le32                  rs_flags;
+       __le32                  rs_unused1;
+       __le64                  rs_unused2;
+};
+
+/* RCOM_STATUS_REPLY data */
 struct rcom_config {
        __le32                  rf_lvblen;
        __le32                  rf_lsflags;
-       __le64                  rf_unused;
+
+       /* DLM_HEADER_SLOTS adds: */
+       __le32                  rf_flags;
+       __le16                  rf_our_slot;
+       __le16                  rf_num_slots;
+       __le32                  rf_generation;
+       __le32                  rf_unused1;
+       __le64                  rf_unused2;
+};
+
+struct rcom_slot {
+       __le32                  ro_nodeid;
+       __le16                  ro_slot;
+       __le16                  ro_unused1;
+       __le64                  ro_unused2;
 };
 
 struct rcom_lock {
@@ -452,6 +483,7 @@ struct dlm_ls {
        struct list_head        ls_list;        /* list of lockspaces */
        dlm_lockspace_t         *ls_local_handle;
        uint32_t                ls_global_id;   /* global unique lockspace ID */
+       uint32_t                ls_generation;
        uint32_t                ls_exflags;
        int                     ls_lvblen;
        int                     ls_count;       /* refcount of processes in
@@ -490,6 +522,11 @@ struct dlm_ls {
        int                     ls_total_weight;
        int                     *ls_node_array;
 
+       int                     ls_slot;
+       int                     ls_num_slots;
+       int                     ls_slots_size;
+       struct dlm_slot         *ls_slots;
+
        struct dlm_rsb          ls_stub_rsb;    /* for returning errors */
        struct dlm_lkb          ls_stub_lkb;    /* for returning errors */
        struct dlm_message      ls_stub_ms;     /* for faking a reply */
@@ -537,6 +574,9 @@ struct dlm_ls {
        struct list_head        ls_root_list;   /* root resources */
        struct rw_semaphore     ls_root_sem;    /* protect root_list */
 
+       const struct dlm_lockspace_ops *ls_ops;
+       void                    *ls_ops_arg;
+
        int                     ls_namelen;
        char                    ls_name[1];
 };
index 83b5e32514e17b32c0bc809413be60694ae019e5..d47183043c5942ba19100d9b0eaf67147aaddb31 100644 (file)
@@ -56,6 +56,7 @@
    L: receive_xxxx_reply()     <-  R: send_xxxx_reply()
 */
 #include <linux/types.h>
+#include <linux/rbtree.h>
 #include <linux/slab.h>
 #include "dlm_internal.h"
 #include <linux/dlm_device.h>
@@ -380,6 +381,8 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
 
        r = list_first_entry(&ls->ls_new_rsb, struct dlm_rsb, res_hashchain);
        list_del(&r->res_hashchain);
+       /* Convert the empty list_head to a NULL rb_node for tree usage: */
+       memset(&r->res_hashnode, 0, sizeof(struct rb_node));
        ls->ls_new_rsb_count--;
        spin_unlock(&ls->ls_new_rsb_spin);
 
@@ -388,7 +391,6 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
        memcpy(r->res_name, name, len);
        mutex_init(&r->res_mutex);
 
-       INIT_LIST_HEAD(&r->res_hashchain);
        INIT_LIST_HEAD(&r->res_lookup);
        INIT_LIST_HEAD(&r->res_grantqueue);
        INIT_LIST_HEAD(&r->res_convertqueue);
@@ -400,14 +402,31 @@ static int get_rsb_struct(struct dlm_ls *ls, char *name, int len,
        return 0;
 }
 
-static int search_rsb_list(struct list_head *head, char *name, int len,
+static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen)
+{
+       char maxname[DLM_RESNAME_MAXLEN];
+
+       memset(maxname, 0, DLM_RESNAME_MAXLEN);
+       memcpy(maxname, name, nlen);
+       return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN);
+}
+
+static int search_rsb_tree(struct rb_root *tree, char *name, int len,
                           unsigned int flags, struct dlm_rsb **r_ret)
 {
+       struct rb_node *node = tree->rb_node;
        struct dlm_rsb *r;
        int error = 0;
-
-       list_for_each_entry(r, head, res_hashchain) {
-               if (len == r->res_length && !memcmp(name, r->res_name, len))
+       int rc;
+
+       while (node) {
+               r = rb_entry(node, struct dlm_rsb, res_hashnode);
+               rc = rsb_cmp(r, name, len);
+               if (rc < 0)
+                       node = node->rb_left;
+               else if (rc > 0)
+                       node = node->rb_right;
+               else
                        goto found;
        }
        *r_ret = NULL;
@@ -420,22 +439,54 @@ static int search_rsb_list(struct list_head *head, char *name, int len,
        return error;
 }
 
+static int rsb_insert(struct dlm_rsb *rsb, struct rb_root *tree)
+{
+       struct rb_node **newn = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       int rc;
+
+       while (*newn) {
+               struct dlm_rsb *cur = rb_entry(*newn, struct dlm_rsb,
+                                              res_hashnode);
+
+               parent = *newn;
+               rc = rsb_cmp(cur, rsb->res_name, rsb->res_length);
+               if (rc < 0)
+                       newn = &parent->rb_left;
+               else if (rc > 0)
+                       newn = &parent->rb_right;
+               else {
+                       log_print("rsb_insert match");
+                       dlm_dump_rsb(rsb);
+                       dlm_dump_rsb(cur);
+                       return -EEXIST;
+               }
+       }
+
+       rb_link_node(&rsb->res_hashnode, parent, newn);
+       rb_insert_color(&rsb->res_hashnode, tree);
+       return 0;
+}
+
 static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
                       unsigned int flags, struct dlm_rsb **r_ret)
 {
        struct dlm_rsb *r;
        int error;
 
-       error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
+       error = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r);
        if (!error) {
                kref_get(&r->res_ref);
                goto out;
        }
-       error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+       error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
        if (error)
                goto out;
 
-       list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
+       rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
+       error = rsb_insert(r, &ls->ls_rsbtbl[b].keep);
+       if (error)
+               return error;
 
        if (dlm_no_directory(ls))
                goto out;
@@ -527,8 +578,7 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
                        nodeid = 0;
                r->res_nodeid = nodeid;
        }
-       list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
-       error = 0;
+       error = rsb_insert(r, &ls->ls_rsbtbl[bucket].keep);
  out_unlock:
        spin_unlock(&ls->ls_rsbtbl[bucket].lock);
  out:
@@ -556,7 +606,8 @@ static void toss_rsb(struct kref *kref)
 
        DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
        kref_init(&r->res_ref);
-       list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
+       rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[r->res_bucket].keep);
+       rsb_insert(r, &ls->ls_rsbtbl[r->res_bucket].toss);
        r->res_toss_time = jiffies;
        if (r->res_lvbptr) {
                dlm_free_lvb(r->res_lvbptr);
@@ -1082,19 +1133,19 @@ static void dir_remove(struct dlm_rsb *r)
                                     r->res_name, r->res_length);
 }
 
-/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
-   found since they are in order of newest to oldest? */
+/* FIXME: make this more efficient */
 
 static int shrink_bucket(struct dlm_ls *ls, int b)
 {
+       struct rb_node *n;
        struct dlm_rsb *r;
        int count = 0, found;
 
        for (;;) {
                found = 0;
                spin_lock(&ls->ls_rsbtbl[b].lock);
-               list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
-                                           res_hashchain) {
+               for (n = rb_first(&ls->ls_rsbtbl[b].toss); n; n = rb_next(n)) {
+                       r = rb_entry(n, struct dlm_rsb, res_hashnode);
                        if (!time_after_eq(jiffies, r->res_toss_time +
                                           dlm_config.ci_toss_secs * HZ))
                                continue;
@@ -1108,7 +1159,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
                }
 
                if (kref_put(&r->res_ref, kill_rsb)) {
-                       list_del(&r->res_hashchain);
+                       rb_erase(&r->res_hashnode, &ls->ls_rsbtbl[b].toss);
                        spin_unlock(&ls->ls_rsbtbl[b].lock);
 
                        if (is_master(r))
@@ -4441,10 +4492,12 @@ int dlm_purge_locks(struct dlm_ls *ls)
 
 static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
 {
+       struct rb_node *n;
        struct dlm_rsb *r, *r_ret = NULL;
 
        spin_lock(&ls->ls_rsbtbl[bucket].lock);
-       list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
+       for (n = rb_first(&ls->ls_rsbtbl[bucket].keep); n; n = rb_next(n)) {
+               r = rb_entry(n, struct dlm_rsb, res_hashnode);
                if (!rsb_flag(r, RSB_LOCKS_PURGED))
                        continue;
                hold_rsb(r);
index a1d8f1af144b92af587d9772d1276b625db508b5..a1ea25face828239a3434d6e036f7acffc9cf092 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -386,12 +386,15 @@ static void threads_stop(void)
        dlm_lowcomms_stop();
 }
 
-static int new_lockspace(const char *name, int namelen, void **lockspace,
-                        uint32_t flags, int lvblen)
+static int new_lockspace(const char *name, const char *cluster,
+                        uint32_t flags, int lvblen,
+                        const struct dlm_lockspace_ops *ops, void *ops_arg,
+                        int *ops_result, dlm_lockspace_t **lockspace)
 {
        struct dlm_ls *ls;
        int i, size, error;
        int do_unreg = 0;
+       int namelen = strlen(name);
 
        if (namelen > DLM_LOCKSPACE_LEN)
                return -EINVAL;
@@ -403,8 +406,24 @@ static int new_lockspace(const char *name, int namelen, void **lockspace,
                return -EINVAL;
 
        if (!dlm_user_daemon_available()) {
-               module_put(THIS_MODULE);
-               return -EUNATCH;
+               log_print("dlm user daemon not available");
+               error = -EUNATCH;
+               goto out;
+       }
+
+       if (ops && ops_result) {
+               if (!dlm_config.ci_recover_callbacks)
+                       *ops_result = -EOPNOTSUPP;
+               else
+                       *ops_result = 0;
+       }
+
+       if (dlm_config.ci_recover_callbacks && cluster &&
+           strncmp(cluster, dlm_config.ci_cluster_name, DLM_LOCKSPACE_LEN)) {
+               log_print("dlm cluster name %s mismatch %s",
+                         dlm_config.ci_cluster_name, cluster);
+               error = -EBADR;
+               goto out;
        }
 
        error = 0;
@@ -442,6 +461,11 @@ static int new_lockspace(const char *name, int namelen, void **lockspace,
        ls->ls_flags = 0;
        ls->ls_scan_time = jiffies;
 
+       if (ops && dlm_config.ci_recover_callbacks) {
+               ls->ls_ops = ops;
+               ls->ls_ops_arg = ops_arg;
+       }
+
        if (flags & DLM_LSFL_TIMEWARN)
                set_bit(LSFL_TIMEWARN, &ls->ls_flags);
 
@@ -457,8 +481,8 @@ static int new_lockspace(const char *name, int namelen, void **lockspace,
        if (!ls->ls_rsbtbl)
                goto out_lsfree;
        for (i = 0; i < size; i++) {
-               INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list);
-               INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss);
+               ls->ls_rsbtbl[i].keep.rb_node = NULL;
+               ls->ls_rsbtbl[i].toss.rb_node = NULL;
                spin_lock_init(&ls->ls_rsbtbl[i].lock);
        }
 
@@ -525,6 +549,11 @@ static int new_lockspace(const char *name, int namelen, void **lockspace,
        if (!ls->ls_recover_buf)
                goto out_dirfree;
 
+       ls->ls_slot = 0;
+       ls->ls_num_slots = 0;
+       ls->ls_slots_size = 0;
+       ls->ls_slots = NULL;
+
        INIT_LIST_HEAD(&ls->ls_recover_list);
        spin_lock_init(&ls->ls_recover_list_lock);
        ls->ls_recover_list_count = 0;
@@ -614,8 +643,10 @@ static int new_lockspace(const char *name, int namelen, void **lockspace,
        return error;
 }
 
-int dlm_new_lockspace(const char *name, int namelen, void **lockspace,
-                     uint32_t flags, int lvblen)
+int dlm_new_lockspace(const char *name, const char *cluster,
+                     uint32_t flags, int lvblen,
+                     const struct dlm_lockspace_ops *ops, void *ops_arg,
+                     int *ops_result, dlm_lockspace_t **lockspace)
 {
        int error = 0;
 
@@ -625,7 +656,8 @@ int dlm_new_lockspace(const char *name, int namelen, void **lockspace,
        if (error)
                goto out;
 
-       error = new_lockspace(name, namelen, lockspace, flags, lvblen);
+       error = new_lockspace(name, cluster, flags, lvblen, ops, ops_arg,
+                             ops_result, lockspace);
        if (!error)
                ls_count++;
        if (error > 0)
@@ -685,7 +717,7 @@ static int lockspace_busy(struct dlm_ls *ls, int force)
 static int release_lockspace(struct dlm_ls *ls, int force)
 {
        struct dlm_rsb *rsb;
-       struct list_head *head;
+       struct rb_node *n;
        int i, busy, rv;
 
        busy = lockspace_busy(ls, force);
@@ -746,20 +778,15 @@ static int release_lockspace(struct dlm_ls *ls, int force)
         */
 
        for (i = 0; i < ls->ls_rsbtbl_size; i++) {
-               head = &ls->ls_rsbtbl[i].list;
-               while (!list_empty(head)) {
-                       rsb = list_entry(head->next, struct dlm_rsb,
-                                        res_hashchain);
-
-                       list_del(&rsb->res_hashchain);
+               while ((n = rb_first(&ls->ls_rsbtbl[i].keep))) {
+                       rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
+                       rb_erase(n, &ls->ls_rsbtbl[i].keep);
                        dlm_free_rsb(rsb);
                }
 
-               head = &ls->ls_rsbtbl[i].toss;
-               while (!list_empty(head)) {
-                       rsb = list_entry(head->next, struct dlm_rsb,
-                                        res_hashchain);
-                       list_del(&rsb->res_hashchain);
+               while ((n = rb_first(&ls->ls_rsbtbl[i].toss))) {
+                       rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
+                       rb_erase(n, &ls->ls_rsbtbl[i].toss);
                        dlm_free_rsb(rsb);
                }
        }
index b12532e553f8e7947bd4c83435f22fff4724366b..862640a36d5cbba1762ad47317dffbd72eab0531 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
 #include "config.h"
 #include "lowcomms.h"
 
+int dlm_slots_version(struct dlm_header *h)
+{
+       if ((h->h_version & 0x0000FFFF) < DLM_HEADER_SLOTS)
+               return 0;
+       return 1;
+}
+
+void dlm_slot_save(struct dlm_ls *ls, struct dlm_rcom *rc,
+                  struct dlm_member *memb)
+{
+       struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
+
+       if (!dlm_slots_version(&rc->rc_header))
+               return;
+
+       memb->slot = le16_to_cpu(rf->rf_our_slot);
+       memb->generation = le32_to_cpu(rf->rf_generation);
+}
+
+void dlm_slots_copy_out(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+       struct dlm_slot *slot;
+       struct rcom_slot *ro;
+       int i;
+
+       ro = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
+
+       /* ls_slots array is sparse, but not rcom_slots */
+
+       for (i = 0; i < ls->ls_slots_size; i++) {
+               slot = &ls->ls_slots[i];
+               if (!slot->nodeid)
+                       continue;
+               ro->ro_nodeid = cpu_to_le32(slot->nodeid);
+               ro->ro_slot = cpu_to_le16(slot->slot);
+               ro++;
+       }
+}
+
+#define SLOT_DEBUG_LINE 128
+
+static void log_debug_slots(struct dlm_ls *ls, uint32_t gen, int num_slots,
+                           struct rcom_slot *ro0, struct dlm_slot *array,
+                           int array_size)
+{
+       char line[SLOT_DEBUG_LINE];
+       int len = SLOT_DEBUG_LINE - 1;
+       int pos = 0;
+       int ret, i;
+
+       if (!dlm_config.ci_log_debug)
+               return;
+
+       memset(line, 0, sizeof(line));
+
+       if (array) {
+               for (i = 0; i < array_size; i++) {
+                       if (!array[i].nodeid)
+                               continue;
+
+                       ret = snprintf(line + pos, len - pos, " %d:%d",
+                                      array[i].slot, array[i].nodeid);
+                       if (ret >= len - pos)
+                               break;
+                       pos += ret;
+               }
+       } else if (ro0) {
+               for (i = 0; i < num_slots; i++) {
+                       ret = snprintf(line + pos, len - pos, " %d:%d",
+                                      ro0[i].ro_slot, ro0[i].ro_nodeid);
+                       if (ret >= len - pos)
+                               break;
+                       pos += ret;
+               }
+       }
+
+       log_debug(ls, "generation %u slots %d%s", gen, num_slots, line);
+}
+
+int dlm_slots_copy_in(struct dlm_ls *ls)
+{
+       struct dlm_member *memb;
+       struct dlm_rcom *rc = ls->ls_recover_buf;
+       struct rcom_config *rf = (struct rcom_config *)rc->rc_buf;
+       struct rcom_slot *ro0, *ro;
+       int our_nodeid = dlm_our_nodeid();
+       int i, num_slots;
+       uint32_t gen;
+
+       if (!dlm_slots_version(&rc->rc_header))
+               return -1;
+
+       gen = le32_to_cpu(rf->rf_generation);
+       if (gen <= ls->ls_generation) {
+               log_error(ls, "dlm_slots_copy_in gen %u old %u",
+                         gen, ls->ls_generation);
+       }
+       ls->ls_generation = gen;
+
+       num_slots = le16_to_cpu(rf->rf_num_slots);
+       if (!num_slots)
+               return -1;
+
+       ro0 = (struct rcom_slot *)(rc->rc_buf + sizeof(struct rcom_config));
+
+       for (i = 0, ro = ro0; i < num_slots; i++, ro++) {
+               ro->ro_nodeid = le32_to_cpu(ro->ro_nodeid);
+               ro->ro_slot = le16_to_cpu(ro->ro_slot);
+       }
+
+       log_debug_slots(ls, gen, num_slots, ro0, NULL, 0);
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               for (i = 0, ro = ro0; i < num_slots; i++, ro++) {
+                       if (ro->ro_nodeid != memb->nodeid)
+                               continue;
+                       memb->slot = ro->ro_slot;
+                       memb->slot_prev = memb->slot;
+                       break;
+               }
+
+               if (memb->nodeid == our_nodeid) {
+                       if (ls->ls_slot && ls->ls_slot != memb->slot) {
+                               log_error(ls, "dlm_slots_copy_in our slot "
+                                         "changed %d %d", ls->ls_slot,
+                                         memb->slot);
+                               return -1;
+                       }
+
+                       if (!ls->ls_slot)
+                               ls->ls_slot = memb->slot;
+               }
+
+               if (!memb->slot) {
+                       log_error(ls, "dlm_slots_copy_in nodeid %d no slot",
+                                  memb->nodeid);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* for any nodes that do not support slots, we will not have set memb->slot
+   in wait_status_all(), so memb->slot will remain -1, and we will not
+   assign slots or set ls_num_slots here */
+
+int dlm_slots_assign(struct dlm_ls *ls, int *num_slots, int *slots_size,
+                    struct dlm_slot **slots_out, uint32_t *gen_out)
+{
+       struct dlm_member *memb;
+       struct dlm_slot *array;
+       int our_nodeid = dlm_our_nodeid();
+       int array_size, max_slots, i;
+       int need = 0;
+       int max = 0;
+       int num = 0;
+       uint32_t gen = 0;
+
+       /* our own memb struct will have slot -1 gen 0 */
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               if (memb->nodeid == our_nodeid) {
+                       memb->slot = ls->ls_slot;
+                       memb->generation = ls->ls_generation;
+                       break;
+               }
+       }
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               if (memb->generation > gen)
+                       gen = memb->generation;
+
+               /* node doesn't support slots */
+
+               if (memb->slot == -1)
+                       return -1;
+
+               /* node needs a slot assigned */
+
+               if (!memb->slot)
+                       need++;
+
+               /* node has a slot assigned */
+
+               num++;
+
+               if (!max || max < memb->slot)
+                       max = memb->slot;
+
+               /* sanity check, once slot is assigned it shouldn't change */
+
+               if (memb->slot_prev && memb->slot && memb->slot_prev != memb->slot) {
+                       log_error(ls, "nodeid %d slot changed %d %d",
+                                 memb->nodeid, memb->slot_prev, memb->slot);
+                       return -1;
+               }
+               memb->slot_prev = memb->slot;
+       }
+
+       array_size = max + need;
+
+       array = kzalloc(array_size * sizeof(struct dlm_slot), GFP_NOFS);
+       if (!array)
+               return -ENOMEM;
+
+       num = 0;
+
+       /* fill in slots (offsets) that are used */
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               if (!memb->slot)
+                       continue;
+
+               if (memb->slot > array_size) {
+                       log_error(ls, "invalid slot number %d", memb->slot);
+                       kfree(array);
+                       return -1;
+               }
+
+               array[memb->slot - 1].nodeid = memb->nodeid;
+               array[memb->slot - 1].slot = memb->slot;
+               num++;
+       }
+
+       /* assign new slots from unused offsets */
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               if (memb->slot)
+                       continue;
+
+               for (i = 0; i < array_size; i++) {
+                       if (array[i].nodeid)
+                               continue;
+
+                       memb->slot = i + 1;
+                       memb->slot_prev = memb->slot;
+                       array[i].nodeid = memb->nodeid;
+                       array[i].slot = memb->slot;
+                       num++;
+
+                       if (!ls->ls_slot && memb->nodeid == our_nodeid)
+                               ls->ls_slot = memb->slot;
+                       break;
+               }
+
+               if (!memb->slot) {
+                       log_error(ls, "no free slot found");
+                       kfree(array);
+                       return -1;
+               }
+       }
+
+       gen++;
+
+       log_debug_slots(ls, gen, num, NULL, array, array_size);
+
+       max_slots = (dlm_config.ci_buffer_size - sizeof(struct dlm_rcom) -
+                    sizeof(struct rcom_config)) / sizeof(struct rcom_slot);
+
+       if (num > max_slots) {
+               log_error(ls, "num_slots %d exceeds max_slots %d",
+                         num, max_slots);
+               kfree(array);
+               return -1;
+       }
+
+       *gen_out = gen;
+       *slots_out = array;
+       *slots_size = array_size;
+       *num_slots = num;
+       return 0;
+}
+
 static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 {
        struct dlm_member *memb = NULL;
@@ -43,59 +317,51 @@ static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
        }
 }
 
-static int dlm_add_member(struct dlm_ls *ls, int nodeid)
+static int dlm_add_member(struct dlm_ls *ls, struct dlm_config_node *node)
 {
        struct dlm_member *memb;
-       int w, error;
+       int error;
 
        memb = kzalloc(sizeof(struct dlm_member), GFP_NOFS);
        if (!memb)
                return -ENOMEM;
 
-       w = dlm_node_weight(ls->ls_name, nodeid);
-       if (w < 0) {
-               kfree(memb);
-               return w;
-       }
-
-       error = dlm_lowcomms_connect_node(nodeid);
+       error = dlm_lowcomms_connect_node(node->nodeid);
        if (error < 0) {
                kfree(memb);
                return error;
        }
 
-       memb->nodeid = nodeid;
-       memb->weight = w;
+       memb->nodeid = node->nodeid;
+       memb->weight = node->weight;
+       memb->comm_seq = node->comm_seq;
        add_ordered_member(ls, memb);
        ls->ls_num_nodes++;
        return 0;
 }
 
-static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)
-{
-       list_move(&memb->list, &ls->ls_nodes_gone);
-       ls->ls_num_nodes--;
-}
-
-int dlm_is_member(struct dlm_ls *ls, int nodeid)
+static struct dlm_member *find_memb(struct list_head *head, int nodeid)
 {
        struct dlm_member *memb;
 
-       list_for_each_entry(memb, &ls->ls_nodes, list) {
+       list_for_each_entry(memb, head, list) {
                if (memb->nodeid == nodeid)
-                       return 1;
+                       return memb;
        }
+       return NULL;
+}
+
+int dlm_is_member(struct dlm_ls *ls, int nodeid)
+{
+       if (find_memb(&ls->ls_nodes, nodeid))
+               return 1;
        return 0;
 }
 
 int dlm_is_removed(struct dlm_ls *ls, int nodeid)
 {
-       struct dlm_member *memb;
-
-       list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
-               if (memb->nodeid == nodeid)
-                       return 1;
-       }
+       if (find_memb(&ls->ls_nodes_gone, nodeid))
+               return 1;
        return 0;
 }
 
@@ -176,7 +442,7 @@ static int ping_members(struct dlm_ls *ls)
                error = dlm_recovery_stopped(ls);
                if (error)
                        break;
-               error = dlm_rcom_status(ls, memb->nodeid);
+               error = dlm_rcom_status(ls, memb->nodeid, 0);
                if (error)
                        break;
        }
@@ -186,10 +452,88 @@ static int ping_members(struct dlm_ls *ls)
        return error;
 }
 
+static void dlm_lsop_recover_prep(struct dlm_ls *ls)
+{
+       if (!ls->ls_ops || !ls->ls_ops->recover_prep)
+               return;
+       ls->ls_ops->recover_prep(ls->ls_ops_arg);
+}
+
+static void dlm_lsop_recover_slot(struct dlm_ls *ls, struct dlm_member *memb)
+{
+       struct dlm_slot slot;
+       uint32_t seq;
+       int error;
+
+       if (!ls->ls_ops || !ls->ls_ops->recover_slot)
+               return;
+
+       /* if there is no comms connection with this node
+          or the present comms connection is newer
+          than the one when this member was added, then
+          we consider the node to have failed (versus
+          being removed due to dlm_release_lockspace) */
+
+       error = dlm_comm_seq(memb->nodeid, &seq);
+
+       if (!error && seq == memb->comm_seq)
+               return;
+
+       slot.nodeid = memb->nodeid;
+       slot.slot = memb->slot;
+
+       ls->ls_ops->recover_slot(ls->ls_ops_arg, &slot);
+}
+
+void dlm_lsop_recover_done(struct dlm_ls *ls)
+{
+       struct dlm_member *memb;
+       struct dlm_slot *slots;
+       int i, num;
+
+       if (!ls->ls_ops || !ls->ls_ops->recover_done)
+               return;
+
+       num = ls->ls_num_nodes;
+
+       slots = kzalloc(num * sizeof(struct dlm_slot), GFP_KERNEL);
+       if (!slots)
+               return;
+
+       i = 0;
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               if (i == num) {
+                       log_error(ls, "dlm_lsop_recover_done bad num %d", num);
+                       goto out;
+               }
+               slots[i].nodeid = memb->nodeid;
+               slots[i].slot = memb->slot;
+               i++;
+       }
+
+       ls->ls_ops->recover_done(ls->ls_ops_arg, slots, num,
+                                ls->ls_slot, ls->ls_generation);
+ out:
+       kfree(slots);
+}
+
+static struct dlm_config_node *find_config_node(struct dlm_recover *rv,
+                                               int nodeid)
+{
+       int i;
+
+       for (i = 0; i < rv->nodes_count; i++) {
+               if (rv->nodes[i].nodeid == nodeid)
+                       return &rv->nodes[i];
+       }
+       return NULL;
+}
+
 int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
 {
        struct dlm_member *memb, *safe;
-       int i, error, found, pos = 0, neg = 0, low = -1;
+       struct dlm_config_node *node;
+       int i, error, neg = 0, low = -1;
 
        /* previously removed members that we've not finished removing need to
           count as a negative change so the "neg" recovery steps will happen */
@@ -202,46 +546,32 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
        /* move departed members from ls_nodes to ls_nodes_gone */
 
        list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
-               found = 0;
-               for (i = 0; i < rv->node_count; i++) {
-                       if (memb->nodeid == rv->nodeids[i]) {
-                               found = 1;
-                               break;
-                       }
-               }
+               node = find_config_node(rv, memb->nodeid);
+               if (node && !node->new)
+                       continue;
 
-               if (!found) {
-                       neg++;
-                       dlm_remove_member(ls, memb);
+               if (!node) {
                        log_debug(ls, "remove member %d", memb->nodeid);
+               } else {
+                       /* removed and re-added */
+                       log_debug(ls, "remove member %d comm_seq %u %u",
+                                 memb->nodeid, memb->comm_seq, node->comm_seq);
                }
-       }
-
-       /* Add an entry to ls_nodes_gone for members that were removed and
-          then added again, so that previous state for these nodes will be
-          cleared during recovery. */
-
-       for (i = 0; i < rv->new_count; i++) {
-               if (!dlm_is_member(ls, rv->new[i]))
-                       continue;
-               log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]);
 
-               memb = kzalloc(sizeof(struct dlm_member), GFP_NOFS);
-               if (!memb)
-                       return -ENOMEM;
-               memb->nodeid = rv->new[i];
-               list_add_tail(&memb->list, &ls->ls_nodes_gone);
                neg++;
+               list_move(&memb->list, &ls->ls_nodes_gone);
+               ls->ls_num_nodes--;
+               dlm_lsop_recover_slot(ls, memb);
        }
 
        /* add new members to ls_nodes */
 
-       for (i = 0; i < rv->node_count; i++) {
-               if (dlm_is_member(ls, rv->nodeids[i]))
+       for (i = 0; i < rv->nodes_count; i++) {
+               node = &rv->nodes[i];
+               if (dlm_is_member(ls, node->nodeid))
                        continue;
-               dlm_add_member(ls, rv->nodeids[i]);
-               pos++;
-               log_debug(ls, "add member %d", rv->nodeids[i]);
+               dlm_add_member(ls, node);
+               log_debug(ls, "add member %d", node->nodeid);
        }
 
        list_for_each_entry(memb, &ls->ls_nodes, list) {
@@ -251,7 +581,6 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
        ls->ls_low_nodeid = low;
 
        make_member_array(ls);
-       dlm_set_recover_status(ls, DLM_RS_NODES);
        *neg_out = neg;
 
        error = ping_members(ls);
@@ -261,12 +590,8 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
                ls->ls_members_result = error;
                complete(&ls->ls_members_done);
        }
-       if (error)
-               goto out;
 
-       error = dlm_recover_members_wait(ls);
- out:
-       log_debug(ls, "total members %d error %d", ls->ls_num_nodes, error);
+       log_debug(ls, "dlm_recover_members %d nodes", ls->ls_num_nodes);
        return error;
 }
 
@@ -327,26 +652,35 @@ int dlm_ls_stop(struct dlm_ls *ls)
         */
 
        dlm_recoverd_suspend(ls);
+
+       spin_lock(&ls->ls_recover_lock);
+       kfree(ls->ls_slots);
+       ls->ls_slots = NULL;
+       ls->ls_num_slots = 0;
+       ls->ls_slots_size = 0;
        ls->ls_recover_status = 0;
+       spin_unlock(&ls->ls_recover_lock);
+
        dlm_recoverd_resume(ls);
 
        if (!ls->ls_recover_begin)
                ls->ls_recover_begin = jiffies;
+
+       dlm_lsop_recover_prep(ls);
        return 0;
 }
 
 int dlm_ls_start(struct dlm_ls *ls)
 {
        struct dlm_recover *rv = NULL, *rv_old;
-       int *ids = NULL, *new = NULL;
-       int error, ids_count = 0, new_count = 0;
+       struct dlm_config_node *nodes;
+       int error, count;
 
        rv = kzalloc(sizeof(struct dlm_recover), GFP_NOFS);
        if (!rv)
                return -ENOMEM;
 
-       error = dlm_nodeid_list(ls->ls_name, &ids, &ids_count,
-                               &new, &new_count);
+       error = dlm_config_nodes(ls->ls_name, &nodes, &count);
        if (error < 0)
                goto fail;
 
@@ -361,10 +695,8 @@ int dlm_ls_start(struct dlm_ls *ls)
                goto fail;
        }
 
-       rv->nodeids = ids;
-       rv->node_count = ids_count;
-       rv->new = new;
-       rv->new_count = new_count;
+       rv->nodes = nodes;
+       rv->nodes_count = count;
        rv->seq = ++ls->ls_recover_seq;
        rv_old = ls->ls_recover_args;
        ls->ls_recover_args = rv;
@@ -372,9 +704,8 @@ int dlm_ls_start(struct dlm_ls *ls)
 
        if (rv_old) {
                log_error(ls, "unused recovery %llx %d",
-                         (unsigned long long)rv_old->seq, rv_old->node_count);
-               kfree(rv_old->nodeids);
-               kfree(rv_old->new);
+                         (unsigned long long)rv_old->seq, rv_old->nodes_count);
+               kfree(rv_old->nodes);
                kfree(rv_old);
        }
 
@@ -383,8 +714,7 @@ int dlm_ls_start(struct dlm_ls *ls)
 
  fail:
        kfree(rv);
-       kfree(ids);
-       kfree(new);
+       kfree(nodes);
        return error;
 }
 
index 7a26fca1e0b5386e6b5906655b57f6fd80e1fe3c..3deb70661c699c809e57e6ae588e03036ad62549 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -20,6 +20,14 @@ void dlm_clear_members_gone(struct dlm_ls *ls);
 int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);
 int dlm_is_removed(struct dlm_ls *ls, int nodeid);
 int dlm_is_member(struct dlm_ls *ls, int nodeid);
+int dlm_slots_version(struct dlm_header *h);
+void dlm_slot_save(struct dlm_ls *ls, struct dlm_rcom *rc,
+                  struct dlm_member *memb);
+void dlm_slots_copy_out(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_slots_copy_in(struct dlm_ls *ls);
+int dlm_slots_assign(struct dlm_ls *ls, int *num_slots, int *slots_size,
+                    struct dlm_slot **slots_out, uint32_t *gen_out);
+void dlm_lsop_recover_done(struct dlm_ls *ls);
 
 #endif                          /* __MEMBER_DOT_H__ */
 
index f10a50f24e8fd6fc1889babedbf68aee0990472e..ac5c616c969643addc81c8920f4da2cf439356e9 100644 (file)
@@ -23,6 +23,7 @@
 #include "memory.h"
 #include "lock.h"
 #include "util.h"
+#include "member.h"
 
 
 static int rcom_response(struct dlm_ls *ls)
@@ -72,20 +73,30 @@ static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh,
        dlm_lowcomms_commit_buffer(mh);
 }
 
+static void set_rcom_status(struct dlm_ls *ls, struct rcom_status *rs,
+                           uint32_t flags)
+{
+       rs->rs_flags = cpu_to_le32(flags);
+}
+
 /* When replying to a status request, a node also sends back its
    configuration values.  The requesting node then checks that the remote
    node is configured the same way as itself. */
 
-static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
+static void set_rcom_config(struct dlm_ls *ls, struct rcom_config *rf,
+                           uint32_t num_slots)
 {
        rf->rf_lvblen = cpu_to_le32(ls->ls_lvblen);
        rf->rf_lsflags = cpu_to_le32(ls->ls_exflags);
+
+       rf->rf_our_slot = cpu_to_le16(ls->ls_slot);
+       rf->rf_num_slots = cpu_to_le16(num_slots);
+       rf->rf_generation =  cpu_to_le32(ls->ls_generation);
 }
 
-static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
+static int check_rcom_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
        struct rcom_config *rf = (struct rcom_config *) rc->rc_buf;
-       size_t conf_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_config);
 
        if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) {
                log_error(ls, "version mismatch: %x nodeid %d: %x",
@@ -94,12 +105,6 @@ static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
                return -EPROTO;
        }
 
-       if (rc->rc_header.h_length < conf_size) {
-               log_error(ls, "config too short: %d nodeid %d",
-                         rc->rc_header.h_length, nodeid);
-               return -EPROTO;
-       }
-
        if (le32_to_cpu(rf->rf_lvblen) != ls->ls_lvblen ||
            le32_to_cpu(rf->rf_lsflags) != ls->ls_exflags) {
                log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
@@ -127,7 +132,18 @@ static void disallow_sync_reply(struct dlm_ls *ls)
        spin_unlock(&ls->ls_rcom_spin);
 }
 
-int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
+/*
+ * low nodeid gathers one slot value at a time from each node.
+ * it sets need_slots=0, and saves rf_our_slot returned from each
+ * rcom_config.
+ *
+ * other nodes gather all slot values at once from the low nodeid.
+ * they set need_slots=1, and ignore the rf_our_slot returned from each
+ * rcom_config.  they use the rf_num_slots returned from the low
+ * node's rcom_config.
+ */
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid, uint32_t status_flags)
 {
        struct dlm_rcom *rc;
        struct dlm_mhandle *mh;
@@ -141,10 +157,13 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
                goto out;
        }
 
-       error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh);
+       error = create_rcom(ls, nodeid, DLM_RCOM_STATUS,
+                           sizeof(struct rcom_status), &rc, &mh);
        if (error)
                goto out;
 
+       set_rcom_status(ls, (struct rcom_status *)rc->rc_buf, status_flags);
+
        allow_sync_reply(ls, &rc->rc_id);
        memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
 
@@ -161,8 +180,11 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
                /* we pretend the remote lockspace exists with 0 status */
                log_debug(ls, "remote node %d not ready", nodeid);
                rc->rc_result = 0;
-       } else
-               error = check_config(ls, rc, nodeid);
+               error = 0;
+       } else {
+               error = check_rcom_config(ls, rc, nodeid);
+       }
+
        /* the caller looks at rc_result for the remote recovery status */
  out:
        return error;
@@ -172,17 +194,60 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 {
        struct dlm_rcom *rc;
        struct dlm_mhandle *mh;
-       int error, nodeid = rc_in->rc_header.h_nodeid;
+       struct rcom_status *rs;
+       uint32_t status;
+       int nodeid = rc_in->rc_header.h_nodeid;
+       int len = sizeof(struct rcom_config);
+       int num_slots = 0;
+       int error;
+
+       if (!dlm_slots_version(&rc_in->rc_header)) {
+               status = dlm_recover_status(ls);
+               goto do_create;
+       }
+
+       rs = (struct rcom_status *)rc_in->rc_buf;
 
+       if (!(rs->rs_flags & DLM_RSF_NEED_SLOTS)) {
+               status = dlm_recover_status(ls);
+               goto do_create;
+       }
+
+       spin_lock(&ls->ls_recover_lock);
+       status = ls->ls_recover_status;
+       num_slots = ls->ls_num_slots;
+       spin_unlock(&ls->ls_recover_lock);
+       len += num_slots * sizeof(struct rcom_slot);
+
+ do_create:
        error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY,
-                           sizeof(struct rcom_config), &rc, &mh);
+                           len, &rc, &mh);
        if (error)
                return;
+
        rc->rc_id = rc_in->rc_id;
        rc->rc_seq_reply = rc_in->rc_seq;
-       rc->rc_result = dlm_recover_status(ls);
-       make_config(ls, (struct rcom_config *) rc->rc_buf);
+       rc->rc_result = status;
+
+       set_rcom_config(ls, (struct rcom_config *)rc->rc_buf, num_slots);
+
+       if (!num_slots)
+               goto do_send;
+
+       spin_lock(&ls->ls_recover_lock);
+       if (ls->ls_num_slots != num_slots) {
+               spin_unlock(&ls->ls_recover_lock);
+               log_debug(ls, "receive_rcom_status num_slots %d to %d",
+                         num_slots, ls->ls_num_slots);
+               rc->rc_result = 0;
+               set_rcom_config(ls, (struct rcom_config *)rc->rc_buf, 0);
+               goto do_send;
+       }
+
+       dlm_slots_copy_out(ls, rc);
+       spin_unlock(&ls->ls_recover_lock);
 
+ do_send:
        send_rcom(ls, mh, rc);
 }
 
index b09abd29ba38cfc3ff64dd2666f3945054520c62..206723ab744dd1c30c687f3a82e50282f631e985 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __RCOM_DOT_H__
 #define __RCOM_DOT_H__
 
-int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid, uint32_t status_flags);
 int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
 int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
 int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
index 14638235f7b2935093e31e43a36a09435dc80c73..34d5adf1fce7d2022679d42e1e00673af0825dae 100644 (file)
@@ -85,14 +85,20 @@ uint32_t dlm_recover_status(struct dlm_ls *ls)
        return status;
 }
 
+static void _set_recover_status(struct dlm_ls *ls, uint32_t status)
+{
+       ls->ls_recover_status |= status;
+}
+
 void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)
 {
        spin_lock(&ls->ls_recover_lock);
-       ls->ls_recover_status |= status;
+       _set_recover_status(ls, status);
        spin_unlock(&ls->ls_recover_lock);
 }
 
-static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
+static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status,
+                          int save_slots)
 {
        struct dlm_rcom *rc = ls->ls_recover_buf;
        struct dlm_member *memb;
@@ -106,10 +112,13 @@ static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
                                goto out;
                        }
 
-                       error = dlm_rcom_status(ls, memb->nodeid);
+                       error = dlm_rcom_status(ls, memb->nodeid, 0);
                        if (error)
                                goto out;
 
+                       if (save_slots)
+                               dlm_slot_save(ls, rc, memb);
+
                        if (rc->rc_result & wait_status)
                                break;
                        if (delay < 1000)
@@ -121,7 +130,8 @@ static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
        return error;
 }
 
-static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
+static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status,
+                          uint32_t status_flags)
 {
        struct dlm_rcom *rc = ls->ls_recover_buf;
        int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;
@@ -132,7 +142,7 @@ static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
                        goto out;
                }
 
-               error = dlm_rcom_status(ls, nodeid);
+               error = dlm_rcom_status(ls, nodeid, status_flags);
                if (error)
                        break;
 
@@ -152,18 +162,56 @@ static int wait_status(struct dlm_ls *ls, uint32_t status)
        int error;
 
        if (ls->ls_low_nodeid == dlm_our_nodeid()) {
-               error = wait_status_all(ls, status);
+               error = wait_status_all(ls, status, 0);
                if (!error)
                        dlm_set_recover_status(ls, status_all);
        } else
-               error = wait_status_low(ls, status_all);
+               error = wait_status_low(ls, status_all, 0);
 
        return error;
 }
 
 int dlm_recover_members_wait(struct dlm_ls *ls)
 {
-       return wait_status(ls, DLM_RS_NODES);
+       struct dlm_member *memb;
+       struct dlm_slot *slots;
+       int num_slots, slots_size;
+       int error, rv;
+       uint32_t gen;
+
+       list_for_each_entry(memb, &ls->ls_nodes, list) {
+               memb->slot = -1;
+               memb->generation = 0;
+       }
+
+       if (ls->ls_low_nodeid == dlm_our_nodeid()) {
+               error = wait_status_all(ls, DLM_RS_NODES, 1);
+               if (error)
+                       goto out;
+
+               /* slots array is sparse, slots_size may be > num_slots */
+
+               rv = dlm_slots_assign(ls, &num_slots, &slots_size, &slots, &gen);
+               if (!rv) {
+                       spin_lock(&ls->ls_recover_lock);
+                       _set_recover_status(ls, DLM_RS_NODES_ALL);
+                       ls->ls_num_slots = num_slots;
+                       ls->ls_slots_size = slots_size;
+                       ls->ls_slots = slots;
+                       ls->ls_generation = gen;
+                       spin_unlock(&ls->ls_recover_lock);
+               } else {
+                       dlm_set_recover_status(ls, DLM_RS_NODES_ALL);
+               }
+       } else {
+               error = wait_status_low(ls, DLM_RS_NODES_ALL, DLM_RSF_NEED_SLOTS);
+               if (error)
+                       goto out;
+
+               dlm_slots_copy_in(ls);
+       }
+ out:
+       return error;
 }
 
 int dlm_recover_directory_wait(struct dlm_ls *ls)
@@ -542,8 +590,6 @@ int dlm_recover_locks(struct dlm_ls *ls)
  out:
        if (error)
                recover_list_clear(ls);
-       else
-               dlm_set_recover_status(ls, DLM_RS_LOCKS);
        return error;
 }
 
@@ -715,6 +761,7 @@ void dlm_recover_rsbs(struct dlm_ls *ls)
 
 int dlm_create_root_list(struct dlm_ls *ls)
 {
+       struct rb_node *n;
        struct dlm_rsb *r;
        int i, error = 0;
 
@@ -727,7 +774,8 @@ int dlm_create_root_list(struct dlm_ls *ls)
 
        for (i = 0; i < ls->ls_rsbtbl_size; i++) {
                spin_lock(&ls->ls_rsbtbl[i].lock);
-               list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
+               for (n = rb_first(&ls->ls_rsbtbl[i].keep); n; n = rb_next(n)) {
+                       r = rb_entry(n, struct dlm_rsb, res_hashnode);
                        list_add(&r->res_root_list, &ls->ls_root_list);
                        dlm_hold_rsb(r);
                }
@@ -741,7 +789,8 @@ int dlm_create_root_list(struct dlm_ls *ls)
                        continue;
                }
 
-               list_for_each_entry(r, &ls->ls_rsbtbl[i].toss, res_hashchain) {
+               for (n = rb_first(&ls->ls_rsbtbl[i].toss); n; n = rb_next(n)) {
+                       r = rb_entry(n, struct dlm_rsb, res_hashnode);
                        list_add(&r->res_root_list, &ls->ls_root_list);
                        dlm_hold_rsb(r);
                }
@@ -771,16 +820,18 @@ void dlm_release_root_list(struct dlm_ls *ls)
 
 void dlm_clear_toss_list(struct dlm_ls *ls)
 {
-       struct dlm_rsb *r, *safe;
+       struct rb_node *n, *next;
+       struct dlm_rsb *rsb;
        int i;
 
        for (i = 0; i < ls->ls_rsbtbl_size; i++) {
                spin_lock(&ls->ls_rsbtbl[i].lock);
-               list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss,
-                                        res_hashchain) {
-                       if (dlm_no_directory(ls) || !is_master(r)) {
-                               list_del(&r->res_hashchain);
-                               dlm_free_rsb(r);
+               for (n = rb_first(&ls->ls_rsbtbl[i].toss); n; n = next) {
+                       next = rb_next(n);;
+                       rsb = rb_entry(n, struct dlm_rsb, res_hashnode);
+                       if (dlm_no_directory(ls) || !is_master(rsb)) {
+                               rb_erase(n, &ls->ls_rsbtbl[i].toss);
+                               dlm_free_rsb(rsb);
                        }
                }
                spin_unlock(&ls->ls_rsbtbl[i].lock);
index 774da3cf92c6b095d99538f971daa21577897750..3780caf7ae0c239776951724c8d951dca5aef5dd 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -54,7 +54,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
        unsigned long start;
        int error, neg = 0;
 
-       log_debug(ls, "recover %llx", (unsigned long long)rv->seq);
+       log_debug(ls, "dlm_recover %llx", (unsigned long long)rv->seq);
 
        mutex_lock(&ls->ls_recoverd_active);
 
@@ -76,14 +76,22 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        /*
         * Add or remove nodes from the lockspace's ls_nodes list.
-        * Also waits for all nodes to complete dlm_recover_members.
         */
 
        error = dlm_recover_members(ls, rv, &neg);
        if (error) {
-               log_debug(ls, "recover_members failed %d", error);
+               log_debug(ls, "dlm_recover_members error %d", error);
                goto fail;
        }
+
+       dlm_set_recover_status(ls, DLM_RS_NODES);
+
+       error = dlm_recover_members_wait(ls);
+       if (error) {
+               log_debug(ls, "dlm_recover_members_wait error %d", error);
+               goto fail;
+       }
+
        start = jiffies;
 
        /*
@@ -93,17 +101,15 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = dlm_recover_directory(ls);
        if (error) {
-               log_debug(ls, "recover_directory failed %d", error);
+               log_debug(ls, "dlm_recover_directory error %d", error);
                goto fail;
        }
 
-       /*
-        * Wait for all nodes to complete directory rebuild.
-        */
+       dlm_set_recover_status(ls, DLM_RS_DIR);
 
        error = dlm_recover_directory_wait(ls);
        if (error) {
-               log_debug(ls, "recover_directory_wait failed %d", error);
+               log_debug(ls, "dlm_recover_directory_wait error %d", error);
                goto fail;
        }
 
@@ -133,7 +139,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_masters(ls);
                if (error) {
-                       log_debug(ls, "recover_masters failed %d", error);
+                       log_debug(ls, "dlm_recover_masters error %d", error);
                        goto fail;
                }
 
@@ -143,13 +149,15 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_locks(ls);
                if (error) {
-                       log_debug(ls, "recover_locks failed %d", error);
+                       log_debug(ls, "dlm_recover_locks error %d", error);
                        goto fail;
                }
 
+               dlm_set_recover_status(ls, DLM_RS_LOCKS);
+
                error = dlm_recover_locks_wait(ls);
                if (error) {
-                       log_debug(ls, "recover_locks_wait failed %d", error);
+                       log_debug(ls, "dlm_recover_locks_wait error %d", error);
                        goto fail;
                }
 
@@ -170,7 +178,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_locks_wait(ls);
                if (error) {
-                       log_debug(ls, "recover_locks_wait failed %d", error);
+                       log_debug(ls, "dlm_recover_locks_wait error %d", error);
                        goto fail;
                }
        }
@@ -186,9 +194,10 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
        dlm_purge_requestqueue(ls);
 
        dlm_set_recover_status(ls, DLM_RS_DONE);
+
        error = dlm_recover_done_wait(ls);
        if (error) {
-               log_debug(ls, "recover_done_wait failed %d", error);
+               log_debug(ls, "dlm_recover_done_wait error %d", error);
                goto fail;
        }
 
@@ -200,34 +209,35 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = enable_locking(ls, rv->seq);
        if (error) {
-               log_debug(ls, "enable_locking failed %d", error);
+               log_debug(ls, "enable_locking error %d", error);
                goto fail;
        }
 
        error = dlm_process_requestqueue(ls);
        if (error) {
-               log_debug(ls, "process_requestqueue failed %d", error);
+               log_debug(ls, "dlm_process_requestqueue error %d", error);
                goto fail;
        }
 
        error = dlm_recover_waiters_post(ls);
        if (error) {
-               log_debug(ls, "recover_waiters_post failed %d", error);
+               log_debug(ls, "dlm_recover_waiters_post error %d", error);
                goto fail;
        }
 
        dlm_grant_after_purge(ls);
 
-       log_debug(ls, "recover %llx done: %u ms",
-                 (unsigned long long)rv->seq,
+       log_debug(ls, "dlm_recover %llx generation %u done: %u ms",
+                 (unsigned long long)rv->seq, ls->ls_generation,
                  jiffies_to_msecs(jiffies - start));
        mutex_unlock(&ls->ls_recoverd_active);
 
+       dlm_lsop_recover_done(ls);
        return 0;
 
  fail:
        dlm_release_root_list(ls);
-       log_debug(ls, "recover %llx error %d",
+       log_debug(ls, "dlm_recover %llx error %d",
                  (unsigned long long)rv->seq, error);
        mutex_unlock(&ls->ls_recoverd_active);
        return error;
@@ -250,8 +260,7 @@ static void do_ls_recovery(struct dlm_ls *ls)
 
        if (rv) {
                ls_recover(ls, rv);
-               kfree(rv->nodeids);
-               kfree(rv->new);
+               kfree(rv->nodes);
                kfree(rv);
        }
 }
index d8ea607564034a87bbc5e9614f5fdff6db347d4b..eb4ed9ba3098198e8d1db357db48c8f6e9e2ff34 100644 (file)
@@ -392,8 +392,9 @@ static int device_create_lockspace(struct dlm_lspace_params *params)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       error = dlm_new_lockspace(params->name, strlen(params->name),
-                                 &lockspace, params->flags, DLM_USER_LVB_LEN);
+       error = dlm_new_lockspace(params->name, NULL, params->flags,
+                                 DLM_USER_LVB_LEN, NULL, NULL, NULL,
+                                 &lockspace);
        if (error)
                return error;
 
index 828e750af23a7923cb9782c9cd3c3b87ed6b4964..aabdfc38cf2499817f150eace1efe8e8f08f1f8f 100644 (file)
@@ -197,6 +197,12 @@ struct eventpoll {
 
        /* The user that created the eventpoll descriptor */
        struct user_struct *user;
+
+       struct file *file;
+
+       /* used to optimize loop detection check */
+       int visited;
+       struct list_head visited_list_link;
 };
 
 /* Wait structure used by the poll hooks */
@@ -255,6 +261,15 @@ static struct kmem_cache *epi_cache __read_mostly;
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
+/* Visited nodes during ep_loop_check(), so we can unset them when we finish */
+static LIST_HEAD(visited_list);
+
+/*
+ * List of files with newly added links, where we may need to limit the number
+ * of emanating paths. Protected by the epmutex.
+ */
+static LIST_HEAD(tfile_check_list);
+
 #ifdef CONFIG_SYSCTL
 
 #include <linux/sysctl.h>
@@ -276,6 +291,12 @@ ctl_table epoll_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static const struct file_operations eventpoll_fops;
+
+static inline int is_file_epoll(struct file *f)
+{
+       return f->f_op == &eventpoll_fops;
+}
 
 /* Setup the structure that is used as key for the RB tree */
 static inline void ep_set_ffd(struct epoll_filefd *ffd,
@@ -711,12 +732,6 @@ static const struct file_operations eventpoll_fops = {
        .llseek         = noop_llseek,
 };
 
-/* Fast test to see if the file is an eventpoll file */
-static inline int is_file_epoll(struct file *f)
-{
-       return f->f_op == &eventpoll_fops;
-}
-
 /*
  * This is called from eventpoll_release() to unlink files from the eventpoll
  * interface. We need to have this facility to cleanup correctly files that are
@@ -926,6 +941,99 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
        rb_insert_color(&epi->rbn, &ep->rbr);
 }
 
+
+
+#define PATH_ARR_SIZE 5
+/*
+ * These are the number paths of length 1 to 5, that we are allowing to emanate
+ * from a single file of interest. For example, we allow 1000 paths of length
+ * 1, to emanate from each file of interest. This essentially represents the
+ * potential wakeup paths, which need to be limited in order to avoid massive
+ * uncontrolled wakeup storms. The common use case should be a single ep which
+ * is connected to n file sources. In this case each file source has 1 path
+ * of length 1. Thus, the numbers below should be more than sufficient. These
+ * path limits are enforced during an EPOLL_CTL_ADD operation, since a modify
+ * and delete can't add additional paths. Protected by the epmutex.
+ */
+static const int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 };
+static int path_count[PATH_ARR_SIZE];
+
+static int path_count_inc(int nests)
+{
+       if (++path_count[nests] > path_limits[nests])
+               return -1;
+       return 0;
+}
+
+static void path_count_init(void)
+{
+       int i;
+
+       for (i = 0; i < PATH_ARR_SIZE; i++)
+               path_count[i] = 0;
+}
+
+static int reverse_path_check_proc(void *priv, void *cookie, int call_nests)
+{
+       int error = 0;
+       struct file *file = priv;
+       struct file *child_file;
+       struct epitem *epi;
+
+       list_for_each_entry(epi, &file->f_ep_links, fllink) {
+               child_file = epi->ep->file;
+               if (is_file_epoll(child_file)) {
+                       if (list_empty(&child_file->f_ep_links)) {
+                               if (path_count_inc(call_nests)) {
+                                       error = -1;
+                                       break;
+                               }
+                       } else {
+                               error = ep_call_nested(&poll_loop_ncalls,
+                                                       EP_MAX_NESTS,
+                                                       reverse_path_check_proc,
+                                                       child_file, child_file,
+                                                       current);
+                       }
+                       if (error != 0)
+                               break;
+               } else {
+                       printk(KERN_ERR "reverse_path_check_proc: "
+                               "file is not an ep!\n");
+               }
+       }
+       return error;
+}
+
+/**
+ * reverse_path_check - The tfile_check_list is list of file *, which have
+ *                      links that are proposed to be newly added. We need to
+ *                      make sure that those added links don't add too many
+ *                      paths such that we will spend all our time waking up
+ *                      eventpoll objects.
+ *
+ * Returns: Returns zero if the proposed links don't create too many paths,
+ *         -1 otherwise.
+ */
+static int reverse_path_check(void)
+{
+       int length = 0;
+       int error = 0;
+       struct file *current_file;
+
+       /* let's call this for all tfiles */
+       list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) {
+               length++;
+               path_count_init();
+               error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                                       reverse_path_check_proc, current_file,
+                                       current_file, current);
+               if (error)
+                       break;
+       }
+       return error;
+}
+
 /*
  * Must be called with "mtx" held.
  */
@@ -987,6 +1095,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
         */
        ep_rbtree_insert(ep, epi);
 
+       /* now check if we've created too many backpaths */
+       error = -EINVAL;
+       if (reverse_path_check())
+               goto error_remove_epi;
+
        /* We have to drop the new item inside our item list to keep track of it */
        spin_lock_irqsave(&ep->lock, flags);
 
@@ -1011,6 +1124,14 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        return 0;
 
+error_remove_epi:
+       spin_lock(&tfile->f_lock);
+       if (ep_is_linked(&epi->fllink))
+               list_del_init(&epi->fllink);
+       spin_unlock(&tfile->f_lock);
+
+       rb_erase(&epi->rbn, &ep->rbr);
+
 error_unregister:
        ep_unregister_pollwait(ep, epi);
 
@@ -1275,18 +1396,36 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
        int error = 0;
        struct file *file = priv;
        struct eventpoll *ep = file->private_data;
+       struct eventpoll *ep_tovisit;
        struct rb_node *rbp;
        struct epitem *epi;
 
        mutex_lock_nested(&ep->mtx, call_nests + 1);
+       ep->visited = 1;
+       list_add(&ep->visited_list_link, &visited_list);
        for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
                epi = rb_entry(rbp, struct epitem, rbn);
                if (unlikely(is_file_epoll(epi->ffd.file))) {
+                       ep_tovisit = epi->ffd.file->private_data;
+                       if (ep_tovisit->visited)
+                               continue;
                        error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
-                                              ep_loop_check_proc, epi->ffd.file,
-                                              epi->ffd.file->private_data, current);
+                                       ep_loop_check_proc, epi->ffd.file,
+                                       ep_tovisit, current);
                        if (error != 0)
                                break;
+               } else {
+                       /*
+                        * If we've reached a file that is not associated with
+                        * an ep, then we need to check if the newly added
+                        * links are going to add too many wakeup paths. We do
+                        * this by adding it to the tfile_check_list, if it's
+                        * not already there, and calling reverse_path_check()
+                        * during ep_insert().
+                        */
+                       if (list_empty(&epi->ffd.file->f_tfile_llink))
+                               list_add(&epi->ffd.file->f_tfile_llink,
+                                        &tfile_check_list);
                }
        }
        mutex_unlock(&ep->mtx);
@@ -1307,8 +1446,31 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
  */
 static int ep_loop_check(struct eventpoll *ep, struct file *file)
 {
-       return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+       int ret;
+       struct eventpoll *ep_cur, *ep_next;
+
+       ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
                              ep_loop_check_proc, file, ep, current);
+       /* clear visited list */
+       list_for_each_entry_safe(ep_cur, ep_next, &visited_list,
+                                                       visited_list_link) {
+               ep_cur->visited = 0;
+               list_del(&ep_cur->visited_list_link);
+       }
+       return ret;
+}
+
+static void clear_tfile_check_list(void)
+{
+       struct file *file;
+
+       /* first clear the tfile_check_list */
+       while (!list_empty(&tfile_check_list)) {
+               file = list_first_entry(&tfile_check_list, struct file,
+                                       f_tfile_llink);
+               list_del_init(&file->f_tfile_llink);
+       }
+       INIT_LIST_HEAD(&tfile_check_list);
 }
 
 /*
@@ -1316,8 +1478,9 @@ static int ep_loop_check(struct eventpoll *ep, struct file *file)
  */
 SYSCALL_DEFINE1(epoll_create1, int, flags)
 {
-       int error;
+       int error, fd;
        struct eventpoll *ep = NULL;
+       struct file *file;
 
        /* Check the EPOLL_* constant for consistency.  */
        BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);
@@ -1334,11 +1497,25 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
         * Creates all the items needed to setup an eventpoll file. That is,
         * a file structure and a free file descriptor.
         */
-       error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
+       fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC));
+       if (fd < 0) {
+               error = fd;
+               goto out_free_ep;
+       }
+       file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep,
                                 O_RDWR | (flags & O_CLOEXEC));
-       if (error < 0)
-               ep_free(ep);
-
+       if (IS_ERR(file)) {
+               error = PTR_ERR(file);
+               goto out_free_fd;
+       }
+       fd_install(fd, file);
+       ep->file = file;
+       return fd;
+
+out_free_fd:
+       put_unused_fd(fd);
+out_free_ep:
+       ep_free(ep);
        return error;
 }
 
@@ -1404,21 +1581,27 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        /*
         * When we insert an epoll file descriptor, inside another epoll file
         * descriptor, there is the change of creating closed loops, which are
-        * better be handled here, than in more critical paths.
+        * better be handled here, than in more critical paths. While we are
+        * checking for loops we also determine the list of files reachable
+        * and hang them on the tfile_check_list, so we can check that we
+        * haven't created too many possible wakeup paths.
         *
-        * We hold epmutex across the loop check and the insert in this case, in
-        * order to prevent two separate inserts from racing and each doing the
-        * insert "at the same time" such that ep_loop_check passes on both
-        * before either one does the insert, thereby creating a cycle.
+        * We need to hold the epmutex across both ep_insert and ep_remove
+        * b/c we want to make sure we are looking at a coherent view of
+        * epoll network.
         */
-       if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) {
+       if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) {
                mutex_lock(&epmutex);
                did_lock_epmutex = 1;
-               error = -ELOOP;
-               if (ep_loop_check(ep, tfile) != 0)
-                       goto error_tgt_fput;
        }
-
+       if (op == EPOLL_CTL_ADD) {
+               if (is_file_epoll(tfile)) {
+                       error = -ELOOP;
+                       if (ep_loop_check(ep, tfile) != 0)
+                               goto error_tgt_fput;
+               } else
+                       list_add(&tfile->f_tfile_llink, &tfile_check_list);
+       }
 
        mutex_lock_nested(&ep->mtx, 0);
 
@@ -1437,6 +1620,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                        error = ep_insert(ep, &epds, tfile, fd);
                } else
                        error = -EEXIST;
+               clear_tfile_check_list();
                break;
        case EPOLL_CTL_DEL:
                if (epi)
@@ -1455,7 +1639,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
-       if (unlikely(did_lock_epmutex))
+       if (did_lock_epmutex)
                mutex_unlock(&epmutex);
 
        fput(tfile);
index 3f64b9f26e7df51f24254f2885d67c1f54648923..aeb135c7ff5c0c1a6f1a1dfe3b5f2018dfbd6731 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -59,6 +59,8 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
+
+#include <trace/events/task.h>
 #include "internal.h"
 
 int core_uses_pid;
@@ -1054,6 +1056,8 @@ void set_task_comm(struct task_struct *tsk, char *buf)
 {
        task_lock(tsk);
 
+       trace_task_rename(tsk, buf);
+
        /*
         * Threads may access current->comm without holding
         * the task lock, so write the string carefully.
index 12ccacda44e0288e13247e3e79ebd414287eb548..f9e2cd8cf711d2f43a74f5a5f4cc830604cd82d9 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <trace/events/ext4.h>
 
+static unsigned ext4_num_base_meta_clusters(struct super_block *sb,
+                                           ext4_group_t block_group);
 /*
  * balloc.c contains the blocks allocation and deallocation routines
  */
@@ -668,7 +670,7 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
  * This function returns the number of file system metadata clusters at
  * the beginning of a block group, including the reserved gdt blocks.
  */
-unsigned ext4_num_base_meta_clusters(struct super_block *sb,
+static unsigned ext4_num_base_meta_clusters(struct super_block *sb,
                                     ext4_group_t block_group)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
index 1554b15f91bce81f0a7b43e13bba1c738361a668..513004fc3d840ee03586a4fedcdb133d8031c642 100644 (file)
@@ -511,6 +511,14 @@ struct ext4_new_group_data {
        __u32 free_blocks_count;
 };
 
+/* Indexes used to index group tables in ext4_new_group_data */
+enum {
+       BLOCK_BITMAP = 0,       /* block bitmap */
+       INODE_BITMAP,           /* inode bitmap */
+       INODE_TABLE,            /* inode tables */
+       GROUP_TABLE_COUNT,
+};
+
 /*
  * Flags used by ext4_map_blocks()
  */
@@ -575,6 +583,7 @@ struct ext4_new_group_data {
  /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
 #define EXT4_IOC_ALLOC_DA_BLKS         _IO('f', 12)
 #define EXT4_IOC_MOVE_EXT              _IOWR('f', 15, struct move_extent)
+#define EXT4_IOC_RESIZE_FS             _IOW('f', 16, __u64)
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
@@ -957,12 +966,13 @@ struct ext4_inode_info {
 #define test_opt2(sb, opt)             (EXT4_SB(sb)->s_mount_opt2 & \
                                         EXT4_MOUNT2_##opt)
 
-#define ext4_set_bit                   __test_and_set_bit_le
+#define ext4_test_and_set_bit          __test_and_set_bit_le
+#define ext4_set_bit                   __set_bit_le
 #define ext4_set_bit_atomic            ext2_set_bit_atomic
-#define ext4_clear_bit                 __test_and_clear_bit_le
+#define ext4_test_and_clear_bit                __test_and_clear_bit_le
+#define ext4_clear_bit                 __clear_bit_le
 #define ext4_clear_bit_atomic          ext2_clear_bit_atomic
 #define ext4_test_bit                  test_bit_le
-#define ext4_find_first_zero_bit       find_first_zero_bit_le
 #define ext4_find_next_zero_bit                find_next_zero_bit_le
 #define ext4_find_next_bit             find_next_bit_le
 
@@ -1397,6 +1407,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
 #define EXT4_FEATURE_RO_COMPAT_BIGALLOC                0x0200
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 
 #define EXT4_FEATURE_INCOMPAT_COMPRESSION      0x0001
 #define EXT4_FEATURE_INCOMPAT_FILETYPE         0x0002
@@ -1409,6 +1420,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG          0x0200
 #define EXT4_FEATURE_INCOMPAT_EA_INODE         0x0400 /* EA in inode */
 #define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000 /* data in dirent */
+#define EXT4_FEATURE_INCOMPAT_INLINEDATA       0x2000 /* data in inode */
+#define EXT4_FEATURE_INCOMPAT_LARGEDIR         0x4000 /* >2GB or 3-lvl htree */
 
 #define EXT2_FEATURE_COMPAT_SUPP       EXT4_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP     (EXT4_FEATURE_INCOMPAT_FILETYPE| \
@@ -1790,8 +1803,6 @@ extern void ext4_init_block_bitmap(struct super_block *sb,
 extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
                                              ext4_group_t block_group,
                                              struct ext4_group_desc *gdp);
-extern unsigned ext4_num_base_meta_clusters(struct super_block *sb,
-                                           ext4_group_t block_group);
 extern unsigned ext4_num_overhead_clusters(struct super_block *sb,
                                           ext4_group_t block_group,
                                           struct ext4_group_desc *gdp);
@@ -1880,16 +1891,9 @@ extern int ext4_alloc_da_blocks(struct inode *inode);
 extern void ext4_set_aops(struct inode *inode);
 extern int ext4_writepage_trans_blocks(struct inode *);
 extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
-extern int ext4_block_truncate_page(handle_t *handle,
-               struct address_space *mapping, loff_t from);
-extern int ext4_block_zero_page_range(handle_t *handle,
-               struct address_space *mapping, loff_t from, loff_t length);
 extern int ext4_discard_partial_page_buffers(handle_t *handle,
                struct address_space *mapping, loff_t from,
                loff_t length, int flags);
-extern int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
-               struct inode *inode, struct page *page, loff_t from,
-               loff_t length, int flags);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern void ext4_da_update_reserve_space(struct inode *inode,
@@ -1924,6 +1928,7 @@ extern int ext4_group_add(struct super_block *sb,
 extern int ext4_group_extend(struct super_block *sb,
                                struct ext4_super_block *es,
                                ext4_fsblk_t n_blocks_count);
+extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
 
 /* super.c */
 extern void *ext4_kvmalloc(size_t size, gfp_t flags);
index 841faf5fb785058477ba59b205fe0e55dd1c0f0d..74f23c292e1b3000bb7bd9cf0e953df27488b698 100644 (file)
@@ -3280,6 +3280,9 @@ static int ext4_find_delalloc_range(struct inode *inode,
        ext4_lblk_t i, pg_lblk;
        pgoff_t index;
 
+       if (!test_opt(inode->i_sb, DELALLOC))
+               return 0;
+
        /* reverse search wont work if fs block size is less than page size */
        if (inode->i_blkbits < PAGE_CACHE_SHIFT)
                search_hint_reverse = 0;
@@ -3452,8 +3455,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
        int err = 0;
        ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
 
-       ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical"
-                 "block %llu, max_blocks %u, flags %d, allocated %u",
+       ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical "
+                 "block %llu, max_blocks %u, flags %x, allocated %u\n",
                  inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
                  flags, allocated);
        ext4_ext_show_leaf(inode, path);
@@ -3624,7 +3627,7 @@ static int get_implied_cluster_alloc(struct super_block *sb,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_lblk_t c_offset = map->m_lblk & (sbi->s_cluster_ratio-1);
        ext4_lblk_t ex_cluster_start, ex_cluster_end;
-       ext4_lblk_t rr_cluster_start, rr_cluster_end;
+       ext4_lblk_t rr_cluster_start;
        ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
        ext4_fsblk_t ee_start = ext4_ext_pblock(ex);
        unsigned short ee_len = ext4_ext_get_actual_len(ex);
@@ -3635,7 +3638,6 @@ static int get_implied_cluster_alloc(struct super_block *sb,
 
        /* The requested region passed into ext4_map_blocks() */
        rr_cluster_start = EXT4_B2C(sbi, map->m_lblk);
-       rr_cluster_end = EXT4_B2C(sbi, map->m_lblk + map->m_len - 1);
 
        if ((rr_cluster_start == ex_cluster_end) ||
            (rr_cluster_start == ex_cluster_start)) {
index 4637af036d9c8ae67e1a93dacc9607b3086d68f0..25d8c9781ad94ea758781f906a34412743b3cda0 100644 (file)
@@ -252,7 +252,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
                fatal = ext4_journal_get_write_access(handle, bh2);
        }
        ext4_lock_group(sb, block_group);
-       cleared = ext4_clear_bit(bit, bitmap_bh->b_data);
+       cleared = ext4_test_and_clear_bit(bit, bitmap_bh->b_data);
        if (fatal || !cleared) {
                ext4_unlock_group(sb, block_group);
                goto out;
@@ -358,7 +358,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_group_t real_ngroups = ext4_get_groups_count(sb);
        int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
-       unsigned int freei, avefreei;
+       unsigned int freei, avefreei, grp_free;
        ext4_fsblk_t freeb, avefreec;
        unsigned int ndirs;
        int max_dirs, min_inodes;
@@ -477,8 +477,8 @@ fallback_retry:
        for (i = 0; i < ngroups; i++) {
                grp = (parent_group + i) % ngroups;
                desc = ext4_get_group_desc(sb, grp, NULL);
-               if (desc && ext4_free_inodes_count(sb, desc) &&
-                   ext4_free_inodes_count(sb, desc) >= avefreei) {
+               grp_free = ext4_free_inodes_count(sb, desc);
+               if (desc && grp_free && grp_free >= avefreei) {
                        *group = grp;
                        return 0;
                }
@@ -618,7 +618,7 @@ static int ext4_claim_inode(struct super_block *sb,
         */
        down_read(&grp->alloc_sem);
        ext4_lock_group(sb, group);
-       if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) {
+       if (ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data)) {
                /* not a free inode */
                retval = 1;
                goto err_ret;
@@ -885,8 +885,12 @@ got:
        if (IS_DIRSYNC(inode))
                ext4_handle_sync(handle);
        if (insert_inode_locked(inode) < 0) {
-               err = -EINVAL;
-               goto fail_drop;
+               /*
+                * Likely a bitmap corruption causing inode to be allocated
+                * twice.
+                */
+               err = -EIO;
+               goto fail;
        }
        spin_lock(&sbi->s_next_gen_lock);
        inode->i_generation = sbi->s_next_generation++;
index aa8efa6572d6d835f5be2a4867d81441a71bb19f..feaa82fe629d067e0900744fcbb50da2768b0183 100644 (file)
@@ -71,6 +71,9 @@ static int ext4_set_bh_endio(struct buffer_head *bh, struct inode *inode);
 static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate);
 static int __ext4_journalled_writepage(struct page *page, unsigned int len);
 static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh);
+static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
+               struct inode *inode, struct page *page, loff_t from,
+               loff_t length, int flags);
 
 /*
  * Test whether an inode is a fast symlink.
@@ -2759,7 +2762,7 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
        if (!io_end || !size)
                goto out;
 
-       ext_debug("ext4_end_io_dio(): io_end 0x%p"
+       ext_debug("ext4_end_io_dio(): io_end 0x%p "
                  "for inode %lu, iocb 0x%p, offset %llu, size %llu\n",
                  iocb->private, io_end->inode->i_ino, iocb, offset,
                  size);
@@ -3160,7 +3163,7 @@ int ext4_discard_partial_page_buffers(handle_t *handle,
  *
  * Returns zero on sucess or negative on failure.
  */
-int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
+static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
                struct inode *inode, struct page *page, loff_t from,
                loff_t length, int flags)
 {
@@ -3300,126 +3303,6 @@ next:
        return err;
 }
 
-/*
- * ext4_block_truncate_page() zeroes out a mapping from file offset `from'
- * up to the end of the block which corresponds to `from'.
- * This required during truncate. We need to physically zero the tail end
- * of that block so it doesn't yield old data if the file is later grown.
- */
-int ext4_block_truncate_page(handle_t *handle,
-               struct address_space *mapping, loff_t from)
-{
-       unsigned offset = from & (PAGE_CACHE_SIZE-1);
-       unsigned length;
-       unsigned blocksize;
-       struct inode *inode = mapping->host;
-
-       blocksize = inode->i_sb->s_blocksize;
-       length = blocksize - (offset & (blocksize - 1));
-
-       return ext4_block_zero_page_range(handle, mapping, from, length);
-}
-
-/*
- * ext4_block_zero_page_range() zeros out a mapping of length 'length'
- * starting from file offset 'from'.  The range to be zero'd must
- * be contained with in one block.  If the specified range exceeds
- * the end of the block it will be shortened to end of the block
- * that cooresponds to 'from'
- */
-int ext4_block_zero_page_range(handle_t *handle,
-               struct address_space *mapping, loff_t from, loff_t length)
-{
-       ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
-       unsigned offset = from & (PAGE_CACHE_SIZE-1);
-       unsigned blocksize, max, pos;
-       ext4_lblk_t iblock;
-       struct inode *inode = mapping->host;
-       struct buffer_head *bh;
-       struct page *page;
-       int err = 0;
-
-       page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT,
-                                  mapping_gfp_mask(mapping) & ~__GFP_FS);
-       if (!page)
-               return -ENOMEM;
-
-       blocksize = inode->i_sb->s_blocksize;
-       max = blocksize - (offset & (blocksize - 1));
-
-       /*
-        * correct length if it does not fall between
-        * 'from' and the end of the block
-        */
-       if (length > max || length < 0)
-               length = max;
-
-       iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
-
-       if (!page_has_buffers(page))
-               create_empty_buffers(page, blocksize, 0);
-
-       /* Find the buffer that contains "offset" */
-       bh = page_buffers(page);
-       pos = blocksize;
-       while (offset >= pos) {
-               bh = bh->b_this_page;
-               iblock++;
-               pos += blocksize;
-       }
-
-       err = 0;
-       if (buffer_freed(bh)) {
-               BUFFER_TRACE(bh, "freed: skip");
-               goto unlock;
-       }
-
-       if (!buffer_mapped(bh)) {
-               BUFFER_TRACE(bh, "unmapped");
-               ext4_get_block(inode, iblock, bh, 0);
-               /* unmapped? It's a hole - nothing to do */
-               if (!buffer_mapped(bh)) {
-                       BUFFER_TRACE(bh, "still unmapped");
-                       goto unlock;
-               }
-       }
-
-       /* Ok, it's mapped. Make sure it's up-to-date */
-       if (PageUptodate(page))
-               set_buffer_uptodate(bh);
-
-       if (!buffer_uptodate(bh)) {
-               err = -EIO;
-               ll_rw_block(READ, 1, &bh);
-               wait_on_buffer(bh);
-               /* Uhhuh. Read error. Complain and punt. */
-               if (!buffer_uptodate(bh))
-                       goto unlock;
-       }
-
-       if (ext4_should_journal_data(inode)) {
-               BUFFER_TRACE(bh, "get write access");
-               err = ext4_journal_get_write_access(handle, bh);
-               if (err)
-                       goto unlock;
-       }
-
-       zero_user(page, offset, length);
-
-       BUFFER_TRACE(bh, "zeroed end of block");
-
-       err = 0;
-       if (ext4_should_journal_data(inode)) {
-               err = ext4_handle_dirty_metadata(handle, inode, bh);
-       } else
-               mark_buffer_dirty(bh);
-
-unlock:
-       unlock_page(page);
-       page_cache_release(page);
-       return err;
-}
-
 int ext4_can_truncate(struct inode *inode)
 {
        if (S_ISREG(inode->i_mode))
@@ -4646,9 +4529,19 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
                return 0;
        if (is_journal_aborted(journal))
                return -EROFS;
+       /* We have to allocate physical blocks for delalloc blocks
+        * before flushing journal. otherwise delalloc blocks can not
+        * be allocated any more. even more truncate on delalloc blocks
+        * could trigger BUG by flushing delalloc blocks in journal.
+        * There is no delalloc block in non-journal data mode.
+        */
+       if (val && test_opt(inode->i_sb, DELALLOC)) {
+               err = ext4_alloc_da_blocks(inode);
+               if (err < 0)
+                       return err;
+       }
 
        jbd2_journal_lock_updates(journal);
-       jbd2_journal_flush(journal);
 
        /*
         * OK, there are no updates running now, and all cached data is
@@ -4660,8 +4553,10 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
 
        if (val)
                ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
-       else
+       else {
+               jbd2_journal_flush(journal);
                ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA);
+       }
        ext4_set_aops(inode);
 
        jbd2_journal_unlock_updates(journal);
index e87a932b073bcf7db1916db8ef1ac469c676ca63..6eee25591b8159bc96d35a16f94f94c0855a35b9 100644 (file)
@@ -18,6 +18,8 @@
 #include "ext4_jbd2.h"
 #include "ext4.h"
 
+#define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
+
 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = filp->f_dentry->d_inode;
@@ -186,19 +188,22 @@ setversion_out:
                if (err)
                        return err;
 
-               if (get_user(n_blocks_count, (__u32 __user *)arg))
-                       return -EFAULT;
+               if (get_user(n_blocks_count, (__u32 __user *)arg)) {
+                       err = -EFAULT;
+                       goto group_extend_out;
+               }
 
                if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
                               EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online resizing not supported with bigalloc");
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       goto group_extend_out;
                }
 
                err = mnt_want_write_file(filp);
                if (err)
-                       return err;
+                       goto group_extend_out;
 
                err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
                if (EXT4_SB(sb)->s_journal) {
@@ -209,8 +214,8 @@ setversion_out:
                if (err == 0)
                        err = err2;
                mnt_drop_write_file(filp);
+group_extend_out:
                ext4_resize_end(sb);
-
                return err;
        }
 
@@ -251,8 +256,7 @@ setversion_out:
                err = ext4_move_extents(filp, donor_filp, me.orig_start,
                                        me.donor_start, me.len, &me.moved_len);
                mnt_drop_write_file(filp);
-               if (me.moved_len > 0)
-                       file_remove_suid(donor_filp);
+               mnt_drop_write(filp->f_path.mnt);
 
                if (copy_to_user((struct move_extent __user *)arg,
                                 &me, sizeof(me)))
@@ -271,19 +275,22 @@ mext_out:
                        return err;
 
                if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
-                               sizeof(input)))
-                       return -EFAULT;
+                               sizeof(input))) {
+                       err = -EFAULT;
+                       goto group_add_out;
+               }
 
                if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
                               EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Online resizing not supported with bigalloc");
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       goto group_add_out;
                }
 
                err = mnt_want_write_file(filp);
                if (err)
-                       return err;
+                       goto group_add_out;
 
                err = ext4_group_add(sb, &input);
                if (EXT4_SB(sb)->s_journal) {
@@ -294,8 +301,8 @@ mext_out:
                if (err == 0)
                        err = err2;
                mnt_drop_write_file(filp);
+group_add_out:
                ext4_resize_end(sb);
-
                return err;
        }
 
@@ -335,6 +342,60 @@ mext_out:
                return err;
        }
 
+       case EXT4_IOC_RESIZE_FS: {
+               ext4_fsblk_t n_blocks_count;
+               struct super_block *sb = inode->i_sb;
+               int err = 0, err2 = 0;
+
+               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                              EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Online resizing not (yet) supported with bigalloc");
+                       return -EOPNOTSUPP;
+               }
+
+               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+                              EXT4_FEATURE_INCOMPAT_META_BG)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Online resizing not (yet) supported with meta_bg");
+                       return -EOPNOTSUPP;
+               }
+
+               if (copy_from_user(&n_blocks_count, (__u64 __user *)arg,
+                                  sizeof(__u64))) {
+                       return -EFAULT;
+               }
+
+               if (n_blocks_count > MAX_32_NUM &&
+                   !EXT4_HAS_INCOMPAT_FEATURE(sb,
+                                              EXT4_FEATURE_INCOMPAT_64BIT)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "File system only supports 32-bit block numbers");
+                       return -EOPNOTSUPP;
+               }
+
+               err = ext4_resize_begin(sb);
+               if (err)
+                       return err;
+
+               err = mnt_want_write(filp->f_path.mnt);
+               if (err)
+                       goto resizefs_out;
+
+               err = ext4_resize_fs(sb, n_blocks_count);
+               if (EXT4_SB(sb)->s_journal) {
+                       jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+                       err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+                       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+               }
+               if (err == 0)
+                       err = err2;
+               mnt_drop_write(filp->f_path.mnt);
+resizefs_out:
+               ext4_resize_end(sb);
+               return err;
+       }
+
        case FITRIM:
        {
                struct request_queue *q = bdev_get_queue(sb->s_bdev);
@@ -433,6 +494,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        }
        case EXT4_IOC_MOVE_EXT:
        case FITRIM:
+       case EXT4_IOC_RESIZE_FS:
                break;
        default:
                return -ENOIOCTLCMD;
index e2d8be8f28bfb8555644bef5100b2f9b8c2cbe9a..cb990b21c698bd9dd1ec0e4bb8488f6e82bbe2f7 100644 (file)
@@ -3671,7 +3671,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b,
        ext4_group_t group;
        ext4_grpblk_t bit;
 
-       trace_ext4_mb_release_group_pa(pa);
+       trace_ext4_mb_release_group_pa(sb, pa);
        BUG_ON(pa->pa_deleted == 0);
        ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
        BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
index 996780ab4f4e83cdfc114e83ab8cad35242f4813..f9d948f0eb861f08de3ef7b589b401846dc627f6 100644 (file)
@@ -134,6 +134,172 @@ static int verify_group_input(struct super_block *sb,
        return err;
 }
 
+/*
+ * ext4_new_flex_group_data is used by 64bit-resize interface to add a flex
+ * group each time.
+ */
+struct ext4_new_flex_group_data {
+       struct ext4_new_group_data *groups;     /* new_group_data for groups
+                                                  in the flex group */
+       __u16 *bg_flags;                        /* block group flags of groups
+                                                  in @groups */
+       ext4_group_t count;                     /* number of groups in @groups
+                                                */
+};
+
+/*
+ * alloc_flex_gd() allocates a ext4_new_flex_group_data with size of
+ * @flexbg_size.
+ *
+ * Returns NULL on failure otherwise address of the allocated structure.
+ */
+static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size)
+{
+       struct ext4_new_flex_group_data *flex_gd;
+
+       flex_gd = kmalloc(sizeof(*flex_gd), GFP_NOFS);
+       if (flex_gd == NULL)
+               goto out3;
+
+       flex_gd->count = flexbg_size;
+
+       flex_gd->groups = kmalloc(sizeof(struct ext4_new_group_data) *
+                                 flexbg_size, GFP_NOFS);
+       if (flex_gd->groups == NULL)
+               goto out2;
+
+       flex_gd->bg_flags = kmalloc(flexbg_size * sizeof(__u16), GFP_NOFS);
+       if (flex_gd->bg_flags == NULL)
+               goto out1;
+
+       return flex_gd;
+
+out1:
+       kfree(flex_gd->groups);
+out2:
+       kfree(flex_gd);
+out3:
+       return NULL;
+}
+
+static void free_flex_gd(struct ext4_new_flex_group_data *flex_gd)
+{
+       kfree(flex_gd->bg_flags);
+       kfree(flex_gd->groups);
+       kfree(flex_gd);
+}
+
+/*
+ * ext4_alloc_group_tables() allocates block bitmaps, inode bitmaps
+ * and inode tables for a flex group.
+ *
+ * This function is used by 64bit-resize.  Note that this function allocates
+ * group tables from the 1st group of groups contained by @flexgd, which may
+ * be a partial of a flex group.
+ *
+ * @sb: super block of fs to which the groups belongs
+ */
+static void ext4_alloc_group_tables(struct super_block *sb,
+                               struct ext4_new_flex_group_data *flex_gd,
+                               int flexbg_size)
+{
+       struct ext4_new_group_data *group_data = flex_gd->groups;
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       ext4_fsblk_t start_blk;
+       ext4_fsblk_t last_blk;
+       ext4_group_t src_group;
+       ext4_group_t bb_index = 0;
+       ext4_group_t ib_index = 0;
+       ext4_group_t it_index = 0;
+       ext4_group_t group;
+       ext4_group_t last_group;
+       unsigned overhead;
+
+       BUG_ON(flex_gd->count == 0 || group_data == NULL);
+
+       src_group = group_data[0].group;
+       last_group  = src_group + flex_gd->count - 1;
+
+       BUG_ON((flexbg_size > 1) && ((src_group & ~(flexbg_size - 1)) !=
+              (last_group & ~(flexbg_size - 1))));
+next_group:
+       group = group_data[0].group;
+       start_blk = ext4_group_first_block_no(sb, src_group);
+       last_blk = start_blk + group_data[src_group - group].blocks_count;
+
+       overhead = ext4_bg_has_super(sb, src_group) ?
+                  (1 + ext4_bg_num_gdb(sb, src_group) +
+                   le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
+
+       start_blk += overhead;
+
+       BUG_ON(src_group >= group_data[0].group + flex_gd->count);
+       /* We collect contiguous blocks as much as possible. */
+       src_group++;
+       for (; src_group <= last_group; src_group++)
+               if (!ext4_bg_has_super(sb, src_group))
+                       last_blk += group_data[src_group - group].blocks_count;
+               else
+                       break;
+
+       /* Allocate block bitmaps */
+       for (; bb_index < flex_gd->count; bb_index++) {
+               if (start_blk >= last_blk)
+                       goto next_group;
+               group_data[bb_index].block_bitmap = start_blk++;
+               ext4_get_group_no_and_offset(sb, start_blk - 1, &group, NULL);
+               group -= group_data[0].group;
+               group_data[group].free_blocks_count--;
+               if (flexbg_size > 1)
+                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+       }
+
+       /* Allocate inode bitmaps */
+       for (; ib_index < flex_gd->count; ib_index++) {
+               if (start_blk >= last_blk)
+                       goto next_group;
+               group_data[ib_index].inode_bitmap = start_blk++;
+               ext4_get_group_no_and_offset(sb, start_blk - 1, &group, NULL);
+               group -= group_data[0].group;
+               group_data[group].free_blocks_count--;
+               if (flexbg_size > 1)
+                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+       }
+
+       /* Allocate inode tables */
+       for (; it_index < flex_gd->count; it_index++) {
+               if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk)
+                       goto next_group;
+               group_data[it_index].inode_table = start_blk;
+               ext4_get_group_no_and_offset(sb, start_blk, &group, NULL);
+               group -= group_data[0].group;
+               group_data[group].free_blocks_count -=
+                                       EXT4_SB(sb)->s_itb_per_group;
+               if (flexbg_size > 1)
+                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+
+               start_blk += EXT4_SB(sb)->s_itb_per_group;
+       }
+
+       if (test_opt(sb, DEBUG)) {
+               int i;
+               group = group_data[0].group;
+
+               printk(KERN_DEBUG "EXT4-fs: adding a flex group with "
+                      "%d groups, flexbg size is %d:\n", flex_gd->count,
+                      flexbg_size);
+
+               for (i = 0; i < flex_gd->count; i++) {
+                       printk(KERN_DEBUG "adding %s group %u: %u "
+                              "blocks (%d free)\n",
+                              ext4_bg_has_super(sb, group + i) ? "normal" :
+                              "no-super", group + i,
+                              group_data[i].blocks_count,
+                              group_data[i].free_blocks_count);
+               }
+       }
+}
+
 static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
                                  ext4_fsblk_t blk)
 {
@@ -179,131 +345,250 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh)
 }
 
 /*
- * Set up the block and inode bitmaps, and the inode table for the new group.
+ * set_flexbg_block_bitmap() mark @count blocks starting from @block used.
+ *
+ * Helper function for ext4_setup_new_group_blocks() which set .
+ *
+ * @sb: super block
+ * @handle: journal handle
+ * @flex_gd: flex group data
+ */
+static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
+                       struct ext4_new_flex_group_data *flex_gd,
+                       ext4_fsblk_t block, ext4_group_t count)
+{
+       ext4_group_t count2;
+
+       ext4_debug("mark blocks [%llu/%u] used\n", block, count);
+       for (count2 = count; count > 0; count -= count2, block += count2) {
+               ext4_fsblk_t start;
+               struct buffer_head *bh;
+               ext4_group_t group;
+               int err;
+
+               ext4_get_group_no_and_offset(sb, block, &group, NULL);
+               start = ext4_group_first_block_no(sb, group);
+               group -= flex_gd->groups[0].group;
+
+               count2 = sb->s_blocksize * 8 - (block - start);
+               if (count2 > count)
+                       count2 = count;
+
+               if (flex_gd->bg_flags[group] & EXT4_BG_BLOCK_UNINIT) {
+                       BUG_ON(flex_gd->count > 1);
+                       continue;
+               }
+
+               err = extend_or_restart_transaction(handle, 1);
+               if (err)
+                       return err;
+
+               bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap);
+               if (!bh)
+                       return -EIO;
+
+               err = ext4_journal_get_write_access(handle, bh);
+               if (err)
+                       return err;
+               ext4_debug("mark block bitmap %#04llx (+%llu/%u)\n", block,
+                          block - start, count2);
+               ext4_set_bits(bh->b_data, block - start, count2);
+
+               err = ext4_handle_dirty_metadata(handle, NULL, bh);
+               if (unlikely(err))
+                       return err;
+               brelse(bh);
+       }
+
+       return 0;
+}
+
+/*
+ * Set up the block and inode bitmaps, and the inode table for the new groups.
  * This doesn't need to be part of the main transaction, since we are only
  * changing blocks outside the actual filesystem.  We still do journaling to
  * ensure the recovery is correct in case of a failure just after resize.
  * If any part of this fails, we simply abort the resize.
+ *
+ * setup_new_flex_group_blocks handles a flex group as follow:
+ *  1. copy super block and GDT, and initialize group tables if necessary.
+ *     In this step, we only set bits in blocks bitmaps for blocks taken by
+ *     super block and GDT.
+ *  2. allocate group tables in block bitmaps, that is, set bits in block
+ *     bitmap for blocks taken by group tables.
  */
-static int setup_new_group_blocks(struct super_block *sb,
-                                 struct ext4_new_group_data *input)
+static int setup_new_flex_group_blocks(struct super_block *sb,
+                               struct ext4_new_flex_group_data *flex_gd)
 {
+       int group_table_count[] = {1, 1, EXT4_SB(sb)->s_itb_per_group};
+       ext4_fsblk_t start;
+       ext4_fsblk_t block;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       ext4_fsblk_t start = ext4_group_first_block_no(sb, input->group);
-       int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
-               le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
-       unsigned long gdblocks = ext4_bg_num_gdb(sb, input->group);
-       struct buffer_head *bh;
+       struct ext4_super_block *es = sbi->s_es;
+       struct ext4_new_group_data *group_data = flex_gd->groups;
+       __u16 *bg_flags = flex_gd->bg_flags;
        handle_t *handle;
-       ext4_fsblk_t block;
-       ext4_grpblk_t bit;
-       int i;
-       int err = 0, err2;
+       ext4_group_t group, count;
+       struct buffer_head *bh = NULL;
+       int reserved_gdb, i, j, err = 0, err2;
+
+       BUG_ON(!flex_gd->count || !group_data ||
+              group_data[0].group != sbi->s_groups_count);
+
+       reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks);
 
        /* This transaction may be extended/restarted along the way */
        handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
-
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
-       BUG_ON(input->group != sbi->s_groups_count);
+       group = group_data[0].group;
+       for (i = 0; i < flex_gd->count; i++, group++) {
+               unsigned long gdblocks;
 
-       /* Copy all of the GDT blocks into the backup in this group */
-       for (i = 0, bit = 1, block = start + 1;
-            i < gdblocks; i++, block++, bit++) {
-               struct buffer_head *gdb;
+               gdblocks = ext4_bg_num_gdb(sb, group);
+               start = ext4_group_first_block_no(sb, group);
 
-               ext4_debug("update backup group %#04llx (+%d)\n", block, bit);
-               err = extend_or_restart_transaction(handle, 1);
-               if (err)
-                       goto exit_journal;
+               /* Copy all of the GDT blocks into the backup in this group */
+               for (j = 0, block = start + 1; j < gdblocks; j++, block++) {
+                       struct buffer_head *gdb;
 
-               gdb = sb_getblk(sb, block);
-               if (!gdb) {
-                       err = -EIO;
-                       goto exit_journal;
-               }
-               if ((err = ext4_journal_get_write_access(handle, gdb))) {
+                       ext4_debug("update backup group %#04llx\n", block);
+                       err = extend_or_restart_transaction(handle, 1);
+                       if (err)
+                               goto out;
+
+                       gdb = sb_getblk(sb, block);
+                       if (!gdb) {
+                               err = -EIO;
+                               goto out;
+                       }
+
+                       err = ext4_journal_get_write_access(handle, gdb);
+                       if (err) {
+                               brelse(gdb);
+                               goto out;
+                       }
+                       memcpy(gdb->b_data, sbi->s_group_desc[j]->b_data,
+                              gdb->b_size);
+                       set_buffer_uptodate(gdb);
+
+                       err = ext4_handle_dirty_metadata(handle, NULL, gdb);
+                       if (unlikely(err)) {
+                               brelse(gdb);
+                               goto out;
+                       }
                        brelse(gdb);
-                       goto exit_journal;
                }
-               memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);
-               set_buffer_uptodate(gdb);
-               err = ext4_handle_dirty_metadata(handle, NULL, gdb);
-               if (unlikely(err)) {
-                       brelse(gdb);
-                       goto exit_journal;
+
+               /* Zero out all of the reserved backup group descriptor
+                * table blocks
+                */
+               if (ext4_bg_has_super(sb, group)) {
+                       err = sb_issue_zeroout(sb, gdblocks + start + 1,
+                                       reserved_gdb, GFP_NOFS);
+                       if (err)
+                               goto out;
                }
-               brelse(gdb);
-       }
 
-       /* Zero out all of the reserved backup group descriptor table blocks */
-       ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
-                       block, sbi->s_itb_per_group);
-       err = sb_issue_zeroout(sb, gdblocks + start + 1, reserved_gdb,
-                              GFP_NOFS);
-       if (err)
-               goto exit_journal;
+               /* Initialize group tables of the grop @group */
+               if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED))
+                       goto handle_bb;
 
-       err = extend_or_restart_transaction(handle, 2);
-       if (err)
-               goto exit_journal;
+               /* Zero out all of the inode table blocks */
+               block = group_data[i].inode_table;
+               ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
+                          block, sbi->s_itb_per_group);
+               err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group,
+                                      GFP_NOFS);
+               if (err)
+                       goto out;
 
-       bh = bclean(handle, sb, input->block_bitmap);
-       if (IS_ERR(bh)) {
-               err = PTR_ERR(bh);
-               goto exit_journal;
-       }
+handle_bb:
+               if (bg_flags[i] & EXT4_BG_BLOCK_UNINIT)
+                       goto handle_ib;
 
-       if (ext4_bg_has_super(sb, input->group)) {
-               ext4_debug("mark backup group tables %#04llx (+0)\n", start);
-               ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb + 1);
-       }
+               /* Initialize block bitmap of the @group */
+               block = group_data[i].block_bitmap;
+               err = extend_or_restart_transaction(handle, 1);
+               if (err)
+                       goto out;
 
-       ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap,
-                  input->block_bitmap - start);
-       ext4_set_bit(input->block_bitmap - start, bh->b_data);
-       ext4_debug("mark inode bitmap %#04llx (+%llu)\n", input->inode_bitmap,
-                  input->inode_bitmap - start);
-       ext4_set_bit(input->inode_bitmap - start, bh->b_data);
-
-       /* Zero out all of the inode table blocks */
-       block = input->inode_table;
-       ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
-                       block, sbi->s_itb_per_group);
-       err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS);
-       if (err)
-               goto exit_bh;
-       ext4_set_bits(bh->b_data, input->inode_table - start,
-                     sbi->s_itb_per_group);
+               bh = bclean(handle, sb, block);
+               if (IS_ERR(bh)) {
+                       err = PTR_ERR(bh);
+                       goto out;
+               }
+               if (ext4_bg_has_super(sb, group)) {
+                       ext4_debug("mark backup superblock %#04llx (+0)\n",
+                                  start);
+                       ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb +
+                                                    1);
+               }
+               ext4_mark_bitmap_end(group_data[i].blocks_count,
+                                    sb->s_blocksize * 8, bh->b_data);
+               err = ext4_handle_dirty_metadata(handle, NULL, bh);
+               if (err)
+                       goto out;
+               brelse(bh);
 
+handle_ib:
+               if (bg_flags[i] & EXT4_BG_INODE_UNINIT)
+                       continue;
 
-       ext4_mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8,
-                            bh->b_data);
-       err = ext4_handle_dirty_metadata(handle, NULL, bh);
-       if (unlikely(err)) {
-               ext4_std_error(sb, err);
-               goto exit_bh;
+               /* Initialize inode bitmap of the @group */
+               block = group_data[i].inode_bitmap;
+               err = extend_or_restart_transaction(handle, 1);
+               if (err)
+                       goto out;
+               /* Mark unused entries in inode bitmap used */
+               bh = bclean(handle, sb, block);
+               if (IS_ERR(bh)) {
+                       err = PTR_ERR(bh);
+                       goto out;
+               }
+
+               ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
+                                    sb->s_blocksize * 8, bh->b_data);
+               err = ext4_handle_dirty_metadata(handle, NULL, bh);
+               if (err)
+                       goto out;
+               brelse(bh);
        }
-       brelse(bh);
-       /* Mark unused entries in inode bitmap used */
-       ext4_debug("clear inode bitmap %#04llx (+%llu)\n",
-                  input->inode_bitmap, input->inode_bitmap - start);
-       if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) {
-               err = PTR_ERR(bh);
-               goto exit_journal;
+       bh = NULL;
+
+       /* Mark group tables in block bitmap */
+       for (j = 0; j < GROUP_TABLE_COUNT; j++) {
+               count = group_table_count[j];
+               start = (&group_data[0].block_bitmap)[j];
+               block = start;
+               for (i = 1; i < flex_gd->count; i++) {
+                       block += group_table_count[j];
+                       if (block == (&group_data[i].block_bitmap)[j]) {
+                               count += group_table_count[j];
+                               continue;
+                       }
+                       err = set_flexbg_block_bitmap(sb, handle,
+                                               flex_gd, start, count);
+                       if (err)
+                               goto out;
+                       count = group_table_count[j];
+                       start = group_data[i].block_bitmap;
+                       block = start;
+               }
+
+               if (count) {
+                       err = set_flexbg_block_bitmap(sb, handle,
+                                               flex_gd, start, count);
+                       if (err)
+                               goto out;
+               }
        }
 
-       ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
-                            bh->b_data);
-       err = ext4_handle_dirty_metadata(handle, NULL, bh);
-       if (unlikely(err))
-               ext4_std_error(sb, err);
-exit_bh:
+out:
        brelse(bh);
-
-exit_journal:
-       if ((err2 = ext4_journal_stop(handle)) && !err)
+       err2 = ext4_journal_stop(handle);
+       if (err2 && !err)
                err = err2;
 
        return err;
@@ -351,10 +636,10 @@ static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,
  * groups in current filesystem that have BACKUPS, or -ve error code.
  */
 static int verify_reserved_gdb(struct super_block *sb,
+                              ext4_group_t end,
                               struct buffer_head *primary)
 {
        const ext4_fsblk_t blk = primary->b_blocknr;
-       const ext4_group_t end = EXT4_SB(sb)->s_groups_count;
        unsigned three = 1;
        unsigned five = 5;
        unsigned seven = 7;
@@ -429,7 +714,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        if (!gdb_bh)
                return -EIO;
 
-       gdbackups = verify_reserved_gdb(sb, gdb_bh);
+       gdbackups = verify_reserved_gdb(sb, group, gdb_bh);
        if (gdbackups < 0) {
                err = gdbackups;
                goto exit_bh;
@@ -592,7 +877,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
                        err = -EIO;
                        goto exit_bh;
                }
-               if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) {
+               gdbackups = verify_reserved_gdb(sb, group, primary[res]);
+               if (gdbackups < 0) {
                        brelse(primary[res]);
                        err = gdbackups;
                        goto exit_bh;
@@ -735,6 +1021,348 @@ exit_err:
        }
 }
 
+/*
+ * ext4_add_new_descs() adds @count group descriptor of groups
+ * starting at @group
+ *
+ * @handle: journal handle
+ * @sb: super block
+ * @group: the group no. of the first group desc to be added
+ * @resize_inode: the resize inode
+ * @count: number of group descriptors to be added
+ */
+static int ext4_add_new_descs(handle_t *handle, struct super_block *sb,
+                             ext4_group_t group, struct inode *resize_inode,
+                             ext4_group_t count)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       struct buffer_head *gdb_bh;
+       int i, gdb_off, gdb_num, err = 0;
+
+       for (i = 0; i < count; i++, group++) {
+               int reserved_gdb = ext4_bg_has_super(sb, group) ?
+                       le16_to_cpu(es->s_reserved_gdt_blocks) : 0;
+
+               gdb_off = group % EXT4_DESC_PER_BLOCK(sb);
+               gdb_num = group / EXT4_DESC_PER_BLOCK(sb);
+
+               /*
+                * We will only either add reserved group blocks to a backup group
+                * or remove reserved blocks for the first group in a new group block.
+                * Doing both would be mean more complex code, and sane people don't
+                * use non-sparse filesystems anymore.  This is already checked above.
+                */
+               if (gdb_off) {
+                       gdb_bh = sbi->s_group_desc[gdb_num];
+                       err = ext4_journal_get_write_access(handle, gdb_bh);
+
+                       if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group))
+                               err = reserve_backup_gdb(handle, resize_inode, group);
+               } else
+                       err = add_new_gdb(handle, resize_inode, group);
+               if (err)
+                       break;
+       }
+       return err;
+}
+
+/*
+ * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg
+ */
+static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb,
+                               struct ext4_new_flex_group_data *flex_gd)
+{
+       struct ext4_new_group_data      *group_data = flex_gd->groups;
+       struct ext4_group_desc          *gdp;
+       struct ext4_sb_info             *sbi = EXT4_SB(sb);
+       struct buffer_head              *gdb_bh;
+       ext4_group_t                    group;
+       __u16                           *bg_flags = flex_gd->bg_flags;
+       int                             i, gdb_off, gdb_num, err = 0;
+       
+
+       for (i = 0; i < flex_gd->count; i++, group_data++, bg_flags++) {
+               group = group_data->group;
+
+               gdb_off = group % EXT4_DESC_PER_BLOCK(sb);
+               gdb_num = group / EXT4_DESC_PER_BLOCK(sb);
+
+               /*
+                * get_write_access() has been called on gdb_bh by ext4_add_new_desc().
+                */
+               gdb_bh = sbi->s_group_desc[gdb_num];
+               /* Update group descriptor block for new group */
+               gdp = (struct ext4_group_desc *)((char *)gdb_bh->b_data +
+                                                gdb_off * EXT4_DESC_SIZE(sb));
+
+               memset(gdp, 0, EXT4_DESC_SIZE(sb));
+               ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap);
+               ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap);
+               ext4_inode_table_set(sb, gdp, group_data->inode_table);
+               ext4_free_group_clusters_set(sb, gdp,
+                                            EXT4_B2C(sbi, group_data->free_blocks_count));
+               ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
+               gdp->bg_flags = cpu_to_le16(*bg_flags);
+               gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
+
+               err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh);
+               if (unlikely(err)) {
+                       ext4_std_error(sb, err);
+                       break;
+               }
+
+               /*
+                * We can allocate memory for mb_alloc based on the new group
+                * descriptor
+                */
+               err = ext4_mb_add_groupinfo(sb, group, gdp);
+               if (err)
+                       break;
+       }
+       return err;
+}
+
+/*
+ * ext4_update_super() updates the super block so that the newly added
+ * groups can be seen by the filesystem.
+ *
+ * @sb: super block
+ * @flex_gd: new added groups
+ */
+static void ext4_update_super(struct super_block *sb,
+                            struct ext4_new_flex_group_data *flex_gd)
+{
+       ext4_fsblk_t blocks_count = 0;
+       ext4_fsblk_t free_blocks = 0;
+       ext4_fsblk_t reserved_blocks = 0;
+       struct ext4_new_group_data *group_data = flex_gd->groups;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       int i;
+
+       BUG_ON(flex_gd->count == 0 || group_data == NULL);
+       /*
+        * Make the new blocks and inodes valid next.  We do this before
+        * increasing the group count so that once the group is enabled,
+        * all of its blocks and inodes are already valid.
+        *
+        * We always allocate group-by-group, then block-by-block or
+        * inode-by-inode within a group, so enabling these
+        * blocks/inodes before the group is live won't actually let us
+        * allocate the new space yet.
+        */
+       for (i = 0; i < flex_gd->count; i++) {
+               blocks_count += group_data[i].blocks_count;
+               free_blocks += group_data[i].free_blocks_count;
+       }
+
+       reserved_blocks = ext4_r_blocks_count(es) * 100;
+       do_div(reserved_blocks, ext4_blocks_count(es));
+       reserved_blocks *= blocks_count;
+       do_div(reserved_blocks, 100);
+
+       ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count);
+       le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) *
+                    flex_gd->count);
+
+       /*
+        * We need to protect s_groups_count against other CPUs seeing
+        * inconsistent state in the superblock.
+        *
+        * The precise rules we use are:
+        *
+        * * Writers must perform a smp_wmb() after updating all
+        *   dependent data and before modifying the groups count
+        *
+        * * Readers must perform an smp_rmb() after reading the groups
+        *   count and before reading any dependent data.
+        *
+        * NB. These rules can be relaxed when checking the group count
+        * while freeing data, as we can only allocate from a block
+        * group after serialising against the group count, and we can
+        * only then free after serialising in turn against that
+        * allocation.
+        */
+       smp_wmb();
+
+       /* Update the global fs size fields */
+       sbi->s_groups_count += flex_gd->count;
+
+       /* Update the reserved block counts only once the new group is
+        * active. */
+       ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
+                               reserved_blocks);
+
+       /* Update the free space counts */
+       percpu_counter_add(&sbi->s_freeclusters_counter,
+                          EXT4_B2C(sbi, free_blocks));
+       percpu_counter_add(&sbi->s_freeinodes_counter,
+                          EXT4_INODES_PER_GROUP(sb) * flex_gd->count);
+
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+                                     EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
+           sbi->s_log_groups_per_flex) {
+               ext4_group_t flex_group;
+               flex_group = ext4_flex_group(sbi, group_data[0].group);
+               atomic_add(EXT4_B2C(sbi, free_blocks),
+                          &sbi->s_flex_groups[flex_group].free_clusters);
+               atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count,
+                          &sbi->s_flex_groups[flex_group].free_inodes);
+       }
+
+       if (test_opt(sb, DEBUG))
+               printk(KERN_DEBUG "EXT4-fs: added group %u:"
+                      "%llu blocks(%llu free %llu reserved)\n", flex_gd->count,
+                      blocks_count, free_blocks, reserved_blocks);
+}
+
+/* Add a flex group to an fs. Ensure we handle all possible error conditions
+ * _before_ we start modifying the filesystem, because we cannot abort the
+ * transaction and not have it write the data to disk.
+ */
+static int ext4_flex_group_add(struct super_block *sb,
+                              struct inode *resize_inode,
+                              struct ext4_new_flex_group_data *flex_gd)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       ext4_fsblk_t o_blocks_count;
+       ext4_grpblk_t last;
+       ext4_group_t group;
+       handle_t *handle;
+       unsigned reserved_gdb;
+       int err = 0, err2 = 0, credit;
+
+       BUG_ON(!flex_gd->count || !flex_gd->groups || !flex_gd->bg_flags);
+
+       reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks);
+       o_blocks_count = ext4_blocks_count(es);
+       ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last);
+       BUG_ON(last);
+
+       err = setup_new_flex_group_blocks(sb, flex_gd);
+       if (err)
+               goto exit;
+       /*
+        * We will always be modifying at least the superblock and  GDT
+        * block.  If we are adding a group past the last current GDT block,
+        * we will also modify the inode and the dindirect block.  If we
+        * are adding a group with superblock/GDT backups  we will also
+        * modify each of the reserved GDT dindirect blocks.
+        */
+       credit = flex_gd->count * 4 + reserved_gdb;
+       handle = ext4_journal_start_sb(sb, credit);
+       if (IS_ERR(handle)) {
+               err = PTR_ERR(handle);
+               goto exit;
+       }
+
+       err = ext4_journal_get_write_access(handle, sbi->s_sbh);
+       if (err)
+               goto exit_journal;
+
+       group = flex_gd->groups[0].group;
+       BUG_ON(group != EXT4_SB(sb)->s_groups_count);
+       err = ext4_add_new_descs(handle, sb, group,
+                               resize_inode, flex_gd->count);
+       if (err)
+               goto exit_journal;
+
+       err = ext4_setup_new_descs(handle, sb, flex_gd);
+       if (err)
+               goto exit_journal;
+
+       ext4_update_super(sb, flex_gd);
+
+       err = ext4_handle_dirty_super(handle, sb);
+
+exit_journal:
+       err2 = ext4_journal_stop(handle);
+       if (!err)
+               err = err2;
+
+       if (!err) {
+               int i;
+               update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
+                              sizeof(struct ext4_super_block));
+               for (i = 0; i < flex_gd->count; i++, group++) {
+                       struct buffer_head *gdb_bh;
+                       int gdb_num;
+                       gdb_num = group / EXT4_BLOCKS_PER_GROUP(sb);
+                       gdb_bh = sbi->s_group_desc[gdb_num];
+                       update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data,
+                                      gdb_bh->b_size);
+               }
+       }
+exit:
+       return err;
+}
+
+static int ext4_setup_next_flex_gd(struct super_block *sb,
+                                   struct ext4_new_flex_group_data *flex_gd,
+                                   ext4_fsblk_t n_blocks_count,
+                                   unsigned long flexbg_size)
+{
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       struct ext4_new_group_data *group_data = flex_gd->groups;
+       ext4_fsblk_t o_blocks_count;
+       ext4_group_t n_group;
+       ext4_group_t group;
+       ext4_group_t last_group;
+       ext4_grpblk_t last;
+       ext4_grpblk_t blocks_per_group;
+       unsigned long i;
+
+       blocks_per_group = EXT4_BLOCKS_PER_GROUP(sb);
+
+       o_blocks_count = ext4_blocks_count(es);
+
+       if (o_blocks_count == n_blocks_count)
+               return 0;
+
+       ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last);
+       BUG_ON(last);
+       ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &last);
+
+       last_group = group | (flexbg_size - 1);
+       if (last_group > n_group)
+               last_group = n_group;
+
+       flex_gd->count = last_group - group + 1;
+
+       for (i = 0; i < flex_gd->count; i++) {
+               int overhead;
+
+               group_data[i].group = group + i;
+               group_data[i].blocks_count = blocks_per_group;
+               overhead = ext4_bg_has_super(sb, group + i) ?
+                          (1 + ext4_bg_num_gdb(sb, group + i) +
+                           le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
+               group_data[i].free_blocks_count = blocks_per_group - overhead;
+               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT |
+                                              EXT4_BG_INODE_UNINIT;
+               else
+                       flex_gd->bg_flags[i] = EXT4_BG_INODE_ZEROED;
+       }
+
+       if (last_group == n_group &&
+           EXT4_HAS_RO_COMPAT_FEATURE(sb,
+                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+               /* We need to initialize block bitmap of last group. */
+               flex_gd->bg_flags[i - 1] &= ~EXT4_BG_BLOCK_UNINIT;
+
+       if ((last_group == n_group) && (last != blocks_per_group - 1)) {
+               group_data[i - 1].blocks_count = last + 1;
+               group_data[i - 1].free_blocks_count -= blocks_per_group-
+                                       last - 1;
+       }
+
+       return 1;
+}
+
 /* Add group descriptor data to an existing or new group descriptor block.
  * Ensure we handle all possible error conditions _before_ we start modifying
  * the filesystem, because we cannot abort the transaction and not have it
@@ -750,16 +1378,15 @@ exit_err:
  */
 int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
 {
+       struct ext4_new_flex_group_data flex_gd;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_super_block *es = sbi->s_es;
        int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
                le16_to_cpu(es->s_reserved_gdt_blocks) : 0;
-       struct buffer_head *primary = NULL;
-       struct ext4_group_desc *gdp;
        struct inode *inode = NULL;
-       handle_t *handle;
        int gdb_off, gdb_num;
-       int err, err2;
+       int err;
+       __u16 bg_flags = 0;
 
        gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
        gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb);
@@ -798,175 +1425,69 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        }
 
 
-       if ((err = verify_group_input(sb, input)))
-               goto exit_put;
+       err = verify_group_input(sb, input);
+       if (err)
+               goto out;
 
-       if ((err = setup_new_group_blocks(sb, input)))
-               goto exit_put;
+       flex_gd.count = 1;
+       flex_gd.groups = input;
+       flex_gd.bg_flags = &bg_flags;
+       err = ext4_flex_group_add(sb, inode, &flex_gd);
+out:
+       iput(inode);
+       return err;
+} /* ext4_group_add */
 
-       /*
-        * We will always be modifying at least the superblock and a GDT
-        * block.  If we are adding a group past the last current GDT block,
-        * we will also modify the inode and the dindirect block.  If we
-        * are adding a group with superblock/GDT backups  we will also
-        * modify each of the reserved GDT dindirect blocks.
+/*
+ * extend a group without checking assuming that checking has been done.
+ */
+static int ext4_group_extend_no_check(struct super_block *sb,
+                                     ext4_fsblk_t o_blocks_count, ext4_grpblk_t add)
+{
+       struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+       handle_t *handle;
+       int err = 0, err2;
+
+       /* We will update the superblock, one block bitmap, and
+        * one group descriptor via ext4_group_add_blocks().
         */
-       handle = ext4_journal_start_sb(sb,
-                                      ext4_bg_has_super(sb, input->group) ?
-                                      3 + reserved_gdb : 4);
+       handle = ext4_journal_start_sb(sb, 3);
        if (IS_ERR(handle)) {
                err = PTR_ERR(handle);
-               goto exit_put;
+               ext4_warning(sb, "error %d on journal start", err);
+               return err;
        }
 
-       if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh)))
-               goto exit_journal;
-
-        /*
-         * We will only either add reserved group blocks to a backup group
-         * or remove reserved blocks for the first group in a new group block.
-         * Doing both would be mean more complex code, and sane people don't
-         * use non-sparse filesystems anymore.  This is already checked above.
-         */
-       if (gdb_off) {
-               primary = sbi->s_group_desc[gdb_num];
-               if ((err = ext4_journal_get_write_access(handle, primary)))
-                       goto exit_journal;
-
-               if (reserved_gdb && ext4_bg_num_gdb(sb, input->group)) {
-                       err = reserve_backup_gdb(handle, inode, input->group);
-                       if (err)
-                               goto exit_journal;
-               }
-       } else {
-               /*
-                * Note that we can access new group descriptor block safely
-                * only if add_new_gdb() succeeds.
-                */
-               err = add_new_gdb(handle, inode, input->group);
-               if (err)
-                       goto exit_journal;
-               primary = sbi->s_group_desc[gdb_num];
+       err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
+       if (err) {
+               ext4_warning(sb, "error %d on journal write access", err);
+               goto errout;
        }
 
-        /*
-         * OK, now we've set up the new group.  Time to make it active.
-         *
-         * so we have to be safe wrt. concurrent accesses the group
-         * data.  So we need to be careful to set all of the relevant
-         * group descriptor data etc. *before* we enable the group.
-         *
-         * The key field here is sbi->s_groups_count: as long as
-         * that retains its old value, nobody is going to access the new
-         * group.
-         *
-         * So first we update all the descriptor metadata for the new
-         * group; then we update the total disk blocks count; then we
-         * update the groups count to enable the group; then finally we
-         * update the free space counts so that the system can start
-         * using the new disk blocks.
-         */
-
-       /* Update group descriptor block for new group */
-       gdp = (struct ext4_group_desc *)((char *)primary->b_data +
-                                        gdb_off * EXT4_DESC_SIZE(sb));
-
-       memset(gdp, 0, EXT4_DESC_SIZE(sb));
-       ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */
-       ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */
-       ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
-       ext4_free_group_clusters_set(sb, gdp, input->free_blocks_count);
-       ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
-       gdp->bg_flags = cpu_to_le16(EXT4_BG_INODE_ZEROED);
-       gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp);
-
-       /*
-        * We can allocate memory for mb_alloc based on the new group
-        * descriptor
-        */
-       err = ext4_mb_add_groupinfo(sb, input->group, gdp);
+       ext4_blocks_count_set(es, o_blocks_count + add);
+       ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
+                  o_blocks_count + add);
+       /* We add the blocks to the bitmap and set the group need init bit */
+       err = ext4_group_add_blocks(handle, sb, o_blocks_count, add);
        if (err)
-               goto exit_journal;
-
-       /*
-        * Make the new blocks and inodes valid next.  We do this before
-        * increasing the group count so that once the group is enabled,
-        * all of its blocks and inodes are already valid.
-        *
-        * We always allocate group-by-group, then block-by-block or
-        * inode-by-inode within a group, so enabling these
-        * blocks/inodes before the group is live won't actually let us
-        * allocate the new space yet.
-        */
-       ext4_blocks_count_set(es, ext4_blocks_count(es) +
-               input->blocks_count);
-       le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb));
-
-       /*
-        * We need to protect s_groups_count against other CPUs seeing
-        * inconsistent state in the superblock.
-        *
-        * The precise rules we use are:
-        *
-        * * Writers must perform a smp_wmb() after updating all dependent
-        *   data and before modifying the groups count
-        *
-        * * Readers must perform an smp_rmb() after reading the groups count
-        *   and before reading any dependent data.
-        *
-        * NB. These rules can be relaxed when checking the group count
-        * while freeing data, as we can only allocate from a block
-        * group after serialising against the group count, and we can
-        * only then free after serialising in turn against that
-        * allocation.
-        */
-       smp_wmb();
-
-       /* Update the global fs size fields */
-       sbi->s_groups_count++;
-
-       err = ext4_handle_dirty_metadata(handle, NULL, primary);
-       if (unlikely(err)) {
-               ext4_std_error(sb, err);
-               goto exit_journal;
-       }
-
-       /* Update the reserved block counts only once the new group is
-        * active. */
-       ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
-               input->reserved_blocks);
-
-       /* Update the free space counts */
-       percpu_counter_add(&sbi->s_freeclusters_counter,
-                          EXT4_B2C(sbi, input->free_blocks_count));
-       percpu_counter_add(&sbi->s_freeinodes_counter,
-                          EXT4_INODES_PER_GROUP(sb));
-
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
-           sbi->s_log_groups_per_flex) {
-               ext4_group_t flex_group;
-               flex_group = ext4_flex_group(sbi, input->group);
-               atomic_add(EXT4_B2C(sbi, input->free_blocks_count),
-                          &sbi->s_flex_groups[flex_group].free_clusters);
-               atomic_add(EXT4_INODES_PER_GROUP(sb),
-                          &sbi->s_flex_groups[flex_group].free_inodes);
-       }
-
+               goto errout;
        ext4_handle_dirty_super(handle, sb);
-
-exit_journal:
-       if ((err2 = ext4_journal_stop(handle)) && !err)
+       ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
+                  o_blocks_count + add);
+errout:
+       err2 = ext4_journal_stop(handle);
+       if (err2 && !err)
                err = err2;
-       if (!err && primary) {
-               update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
+
+       if (!err) {
+               if (test_opt(sb, DEBUG))
+                       printk(KERN_DEBUG "EXT4-fs: extended group to %llu "
+                              "blocks\n", ext4_blocks_count(es));
+               update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,
                               sizeof(struct ext4_super_block));
-               update_backups(sb, primary->b_blocknr, primary->b_data,
-                              primary->b_size);
        }
-exit_put:
-       iput(inode);
        return err;
-} /* ext4_group_add */
+}
 
 /*
  * Extend the filesystem to the new number of blocks specified.  This entry
@@ -985,8 +1506,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        ext4_grpblk_t last;
        ext4_grpblk_t add;
        struct buffer_head *bh;
-       handle_t *handle;
-       int err, err2;
+       int err;
        ext4_group_t group;
 
        o_blocks_count = ext4_blocks_count(es);
@@ -1042,42 +1562,119 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
        }
        brelse(bh);
 
-       /* We will update the superblock, one block bitmap, and
-        * one group descriptor via ext4_free_blocks().
-        */
-       handle = ext4_journal_start_sb(sb, 3);
-       if (IS_ERR(handle)) {
-               err = PTR_ERR(handle);
-               ext4_warning(sb, "error %d on journal start", err);
-               goto exit_put;
+       err = ext4_group_extend_no_check(sb, o_blocks_count, add);
+       return err;
+} /* ext4_group_extend */
+
+/*
+ * ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count
+ *
+ * @sb: super block of the fs to be resized
+ * @n_blocks_count: the number of blocks resides in the resized fs
+ */
+int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
+{
+       struct ext4_new_flex_group_data *flex_gd = NULL;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       struct buffer_head *bh;
+       struct inode *resize_inode;
+       ext4_fsblk_t o_blocks_count;
+       ext4_group_t o_group;
+       ext4_group_t n_group;
+       ext4_grpblk_t offset;
+       unsigned long n_desc_blocks;
+       unsigned long o_desc_blocks;
+       unsigned long desc_blocks;
+       int err = 0, flexbg_size = 1;
+
+       o_blocks_count = ext4_blocks_count(es);
+
+       if (test_opt(sb, DEBUG))
+               printk(KERN_DEBUG "EXT4-fs: resizing filesystem from %llu "
+                      "upto %llu blocks\n", o_blocks_count, n_blocks_count);
+
+       if (n_blocks_count < o_blocks_count) {
+               /* On-line shrinking not supported */
+               ext4_warning(sb, "can't shrink FS - resize aborted");
+               return -EINVAL;
        }
 
-       if ((err = ext4_journal_get_write_access(handle,
-                                                EXT4_SB(sb)->s_sbh))) {
-               ext4_warning(sb, "error %d on journal write access", err);
-               ext4_journal_stop(handle);
-               goto exit_put;
+       if (n_blocks_count == o_blocks_count)
+               /* Nothing need to do */
+               return 0;
+
+       ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
+       ext4_get_group_no_and_offset(sb, o_blocks_count, &o_group, &offset);
+
+       n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) /
+                       EXT4_DESC_PER_BLOCK(sb);
+       o_desc_blocks = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
+                       EXT4_DESC_PER_BLOCK(sb);
+       desc_blocks = n_desc_blocks - o_desc_blocks;
+
+       if (desc_blocks &&
+           (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE) ||
+            le16_to_cpu(es->s_reserved_gdt_blocks) < desc_blocks)) {
+               ext4_warning(sb, "No reserved GDT blocks, can't resize");
+               return -EPERM;
        }
-       ext4_blocks_count_set(es, o_blocks_count + add);
-       ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
-                  o_blocks_count + add);
-       /* We add the blocks to the bitmap and set the group need init bit */
-       err = ext4_group_add_blocks(handle, sb, o_blocks_count, add);
-       ext4_handle_dirty_super(handle, sb);
-       ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
-                  o_blocks_count + add);
-       err2 = ext4_journal_stop(handle);
-       if (!err && err2)
-               err = err2;
 
-       if (err)
-               goto exit_put;
+       resize_inode = ext4_iget(sb, EXT4_RESIZE_INO);
+       if (IS_ERR(resize_inode)) {
+               ext4_warning(sb, "Error opening resize inode");
+               return PTR_ERR(resize_inode);
+       }
 
+       /* See if the device is actually as big as what was requested */
+       bh = sb_bread(sb, n_blocks_count - 1);
+       if (!bh) {
+               ext4_warning(sb, "can't read last block, resize aborted");
+               return -ENOSPC;
+       }
+       brelse(bh);
+
+       if (offset != 0) {
+               /* extend the last group */
+               ext4_grpblk_t add;
+               add = EXT4_BLOCKS_PER_GROUP(sb) - offset;
+               err = ext4_group_extend_no_check(sb, o_blocks_count, add);
+               if (err)
+                       goto out;
+       }
+
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
+           es->s_log_groups_per_flex)
+               flexbg_size = 1 << es->s_log_groups_per_flex;
+
+       o_blocks_count = ext4_blocks_count(es);
+       if (o_blocks_count == n_blocks_count)
+               goto out;
+
+       flex_gd = alloc_flex_gd(flexbg_size);
+       if (flex_gd == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Add flex groups. Note that a regular group is a
+        * flex group with 1 group.
+        */
+       while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count,
+                                             flexbg_size)) {
+               ext4_alloc_group_tables(sb, flex_gd, flexbg_size);
+               err = ext4_flex_group_add(sb, resize_inode, flex_gd);
+               if (unlikely(err))
+                       break;
+       }
+
+out:
+       if (flex_gd)
+               free_flex_gd(flex_gd);
+
+       iput(resize_inode);
        if (test_opt(sb, DEBUG))
-               printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n",
-                      ext4_blocks_count(es));
-       update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,
-                      sizeof(struct ext4_super_block));
-exit_put:
+               printk(KERN_DEBUG "EXT4-fs: resized filesystem from %llu "
+                      "upto %llu blocks\n", o_blocks_count, n_blocks_count);
        return err;
-} /* ext4_group_extend */
+}
index ed3ce82e2de4ce8ef303075028db8651a1571e17..502c61fd739262306f7665b355cbdeba4d1e1c43 100644 (file)
@@ -1095,7 +1095,7 @@ static int ext4_show_options(struct seq_file *seq, struct dentry *root)
        }
        if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) {
                seq_printf(seq, ",max_batch_time=%u",
-                          (unsigned) sbi->s_min_batch_time);
+                          (unsigned) sbi->s_max_batch_time);
        }
 
        /*
@@ -2005,17 +2005,16 @@ static int ext4_fill_flex_info(struct super_block *sb)
        struct ext4_group_desc *gdp = NULL;
        ext4_group_t flex_group_count;
        ext4_group_t flex_group;
-       int groups_per_flex = 0;
+       unsigned int groups_per_flex = 0;
        size_t size;
        int i;
 
        sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
-       groups_per_flex = 1 << sbi->s_log_groups_per_flex;
-
-       if (groups_per_flex < 2) {
+       if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) {
                sbi->s_log_groups_per_flex = 0;
                return 1;
        }
+       groups_per_flex = 1 << sbi->s_log_groups_per_flex;
 
        /* We allocate both existing and potentially added groups */
        flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
@@ -3506,7 +3505,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * of the filesystem.
         */
        if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) {
-                ext4_msg(sb, KERN_WARNING, "bad geometry: first data"
+               ext4_msg(sb, KERN_WARNING, "bad geometry: first data "
                         "block %u is beyond end of filesystem (%llu)",
                         le32_to_cpu(es->s_first_data_block),
                         ext4_blocks_count(es));
index b60f9f81e33c4371985d83621020ed69f88de779..d2a200624af59a61ef29b88e4320609ddf2c02d0 100644 (file)
@@ -47,8 +47,9 @@ ext4_xattr_security_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-int ext4_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-                   void *fs_info)
+static int
+ext4_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+               void *fs_info)
 {
        const struct xattr *xattr;
        handle_t *handle = fs_info;
index e2951506434de6dbeb6bd9e0288b50d0d4977ac9..f855916657ba910f676eeb72ad795317c62fcbd5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 #include <linux/writeback.h>
 #include <linux/tracepoint.h>
 #include "internal.h"
 
+/*
+ * 4MB minimal write chunk size
+ */
+#define MIN_WRITEBACK_PAGES    (4096UL >> (PAGE_CACHE_SHIFT - 10))
+
 /*
  * Passed into wb_writeback(), essentially a subset of writeback_control
  */
@@ -742,11 +748,17 @@ static long wb_writeback(struct bdi_writeback *wb,
                if (work->for_background && !over_bground_thresh(wb->bdi))
                        break;
 
+               /*
+                * Kupdate and background works are special and we want to
+                * include all inodes that need writing. Livelock avoidance is
+                * handled by these works yielding to any other work so we are
+                * safe.
+                */
                if (work->for_kupdate) {
                        oldest_jif = jiffies -
                                msecs_to_jiffies(dirty_expire_interval * 10);
-                       work->older_than_this = &oldest_jif;
-               }
+               } else if (work->for_background)
+                       oldest_jif = jiffies;
 
                trace_writeback_start(wb->bdi, work);
                if (list_empty(&wb->b_io))
index 2aaf3eaaf13da03e328ac3523fe16ca09a60c690..5f3368ab0fa9d44ff8b5121db33d158ef5989da9 100644 (file)
@@ -1378,7 +1378,59 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
        down_read(&fc->killsb);
        err = -ENOENT;
        if (fc->sb)
-               err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name);
+               err = fuse_reverse_inval_entry(fc->sb, outarg.parent, 0, &name);
+       up_read(&fc->killsb);
+       kfree(buf);
+       return err;
+
+err:
+       kfree(buf);
+       fuse_copy_finish(cs);
+       return err;
+}
+
+static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
+                             struct fuse_copy_state *cs)
+{
+       struct fuse_notify_delete_out outarg;
+       int err = -ENOMEM;
+       char *buf;
+       struct qstr name;
+
+       buf = kzalloc(FUSE_NAME_MAX + 1, GFP_KERNEL);
+       if (!buf)
+               goto err;
+
+       err = -EINVAL;
+       if (size < sizeof(outarg))
+               goto err;
+
+       err = fuse_copy_one(cs, &outarg, sizeof(outarg));
+       if (err)
+               goto err;
+
+       err = -ENAMETOOLONG;
+       if (outarg.namelen > FUSE_NAME_MAX)
+               goto err;
+
+       err = -EINVAL;
+       if (size != sizeof(outarg) + outarg.namelen + 1)
+               goto err;
+
+       name.name = buf;
+       name.len = outarg.namelen;
+       err = fuse_copy_one(cs, buf, outarg.namelen + 1);
+       if (err)
+               goto err;
+       fuse_copy_finish(cs);
+       buf[outarg.namelen] = 0;
+       name.hash = full_name_hash(name.name, name.len);
+
+       down_read(&fc->killsb);
+       err = -ENOENT;
+       if (fc->sb)
+               err = fuse_reverse_inval_entry(fc->sb, outarg.parent,
+                                              outarg.child, &name);
        up_read(&fc->killsb);
        kfree(buf);
        return err;
@@ -1597,6 +1649,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
        case FUSE_NOTIFY_RETRIEVE:
                return fuse_notify_retrieve(fc, size, cs);
 
+       case FUSE_NOTIFY_DELETE:
+               return fuse_notify_delete(fc, size, cs);
+
        default:
                fuse_copy_finish(cs);
                return -EINVAL;
index 5ddd6ea8f839a87c3824c993a8c520b570706d04..206632887bb40ccf48bb80b96e497c2107c172d9 100644 (file)
@@ -868,7 +868,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
 }
 
 int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
-                            struct qstr *name)
+                            u64 child_nodeid, struct qstr *name)
 {
        int err = -ENOTDIR;
        struct inode *parent;
@@ -895,8 +895,36 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
 
        fuse_invalidate_attr(parent);
        fuse_invalidate_entry(entry);
+
+       if (child_nodeid != 0 && entry->d_inode) {
+               mutex_lock(&entry->d_inode->i_mutex);
+               if (get_node_id(entry->d_inode) != child_nodeid) {
+                       err = -ENOENT;
+                       goto badentry;
+               }
+               if (d_mountpoint(entry)) {
+                       err = -EBUSY;
+                       goto badentry;
+               }
+               if (S_ISDIR(entry->d_inode->i_mode)) {
+                       shrink_dcache_parent(entry);
+                       if (!simple_empty(entry)) {
+                               err = -ENOTEMPTY;
+                               goto badentry;
+                       }
+                       entry->d_inode->i_flags |= S_DEAD;
+               }
+               dont_mount(entry);
+               clear_nlink(entry->d_inode);
+               err = 0;
+ badentry:
+               mutex_unlock(&entry->d_inode->i_mutex);
+               if (!err)
+                       d_delete(entry);
+       } else {
+               err = 0;
+       }
        dput(entry);
-       err = 0;
 
  unlock:
        mutex_unlock(&parent->i_mutex);
@@ -1182,6 +1210,30 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
        return fuse_fsync_common(file, start, end, datasync, 1);
 }
 
+static long fuse_dir_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
+
+       /* FUSE_IOCTL_DIR only supported for API version >= 7.18 */
+       if (fc->minor < 18)
+               return -ENOTTY;
+
+       return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_DIR);
+}
+
+static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
+                                  unsigned long arg)
+{
+       struct fuse_conn *fc = get_fuse_conn(file->f_mapping->host);
+
+       if (fc->minor < 18)
+               return -ENOTTY;
+
+       return fuse_ioctl_common(file, cmd, arg,
+                                FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
+}
+
 static bool update_mtime(unsigned ivalid)
 {
        /* Always update if mtime is explicitly set  */
@@ -1596,6 +1648,8 @@ static const struct file_operations fuse_dir_operations = {
        .open           = fuse_dir_open,
        .release        = fuse_dir_release,
        .fsync          = fuse_dir_fsync,
+       .unlocked_ioctl = fuse_dir_ioctl,
+       .compat_ioctl   = fuse_dir_compat_ioctl,
 };
 
 static const struct inode_operations fuse_common_inode_operations = {
index 0c84100acd4492966e2fa48de6fbfacca0f10172..4a199fd93fbddaace1a65f74bc3872bfcbb76cc5 100644 (file)
@@ -1555,48 +1555,16 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
        loff_t retval;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       mutex_lock(&inode->i_mutex);
-       if (origin != SEEK_CUR && origin != SEEK_SET) {
-               retval = fuse_update_attributes(inode, NULL, file, NULL);
-               if (retval)
-                       goto exit;
-       }
+       /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
+       if (origin == SEEK_CUR || origin == SEEK_SET)
+               return generic_file_llseek(file, offset, origin);
 
-       switch (origin) {
-       case SEEK_END:
-               offset += i_size_read(inode);
-               break;
-       case SEEK_CUR:
-               if (offset == 0) {
-                       retval = file->f_pos;
-                       goto exit;
-               }
-               offset += file->f_pos;
-               break;
-       case SEEK_DATA:
-               if (offset >= i_size_read(inode)) {
-                       retval = -ENXIO;
-                       goto exit;
-               }
-               break;
-       case SEEK_HOLE:
-               if (offset >= i_size_read(inode)) {
-                       retval = -ENXIO;
-                       goto exit;
-               }
-               offset = i_size_read(inode);
-               break;
-       }
-       retval = -EINVAL;
-       if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
-               if (offset != file->f_pos) {
-                       file->f_pos = offset;
-                       file->f_version = 0;
-               }
-               retval = offset;
-       }
-exit:
+       mutex_lock(&inode->i_mutex);
+       retval = fuse_update_attributes(inode, NULL, file, NULL);
+       if (!retval)
+               retval = generic_file_llseek(file, offset, origin);
        mutex_unlock(&inode->i_mutex);
+
        return retval;
 }
 
@@ -1808,7 +1776,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
        BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
 
        err = -ENOMEM;
-       pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL);
+       pages = kcalloc(FUSE_MAX_PAGES_PER_REQ, sizeof(pages[0]), GFP_KERNEL);
        iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
        if (!pages || !iov_page)
                goto out;
@@ -1958,8 +1926,8 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
 }
 EXPORT_SYMBOL_GPL(fuse_do_ioctl);
 
-static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
-                                  unsigned long arg, unsigned int flags)
+long fuse_ioctl_common(struct file *file, unsigned int cmd,
+                      unsigned long arg, unsigned int flags)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -1976,13 +1944,13 @@ static long fuse_file_ioctl_common(struct file *file, unsigned int cmd,
 static long fuse_file_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
 {
-       return fuse_file_ioctl_common(file, cmd, arg, 0);
+       return fuse_ioctl_common(file, cmd, arg, 0);
 }
 
 static long fuse_file_compat_ioctl(struct file *file, unsigned int cmd,
                                   unsigned long arg)
 {
-       return fuse_file_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
+       return fuse_ioctl_common(file, cmd, arg, FUSE_IOCTL_COMPAT);
 }
 
 /*
index 1964da0257d9bbeac2852ffa52a04ecaebbc7b08..572cefc7801296ce1b15cba6223f09d9a9826072 100644 (file)
@@ -755,9 +755,15 @@ int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid,
 /**
  * File-system tells the kernel to invalidate parent attributes and
  * the dentry matching parent/name.
+ *
+ * If the child_nodeid is non-zero and:
+ *    - matches the inode number for the dentry matching parent/name,
+ *    - is not a mount point
+ *    - is a file or oan empty directory
+ * then the dentry is unhashed (d_delete()).
  */
 int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
-                            struct qstr *name);
+                            u64 child_nodeid, struct qstr *name);
 
 int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
                 bool isdir);
@@ -765,6 +771,8 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf,
                       size_t count, loff_t *ppos, int write);
 long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
                   unsigned int flags);
+long fuse_ioctl_common(struct file *file, unsigned int cmd,
+                      unsigned long arg, unsigned int flags);
 unsigned fuse_file_poll(struct file *file, poll_table *wait);
 int fuse_dev_release(struct inode *inode, struct file *file);
 
index 88e8a23d0026375c52bf6fd3b69bfd2a87fca598..376816fcd04084f0cad9ad522aab51d8ce0ff7f1 100644 (file)
@@ -1353,7 +1353,7 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
        spin_lock(&gl->gl_spin);
        gl->gl_reply = ret;
 
-       if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) {
+       if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))) {
                if (gfs2_should_freeze(gl)) {
                        set_bit(GLF_FROZEN, &gl->gl_flags);
                        spin_unlock(&gl->gl_spin);
index 2553b858a72e8374b04ea765938da1eacb7d925c..307ac31df781ea80ac8f77e01bfe5f4970710cb3 100644 (file)
@@ -121,8 +121,11 @@ enum {
 
 struct lm_lockops {
        const char *lm_proto_name;
-       int (*lm_mount) (struct gfs2_sbd *sdp, const char *fsname);
-       void (*lm_unmount) (struct gfs2_sbd *sdp);
+       int (*lm_mount) (struct gfs2_sbd *sdp, const char *table);
+       void (*lm_first_done) (struct gfs2_sbd *sdp);
+       void (*lm_recovery_result) (struct gfs2_sbd *sdp, unsigned int jid,
+                                   unsigned int result);
+       void (*lm_unmount) (struct gfs2_sbd *sdp);
        void (*lm_withdraw) (struct gfs2_sbd *sdp);
        void (*lm_put_lock) (struct gfs2_glock *gl);
        int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state,
index e1d3bb59945c7e2794880095ba330cc36cfeca1c..97742a7ea9ccf02e58c7ae8f64228790fdf0c8d7 100644 (file)
@@ -139,8 +139,45 @@ struct gfs2_bufdata {
 #define GDLM_STRNAME_BYTES     25
 #define GDLM_LVB_SIZE          32
 
+/*
+ * ls_recover_flags:
+ *
+ * DFL_BLOCK_LOCKS: dlm is in recovery and will grant locks that had been
+ * held by failed nodes whose journals need recovery.  Those locks should
+ * only be used for journal recovery until the journal recovery is done.
+ * This is set by the dlm recover_prep callback and cleared by the
+ * gfs2_control thread when journal recovery is complete.  To avoid
+ * races between recover_prep setting and gfs2_control clearing, recover_spin
+ * is held while changing this bit and reading/writing recover_block
+ * and recover_start.
+ *
+ * DFL_NO_DLM_OPS: dlm lockspace ops/callbacks are not being used.
+ *
+ * DFL_FIRST_MOUNT: this node is the first to mount this fs and is doing
+ * recovery of all journals before allowing other nodes to mount the fs.
+ * This is cleared when FIRST_MOUNT_DONE is set.
+ *
+ * DFL_FIRST_MOUNT_DONE: this node was the first mounter, and has finished
+ * recovery of all journals, and now allows other nodes to mount the fs.
+ *
+ * DFL_MOUNT_DONE: gdlm_mount has completed successfully and cleared
+ * BLOCK_LOCKS for the first time.  The gfs2_control thread should now
+ * control clearing BLOCK_LOCKS for further recoveries.
+ *
+ * DFL_UNMOUNT: gdlm_unmount sets to keep sdp off gfs2_control_wq.
+ *
+ * DFL_DLM_RECOVERY: set while dlm is in recovery, between recover_prep()
+ * and recover_done(), i.e. set while recover_block == recover_start.
+ */
+
 enum {
        DFL_BLOCK_LOCKS         = 0,
+       DFL_NO_DLM_OPS          = 1,
+       DFL_FIRST_MOUNT         = 2,
+       DFL_FIRST_MOUNT_DONE    = 3,
+       DFL_MOUNT_DONE          = 4,
+       DFL_UNMOUNT             = 5,
+       DFL_DLM_RECOVERY        = 6,
 };
 
 struct lm_lockname {
@@ -392,6 +429,7 @@ struct gfs2_jdesc {
 #define JDF_RECOVERY 1
        unsigned int jd_jid;
        unsigned int jd_blocks;
+       int jd_recover_error;
 };
 
 struct gfs2_statfs_change_host {
@@ -461,6 +499,7 @@ enum {
        SDF_NORECOVERY          = 4,
        SDF_DEMOTE              = 5,
        SDF_NOJOURNALID         = 6,
+       SDF_RORECOVERY          = 7, /* read only recovery */
 };
 
 #define GFS2_FSNAME_LEN                256
@@ -499,14 +538,26 @@ struct gfs2_sb_host {
 struct lm_lockstruct {
        int ls_jid;
        unsigned int ls_first;
-       unsigned int ls_first_done;
        unsigned int ls_nodir;
        const struct lm_lockops *ls_ops;
-       unsigned long ls_flags;
        dlm_lockspace_t *ls_dlm;
 
-       int ls_recover_jid_done;
-       int ls_recover_jid_status;
+       int ls_recover_jid_done;   /* These two are deprecated, */
+       int ls_recover_jid_status; /* used previously by gfs_controld */
+
+       struct dlm_lksb ls_mounted_lksb; /* mounted_lock */
+       struct dlm_lksb ls_control_lksb; /* control_lock */
+       char ls_control_lvb[GDLM_LVB_SIZE]; /* control_lock lvb */
+       struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */
+
+       spinlock_t ls_recover_spin; /* protects following fields */
+       unsigned long ls_recover_flags; /* DFL_ */
+       uint32_t ls_recover_mount; /* gen in first recover_done cb */
+       uint32_t ls_recover_start; /* gen in last recover_done cb */
+       uint32_t ls_recover_block; /* copy recover_start in last recover_prep */
+       uint32_t ls_recover_size; /* size of recover_submit, recover_result */
+       uint32_t *ls_recover_submit; /* gen in last recover_slot cb per jid */
+       uint32_t *ls_recover_result; /* result of last jid recovery */
 };
 
 struct gfs2_sbd {
@@ -544,6 +595,7 @@ struct gfs2_sbd {
        wait_queue_head_t sd_glock_wait;
        atomic_t sd_glock_disposal;
        struct completion sd_locking_init;
+       struct delayed_work sd_control_work;
 
        /* Inode Stuff */
 
index 017960cf1d7aaa198bef71664bdfed82a6fa7f9b..a7d611b93f0fca912ce716736df2524cad7b40be 100644 (file)
@@ -599,9 +599,7 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error)
                goto fail_end_trans;
-       inc_nlink(&ip->i_inode);
-       if (S_ISDIR(ip->i_inode.i_mode))
-               inc_nlink(&ip->i_inode);
+       set_nlink(&ip->i_inode, S_ISDIR(ip->i_inode.i_mode) ? 2 : 1);
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
index 98c80d8c2a62df79273433cb494a3f05d35ae02c..8944d1e32ab55c09073ae0b0d0a25280491ff631 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
+ * Copyright 2004-2011 Red Hat, Inc.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
 #include <linux/dlm.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <linux/gfs2_ondisk.h>
 
 #include "incore.h"
 #include "glock.h"
 #include "util.h"
+#include "sys.h"
 
+extern struct workqueue_struct *gfs2_control_wq;
 
 static void gdlm_ast(void *arg)
 {
@@ -185,34 +188,1002 @@ static void gdlm_cancel(struct gfs2_glock *gl)
        dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl);
 }
 
-static int gdlm_mount(struct gfs2_sbd *sdp, const char *fsname)
+/*
+ * dlm/gfs2 recovery coordination using dlm_recover callbacks
+ *
+ *  1. dlm_controld sees lockspace members change
+ *  2. dlm_controld blocks dlm-kernel locking activity
+ *  3. dlm_controld within dlm-kernel notifies gfs2 (recover_prep)
+ *  4. dlm_controld starts and finishes its own user level recovery
+ *  5. dlm_controld starts dlm-kernel dlm_recoverd to do kernel recovery
+ *  6. dlm_recoverd notifies gfs2 of failed nodes (recover_slot)
+ *  7. dlm_recoverd does its own lock recovery
+ *  8. dlm_recoverd unblocks dlm-kernel locking activity
+ *  9. dlm_recoverd notifies gfs2 when done (recover_done with new generation)
+ * 10. gfs2_control updates control_lock lvb with new generation and jid bits
+ * 11. gfs2_control enqueues journals for gfs2_recover to recover (maybe none)
+ * 12. gfs2_recover dequeues and recovers journals of failed nodes
+ * 13. gfs2_recover provides recovery results to gfs2_control (recovery_result)
+ * 14. gfs2_control updates control_lock lvb jid bits for recovered journals
+ * 15. gfs2_control unblocks normal locking when all journals are recovered
+ *
+ * - failures during recovery
+ *
+ * recover_prep() may set BLOCK_LOCKS (step 3) again before gfs2_control
+ * clears BLOCK_LOCKS (step 15), e.g. another node fails while still
+ * recovering for a prior failure.  gfs2_control needs a way to detect
+ * this so it can leave BLOCK_LOCKS set in step 15.  This is managed using
+ * the recover_block and recover_start values.
+ *
+ * recover_done() provides a new lockspace generation number each time it
+ * is called (step 9).  This generation number is saved as recover_start.
+ * When recover_prep() is called, it sets BLOCK_LOCKS and sets
+ * recover_block = recover_start.  So, while recover_block is equal to
+ * recover_start, BLOCK_LOCKS should remain set.  (recover_spin must
+ * be held around the BLOCK_LOCKS/recover_block/recover_start logic.)
+ *
+ * - more specific gfs2 steps in sequence above
+ *
+ *  3. recover_prep sets BLOCK_LOCKS and sets recover_block = recover_start
+ *  6. recover_slot records any failed jids (maybe none)
+ *  9. recover_done sets recover_start = new generation number
+ * 10. gfs2_control sets control_lock lvb = new gen + bits for failed jids
+ * 12. gfs2_recover does journal recoveries for failed jids identified above
+ * 14. gfs2_control clears control_lock lvb bits for recovered jids
+ * 15. gfs2_control checks if recover_block == recover_start (step 3 occured
+ *     again) then do nothing, otherwise if recover_start > recover_block
+ *     then clear BLOCK_LOCKS.
+ *
+ * - parallel recovery steps across all nodes
+ *
+ * All nodes attempt to update the control_lock lvb with the new generation
+ * number and jid bits, but only the first to get the control_lock EX will
+ * do so; others will see that it's already done (lvb already contains new
+ * generation number.)
+ *
+ * . All nodes get the same recover_prep/recover_slot/recover_done callbacks
+ * . All nodes attempt to set control_lock lvb gen + bits for the new gen
+ * . One node gets control_lock first and writes the lvb, others see it's done
+ * . All nodes attempt to recover jids for which they see control_lock bits set
+ * . One node succeeds for a jid, and that one clears the jid bit in the lvb
+ * . All nodes will eventually see all lvb bits clear and unblock locks
+ *
+ * - is there a problem with clearing an lvb bit that should be set
+ *   and missing a journal recovery?
+ *
+ * 1. jid fails
+ * 2. lvb bit set for step 1
+ * 3. jid recovered for step 1
+ * 4. jid taken again (new mount)
+ * 5. jid fails (for step 4)
+ * 6. lvb bit set for step 5 (will already be set)
+ * 7. lvb bit cleared for step 3
+ *
+ * This is not a problem because the failure in step 5 does not
+ * require recovery, because the mount in step 4 could not have
+ * progressed far enough to unblock locks and access the fs.  The
+ * control_mount() function waits for all recoveries to be complete
+ * for the latest lockspace generation before ever unblocking locks
+ * and returning.  The mount in step 4 waits until the recovery in
+ * step 1 is done.
+ *
+ * - special case of first mounter: first node to mount the fs
+ *
+ * The first node to mount a gfs2 fs needs to check all the journals
+ * and recover any that need recovery before other nodes are allowed
+ * to mount the fs.  (Others may begin mounting, but they must wait
+ * for the first mounter to be done before taking locks on the fs
+ * or accessing the fs.)  This has two parts:
+ *
+ * 1. The mounted_lock tells a node it's the first to mount the fs.
+ * Each node holds the mounted_lock in PR while it's mounted.
+ * Each node tries to acquire the mounted_lock in EX when it mounts.
+ * If a node is granted the mounted_lock EX it means there are no
+ * other mounted nodes (no PR locks exist), and it is the first mounter.
+ * The mounted_lock is demoted to PR when first recovery is done, so
+ * others will fail to get an EX lock, but will get a PR lock.
+ *
+ * 2. The control_lock blocks others in control_mount() while the first
+ * mounter is doing first mount recovery of all journals.
+ * A mounting node needs to acquire control_lock in EX mode before
+ * it can proceed.  The first mounter holds control_lock in EX while doing
+ * the first mount recovery, blocking mounts from other nodes, then demotes
+ * control_lock to NL when it's done (others_may_mount/first_done),
+ * allowing other nodes to continue mounting.
+ *
+ * first mounter:
+ * control_lock EX/NOQUEUE success
+ * mounted_lock EX/NOQUEUE success (no other PR, so no other mounters)
+ * set first=1
+ * do first mounter recovery
+ * mounted_lock EX->PR
+ * control_lock EX->NL, write lvb generation
+ *
+ * other mounter:
+ * control_lock EX/NOQUEUE success (if fail -EAGAIN, retry)
+ * mounted_lock EX/NOQUEUE fail -EAGAIN (expected due to other mounters PR)
+ * mounted_lock PR/NOQUEUE success
+ * read lvb generation
+ * control_lock EX->NL
+ * set first=0
+ *
+ * - mount during recovery
+ *
+ * If a node mounts while others are doing recovery (not first mounter),
+ * the mounting node will get its initial recover_done() callback without
+ * having seen any previous failures/callbacks.
+ *
+ * It must wait for all recoveries preceding its mount to be finished
+ * before it unblocks locks.  It does this by repeating the "other mounter"
+ * steps above until the lvb generation number is >= its mount generation
+ * number (from initial recover_done) and all lvb bits are clear.
+ *
+ * - control_lock lvb format
+ *
+ * 4 bytes generation number: the latest dlm lockspace generation number
+ * from recover_done callback.  Indicates the jid bitmap has been updated
+ * to reflect all slot failures through that generation.
+ * 4 bytes unused.
+ * GDLM_LVB_SIZE-8 bytes of jid bit map. If bit N is set, it indicates
+ * that jid N needs recovery.
+ */
+
+#define JID_BITMAP_OFFSET 8 /* 4 byte generation number + 4 byte unused */
+
+static void control_lvb_read(struct lm_lockstruct *ls, uint32_t *lvb_gen,
+                            char *lvb_bits)
+{
+       uint32_t gen;
+       memcpy(lvb_bits, ls->ls_control_lvb, GDLM_LVB_SIZE);
+       memcpy(&gen, lvb_bits, sizeof(uint32_t));
+       *lvb_gen = le32_to_cpu(gen);
+}
+
+static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen,
+                             char *lvb_bits)
+{
+       uint32_t gen;
+       memcpy(ls->ls_control_lvb, lvb_bits, GDLM_LVB_SIZE);
+       gen = cpu_to_le32(lvb_gen);
+       memcpy(ls->ls_control_lvb, &gen, sizeof(uint32_t));
+}
+
+static int all_jid_bits_clear(char *lvb)
+{
+       int i;
+       for (i = JID_BITMAP_OFFSET; i < GDLM_LVB_SIZE; i++) {
+               if (lvb[i])
+                       return 0;
+       }
+       return 1;
+}
+
+static void sync_wait_cb(void *arg)
+{
+       struct lm_lockstruct *ls = arg;
+       complete(&ls->ls_sync_wait);
+}
+
+static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
        int error;
 
-       if (fsname == NULL) {
-               fs_info(sdp, "no fsname found\n");
-               return -EINVAL;
+       error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
+       if (error) {
+               fs_err(sdp, "%s lkid %x error %d\n",
+                      name, lksb->sb_lkid, error);
+               return error;
+       }
+
+       wait_for_completion(&ls->ls_sync_wait);
+
+       if (lksb->sb_status != -DLM_EUNLOCK) {
+               fs_err(sdp, "%s lkid %x status %d\n",
+                      name, lksb->sb_lkid, lksb->sb_status);
+               return -1;
+       }
+       return 0;
+}
+
+static int sync_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags,
+                    unsigned int num, struct dlm_lksb *lksb, char *name)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char strname[GDLM_STRNAME_BYTES];
+       int error, status;
+
+       memset(strname, 0, GDLM_STRNAME_BYTES);
+       snprintf(strname, GDLM_STRNAME_BYTES, "%8x%16x", LM_TYPE_NONDISK, num);
+
+       error = dlm_lock(ls->ls_dlm, mode, lksb, flags,
+                        strname, GDLM_STRNAME_BYTES - 1,
+                        0, sync_wait_cb, ls, NULL);
+       if (error) {
+               fs_err(sdp, "%s lkid %x flags %x mode %d error %d\n",
+                      name, lksb->sb_lkid, flags, mode, error);
+               return error;
+       }
+
+       wait_for_completion(&ls->ls_sync_wait);
+
+       status = lksb->sb_status;
+
+       if (status && status != -EAGAIN) {
+               fs_err(sdp, "%s lkid %x flags %x mode %d status %d\n",
+                      name, lksb->sb_lkid, flags, mode, status);
+       }
+
+       return status;
+}
+
+static int mounted_unlock(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_unlock(sdp, &ls->ls_mounted_lksb, "mounted_lock");
+}
+
+static int mounted_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_lock(sdp, mode, flags, GFS2_MOUNTED_LOCK,
+                        &ls->ls_mounted_lksb, "mounted_lock");
+}
+
+static int control_unlock(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_unlock(sdp, &ls->ls_control_lksb, "control_lock");
+}
+
+static int control_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       return sync_lock(sdp, mode, flags, GFS2_CONTROL_LOCK,
+                        &ls->ls_control_lksb, "control_lock");
+}
+
+static void gfs2_control_func(struct work_struct *work)
+{
+       struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t block_gen, start_gen, lvb_gen, flags;
+       int recover_set = 0;
+       int write_lvb = 0;
+       int recover_size;
+       int i, error;
+
+       spin_lock(&ls->ls_recover_spin);
+       /*
+        * No MOUNT_DONE means we're still mounting; control_mount()
+        * will set this flag, after which this thread will take over
+        * all further clearing of BLOCK_LOCKS.
+        *
+        * FIRST_MOUNT means this node is doing first mounter recovery,
+        * for which recovery control is handled by
+        * control_mount()/control_first_done(), not this thread.
+        */
+       if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+            test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       block_gen = ls->ls_recover_block;
+       start_gen = ls->ls_recover_start;
+       spin_unlock(&ls->ls_recover_spin);
+
+       /*
+        * Equal block_gen and start_gen implies we are between
+        * recover_prep and recover_done callbacks, which means
+        * dlm recovery is in progress and dlm locking is blocked.
+        * There's no point trying to do any work until recover_done.
+        */
+
+       if (block_gen == start_gen)
+               return;
+
+       /*
+        * Propagate recover_submit[] and recover_result[] to lvb:
+        * dlm_recoverd adds to recover_submit[] jids needing recovery
+        * gfs2_recover adds to recover_result[] journal recovery results
+        *
+        * set lvb bit for jids in recover_submit[] if the lvb has not
+        * yet been updated for the generation of the failure
+        *
+        * clear lvb bit for jids in recover_result[] if the result of
+        * the journal recovery is SUCCESS
+        */
+
+       error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
+       if (error) {
+               fs_err(sdp, "control lock EX error %d\n", error);
+               return;
+       }
+
+       control_lvb_read(ls, &lvb_gen, lvb_bits);
+
+       spin_lock(&ls->ls_recover_spin);
+       if (block_gen != ls->ls_recover_block ||
+           start_gen != ls->ls_recover_start) {
+               fs_info(sdp, "recover generation %u block1 %u %u\n",
+                       start_gen, block_gen, ls->ls_recover_block);
+               spin_unlock(&ls->ls_recover_spin);
+               control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+               return;
+       }
+
+       recover_size = ls->ls_recover_size;
+
+       if (lvb_gen <= start_gen) {
+               /*
+                * Clear lvb bits for jids we've successfully recovered.
+                * Because all nodes attempt to recover failed journals,
+                * a journal can be recovered multiple times successfully
+                * in succession.  Only the first will really do recovery,
+                * the others find it clean, but still report a successful
+                * recovery.  So, another node may have already recovered
+                * the jid and cleared the lvb bit for it.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (ls->ls_recover_result[i] != LM_RD_SUCCESS)
+                               continue;
+
+                       ls->ls_recover_result[i] = 0;
+
+                       if (!test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET))
+                               continue;
+
+                       __clear_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                       write_lvb = 1;
+               }
+       }
+
+       if (lvb_gen == start_gen) {
+               /*
+                * Failed slots before start_gen are already set in lvb.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (!ls->ls_recover_submit[i])
+                               continue;
+                       if (ls->ls_recover_submit[i] < lvb_gen)
+                               ls->ls_recover_submit[i] = 0;
+               }
+       } else if (lvb_gen < start_gen) {
+               /*
+                * Failed slots before start_gen are not yet set in lvb.
+                */
+               for (i = 0; i < recover_size; i++) {
+                       if (!ls->ls_recover_submit[i])
+                               continue;
+                       if (ls->ls_recover_submit[i] < start_gen) {
+                               ls->ls_recover_submit[i] = 0;
+                               __set_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                       }
+               }
+               /* even if there are no bits to set, we need to write the
+                  latest generation to the lvb */
+               write_lvb = 1;
+       } else {
+               /*
+                * we should be getting a recover_done() for lvb_gen soon
+                */
+       }
+       spin_unlock(&ls->ls_recover_spin);
+
+       if (write_lvb) {
+               control_lvb_write(ls, start_gen, lvb_bits);
+               flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK;
+       } else {
+               flags = DLM_LKF_CONVERT;
+       }
+
+       error = control_lock(sdp, DLM_LOCK_NL, flags);
+       if (error) {
+               fs_err(sdp, "control lock NL error %d\n", error);
+               return;
+       }
+
+       /*
+        * Everyone will see jid bits set in the lvb, run gfs2_recover_set(),
+        * and clear a jid bit in the lvb if the recovery is a success.
+        * Eventually all journals will be recovered, all jid bits will
+        * be cleared in the lvb, and everyone will clear BLOCK_LOCKS.
+        */
+
+       for (i = 0; i < recover_size; i++) {
+               if (test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) {
+                       fs_info(sdp, "recover generation %u jid %d\n",
+                               start_gen, i);
+                       gfs2_recover_set(sdp, i);
+                       recover_set++;
+               }
+       }
+       if (recover_set)
+               return;
+
+       /*
+        * No more jid bits set in lvb, all recovery is done, unblock locks
+        * (unless a new recover_prep callback has occured blocking locks
+        * again while working above)
+        */
+
+       spin_lock(&ls->ls_recover_spin);
+       if (ls->ls_recover_block == block_gen &&
+           ls->ls_recover_start == start_gen) {
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "recover generation %u done\n", start_gen);
+               gfs2_glock_thaw(sdp);
+       } else {
+               fs_info(sdp, "recover generation %u block2 %u %u\n",
+                       start_gen, block_gen, ls->ls_recover_block);
+               spin_unlock(&ls->ls_recover_spin);
+       }
+}
+
+static int control_mount(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t start_gen, block_gen, mount_gen, lvb_gen;
+       int mounted_mode;
+       int retries = 0;
+       int error;
+
+       memset(&ls->ls_mounted_lksb, 0, sizeof(struct dlm_lksb));
+       memset(&ls->ls_control_lksb, 0, sizeof(struct dlm_lksb));
+       memset(&ls->ls_control_lvb, 0, GDLM_LVB_SIZE);
+       ls->ls_control_lksb.sb_lvbptr = ls->ls_control_lvb;
+       init_completion(&ls->ls_sync_wait);
+
+       set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_VALBLK);
+       if (error) {
+               fs_err(sdp, "control_mount control_lock NL error %d\n", error);
+               return error;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_NL, 0);
+       if (error) {
+               fs_err(sdp, "control_mount mounted_lock NL error %d\n", error);
+               control_unlock(sdp);
+               return error;
+       }
+       mounted_mode = DLM_LOCK_NL;
+
+restart:
+       if (retries++ && signal_pending(current)) {
+               error = -EINTR;
+               goto fail;
+       }
+
+       /*
+        * We always start with both locks in NL. control_lock is
+        * demoted to NL below so we don't need to do it here.
+        */
+
+       if (mounted_mode != DLM_LOCK_NL) {
+               error = mounted_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+               if (error)
+                       goto fail;
+               mounted_mode = DLM_LOCK_NL;
+       }
+
+       /*
+        * Other nodes need to do some work in dlm recovery and gfs2_control
+        * before the recover_done and control_lock will be ready for us below.
+        * A delay here is not required but often avoids having to retry.
+        */
+
+       msleep_interruptible(500);
+
+       /*
+        * Acquire control_lock in EX and mounted_lock in either EX or PR.
+        * control_lock lvb keeps track of any pending journal recoveries.
+        * mounted_lock indicates if any other nodes have the fs mounted.
+        */
+
+       error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE|DLM_LKF_VALBLK);
+       if (error == -EAGAIN) {
+               goto restart;
+       } else if (error) {
+               fs_err(sdp, "control_mount control_lock EX error %d\n", error);
+               goto fail;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
+       if (!error) {
+               mounted_mode = DLM_LOCK_EX;
+               goto locks_done;
+       } else if (error != -EAGAIN) {
+               fs_err(sdp, "control_mount mounted_lock EX error %d\n", error);
+               goto fail;
+       }
+
+       error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
+       if (!error) {
+               mounted_mode = DLM_LOCK_PR;
+               goto locks_done;
+       } else {
+               /* not even -EAGAIN should happen here */
+               fs_err(sdp, "control_mount mounted_lock PR error %d\n", error);
+               goto fail;
+       }
+
+locks_done:
+       /*
+        * If we got both locks above in EX, then we're the first mounter.
+        * If not, then we need to wait for the control_lock lvb to be
+        * updated by other mounted nodes to reflect our mount generation.
+        *
+        * In simple first mounter cases, first mounter will see zero lvb_gen,
+        * but in cases where all existing nodes leave/fail before mounting
+        * nodes finish control_mount, then all nodes will be mounting and
+        * lvb_gen will be non-zero.
+        */
+
+       control_lvb_read(ls, &lvb_gen, lvb_bits);
+
+       if (lvb_gen == 0xFFFFFFFF) {
+               /* special value to force mount attempts to fail */
+               fs_err(sdp, "control_mount control_lock disabled\n");
+               error = -EINVAL;
+               goto fail;
+       }
+
+       if (mounted_mode == DLM_LOCK_EX) {
+               /* first mounter, keep both EX while doing first recovery */
+               spin_lock(&ls->ls_recover_spin);
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+               set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
+               set_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "first mounter control generation %u\n", lvb_gen);
+               return 0;
+       }
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
+       if (error)
+               goto fail;
+
+       /*
+        * We are not first mounter, now we need to wait for the control_lock
+        * lvb generation to be >= the generation from our first recover_done
+        * and all lvb bits to be clear (no pending journal recoveries.)
+        */
+
+       if (!all_jid_bits_clear(lvb_bits)) {
+               /* journals need recovery, wait until all are clear */
+               fs_info(sdp, "control_mount wait for journal recovery\n");
+               goto restart;
+       }
+
+       spin_lock(&ls->ls_recover_spin);
+       block_gen = ls->ls_recover_block;
+       start_gen = ls->ls_recover_start;
+       mount_gen = ls->ls_recover_mount;
+
+       if (lvb_gen < mount_gen) {
+               /* wait for mounted nodes to update control_lock lvb to our
+                  generation, which might include new recovery bits set */
+               fs_info(sdp, "control_mount wait1 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
+       }
+
+       if (lvb_gen != start_gen) {
+               /* wait for mounted nodes to update control_lock lvb to the
+                  latest recovery generation */
+               fs_info(sdp, "control_mount wait2 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
+       }
+
+       if (block_gen == start_gen) {
+               /* dlm recovery in progress, wait for it to finish */
+               fs_info(sdp, "control_mount wait3 block %u start %u mount %u "
+                       "lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
+                       lvb_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               goto restart;
        }
 
-       error = dlm_new_lockspace(fsname, strlen(fsname), &ls->ls_dlm,
-                                 DLM_LSFL_FS | DLM_LSFL_NEWEXCL |
-                                 (ls->ls_nodir ? DLM_LSFL_NODIR : 0),
-                                 GDLM_LVB_SIZE);
+       clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+       set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
+       memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
+       memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
+       spin_unlock(&ls->ls_recover_spin);
+       return 0;
+
+fail:
+       mounted_unlock(sdp);
+       control_unlock(sdp);
+       return error;
+}
+
+static int dlm_recovery_wait(void *word)
+{
+       schedule();
+       return 0;
+}
+
+static int control_first_done(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char lvb_bits[GDLM_LVB_SIZE];
+       uint32_t start_gen, block_gen;
+       int error;
+
+restart:
+       spin_lock(&ls->ls_recover_spin);
+       start_gen = ls->ls_recover_start;
+       block_gen = ls->ls_recover_block;
+
+       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags) ||
+           !test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+           !test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               /* sanity check, should not happen */
+               fs_err(sdp, "control_first_done start %u block %u flags %lx\n",
+                      start_gen, block_gen, ls->ls_recover_flags);
+               spin_unlock(&ls->ls_recover_spin);
+               control_unlock(sdp);
+               return -1;
+       }
+
+       if (start_gen == block_gen) {
+               /*
+                * Wait for the end of a dlm recovery cycle to switch from
+                * first mounter recovery.  We can ignore any recover_slot
+                * callbacks between the recover_prep and next recover_done
+                * because we are still the first mounter and any failed nodes
+                * have not fully mounted, so they don't need recovery.
+                */
+               spin_unlock(&ls->ls_recover_spin);
+               fs_info(sdp, "control_first_done wait gen %u\n", start_gen);
+
+               wait_on_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY,
+                           dlm_recovery_wait, TASK_UNINTERRUPTIBLE);
+               goto restart;
+       }
+
+       clear_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+       set_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags);
+       memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
+       memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
+       spin_unlock(&ls->ls_recover_spin);
+
+       memset(lvb_bits, 0, sizeof(lvb_bits));
+       control_lvb_write(ls, start_gen, lvb_bits);
+
+       error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
+       if (error)
+               fs_err(sdp, "control_first_done mounted PR error %d\n", error);
+
+       error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
        if (error)
-               printk(KERN_ERR "dlm_new_lockspace error %d", error);
+               fs_err(sdp, "control_first_done control NL error %d\n", error);
 
        return error;
 }
 
+/*
+ * Expand static jid arrays if necessary (by increments of RECOVER_SIZE_INC)
+ * to accomodate the largest slot number.  (NB dlm slot numbers start at 1,
+ * gfs2 jids start at 0, so jid = slot - 1)
+ */
+
+#define RECOVER_SIZE_INC 16
+
+static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
+                           int num_slots)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       uint32_t *submit = NULL;
+       uint32_t *result = NULL;
+       uint32_t old_size, new_size;
+       int i, max_jid;
+
+       max_jid = 0;
+       for (i = 0; i < num_slots; i++) {
+               if (max_jid < slots[i].slot - 1)
+                       max_jid = slots[i].slot - 1;
+       }
+
+       old_size = ls->ls_recover_size;
+
+       if (old_size >= max_jid + 1)
+               return 0;
+
+       new_size = old_size + RECOVER_SIZE_INC;
+
+       submit = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS);
+       result = kzalloc(new_size * sizeof(uint32_t), GFP_NOFS);
+       if (!submit || !result) {
+               kfree(submit);
+               kfree(result);
+               return -ENOMEM;
+       }
+
+       spin_lock(&ls->ls_recover_spin);
+       memcpy(submit, ls->ls_recover_submit, old_size * sizeof(uint32_t));
+       memcpy(result, ls->ls_recover_result, old_size * sizeof(uint32_t));
+       kfree(ls->ls_recover_submit);
+       kfree(ls->ls_recover_result);
+       ls->ls_recover_submit = submit;
+       ls->ls_recover_result = result;
+       ls->ls_recover_size = new_size;
+       spin_unlock(&ls->ls_recover_spin);
+       return 0;
+}
+
+static void free_recover_size(struct lm_lockstruct *ls)
+{
+       kfree(ls->ls_recover_submit);
+       kfree(ls->ls_recover_result);
+       ls->ls_recover_submit = NULL;
+       ls->ls_recover_result = NULL;
+       ls->ls_recover_size = 0;
+}
+
+/* dlm calls before it does lock recovery */
+
+static void gdlm_recover_prep(void *arg)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       spin_lock(&ls->ls_recover_spin);
+       ls->ls_recover_block = ls->ls_recover_start;
+       set_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags);
+
+       if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
+            test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* dlm calls after recover_prep has been completed on all lockspace members;
+   identifies slot/jid of failed member */
+
+static void gdlm_recover_slot(void *arg, struct dlm_slot *slot)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int jid = slot->slot - 1;
+
+       spin_lock(&ls->ls_recover_spin);
+       if (ls->ls_recover_size < jid + 1) {
+               fs_err(sdp, "recover_slot jid %d gen %u short size %d",
+                      jid, ls->ls_recover_block, ls->ls_recover_size);
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+
+       if (ls->ls_recover_submit[jid]) {
+               fs_info(sdp, "recover_slot jid %d gen %u prev %u",
+                       jid, ls->ls_recover_block, ls->ls_recover_submit[jid]);
+       }
+       ls->ls_recover_submit[jid] = ls->ls_recover_block;
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* dlm calls after recover_slot and after it completes lock recovery */
+
+static void gdlm_recover_done(void *arg, struct dlm_slot *slots, int num_slots,
+                             int our_slot, uint32_t generation)
+{
+       struct gfs2_sbd *sdp = arg;
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       /* ensure the ls jid arrays are large enough */
+       set_recover_size(sdp, slots, num_slots);
+
+       spin_lock(&ls->ls_recover_spin);
+       ls->ls_recover_start = generation;
+
+       if (!ls->ls_recover_mount) {
+               ls->ls_recover_mount = generation;
+               ls->ls_jid = our_slot - 1;
+       }
+
+       if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
+               queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work, 0);
+
+       clear_bit(DFL_DLM_RECOVERY, &ls->ls_recover_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+/* gfs2_recover thread has a journal recovery result */
+
+static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
+                                unsigned int result)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               return;
+
+       /* don't care about the recovery of own journal during mount */
+       if (jid == ls->ls_jid)
+               return;
+
+       spin_lock(&ls->ls_recover_spin);
+       if (test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+       if (ls->ls_recover_size < jid + 1) {
+               fs_err(sdp, "recovery_result jid %d short size %d",
+                      jid, ls->ls_recover_size);
+               spin_unlock(&ls->ls_recover_spin);
+               return;
+       }
+
+       fs_info(sdp, "recover jid %d result %s\n", jid,
+               result == LM_RD_GAVEUP ? "busy" : "success");
+
+       ls->ls_recover_result[jid] = result;
+
+       /* GAVEUP means another node is recovering the journal; delay our
+          next attempt to recover it, to give the other node a chance to
+          finish before trying again */
+
+       if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
+               queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work,
+                                  result == LM_RD_GAVEUP ? HZ : 0);
+       spin_unlock(&ls->ls_recover_spin);
+}
+
+const struct dlm_lockspace_ops gdlm_lockspace_ops = {
+       .recover_prep = gdlm_recover_prep,
+       .recover_slot = gdlm_recover_slot,
+       .recover_done = gdlm_recover_done,
+};
+
+static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       char cluster[GFS2_LOCKNAME_LEN];
+       const char *fsname;
+       uint32_t flags;
+       int error, ops_result;
+
+       /*
+        * initialize everything
+        */
+
+       INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func);
+       spin_lock_init(&ls->ls_recover_spin);
+       ls->ls_recover_flags = 0;
+       ls->ls_recover_mount = 0;
+       ls->ls_recover_start = 0;
+       ls->ls_recover_block = 0;
+       ls->ls_recover_size = 0;
+       ls->ls_recover_submit = NULL;
+       ls->ls_recover_result = NULL;
+
+       error = set_recover_size(sdp, NULL, 0);
+       if (error)
+               goto fail;
+
+       /*
+        * prepare dlm_new_lockspace args
+        */
+
+       fsname = strchr(table, ':');
+       if (!fsname) {
+               fs_info(sdp, "no fsname found\n");
+               error = -EINVAL;
+               goto fail_free;
+       }
+       memset(cluster, 0, sizeof(cluster));
+       memcpy(cluster, table, strlen(table) - strlen(fsname));
+       fsname++;
+
+       flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;
+       if (ls->ls_nodir)
+               flags |= DLM_LSFL_NODIR;
+
+       /*
+        * create/join lockspace
+        */
+
+       error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE,
+                                 &gdlm_lockspace_ops, sdp, &ops_result,
+                                 &ls->ls_dlm);
+       if (error) {
+               fs_err(sdp, "dlm_new_lockspace error %d\n", error);
+               goto fail_free;
+       }
+
+       if (ops_result < 0) {
+               /*
+                * dlm does not support ops callbacks,
+                * old dlm_controld/gfs_controld are used, try without ops.
+                */
+               fs_info(sdp, "dlm lockspace ops not used\n");
+               free_recover_size(ls);
+               set_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags);
+               return 0;
+       }
+
+       if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags)) {
+               fs_err(sdp, "dlm lockspace ops disallow jid preset\n");
+               error = -EINVAL;
+               goto fail_release;
+       }
+
+       /*
+        * control_mount() uses control_lock to determine first mounter,
+        * and for later mounts, waits for any recoveries to be cleared.
+        */
+
+       error = control_mount(sdp);
+       if (error) {
+               fs_err(sdp, "mount control error %d\n", error);
+               goto fail_release;
+       }
+
+       ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
+       clear_bit(SDF_NOJOURNALID, &sdp->sd_flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
+       return 0;
+
+fail_release:
+       dlm_release_lockspace(ls->ls_dlm, 2);
+fail_free:
+       free_recover_size(ls);
+fail:
+       return error;
+}
+
+static void gdlm_first_done(struct gfs2_sbd *sdp)
+{
+       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int error;
+
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               return;
+
+       error = control_first_done(sdp);
+       if (error)
+               fs_err(sdp, "mount first_done error %d\n", error);
+}
+
 static void gdlm_unmount(struct gfs2_sbd *sdp)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
 
+       if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
+               goto release;
+
+       /* wait for gfs2_control_wq to be done with this mount */
+
+       spin_lock(&ls->ls_recover_spin);
+       set_bit(DFL_UNMOUNT, &ls->ls_recover_flags);
+       spin_unlock(&ls->ls_recover_spin);
+       flush_delayed_work_sync(&sdp->sd_control_work);
+
+       /* mounted_lock and control_lock will be purged in dlm recovery */
+release:
        if (ls->ls_dlm) {
                dlm_release_lockspace(ls->ls_dlm, 2);
                ls->ls_dlm = NULL;
        }
+
+       free_recover_size(ls);
 }
 
 static const match_table_t dlm_tokens = {
@@ -226,6 +1197,8 @@ static const match_table_t dlm_tokens = {
 const struct lm_lockops gfs2_dlm_ops = {
        .lm_proto_name = "lock_dlm",
        .lm_mount = gdlm_mount,
+       .lm_first_done = gdlm_first_done,
+       .lm_recovery_result = gdlm_recovery_result,
        .lm_unmount = gdlm_unmount,
        .lm_put_lock = gdlm_put_lock,
        .lm_lock = gdlm_lock,
index c150298e2d8e022d18e71ccec7d6c68d38864e10..a8d9bcd0e19cbbb5c050b89e963b00651d50acb1 100644 (file)
@@ -28,6 +28,8 @@
 #include "recovery.h"
 #include "dir.h"
 
+struct workqueue_struct *gfs2_control_wq;
+
 static struct shrinker qd_shrinker = {
        .shrink = gfs2_shrink_qd_memory,
        .seeks = DEFAULT_SEEKS,
@@ -146,12 +148,19 @@ static int __init init_gfs2_fs(void)
        if (!gfs_recovery_wq)
                goto fail_wq;
 
+       gfs2_control_wq = alloc_workqueue("gfs2_control",
+                              WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
+       if (!gfs2_control_wq)
+               goto fail_control;
+
        gfs2_register_debugfs();
 
        printk("GFS2 installed\n");
 
        return 0;
 
+fail_control:
+       destroy_workqueue(gfs_recovery_wq);
 fail_wq:
        unregister_filesystem(&gfs2meta_fs_type);
 fail_unregister:
@@ -195,6 +204,7 @@ static void __exit exit_gfs2_fs(void)
        unregister_filesystem(&gfs2_fs_type);
        unregister_filesystem(&gfs2meta_fs_type);
        destroy_workqueue(gfs_recovery_wq);
+       destroy_workqueue(gfs2_control_wq);
 
        rcu_barrier();
 
index fe72e79e6ff98ed66678d56c3b4be50243fd67eb..6aacf3f230a29d934347d2d2b130547769b2004e 100644 (file)
@@ -562,8 +562,12 @@ static void gfs2_others_may_mount(struct gfs2_sbd *sdp)
 {
        char *message = "FIRSTMOUNT=Done";
        char *envp[] = { message, NULL };
-       struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       ls->ls_first_done = 1;
+
+       fs_info(sdp, "first mount done, others may mount\n");
+
+       if (sdp->sd_lockstruct.ls_ops->lm_first_done)
+               sdp->sd_lockstruct.ls_ops->lm_first_done(sdp);
+
        kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
 }
 
@@ -944,7 +948,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
        struct gfs2_args *args = &sdp->sd_args;
        const char *proto = sdp->sd_proto_name;
        const char *table = sdp->sd_table_name;
-       const char *fsname;
        char *o, *options;
        int ret;
 
@@ -1004,21 +1007,12 @@ hostdata_error:
                }
        }
 
-       if (sdp->sd_args.ar_spectator)
-               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
-       else
-               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
-                        sdp->sd_lockstruct.ls_jid);
-
-       fsname = strchr(table, ':');
-       if (fsname)
-               fsname++;
        if (lm->lm_mount == NULL) {
                fs_info(sdp, "Now mounting FS...\n");
                complete_all(&sdp->sd_locking_init);
                return 0;
        }
-       ret = lm->lm_mount(sdp, fsname);
+       ret = lm->lm_mount(sdp, table);
        if (ret == 0)
                fs_info(sdp, "Joined cluster. Now mounting FS...\n");
        complete_all(&sdp->sd_locking_init);
@@ -1084,7 +1078,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
 
        if (sdp->sd_args.ar_spectator) {
                 sb->s_flags |= MS_RDONLY;
-               set_bit(SDF_NORECOVERY, &sdp->sd_flags);
+               set_bit(SDF_RORECOVERY, &sdp->sd_flags);
        }
        if (sdp->sd_args.ar_posix_acl)
                sb->s_flags |= MS_POSIXACL;
@@ -1124,6 +1118,8 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
        if (error)
                goto fail;
 
+       snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s", sdp->sd_table_name);
+
        gfs2_create_debugfs_file(sdp);
 
        error = gfs2_sys_fs_add(sdp);
@@ -1160,6 +1156,13 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
                goto fail_sb;
        }
 
+       if (sdp->sd_args.ar_spectator)
+               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s",
+                        sdp->sd_table_name);
+       else
+               snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u",
+                        sdp->sd_table_name, sdp->sd_lockstruct.ls_jid);
+
        error = init_inodes(sdp, DO);
        if (error)
                goto fail_sb;
index f2a02edcac8f43e9de1dd22fd4c72ac7347f39a5..963b2d75200c7fc5ae62591f458133540178db30 100644 (file)
@@ -436,12 +436,16 @@ static void gfs2_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
        char env_status[20];
        char *envp[] = { env_jid, env_status, NULL };
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+
         ls->ls_recover_jid_done = jid;
         ls->ls_recover_jid_status = message;
        sprintf(env_jid, "JID=%d", jid);
        sprintf(env_status, "RECOVERY=%s",
                message == LM_RD_SUCCESS ? "Done" : "Failed");
         kobject_uevent_env(&sdp->sd_kobj, KOBJ_CHANGE, envp);
+
+       if (sdp->sd_lockstruct.ls_ops->lm_recovery_result)
+               sdp->sd_lockstruct.ls_ops->lm_recovery_result(sdp, jid, message);
 }
 
 void gfs2_recover_func(struct work_struct *work)
@@ -512,7 +516,9 @@ void gfs2_recover_func(struct work_struct *work)
                if (error)
                        goto fail_gunlock_ji;
 
-               if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
+               if (test_bit(SDF_RORECOVERY, &sdp->sd_flags)) {
+                       ro = 1;
+               } else if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
                        if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
                                ro = 1;
                } else {
@@ -577,6 +583,7 @@ fail_gunlock_j:
 
        fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
 fail:
+       jd->jd_recover_error = error;
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
 done:
        clear_bit(JDF_RECOVERY, &jd->jd_flags);
@@ -605,6 +612,6 @@ int gfs2_recover_journal(struct gfs2_jdesc *jd, bool wait)
                wait_on_bit(&jd->jd_flags, JDF_RECOVERY, gfs2_recovery_wait,
                            TASK_UNINTERRUPTIBLE);
 
-       return 0;
+       return wait ? jd->jd_recover_error : 0;
 }
 
index 22234627f684462b9c5bc2fbb6110b4496b2cc5a..981bfa32121a16c11c53fea23f0e734617755bfa 100644 (file)
@@ -1108,9 +1108,9 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 {
        struct gfs2_blkreserv *rs = ip->i_res;
 
-       gfs2_blkrsv_put(ip);
        if (rs->rs_rgd_gh.gh_gl)
                gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
+       gfs2_blkrsv_put(ip);
 }
 
 /**
index 443cabcfcd23f834f64bc800c6c4cd518a0e58db..d33172c291bad63064dba6eebdddc8daba16b3f6 100644 (file)
@@ -298,7 +298,7 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)
        ssize_t ret;
        int val = 0;
 
-       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))
+       if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))
                val = 1;
        ret = sprintf(buf, "%d\n", val);
        return ret;
@@ -313,9 +313,9 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
        val = simple_strtol(buf, NULL, 0);
 
        if (val == 1)
-               set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+               set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
        else if (val == 0) {
-               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags);
+               clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
                smp_mb__after_clear_bit();
                gfs2_glock_thaw(sdp);
        } else {
@@ -350,8 +350,8 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
                goto out;
        if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
                goto out;
-        sdp->sd_lockstruct.ls_first = first;
-        rv = 0;
+       sdp->sd_lockstruct.ls_first = first;
+       rv = 0;
 out:
         spin_unlock(&sdp->sd_jindex_spin);
         return rv ? rv : len;
@@ -360,19 +360,14 @@ out:
 static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       return sprintf(buf, "%d\n", ls->ls_first_done);
+       return sprintf(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));
 }
 
-static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
 {
-       unsigned jid;
        struct gfs2_jdesc *jd;
        int rv;
 
-       rv = sscanf(buf, "%u", &jid);
-       if (rv != 1)
-               return -EINVAL;
-
        rv = -ESHUTDOWN;
        spin_lock(&sdp->sd_jindex_spin);
        if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
@@ -389,6 +384,20 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
        }
 out:
        spin_unlock(&sdp->sd_jindex_spin);
+       return rv;
+}
+
+static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+       unsigned jid;
+       int rv;
+
+       rv = sscanf(buf, "%u", &jid);
+       if (rv != 1)
+               return -EINVAL;
+
+       rv = gfs2_recover_set(sdp, jid);
+
        return rv ? rv : len;
 }
 
index e94560e836d79d008eb33100e00826952cea6efb..79182d6ad6ac01c4cdae76f564c39626f4a7c287 100644 (file)
@@ -19,5 +19,7 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp);
 int gfs2_sys_init(void);
 void gfs2_sys_uninit(void);
 
+int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid);
+
 #endif /* __SYS_DOT_H__ */
 
index edf0a801446b3d83c4c1e0e04cf88e546317760e..427682ca9e48d3e6aeac2087100c40725a811e2c 100644 (file)
@@ -499,9 +499,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                if (!sbi->hidden_dir) {
                        mutex_lock(&sbi->vh_mutex);
                        sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
-                       hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
-                                          sbi->hidden_dir);
+                       if (!sbi->hidden_dir) {
+                               mutex_unlock(&sbi->vh_mutex);
+                               err = -ENOMEM;
+                               goto out_put_root;
+                       }
+                       err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
+                                                &str, sbi->hidden_dir);
                        mutex_unlock(&sbi->vh_mutex);
+                       if (err)
+                               goto out_put_hidden_dir;
 
                        hfsplus_mark_inode_dirty(sbi->hidden_dir,
                                                 HFSPLUS_I_CAT_DIRTY);
index e425ad9d049008fb23d8f65cf5c1a9147154f69c..1e85a7ac021759da6a3ad118b5c1734db0bd1cc0 100644 (file)
@@ -583,7 +583,8 @@ static int hugetlbfs_set_page_dirty(struct page *page)
 }
 
 static int hugetlbfs_migrate_page(struct address_space *mapping,
-                               struct page *newpage, struct page *page)
+                               struct page *newpage, struct page *page,
+                               enum migrate_mode mode)
 {
        int rc;
 
index 87535753ab04a70b4556b58d4f1443774305da7a..4fa4f0916af9047ef57d8db43315244d92fef427 100644 (file)
@@ -776,6 +776,8 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan)
        else
                __count_vm_events(PGINODESTEAL, reap);
        spin_unlock(&sb->s_inode_lru_lock);
+       if (current->reclaim_state)
+               current->reclaim_state->reclaimed_slab += reap;
 
        dispose_list(&freeable);
 }
index 68d704db787f108350f9cc47fd506628685399c7..5069b84751509e65bb9689c153ac87e36c26b843 100644 (file)
@@ -429,6 +429,12 @@ void jbd2_journal_commit_transaction(journal_t *journal)
 
        jbd_debug(3, "JBD2: commit phase 1\n");
 
+       /*
+        * Clear revoked flag to reflect there is no revoked buffers
+        * in the next transaction which is going to be started.
+        */
+       jbd2_clear_buffer_revoked_flags(journal);
+
        /*
         * Switch to a new revoke table.
         */
index 69fd93588118027961923d26685b8edecfe3c268..30b2867d6cc950cb7eeceeb528f18d073405117b 100644 (file)
  *   overwriting the new data.  We don't even need to clear the revoke
  *   bit here.
  *
+ * We cache revoke status of a buffer in the current transaction in b_states
+ * bits.  As the name says, revokevalid flag indicates that the cached revoke
+ * status of a buffer is valid and we can rely on the cached status.
+ *
  * Revoke information on buffers is a tri-state value:
  *
  * RevokeValid clear:  no cached revoke status, need to look it up
@@ -478,6 +482,36 @@ int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
        return did_revoke;
 }
 
+/*
+ * journal_clear_revoked_flag clears revoked flag of buffers in
+ * revoke table to reflect there is no revoked buffers in the next
+ * transaction which is going to be started.
+ */
+void jbd2_clear_buffer_revoked_flags(journal_t *journal)
+{
+       struct jbd2_revoke_table_s *revoke = journal->j_revoke;
+       int i = 0;
+
+       for (i = 0; i < revoke->hash_size; i++) {
+               struct list_head *hash_list;
+               struct list_head *list_entry;
+               hash_list = &revoke->hash_table[i];
+
+               list_for_each(list_entry, hash_list) {
+                       struct jbd2_revoke_record_s *record;
+                       struct buffer_head *bh;
+                       record = (struct jbd2_revoke_record_s *)list_entry;
+                       bh = __find_get_block(journal->j_fs_dev,
+                                             record->blocknr,
+                                             journal->j_blocksize);
+                       if (bh) {
+                               clear_buffer_revoked(bh);
+                               __brelse(bh);
+                       }
+               }
+       }
+}
+
 /* journal_switch_revoke table select j_revoke for next transaction
  * we do not want to suspend any processing until all revokes are
  * written -bzzz
index a0e41a4c080e9b2d3a51f5b4c6404cb8b8bc9c2b..35ae096bed5dca819181c1d7bfa94194fa3b0c01 100644 (file)
@@ -517,12 +517,13 @@ void jbd2_journal_lock_updates(journal_t *journal)
                        break;
 
                spin_lock(&transaction->t_handle_lock);
+               prepare_to_wait(&journal->j_wait_updates, &wait,
+                               TASK_UNINTERRUPTIBLE);
                if (!atomic_read(&transaction->t_updates)) {
                        spin_unlock(&transaction->t_handle_lock);
+                       finish_wait(&journal->j_wait_updates, &wait);
                        break;
                }
-               prepare_to_wait(&journal->j_wait_updates, &wait,
-                               TASK_UNINTERRUPTIBLE);
                spin_unlock(&transaction->t_handle_lock);
                write_unlock(&journal->j_state_lock);
                schedule();
index 43926add945b0a4a88625b23062e1cdd393a743d..54cea8ad5a76ff6f8796030c4f42ad7f70d12ca6 100644 (file)
@@ -339,7 +339,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
        dprintk("%s enter. slotid %d seqid %d\n",
                __func__, args->csa_slotid, args->csa_sequenceid);
 
-       if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS)
+       if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS)
                return htonl(NFS4ERR_BADSLOT);
 
        slot = tbl->slots + args->csa_slotid;
index 873bf00d51a2b8d000ef9d45bdb9f139186ec6e5..277dfaf2e99ac063dee95c4eddbfb8bb9afbfe1e 100644 (file)
@@ -84,7 +84,7 @@ retry:
 /*
  * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
  */
-static int nfs4_disable_idmapping = 0;
+static int nfs4_disable_idmapping = 1;
 
 /*
  * RPC cruft for NFS
@@ -185,7 +185,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        clp->cl_minorversion = cl_init->minorversion;
        clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
 #endif
-       cred = rpc_lookup_machine_cred();
+       cred = rpc_lookup_machine_cred("*");
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
        nfs_fscache_get_client_cookie(clp);
@@ -250,6 +250,11 @@ static void pnfs_init_server(struct nfs_server *server)
        rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
 }
 
+static void nfs4_destroy_server(struct nfs_server *server)
+{
+       nfs4_purge_state_owners(server);
+}
+
 #else
 static void nfs4_shutdown_client(struct nfs_client *clp)
 {
@@ -1065,6 +1070,7 @@ static struct nfs_server *nfs_alloc_server(void)
        INIT_LIST_HEAD(&server->master_link);
        INIT_LIST_HEAD(&server->delegations);
        INIT_LIST_HEAD(&server->layouts);
+       INIT_LIST_HEAD(&server->state_owners_lru);
 
        atomic_set(&server->active, 0);
 
@@ -1538,6 +1544,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
 
        nfs_server_insert_lists(server);
        server->mount_time = jiffies;
+       server->destroy = nfs4_destroy_server;
 out:
        nfs_free_fattr(fattr);
        return error;
@@ -1719,6 +1726,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
 
        /* Copy data from the source */
        server->nfs_client = source->nfs_client;
+       server->destroy = source->destroy;
        atomic_inc(&server->nfs_client->cl_count);
        nfs_server_copy_userdata(server, source);
 
index 606ef0f20aed58d7e67b33ab2696382ece03c6f5..c43a452f7da2e70c084bddb7dfe6415d194bdf3e 100644 (file)
@@ -272,13 +272,13 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                        datasync);
 
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret)
-               return ret;
        mutex_lock(&inode->i_mutex);
 
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
        have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
+       if (status >= 0 && ret < 0)
+               status = ret;
        have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        if (have_error)
                ret = xchg(&ctx->error, 0);
index 47d1c6ff2d8e845625e60fbcf3ba5cf65786282e..2c05f1991e1e1c3664c8ffb9f0159687b53b8449 100644 (file)
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/nfs_idmap.h>
+#include <linux/nfs_fs.h>
+
+/**
+ * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
+ * @fattr: fully initialised struct nfs_fattr
+ * @owner_name: owner name string cache
+ * @group_name: group name string cache
+ */
+void nfs_fattr_init_names(struct nfs_fattr *fattr,
+               struct nfs4_string *owner_name,
+               struct nfs4_string *group_name)
+{
+       fattr->owner_name = owner_name;
+       fattr->group_name = group_name;
+}
+
+static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr)
+{
+       fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME;
+       kfree(fattr->owner_name->data);
+}
+
+static void nfs_fattr_free_group_name(struct nfs_fattr *fattr)
+{
+       fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME;
+       kfree(fattr->group_name->data);
+}
+
+static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr)
+{
+       struct nfs4_string *owner = fattr->owner_name;
+       __u32 uid;
+
+       if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
+               return false;
+       if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
+               fattr->uid = uid;
+               fattr->valid |= NFS_ATTR_FATTR_OWNER;
+       }
+       return true;
+}
+
+static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr)
+{
+       struct nfs4_string *group = fattr->group_name;
+       __u32 gid;
+
+       if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
+               return false;
+       if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
+               fattr->gid = gid;
+               fattr->valid |= NFS_ATTR_FATTR_GROUP;
+       }
+       return true;
+}
+
+/**
+ * nfs_fattr_free_names - free up the NFSv4 owner and group strings
+ * @fattr: a fully initialised nfs_fattr structure
+ */
+void nfs_fattr_free_names(struct nfs_fattr *fattr)
+{
+       if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)
+               nfs_fattr_free_owner_name(fattr);
+       if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)
+               nfs_fattr_free_group_name(fattr);
+}
+
+/**
+ * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free
+ * @server: pointer to the filesystem nfs_server structure
+ * @fattr: a fully initialised nfs_fattr structure
+ *
+ * This helper maps the cached NFSv4 owner/group strings in fattr into
+ * their numeric uid/gid equivalents, and then frees the cached strings.
+ */
+void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr)
+{
+       if (nfs_fattr_map_owner_name(server, fattr))
+               nfs_fattr_free_owner_name(fattr);
+       if (nfs_fattr_map_group_name(server, fattr))
+               nfs_fattr_free_group_name(fattr);
+}
 
 static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
 {
index 81db25e92e108133ed7995510a9ffe1e48e14137..25c3bfad7953645309272c324ba442680546eef3 100644 (file)
@@ -1020,6 +1020,8 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
        fattr->valid = 0;
        fattr->time_start = jiffies;
        fattr->gencount = nfs_inc_attr_generation_counter();
+       fattr->owner_name = NULL;
+       fattr->group_name = NULL;
 }
 
 struct nfs_fattr *nfs_alloc_fattr(void)
index 3f4d95751d52f3e152fc7f2dcb5d1a6d8fc2184b..8102db9b926c2eb56d9035126fa27b33058d711f 100644 (file)
@@ -307,6 +307,8 @@ extern void nfs_readdata_release(struct nfs_read_data *rdata);
 /* write.c */
 extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
                struct list_head *head);
+extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
+                                 struct inode *inode, int ioflags);
 extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_writedata_release(struct nfs_write_data *wdata);
 extern void nfs_commit_free(struct nfs_write_data *p);
@@ -330,7 +332,7 @@ void nfs_commit_release_pages(struct nfs_write_data *data);
 
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
-               struct page *, struct page *);
+               struct page *, struct page *, enum migrate_mode);
 #else
 #define nfs_migrate_page NULL
 #endif
index 693ae22f873194d0c36adc384d7cb05fefbc8b6c..4d7d0aedc101831ecb3b10cf345f0e18e7ca56ad 100644 (file)
@@ -94,6 +94,8 @@ struct nfs_unique_id {
 struct nfs4_state_owner {
        struct nfs_unique_id so_owner_id;
        struct nfs_server    *so_server;
+       struct list_head     so_lru;
+       unsigned long        so_expires;
        struct rb_node       so_server_node;
 
        struct rpc_cred      *so_cred;   /* Associated cred */
@@ -319,6 +321,7 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session)
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
 extern void nfs4_put_state_owner(struct nfs4_state_owner *);
+extern void nfs4_purge_state_owners(struct nfs_server *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_close_state(struct nfs4_state *, fmode_t);
index a62d36b9a99ebb912286a8fcf87f425e6b06f203..71ec08617e23820b8e3d11ee8e47a4217ee52e55 100644 (file)
@@ -49,13 +49,14 @@ filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
                            loff_t offset)
 {
        u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
-       u64 tmp;
+       u64 stripe_no;
+       u32 rem;
 
        offset -= flseg->pattern_offset;
-       tmp = offset;
-       do_div(tmp, stripe_width);
+       stripe_no = div_u64(offset, stripe_width);
+       div_u64_rem(offset, flseg->stripe_unit, &rem);
 
-       return tmp * flseg->stripe_unit + do_div(offset, flseg->stripe_unit);
+       return stripe_no * flseg->stripe_unit + rem;
 }
 
 /* This function is used by the layout driver to calculate the
index dcda0ba7af6034b6c8d983082ee00ffbbb4d6cde..75366dc89686d88655c6569f4840a1651ca98690 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/namei.h>
 #include <linux/mount.h>
 #include <linux/module.h>
+#include <linux/nfs_idmap.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
 #include <linux/utsname.h>
@@ -364,9 +365,8 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
  * Must be called while holding tbl->slot_tbl_lock
  */
 static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
+nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
 {
-       int free_slotid = free_slot - tbl->slots;
        int slotid = free_slotid;
 
        BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
@@ -431,7 +431,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        }
 
        spin_lock(&tbl->slot_tbl_lock);
-       nfs4_free_slot(tbl, res->sr_slot);
+       nfs4_free_slot(tbl, res->sr_slot - tbl->slots);
        nfs4_check_drain_fc_complete(res->sr_session);
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
@@ -554,13 +554,10 @@ int nfs41_setup_sequence(struct nfs4_session *session,
        spin_lock(&tbl->slot_tbl_lock);
        if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
            !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
-               /*
-                * The state manager will wait until the slot table is empty.
-                * Schedule the reset thread
-                */
+               /* The state manager will wait until the slot table is empty */
                rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
                spin_unlock(&tbl->slot_tbl_lock);
-               dprintk("%s Schedule Session Reset\n", __func__);
+               dprintk("%s session is draining\n", __func__);
                return -EAGAIN;
        }
 
@@ -765,6 +762,8 @@ struct nfs4_opendata {
        struct nfs_openres o_res;
        struct nfs_open_confirmargs c_arg;
        struct nfs_open_confirmres c_res;
+       struct nfs4_string owner_name;
+       struct nfs4_string group_name;
        struct nfs_fattr f_attr;
        struct nfs_fattr dir_attr;
        struct dentry *dir;
@@ -788,6 +787,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.server = p->o_arg.server;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init(&p->dir_attr);
+       nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
 }
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
@@ -819,6 +819,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.name = &dentry->d_name;
        p->o_arg.server = server;
        p->o_arg.bitmask = server->attr_bitmask;
+       p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
        p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
        if (flags & O_CREAT) {
                u32 *s;
@@ -855,6 +856,7 @@ static void nfs4_opendata_free(struct kref *kref)
        dput(p->dir);
        dput(p->dentry);
        nfs_sb_deactive(sb);
+       nfs_fattr_free_names(&p->f_attr);
        kfree(p);
 }
 
@@ -1579,6 +1581,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
        if (status != 0 || !data->rpc_done)
                return status;
 
+       nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
+
        nfs_refresh_inode(dir, o_res->dir_attr);
 
        if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
@@ -1611,6 +1615,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
                return status;
        }
 
+       nfs_fattr_map_and_free_names(server, &data->f_attr);
+
        if (o_arg->open_flags & O_CREAT) {
                update_changeattr(dir, &o_res->cinfo);
                nfs_post_op_update_inode(dir, o_res->dir_attr);
@@ -3431,19 +3437,6 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
  */
 #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
 
-static void buf_to_pages(const void *buf, size_t buflen,
-               struct page **pages, unsigned int *pgbase)
-{
-       const void *p = buf;
-
-       *pgbase = offset_in_page(buf);
-       p -= *pgbase;
-       while (p < buf + buflen) {
-               *(pages++) = virt_to_page(p);
-               p += PAGE_CACHE_SIZE;
-       }
-}
-
 static int buf_to_pages_noslab(const void *buf, size_t buflen,
                struct page **pages, unsigned int *pgbase)
 {
@@ -3540,9 +3533,19 @@ out:
        nfs4_set_cached_acl(inode, acl);
 }
 
+/*
+ * The getxattr API returns the required buffer length when called with a
+ * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
+ * the required buf.  On a NULL buf, we send a page of data to the server
+ * guessing that the ACL request can be serviced by a page. If so, we cache
+ * up to the page of ACL data, and the 2nd call to getxattr is serviced by
+ * the cache. If not so, we throw away the page, and cache the required
+ * length. The next getxattr call will then produce another round trip to
+ * the server, this time with the input buf of the required size.
+ */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-       struct page *pages[NFS4ACL_MAXPAGES];
+       struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
                .acl_pages = pages,
@@ -3557,41 +3560,60 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       struct page *localpage = NULL;
-       int ret;
+       int ret = -ENOMEM, npages, i, acl_len = 0;
 
-       if (buflen < PAGE_SIZE) {
-               /* As long as we're doing a round trip to the server anyway,
-                * let's be prepared for a page of acl data. */
-               localpage = alloc_page(GFP_KERNEL);
-               resp_buf = page_address(localpage);
-               if (localpage == NULL)
-                       return -ENOMEM;
-               args.acl_pages[0] = localpage;
-               args.acl_pgbase = 0;
-               args.acl_len = PAGE_SIZE;
-       } else {
-               resp_buf = buf;
-               buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);
+       npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       /* As long as we're doing a round trip to the server anyway,
+        * let's be prepared for a page of acl data. */
+       if (npages == 0)
+               npages = 1;
+
+       for (i = 0; i < npages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL);
+               if (!pages[i])
+                       goto out_free;
        }
-       ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
+       if (npages > 1) {
+               /* for decoding across pages */
+               args.acl_scratch = alloc_page(GFP_KERNEL);
+               if (!args.acl_scratch)
+                       goto out_free;
+       }
+       args.acl_len = npages * PAGE_SIZE;
+       args.acl_pgbase = 0;
+       /* Let decode_getfacl know not to fail if the ACL data is larger than
+        * the page we send as a guess */
+       if (buf == NULL)
+               res.acl_flags |= NFS4_ACL_LEN_REQUEST;
+       resp_buf = page_address(pages[0]);
+
+       dprintk("%s  buf %p buflen %ld npages %d args.acl_len %ld\n",
+               __func__, buf, buflen, npages, args.acl_len);
+       ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
+                            &msg, &args.seq_args, &res.seq_res, 0);
        if (ret)
                goto out_free;
-       if (res.acl_len > args.acl_len)
-               nfs4_write_cached_acl(inode, NULL, res.acl_len);
+
+       acl_len = res.acl_len - res.acl_data_offset;
+       if (acl_len > args.acl_len)
+               nfs4_write_cached_acl(inode, NULL, acl_len);
        else
-               nfs4_write_cached_acl(inode, resp_buf, res.acl_len);
+               nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset,
+                                     acl_len);
        if (buf) {
                ret = -ERANGE;
-               if (res.acl_len > buflen)
+               if (acl_len > buflen)
                        goto out_free;
-               if (localpage)
-                       memcpy(buf, resp_buf, res.acl_len);
+               _copy_from_pages(buf, pages, res.acl_data_offset,
+                               res.acl_len);
        }
-       ret = res.acl_len;
+       ret = acl_len;
 out_free:
-       if (localpage)
-               __free_page(localpage);
+       for (i = 0; i < npages; i++)
+               if (pages[i])
+                       __free_page(pages[i]);
+       if (args.acl_scratch)
+               __free_page(args.acl_scratch);
        return ret;
 }
 
@@ -3622,6 +3644,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
                nfs_zap_acl_cache(inode);
        ret = nfs4_read_cached_acl(inode, buf, buflen);
        if (ret != -ENOENT)
+               /* -ENOENT is returned if there is no ACL or if there is an ACL
+                * but no cached acl data, just the acl length */
                return ret;
        return nfs4_get_acl_uncached(inode, buf, buflen);
 }
@@ -5022,23 +5046,6 @@ out:
        return ret;
 }
 
-/*
- * Reset the forechannel and backchannel slot tables
- */
-static int nfs4_reset_slot_tables(struct nfs4_session *session)
-{
-       int status;
-
-       status = nfs4_reset_slot_table(&session->fc_slot_table,
-                       session->fc_attrs.max_reqs, 1);
-       if (status)
-               return status;
-
-       status = nfs4_reset_slot_table(&session->bc_slot_table,
-                       session->bc_attrs.max_reqs, 0);
-       return status;
-}
-
 /* Destroy the slot table */
 static void nfs4_destroy_slot_tables(struct nfs4_session *session)
 {
@@ -5084,29 +5091,35 @@ out:
 }
 
 /*
- * Initialize the forechannel and backchannel tables
+ * Initialize or reset the forechannel and backchannel tables
  */
-static int nfs4_init_slot_tables(struct nfs4_session *session)
+static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
 {
        struct nfs4_slot_table *tbl;
-       int status = 0;
+       int status;
 
-       tbl = &session->fc_slot_table;
+       dprintk("--> %s\n", __func__);
+       /* Fore channel */
+       tbl = &ses->fc_slot_table;
        if (tbl->slots == NULL) {
-               status = nfs4_init_slot_table(tbl,
-                               session->fc_attrs.max_reqs, 1);
+               status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
+               if (status) /* -ENOMEM */
+                       return status;
+       } else {
+               status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
                if (status)
                        return status;
        }
-
-       tbl = &session->bc_slot_table;
+       /* Back channel */
+       tbl = &ses->bc_slot_table;
        if (tbl->slots == NULL) {
-               status = nfs4_init_slot_table(tbl,
-                               session->bc_attrs.max_reqs, 0);
+               status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
                if (status)
-                       nfs4_destroy_slot_tables(session);
-       }
-
+                       /* Fore and back channel share a connection so get
+                        * both slot tables or neither */
+                       nfs4_destroy_slot_tables(ses);
+       } else
+               status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
        return status;
 }
 
@@ -5294,13 +5307,9 @@ int nfs4_proc_create_session(struct nfs_client *clp)
        if (status)
                goto out;
 
-       /* Init and reset the fore channel */
-       status = nfs4_init_slot_tables(session);
-       dprintk("slot table initialization returned %d\n", status);
-       if (status)
-               goto out;
-       status = nfs4_reset_slot_tables(session);
-       dprintk("slot table reset returned %d\n", status);
+       /* Init or reset the session slot tables */
+       status = nfs4_setup_session_slot_tables(session);
+       dprintk("slot table setup returned %d\n", status);
        if (status)
                goto out;
 
index 6a7107ae6b72d407bf95c4953bd1017e4704f63f..a53f33b4ac3a5cf333afe80b358f27fe4130289f 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/ratelimit.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include "nfs4_fs.h"
 #include "callback.h"
@@ -377,31 +378,24 @@ nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
 {
        struct rb_node **p = &server->state_owners.rb_node,
                       *parent = NULL;
-       struct nfs4_state_owner *sp, *res = NULL;
+       struct nfs4_state_owner *sp;
 
        while (*p != NULL) {
                parent = *p;
                sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
 
-               if (server < sp->so_server) {
-                       p = &parent->rb_left;
-                       continue;
-               }
-               if (server > sp->so_server) {
-                       p = &parent->rb_right;
-                       continue;
-               }
                if (cred < sp->so_cred)
                        p = &parent->rb_left;
                else if (cred > sp->so_cred)
                        p = &parent->rb_right;
                else {
+                       if (!list_empty(&sp->so_lru))
+                               list_del_init(&sp->so_lru);
                        atomic_inc(&sp->so_count);
-                       res = sp;
-                       break;
+                       return sp;
                }
        }
-       return res;
+       return NULL;
 }
 
 static struct nfs4_state_owner *
@@ -421,6 +415,8 @@ nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
                else if (new->so_cred > sp->so_cred)
                        p = &parent->rb_right;
                else {
+                       if (!list_empty(&sp->so_lru))
+                               list_del_init(&sp->so_lru);
                        atomic_inc(&sp->so_count);
                        return sp;
                }
@@ -462,6 +458,7 @@ nfs4_alloc_state_owner(void)
        spin_lock_init(&sp->so_sequence.lock);
        INIT_LIST_HEAD(&sp->so_sequence.list);
        atomic_set(&sp->so_count, 1);
+       INIT_LIST_HEAD(&sp->so_lru);
        return sp;
 }
 
@@ -479,6 +476,38 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
        }
 }
 
+static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
+{
+       rpc_destroy_wait_queue(&sp->so_sequence.wait);
+       put_rpccred(sp->so_cred);
+       kfree(sp);
+}
+
+static void nfs4_gc_state_owners(struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_state_owner *sp, *tmp;
+       unsigned long time_min, time_max;
+       LIST_HEAD(doomed);
+
+       spin_lock(&clp->cl_lock);
+       time_max = jiffies;
+       time_min = (long)time_max - (long)clp->cl_lease_time;
+       list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
+               /* NB: LRU is sorted so that oldest is at the head */
+               if (time_in_range(sp->so_expires, time_min, time_max))
+                       break;
+               list_move(&sp->so_lru, &doomed);
+               nfs4_remove_state_owner_locked(sp);
+       }
+       spin_unlock(&clp->cl_lock);
+
+       list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
+               list_del(&sp->so_lru);
+               nfs4_free_state_owner(sp);
+       }
+}
+
 /**
  * nfs4_get_state_owner - Look up a state owner given a credential
  * @server: nfs_server to search
@@ -496,10 +525,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
        sp = nfs4_find_state_owner_locked(server, cred);
        spin_unlock(&clp->cl_lock);
        if (sp != NULL)
-               return sp;
+               goto out;
        new = nfs4_alloc_state_owner();
        if (new == NULL)
-               return NULL;
+               goto out;
        new->so_server = server;
        new->so_cred = cred;
        spin_lock(&clp->cl_lock);
@@ -511,26 +540,58 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
                rpc_destroy_wait_queue(&new->so_sequence.wait);
                kfree(new);
        }
+out:
+       nfs4_gc_state_owners(server);
        return sp;
 }
 
 /**
  * nfs4_put_state_owner - Release a nfs4_state_owner
  * @sp: state owner data to release
- *
  */
 void nfs4_put_state_owner(struct nfs4_state_owner *sp)
 {
-       struct nfs_client *clp = sp->so_server->nfs_client;
-       struct rpc_cred *cred = sp->so_cred;
+       struct nfs_server *server = sp->so_server;
+       struct nfs_client *clp = server->nfs_client;
 
        if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
                return;
-       nfs4_remove_state_owner_locked(sp);
+
+       if (!RB_EMPTY_NODE(&sp->so_server_node)) {
+               sp->so_expires = jiffies;
+               list_add_tail(&sp->so_lru, &server->state_owners_lru);
+               spin_unlock(&clp->cl_lock);
+       } else {
+               nfs4_remove_state_owner_locked(sp);
+               spin_unlock(&clp->cl_lock);
+               nfs4_free_state_owner(sp);
+       }
+}
+
+/**
+ * nfs4_purge_state_owners - Release all cached state owners
+ * @server: nfs_server with cached state owners to release
+ *
+ * Called at umount time.  Remaining state owners will be on
+ * the LRU with ref count of zero.
+ */
+void nfs4_purge_state_owners(struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_state_owner *sp, *tmp;
+       LIST_HEAD(doomed);
+
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
+               list_move(&sp->so_lru, &doomed);
+               nfs4_remove_state_owner_locked(sp);
+       }
        spin_unlock(&clp->cl_lock);
-       rpc_destroy_wait_queue(&sp->so_sequence.wait);
-       put_rpccred(cred);
-       kfree(sp);
+
+       list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
+               list_del(&sp->so_lru);
+               nfs4_free_state_owner(sp);
+       }
 }
 
 static struct nfs4_state *
@@ -1402,6 +1463,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
 restart:
        rcu_read_lock();
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
+               nfs4_purge_state_owners(server);
                spin_lock(&clp->cl_lock);
                for (pos = rb_first(&server->state_owners);
                     pos != NULL;
index e6161b213ed122d04dfe3e5fe7dfdc25e80a2c2e..95e92e438407c8ea39d2a6a717faeb919dd14819 100644 (file)
@@ -2298,7 +2298,7 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_getfh(xdr, &hdr);
        encode_getfattr(xdr, args->bitmask, &hdr);
        encode_restorefh(xdr, &hdr);
-       encode_getfattr(xdr, args->bitmask, &hdr);
+       encode_getfattr(xdr, args->dir_bitmask, &hdr);
        encode_nops(&hdr);
 }
 
@@ -2517,11 +2517,13 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fh, &hdr);
-       replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
+       replen = hdr.replen + op_decode_hdr_maxsz + 1;
        encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
                args->acl_pages, args->acl_pgbase, args->acl_len);
+       xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE);
+
        encode_nops(&hdr);
 }
 
@@ -3790,7 +3792,8 @@ out_overflow:
 }
 
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
-               const struct nfs_server *server, uint32_t *uid, int may_sleep)
+               const struct nfs_server *server, uint32_t *uid,
+               struct nfs4_string *owner_name)
 {
        uint32_t len;
        __be32 *p;
@@ -3807,8 +3810,12 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
                p = xdr_inline_decode(xdr, len);
                if (unlikely(!p))
                        goto out_overflow;
-               if (!may_sleep) {
-                       /* do nothing */
+               if (owner_name != NULL) {
+                       owner_name->data = kmemdup(p, len, GFP_NOWAIT);
+                       if (owner_name->data != NULL) {
+                               owner_name->len = len;
+                               ret = NFS_ATTR_FATTR_OWNER_NAME;
+                       }
                } else if (len < XDR_MAX_NETOBJ) {
                        if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
                                ret = NFS_ATTR_FATTR_OWNER;
@@ -3828,7 +3835,8 @@ out_overflow:
 }
 
 static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
-               const struct nfs_server *server, uint32_t *gid, int may_sleep)
+               const struct nfs_server *server, uint32_t *gid,
+               struct nfs4_string *group_name)
 {
        uint32_t len;
        __be32 *p;
@@ -3845,8 +3853,12 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
                p = xdr_inline_decode(xdr, len);
                if (unlikely(!p))
                        goto out_overflow;
-               if (!may_sleep) {
-                       /* do nothing */
+               if (group_name != NULL) {
+                       group_name->data = kmemdup(p, len, GFP_NOWAIT);
+                       if (group_name->data != NULL) {
+                               group_name->len = len;
+                               ret = NFS_ATTR_FATTR_GROUP_NAME;
+                       }
                } else if (len < XDR_MAX_NETOBJ) {
                        if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
                                ret = NFS_ATTR_FATTR_GROUP;
@@ -4283,7 +4295,7 @@ xdr_error:
 
 static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                struct nfs_fattr *fattr, struct nfs_fh *fh,
-               const struct nfs_server *server, int may_sleep)
+               const struct nfs_server *server)
 {
        int status;
        umode_t fmode = 0;
@@ -4350,12 +4362,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep);
+       status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, fattr->owner_name);
        if (status < 0)
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep);
+       status = decode_attr_group(xdr, bitmap, server, &fattr->gid, fattr->group_name);
        if (status < 0)
                goto xdr_error;
        fattr->valid |= status;
@@ -4396,7 +4408,7 @@ xdr_error:
 }
 
 static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
-               struct nfs_fh *fh, const struct nfs_server *server, int may_sleep)
+               struct nfs_fh *fh, const struct nfs_server *server)
 {
        __be32 *savep;
        uint32_t attrlen,
@@ -4415,7 +4427,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
        if (status < 0)
                goto xdr_error;
 
-       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep);
+       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server);
        if (status < 0)
                goto xdr_error;
 
@@ -4426,9 +4438,9 @@ xdr_error:
 }
 
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
-               const struct nfs_server *server, int may_sleep)
+               const struct nfs_server *server)
 {
-       return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep);
+       return decode_getfattr_generic(xdr, fattr, NULL, server);
 }
 
 /*
@@ -4957,17 +4969,18 @@ decode_restorefh(struct xdr_stream *xdr)
 }
 
 static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
-               size_t *acl_len)
+                        struct nfs_getaclres *res)
 {
-       __be32 *savep;
+       __be32 *savep, *bm_p;
        uint32_t attrlen,
                 bitmap[3] = {0};
        struct kvec *iov = req->rq_rcv_buf.head;
        int status;
 
-       *acl_len = 0;
+       res->acl_len = 0;
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
                goto out;
+       bm_p = xdr->p;
        if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
                goto out;
        if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
@@ -4979,18 +4992,30 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                size_t hdrlen;
                u32 recvd;
 
+               /* The bitmap (xdr len + bitmaps) and the attr xdr len words
+                * are stored with the acl data to handle the problem of
+                * variable length bitmaps.*/
+               xdr->p = bm_p;
+               res->acl_data_offset = be32_to_cpup(bm_p) + 2;
+               res->acl_data_offset <<= 2;
+
                /* We ignore &savep and don't do consistency checks on
                 * the attr length.  Let userspace figure it out.... */
                hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
+               attrlen += res->acl_data_offset;
                recvd = req->rq_rcv_buf.len - hdrlen;
                if (attrlen > recvd) {
-                       dprintk("NFS: server cheating in getattr"
-                                       " acl reply: attrlen %u > recvd %u\n",
+                       if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
+                               /* getxattr interface called with a NULL buf */
+                               res->acl_len = attrlen;
+                               goto out;
+                       }
+                       dprintk("NFS: acl reply: attrlen %u > recvd %u\n",
                                        attrlen, recvd);
                        return -EINVAL;
                }
                xdr_read_pages(xdr, attrlen);
-               *acl_len = attrlen;
+               res->acl_len = attrlen;
        } else
                status = -EOPNOTSUPP;
 
@@ -5696,8 +5721,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
        status = decode_open_downgrade(xdr, res);
        if (status != 0)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -5723,8 +5747,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_access(xdr, res);
        if (status != 0)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -5753,8 +5776,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_getfh(xdr, res->fh);
        if (status)
                goto out;
-       status = decode_getfattr(xdr, res->fattr, res->server
-                       ,!RPC_IS_ASYNC(rqstp->rq_task));
+       status = decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -5780,8 +5802,7 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
                goto out;
        status = decode_getfh(xdr, res->fh);
        if (status == 0)
-               status = decode_getfattr(xdr, res->fattr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task));
+               status = decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -5807,8 +5828,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_remove(xdr, &res->cinfo);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->dir_attr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->dir_attr, res->server);
 out:
        return status;
 }
@@ -5841,14 +5861,12 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        /* Current FH is target directory */
-       if (decode_getfattr(xdr, res->new_fattr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
+       if (decode_getfattr(xdr, res->new_fattr, res->server))
                goto out;
        status = decode_restorefh(xdr);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->old_fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->old_fattr, res->server);
 out:
        return status;
 }
@@ -5884,14 +5902,12 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
         * Note order: OP_LINK leaves the directory as the current
         *             filehandle.
         */
-       if (decode_getfattr(xdr, res->dir_attr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
+       if (decode_getfattr(xdr, res->dir_attr, res->server))
                goto out;
        status = decode_restorefh(xdr);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -5923,14 +5939,12 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_getfh(xdr, res->fh);
        if (status)
                goto out;
-       if (decode_getfattr(xdr, res->fattr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
+       if (decode_getfattr(xdr, res->fattr, res->server))
                goto out;
        status = decode_restorefh(xdr);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->dir_fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->dir_fattr, res->server);
 out:
        return status;
 }
@@ -5962,8 +5976,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_putfh(xdr);
        if (status)
                goto out;
-       status = decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       status = decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6028,7 +6041,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        status = decode_putfh(xdr);
        if (status)
                goto out;
-       status = decode_getacl(xdr, rqstp, &res->acl_len);
+       status = decode_getacl(xdr, rqstp, res);
 
 out:
        return status;
@@ -6061,8 +6074,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
         *      an ESTALE error. Shouldn't be a problem,
         *      though, since fattr->valid will remain unset.
         */
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6093,13 +6105,11 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
                goto out;
        if (decode_getfh(xdr, &res->fh) != 0)
                goto out;
-       if (decode_getfattr(xdr, res->f_attr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
+       if (decode_getfattr(xdr, res->f_attr, res->server) != 0)
                goto out;
        if (decode_restorefh(xdr) != 0)
                goto out;
-       decode_getfattr(xdr, res->dir_attr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->dir_attr, res->server);
 out:
        return status;
 }
@@ -6147,8 +6157,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
        status = decode_open(xdr, res);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->f_attr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->f_attr, res->server);
 out:
        return status;
 }
@@ -6175,8 +6184,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
        status = decode_setattr(xdr);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6356,8 +6364,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        if (res->fattr)
-               decode_getfattr(xdr, res->fattr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task));
+               decode_getfattr(xdr, res->fattr, res->server);
        if (!status)
                status = res->count;
 out:
@@ -6386,8 +6393,7 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
        if (status)
                goto out;
        if (res->fattr)
-               decode_getfattr(xdr, res->fattr, res->server,
-                               !RPC_IS_ASYNC(rqstp->rq_task));
+               decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6546,8 +6552,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
        status = decode_delegreturn(xdr);
        if (status != 0)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6576,8 +6581,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
                goto out;
        xdr_enter_page(xdr, PAGE_SIZE);
        status = decode_getfattr(xdr, &res->fs_locations->fattr,
-                                res->fs_locations->server,
-                                !RPC_IS_ASYNC(req->rq_task));
+                                res->fs_locations->server);
 out:
        return status;
 }
@@ -6826,8 +6830,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
        status = decode_layoutcommit(xdr, rqstp, res);
        if (status)
                goto out;
-       decode_getfattr(xdr, res->fattr, res->server,
-                       !RPC_IS_ASYNC(rqstp->rq_task));
+       decode_getfattr(xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -6958,7 +6961,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                goto out_overflow;
 
        if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
-                                       entry->server, 1) < 0)
+                                       entry->server) < 0)
                goto out_overflow;
        if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
                entry->ino = entry->fattr->mounted_on_fileid;
index c807ab93140e519135f76ab88318a6cb68212978..55d01280a6098264cc5e6d7133c72347e392d109 100644 (file)
@@ -551,7 +551,8 @@ static const struct nfs_pageio_ops objio_pg_write_ops = {
 static struct pnfs_layoutdriver_type objlayout_type = {
        .id = LAYOUT_OSD2_OBJECTS,
        .name = "LAYOUT_OSD2_OBJECTS",
-       .flags                   = PNFS_LAYOUTRET_ON_SETATTR,
+       .flags                   = PNFS_LAYOUTRET_ON_SETATTR |
+                                  PNFS_LAYOUTRET_ON_ERROR,
 
        .alloc_layout_hdr        = objlayout_alloc_layout_hdr,
        .free_layout_hdr         = objlayout_free_layout_hdr,
index 72074e3a04f922705151e38a586e7af5f2611f4a..b3c29039f5b893e69058cd404547d218cfa8dff8 100644 (file)
@@ -254,6 +254,8 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
        oir->status = rdata->task.tk_status = status;
        if (status >= 0)
                rdata->res.count = status;
+       else
+               rdata->pnfs_error = status;
        objlayout_iodone(oir);
        /* must not use oir after this point */
 
@@ -334,6 +336,8 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync)
        if (status >= 0) {
                wdata->res.count = status;
                wdata->verf.committed = oir->committed;
+       } else {
+               wdata->pnfs_error = status;
        }
        objlayout_iodone(oir);
        /* must not use oir after this point */
index 8e672a2b2d693193e8ca7252d70c73578d739e0f..17149a4900653af5326dfd6e0490e6e439b1426f 100644 (file)
@@ -1166,6 +1166,33 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
 
+static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head)
+{
+       struct nfs_pageio_descriptor pgio;
+       LIST_HEAD(failed);
+
+       /* Resend all requests through the MDS */
+       nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE);
+       while (!list_empty(head)) {
+               struct nfs_page *req = nfs_list_entry(head->next);
+
+               nfs_list_remove_request(req);
+               if (!nfs_pageio_add_request(&pgio, req))
+                       nfs_list_add_request(req, &failed);
+       }
+       nfs_pageio_complete(&pgio);
+
+       if (!list_empty(&failed)) {
+               /* For some reason our attempt to resend pages. Mark the
+                * overall send request as having failed, and let
+                * nfs_writeback_release_full deal with the error.
+                */
+               list_move(&failed, head);
+               return -EIO;
+       }
+       return 0;
+}
+
 /*
  * Called by non rpc-based layout drivers
  */
@@ -1175,9 +1202,17 @@ void pnfs_ld_write_done(struct nfs_write_data *data)
                pnfs_set_layoutcommit(data);
                data->mds_ops->rpc_call_done(&data->task, data);
        } else {
-               put_lseg(data->lseg);
-               data->lseg = NULL;
                dprintk("pnfs write error = %d\n", data->pnfs_error);
+               if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
+                                               PNFS_LAYOUTRET_ON_ERROR) {
+                       /* Don't lo_commit on error, Server will needs to
+                        * preform a file recovery.
+                        */
+                       clear_bit(NFS_INO_LAYOUTCOMMIT,
+                                 &NFS_I(data->inode)->flags);
+                       pnfs_return_layout(data->inode);
+               }
+               data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
        }
        data->mds_ops->rpc_release(data);
 }
@@ -1267,6 +1302,9 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
        put_lseg(data->lseg);
        data->lseg = NULL;
        dprintk("pnfs write error = %d\n", data->pnfs_error);
+       if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags &
+                                               PNFS_LAYOUTRET_ON_ERROR)
+               pnfs_return_layout(data->inode);
 
        nfs_pageio_init_read_mds(&pgio, data->inode);
 
index 1509530cb111fadfdd7b47bb48bbb9f88c4b1176..53d593a0a4f265a69c9f4fbc5d2ccb759291686a 100644 (file)
@@ -68,6 +68,7 @@ enum {
 enum layoutdriver_policy_flags {
        /* Should the pNFS client commit and return the layout upon a setattr */
        PNFS_LAYOUTRET_ON_SETATTR       = 1 << 0,
+       PNFS_LAYOUTRET_ON_ERROR         = 1 << 1,
 };
 
 struct nfs4_deviceid_node;
index e463967aafb8cf1d48be42e8c7b191cba607fbeb..3dfa4f112c0ab8be8d5b3f897173a68502406b6c 100644 (file)
@@ -908,10 +908,24 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve
                data->auth_flavor_len   = 1;
                data->version           = version;
                data->minorversion      = 0;
+               security_init_mnt_opts(&data->lsm_opts);
        }
        return data;
 }
 
+static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+{
+       if (data) {
+               kfree(data->client_address);
+               kfree(data->mount_server.hostname);
+               kfree(data->nfs_server.export_path);
+               kfree(data->nfs_server.hostname);
+               kfree(data->fscache_uniq);
+               security_free_mnt_opts(&data->lsm_opts);
+               kfree(data);
+       }
+}
+
 /*
  * Sanity-check a server address provided by the mount command.
  *
@@ -2219,9 +2233,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
        data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
        mntfh = nfs_alloc_fhandle();
        if (data == NULL || mntfh == NULL)
-               goto out_free_fh;
-
-       security_init_mnt_opts(&data->lsm_opts);
+               goto out;
 
        /* Validate the mount data */
        error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
@@ -2233,8 +2245,6 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
 #ifdef CONFIG_NFS_V4
        if (data->version == 4) {
                mntroot = nfs4_try_mount(flags, dev_name, data);
-               kfree(data->client_address);
-               kfree(data->nfs_server.export_path);
                goto out;
        }
 #endif /* CONFIG_NFS_V4 */
@@ -2289,13 +2299,8 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
        s->s_flags |= MS_ACTIVE;
 
 out:
-       kfree(data->nfs_server.hostname);
-       kfree(data->mount_server.hostname);
-       kfree(data->fscache_uniq);
-       security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
+       nfs_free_parsed_mount_data(data);
        nfs_free_fhandle(mntfh);
-       kfree(data);
        return mntroot;
 
 out_err_nosb:
@@ -2622,9 +2627,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 
        mntfh = nfs_alloc_fhandle();
        if (data == NULL || mntfh == NULL)
-               goto out_free_fh;
-
-       security_init_mnt_opts(&data->lsm_opts);
+               goto out;
 
        /* Get a volume representation */
        server = nfs4_create_server(data, mntfh);
@@ -2676,13 +2679,10 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
 
        s->s_flags |= MS_ACTIVE;
 
-       security_free_mnt_opts(&data->lsm_opts);
        nfs_free_fhandle(mntfh);
        return mntroot;
 
 out:
-       security_free_mnt_opts(&data->lsm_opts);
-out_free_fh:
        nfs_free_fhandle(mntfh);
        return ERR_PTR(error);
 
@@ -2839,7 +2839,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type,
 
        data = nfs_alloc_parsed_mount_data(4);
        if (data == NULL)
-               goto out_free_data;
+               goto out;
 
        /* Validate the mount data */
        error = nfs4_validate_mount_data(raw_data, data, dev_name);
@@ -2853,12 +2853,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type,
                error = PTR_ERR(res);
 
 out:
-       kfree(data->client_address);
-       kfree(data->nfs_server.export_path);
-       kfree(data->nfs_server.hostname);
-       kfree(data->fscache_uniq);
-out_free_data:
-       kfree(data);
+       nfs_free_parsed_mount_data(data);
        dprintk("<-- nfs4_mount() = %d%s\n", error,
                        error != 0 ? " [error]" : "");
        return res;
index 1dda78db6a73256e8aeee11254e968f0547e4075..834f0fe96f89f4acf707df504e1a244fc56d466b 100644 (file)
@@ -1052,7 +1052,7 @@ static const struct nfs_pageio_ops nfs_pageio_write_ops = {
        .pg_doio = nfs_generic_pg_writepages,
 };
 
-static void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
+void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
                                  struct inode *inode, int ioflags)
 {
        nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops,
@@ -1166,13 +1166,7 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
 static void nfs_writeback_release_full(void *calldata)
 {
        struct nfs_write_data   *data = calldata;
-       int ret, status = data->task.tk_status;
-       struct nfs_pageio_descriptor pgio;
-
-       if (data->pnfs_error) {
-               nfs_pageio_init_write_mds(&pgio, data->inode, FLUSH_STABLE);
-               pgio.pg_recoalesce = 1;
-       }
+       int status = data->task.tk_status;
 
        /* Update attributes as result of writeback. */
        while (!list_empty(&data->pages)) {
@@ -1188,11 +1182,6 @@ static void nfs_writeback_release_full(void *calldata)
                        req->wb_bytes,
                        (long long)req_offset(req));
 
-               if (data->pnfs_error) {
-                       dprintk(", pnfs error = %d\n", data->pnfs_error);
-                       goto next;
-               }
-
                if (status < 0) {
                        nfs_set_pageerror(page);
                        nfs_context_set_write_error(req->wb_context, status);
@@ -1212,19 +1201,7 @@ remove_request:
        next:
                nfs_clear_page_tag_locked(req);
                nfs_end_page_writeback(page);
-               if (data->pnfs_error) {
-                       lock_page(page);
-                       nfs_pageio_cond_complete(&pgio, page->index);
-                       ret = nfs_page_async_flush(&pgio, page, 0);
-                       if (ret) {
-                               nfs_set_pageerror(page);
-                               dprintk("rewrite to MDS error = %d\n", ret);
-                       }
-                       unlock_page(page);
-               }
        }
-       if (data->pnfs_error)
-               nfs_pageio_complete(&pgio);
        nfs_writedata_release(calldata);
 }
 
@@ -1711,7 +1688,7 @@ out_error:
 
 #ifdef CONFIG_MIGRATION
 int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
-               struct page *page)
+               struct page *page, enum migrate_mode mode)
 {
        /*
         * If PagePrivate is set, then the page is currently associated with
@@ -1726,7 +1703,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
 
        nfs_fscache_release_page(page, GFP_KERNEL);
 
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 #endif
 
index 7748d6a18d9746b480745ba0313002a7d72b10ad..6f3ebb48b12fad4532884df525e8942bd3564c90 100644 (file)
@@ -718,7 +718,7 @@ int set_callback_cred(void)
 {
        if (callback_cred)
                return 0;
-       callback_cred = rpc_lookup_machine_cred();
+       callback_cred = rpc_lookup_machine_cred("nfs");
        if (!callback_cred)
                return -ENOMEM;
        return 0;
index a5ebe421195fea3df8d66f2dc3573534a3bc298a..286edf1e231f3598b0e33c77297bc8cf0d91ebe2 100644 (file)
@@ -827,8 +827,8 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn)
                goto out;
        }
 
-       rc = dlm_new_lockspace(conn->cc_name, strlen(conn->cc_name),
-                              &fsdlm, DLM_LSFL_FS, DLM_LVB_LEN);
+       rc = dlm_new_lockspace(conn->cc_name, NULL, DLM_LSFL_FS, DLM_LVB_LEN,
+                              NULL, NULL, NULL, &fsdlm);
        if (rc) {
                ocfs2_live_connection_drop(control);
                goto out;
index f0e485d54e6475fbbce59a2876f6163086031395..a932ced92a1609b6466dab7a77f0ad4cbc14e256 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1137,7 +1137,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
        if (nr_pages < pipe->nrbufs)
                return -EBUSY;
 
-       bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL);
+       bufs = kcalloc(nr_pages, sizeof(*bufs), GFP_KERNEL | __GFP_NOWARN);
        if (unlikely(!bufs))
                return -ENOMEM;
 
index 8c344f037bd0195b8fad3a0630190cf32428883c..9252ee3b71e3815c03e3dc399b11a5635297214b 100644 (file)
@@ -464,7 +464,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 
        seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld %lu %lu %lu\n",
                pid_nr_ns(pid, ns),
                tcomm,
                state,
@@ -511,7 +511,10 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                task->policy,
                (unsigned long long)delayacct_blkio_ticks(task),
                cputime_to_clock_t(gtime),
-               cputime_to_clock_t(cgtime));
+               cputime_to_clock_t(cgtime),
+               (mm && permitted) ? mm->start_data : 0,
+               (mm && permitted) ? mm->end_data : 0,
+               (mm && permitted) ? mm->start_brk : 0);
        if (mm)
                mmput(mm);
        return 0;
index a1dddda999f208b2083582bcce9449f5a95e7a20..5485a5388ecb2919ecb5033cbf99d1d22916a72b 100644 (file)
 #include <linux/pid_namespace.h>
 #include <linux/fs_struct.h>
 #include <linux/slab.h>
+#include <linux/flex_array.h>
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
+#include <trace/events/oom.h>
 #include "internal.h"
 
 /* NOTE:
@@ -133,6 +135,8 @@ struct pid_entry {
                NULL, &proc_single_file_operations,     \
                { .proc_show = show } )
 
+static int proc_fd_permission(struct inode *inode, int mask);
+
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
  * and .. links.
@@ -165,9 +169,9 @@ static int get_task_root(struct task_struct *task, struct path *root)
        return result;
 }
 
-static int proc_cwd_link(struct inode *inode, struct path *path)
+static int proc_cwd_link(struct dentry *dentry, struct path *path)
 {
-       struct task_struct *task = get_proc_task(inode);
+       struct task_struct *task = get_proc_task(dentry->d_inode);
        int result = -ENOENT;
 
        if (task) {
@@ -182,9 +186,9 @@ static int proc_cwd_link(struct inode *inode, struct path *path)
        return result;
 }
 
-static int proc_root_link(struct inode *inode, struct path *path)
+static int proc_root_link(struct dentry *dentry, struct path *path)
 {
-       struct task_struct *task = get_proc_task(inode);
+       struct task_struct *task = get_proc_task(dentry->d_inode);
        int result = -ENOENT;
 
        if (task) {
@@ -627,6 +631,52 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
        return 0;
 }
 
+/*
+ * May current process learn task's sched/cmdline info (for hide_pid_min=1)
+ * or euid/egid (for hide_pid_min=2)?
+ */
+static bool has_pid_permissions(struct pid_namespace *pid,
+                                struct task_struct *task,
+                                int hide_pid_min)
+{
+       if (pid->hide_pid < hide_pid_min)
+               return true;
+       if (in_group_p(pid->pid_gid))
+               return true;
+       return ptrace_may_access(task, PTRACE_MODE_READ);
+}
+
+
+static int proc_pid_permission(struct inode *inode, int mask)
+{
+       struct pid_namespace *pid = inode->i_sb->s_fs_info;
+       struct task_struct *task;
+       bool has_perms;
+
+       task = get_proc_task(inode);
+       if (!task)
+               return -ESRCH;
+       has_perms = has_pid_permissions(pid, task, 1);
+       put_task_struct(task);
+
+       if (!has_perms) {
+               if (pid->hide_pid == 2) {
+                       /*
+                        * Let's make getdents(), stat(), and open()
+                        * consistent with each other.  If a process
+                        * may not stat() a file, it shouldn't be seen
+                        * in procfs at all.
+                        */
+                       return -ENOENT;
+               }
+
+               return -EPERM;
+       }
+       return generic_permission(inode, mask);
+}
+
+
+
 static const struct inode_operations proc_def_inode_operations = {
        .setattr        = proc_setattr,
 };
@@ -1010,6 +1060,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        else
                task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
                                                                -OOM_DISABLE;
+       trace_oom_score_adj_update(task);
 err_sighand:
        unlock_task_sighand(task, &flags);
 err_task_lock:
@@ -1097,6 +1148,7 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
        task->signal->oom_score_adj = oom_score_adj;
        if (has_capability_noaudit(current, CAP_SYS_RESOURCE))
                task->signal->oom_score_adj_min = oom_score_adj;
+       trace_oom_score_adj_update(task);
        /*
         * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
         * always attainable.
@@ -1453,13 +1505,13 @@ static const struct file_operations proc_pid_set_comm_operations = {
        .release        = single_release,
 };
 
-static int proc_exe_link(struct inode *inode, struct path *exe_path)
+static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 {
        struct task_struct *task;
        struct mm_struct *mm;
        struct file *exe_file;
 
-       task = get_proc_task(inode);
+       task = get_proc_task(dentry->d_inode);
        if (!task)
                return -ENOENT;
        mm = get_task_mm(task);
@@ -1489,7 +1541,7 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
        if (!proc_fd_access_allowed(inode))
                goto out;
 
-       error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
+       error = PROC_I(inode)->op.proc_get_link(dentry, &nd->path);
 out:
        return ERR_PTR(error);
 }
@@ -1528,7 +1580,7 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
        if (!proc_fd_access_allowed(inode))
                goto out;
 
-       error = PROC_I(inode)->op.proc_get_link(inode, &path);
+       error = PROC_I(inode)->op.proc_get_link(dentry, &path);
        if (error)
                goto out;
 
@@ -1609,6 +1661,7 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        struct inode *inode = dentry->d_inode;
        struct task_struct *task;
        const struct cred *cred;
+       struct pid_namespace *pid = dentry->d_sb->s_fs_info;
 
        generic_fillattr(inode, stat);
 
@@ -1617,6 +1670,14 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        stat->gid = 0;
        task = pid_task(proc_pid(inode), PIDTYPE_PID);
        if (task) {
+               if (!has_pid_permissions(pid, task, 2)) {
+                       rcu_read_unlock();
+                       /*
+                        * This doesn't prevent learning whether PID exists,
+                        * it only makes getattr() consistent with readdir().
+                        */
+                       return -ENOENT;
+               }
                if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
                    task_dumpable(task)) {
                        cred = __task_cred(task);
@@ -1820,9 +1881,9 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info)
        return -ENOENT;
 }
 
-static int proc_fd_link(struct inode *inode, struct path *path)
+static int proc_fd_link(struct dentry *dentry, struct path *path)
 {
-       return proc_fd_info(inode, path, NULL);
+       return proc_fd_info(dentry->d_inode, path, NULL);
 }
 
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -2043,6 +2104,355 @@ static const struct file_operations proc_fd_operations = {
        .llseek         = default_llseek,
 };
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+
+/*
+ * dname_to_vma_addr - maps a dentry name into two unsigned longs
+ * which represent vma start and end addresses.
+ */
+static int dname_to_vma_addr(struct dentry *dentry,
+                            unsigned long *start, unsigned long *end)
+{
+       if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       unsigned long vm_start, vm_end;
+       bool exact_vma_exists = false;
+       struct mm_struct *mm = NULL;
+       struct task_struct *task;
+       const struct cred *cred;
+       struct inode *inode;
+       int status = 0;
+
+       if (nd && nd->flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               status = -EACCES;
+               goto out_notask;
+       }
+
+       inode = dentry->d_inode;
+       task = get_proc_task(inode);
+       if (!task)
+               goto out_notask;
+
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto out;
+
+       mm = get_task_mm(task);
+       if (!mm)
+               goto out;
+
+       if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
+               down_read(&mm->mmap_sem);
+               exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
+               up_read(&mm->mmap_sem);
+       }
+
+       mmput(mm);
+
+       if (exact_vma_exists) {
+               if (task_dumpable(task)) {
+                       rcu_read_lock();
+                       cred = __task_cred(task);
+                       inode->i_uid = cred->euid;
+                       inode->i_gid = cred->egid;
+                       rcu_read_unlock();
+               } else {
+                       inode->i_uid = 0;
+                       inode->i_gid = 0;
+               }
+               security_task_to_inode(task, inode);
+               status = 1;
+       }
+
+out:
+       put_task_struct(task);
+
+out_notask:
+       if (status <= 0)
+               d_drop(dentry);
+
+       return status;
+}
+
+static const struct dentry_operations tid_map_files_dentry_operations = {
+       .d_revalidate   = map_files_d_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
+{
+       unsigned long vm_start, vm_end;
+       struct vm_area_struct *vma;
+       struct task_struct *task;
+       struct mm_struct *mm;
+       int rc;
+
+       rc = -ENOENT;
+       task = get_proc_task(dentry->d_inode);
+       if (!task)
+               goto out;
+
+       mm = get_task_mm(task);
+       put_task_struct(task);
+       if (!mm)
+               goto out;
+
+       rc = dname_to_vma_addr(dentry, &vm_start, &vm_end);
+       if (rc)
+               goto out_mmput;
+
+       down_read(&mm->mmap_sem);
+       vma = find_exact_vma(mm, vm_start, vm_end);
+       if (vma && vma->vm_file) {
+               *path = vma->vm_file->f_path;
+               path_get(path);
+               rc = 0;
+       }
+       up_read(&mm->mmap_sem);
+
+out_mmput:
+       mmput(mm);
+out:
+       return rc;
+}
+
+struct map_files_info {
+       struct file     *file;
+       unsigned long   len;
+       unsigned char   name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */
+};
+
+static struct dentry *
+proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
+                          struct task_struct *task, const void *ptr)
+{
+       const struct file *file = ptr;
+       struct proc_inode *ei;
+       struct inode *inode;
+
+       if (!file)
+               return ERR_PTR(-ENOENT);
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               return ERR_PTR(-ENOENT);
+
+       ei = PROC_I(inode);
+       ei->op.proc_get_link = proc_map_files_get_link;
+
+       inode->i_op = &proc_pid_link_inode_operations;
+       inode->i_size = 64;
+       inode->i_mode = S_IFLNK;
+
+       if (file->f_mode & FMODE_READ)
+               inode->i_mode |= S_IRUSR;
+       if (file->f_mode & FMODE_WRITE)
+               inode->i_mode |= S_IWUSR;
+
+       d_set_d_op(dentry, &tid_map_files_dentry_operations);
+       d_add(dentry, inode);
+
+       return NULL;
+}
+
+static struct dentry *proc_map_files_lookup(struct inode *dir,
+               struct dentry *dentry, struct nameidata *nd)
+{
+       unsigned long vm_start, vm_end;
+       struct vm_area_struct *vma;
+       struct task_struct *task;
+       struct dentry *result;
+       struct mm_struct *mm;
+
+       result = ERR_PTR(-EACCES);
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
+
+       result = ERR_PTR(-ENOENT);
+       task = get_proc_task(dir);
+       if (!task)
+               goto out;
+
+       result = ERR_PTR(-EACCES);
+       if (lock_trace(task))
+               goto out_put_task;
+
+       result = ERR_PTR(-ENOENT);
+       if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
+               goto out_unlock;
+
+       mm = get_task_mm(task);
+       if (!mm)
+               goto out_unlock;
+
+       down_read(&mm->mmap_sem);
+       vma = find_exact_vma(mm, vm_start, vm_end);
+       if (!vma)
+               goto out_no_vma;
+
+       result = proc_map_files_instantiate(dir, dentry, task, vma->vm_file);
+
+out_no_vma:
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+out_unlock:
+       unlock_trace(task);
+out_put_task:
+       put_task_struct(task);
+out:
+       return result;
+}
+
+static const struct inode_operations proc_map_files_inode_operations = {
+       .lookup         = proc_map_files_lookup,
+       .permission     = proc_fd_permission,
+       .setattr        = proc_setattr,
+};
+
+static int
+proc_map_files_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct vm_area_struct *vma;
+       struct task_struct *task;
+       struct mm_struct *mm;
+       ino_t ino;
+       int ret;
+
+       ret = -EACCES;
+       if (!capable(CAP_SYS_ADMIN))
+               goto out;
+
+       ret = -ENOENT;
+       task = get_proc_task(inode);
+       if (!task)
+               goto out;
+
+       ret = -EACCES;
+       if (lock_trace(task))
+               goto out_put_task;
+
+       ret = 0;
+       switch (filp->f_pos) {
+       case 0:
+               ino = inode->i_ino;
+               if (filldir(dirent, ".", 1, 0, ino, DT_DIR) < 0)
+                       goto out_unlock;
+               filp->f_pos++;
+       case 1:
+               ino = parent_ino(dentry);
+               if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
+                       goto out_unlock;
+               filp->f_pos++;
+       default:
+       {
+               unsigned long nr_files, pos, i;
+               struct flex_array *fa = NULL;
+               struct map_files_info info;
+               struct map_files_info *p;
+
+               mm = get_task_mm(task);
+               if (!mm)
+                       goto out_unlock;
+               down_read(&mm->mmap_sem);
+
+               nr_files = 0;
+
+               /*
+                * We need two passes here:
+                *
+                *  1) Collect vmas of mapped files with mmap_sem taken
+                *  2) Release mmap_sem and instantiate entries
+                *
+                * otherwise we get lockdep complained, since filldir()
+                * routine might require mmap_sem taken in might_fault().
+                */
+
+               for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
+                       if (vma->vm_file && ++pos > filp->f_pos)
+                               nr_files++;
+               }
+
+               if (nr_files) {
+                       fa = flex_array_alloc(sizeof(info), nr_files,
+                                               GFP_KERNEL);
+                       if (!fa || flex_array_prealloc(fa, 0, nr_files,
+                                                       GFP_KERNEL)) {
+                               ret = -ENOMEM;
+                               if (fa)
+                                       flex_array_free(fa);
+                               up_read(&mm->mmap_sem);
+                               mmput(mm);
+                               goto out_unlock;
+                       }
+                       for (i = 0, vma = mm->mmap, pos = 2; vma;
+                                       vma = vma->vm_next) {
+                               if (!vma->vm_file)
+                                       continue;
+                               if (++pos <= filp->f_pos)
+                                       continue;
+
+                               get_file(vma->vm_file);
+                               info.file = vma->vm_file;
+                               info.len = snprintf(info.name,
+                                               sizeof(info.name), "%lx-%lx",
+                                               vma->vm_start, vma->vm_end);
+                               if (flex_array_put(fa, i++, &info, GFP_KERNEL))
+                                       BUG();
+                       }
+               }
+               up_read(&mm->mmap_sem);
+
+               for (i = 0; i < nr_files; i++) {
+                       p = flex_array_get(fa, i);
+                       ret = proc_fill_cache(filp, dirent, filldir,
+                                             p->name, p->len,
+                                             proc_map_files_instantiate,
+                                             task, p->file);
+                       if (ret)
+                               break;
+                       filp->f_pos++;
+                       fput(p->file);
+               }
+               for (; i < nr_files; i++) {
+                       /*
+                        * In case of error don't forget
+                        * to put rest of file refs.
+                        */
+                       p = flex_array_get(fa, i);
+                       fput(p->file);
+               }
+               if (fa)
+                       flex_array_free(fa);
+               mmput(mm);
+       }
+       }
+
+out_unlock:
+       unlock_trace(task);
+out_put_task:
+       put_task_struct(task);
+out:
+       return ret;
+}
+
+static const struct file_operations proc_map_files_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_map_files_readdir,
+       .llseek         = default_llseek,
+};
+
+#endif /* CONFIG_CHECKPOINT_RESTORE */
+
 /*
  * /proc/pid/fd needs a special permission handler so that a process can still
  * access /proc/self/fd after it has executed a setuid().
@@ -2658,6 +3068,9 @@ static const struct inode_operations proc_task_inode_operations;
 static const struct pid_entry tgid_base_stuff[] = {
        DIR("task",       S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
        DIR("fd",         S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       DIR("map_files",  S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations),
+#endif
        DIR("fdinfo",     S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
        DIR("ns",         S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
 #ifdef CONFIG_NET
@@ -2761,6 +3174,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
        .lookup         = proc_tgid_base_lookup,
        .getattr        = pid_getattr,
        .setattr        = proc_setattr,
+       .permission     = proc_pid_permission,
 };
 
 static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
@@ -2964,6 +3378,12 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi
                                proc_pid_instantiate, iter.task, NULL);
 }
 
+static int fake_filldir(void *buf, const char *name, int namelen,
+                       loff_t offset, u64 ino, unsigned d_type)
+{
+       return 0;
+}
+
 /* for the /proc/ directory itself, after non-process stuff has been done */
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
@@ -2971,6 +3391,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
        struct task_struct *reaper;
        struct tgid_iter iter;
        struct pid_namespace *ns;
+       filldir_t __filldir;
 
        if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET)
                goto out_no_task;
@@ -2992,8 +3413,13 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
        for (iter = next_tgid(ns, iter);
             iter.task;
             iter.tgid += 1, iter = next_tgid(ns, iter)) {
+               if (has_pid_permissions(ns, iter.task, 2))
+                       __filldir = filldir;
+               else
+                       __filldir = fake_filldir;
+
                filp->f_pos = iter.tgid + TGID_OFFSET;
-               if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) {
+               if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) {
                        put_task_struct(iter.task);
                        goto out;
                }
@@ -3328,6 +3754,7 @@ static const struct inode_operations proc_task_inode_operations = {
        .lookup         = proc_task_lookup,
        .getattr        = proc_task_getattr,
        .setattr        = proc_setattr,
+       .permission     = proc_pid_permission,
 };
 
 static const struct file_operations proc_task_operations = {
index 51a176622b8fda3b3867381302acc3ac200fb4ae..84fd3235a5902b73eb59dbc9d18d42be4969b3a3 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/time.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
+#include <linux/pid_namespace.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/stat.h>
@@ -17,7 +18,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sysctl.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/mount.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -101,12 +104,27 @@ void __init proc_init_inodecache(void)
                                             init_once);
 }
 
+static int proc_show_options(struct seq_file *seq, struct dentry *root)
+{
+       struct super_block *sb = root->d_sb;
+       struct pid_namespace *pid = sb->s_fs_info;
+
+       if (pid->pid_gid)
+               seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid);
+       if (pid->hide_pid != 0)
+               seq_printf(seq, ",hidepid=%u", pid->hide_pid);
+
+       return 0;
+}
+
 static const struct super_operations proc_sops = {
        .alloc_inode    = proc_alloc_inode,
        .destroy_inode  = proc_destroy_inode,
        .drop_inode     = generic_delete_inode,
        .evict_inode    = proc_evict_inode,
        .statfs         = simple_statfs,
+       .remount_fs     = proc_remount,
+       .show_options   = proc_show_options,
 };
 
 static void __pde_users_dec(struct proc_dir_entry *pde)
index 7838e5cfec145d4655d4af0e291a8d8bebad91cd..292577531ad13e665bfd94ff63dbfd5a206a5472 100644 (file)
@@ -117,6 +117,7 @@ void pde_put(struct proc_dir_entry *pde);
 
 int proc_fill_super(struct super_block *);
 struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
+int proc_remount(struct super_block *sb, int *flags, char *data);
 
 /*
  * These are generic /proc routines that use the internal
index 03102d978180eba68469ef01d13ad25465f5b796..46a15d8a29ca74d9ca0a68a57e416108e6b599f3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bitops.h>
 #include <linux/mount.h>
 #include <linux/pid_namespace.h>
+#include <linux/parser.h>
 
 #include "internal.h"
 
@@ -36,6 +37,63 @@ static int proc_set_super(struct super_block *sb, void *data)
        return err;
 }
 
+enum {
+       Opt_gid, Opt_hidepid, Opt_err,
+};
+
+static const match_table_t tokens = {
+       {Opt_hidepid, "hidepid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_err, NULL},
+};
+
+static int proc_parse_options(char *options, struct pid_namespace *pid)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+
+               args[0].to = args[0].from = 0;
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       pid->pid_gid = option;
+                       break;
+               case Opt_hidepid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       if (option < 0 || option > 2) {
+                               pr_err("proc: hidepid value must be between 0 and 2.\n");
+                               return 0;
+                       }
+                       pid->hide_pid = option;
+                       break;
+               default:
+                       pr_err("proc: unrecognized mount option \"%s\" "
+                              "or missing value\n", p);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+int proc_remount(struct super_block *sb, int *flags, char *data)
+{
+       struct pid_namespace *pid = sb->s_fs_info;
+       return !proc_parse_options(data, pid);
+}
+
 static struct dentry *proc_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
@@ -43,11 +101,15 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
        struct super_block *sb;
        struct pid_namespace *ns;
        struct proc_inode *ei;
+       char *options;
 
-       if (flags & MS_KERNMOUNT)
+       if (flags & MS_KERNMOUNT) {
                ns = (struct pid_namespace *)data;
-       else
+               options = NULL;
+       } else {
                ns = current->nsproxy->pid_ns;
+               options = data;
+       }
 
        sb = sget(fs_type, proc_test_super, proc_set_super, ns);
        if (IS_ERR(sb))
@@ -55,6 +117,10 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
 
        if (!sb->s_root) {
                sb->s_flags = flags;
+               if (!proc_parse_options(options, ns)) {
+                       deactivate_locked_super(sb);
+                       return ERR_PTR(-EINVAL);
+               }
                err = proc_fill_super(sb);
                if (err) {
                        deactivate_locked_super(sb);
index a945cd265228684418cfb8a4fd1d3df15d2013d5..70de42f09f1d1cfcef2c78aaf7552b851cb00099 100644 (file)
@@ -1364,10 +1364,7 @@ int reiserfs_init_bitmap_cache(struct super_block *sb)
        struct reiserfs_bitmap_info *bitmap;
        unsigned int bmap_nr = reiserfs_bmap_count(sb);
 
-       /* Avoid lock recursion in fault case */
-       reiserfs_write_unlock(sb);
        bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
-       reiserfs_write_lock(sb);
        if (bitmap == NULL)
                return -ENOMEM;
 
index eb711060a6f2b771d4b4e68613ea4890273633dd..c3cf54fd4de327c343c0964488a89e8056665062 100644 (file)
@@ -2678,16 +2678,10 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        char b[BDEVNAME_SIZE];
        int ret;
 
-       /*
-        * Unlock here to avoid various RECLAIM-FS-ON <-> IN-RECLAIM-FS
-        * dependency inversion warnings.
-        */
-       reiserfs_write_unlock(sb);
        journal = SB_JOURNAL(sb) = vzalloc(sizeof(struct reiserfs_journal));
        if (!journal) {
                reiserfs_warning(sb, "journal-1256",
                                 "unable to get memory for journal structure");
-               reiserfs_write_lock(sb);
                return 1;
        }
        INIT_LIST_HEAD(&journal->j_bitmap_nodes);
@@ -2695,10 +2689,8 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        INIT_LIST_HEAD(&journal->j_working_list);
        INIT_LIST_HEAD(&journal->j_journal_list);
        journal->j_persistent_trans = 0;
-       ret = reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap,
-                                          reiserfs_bmap_count(sb));
-       reiserfs_write_lock(sb);
-       if (ret)
+       if (reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap,
+                                          reiserfs_bmap_count(sb)))
                goto free_and_return;
 
        allocate_bitmap_nodes(sb);
@@ -2727,27 +2719,11 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
                goto free_and_return;
        }
 
-       /*
-        * We need to unlock here to avoid creating the following
-        * dependency:
-        * reiserfs_lock -> sysfs_mutex
-        * Because the reiserfs mmap path creates the following dependency:
-        * mm->mmap -> reiserfs_lock, hence we have
-        * mm->mmap -> reiserfs_lock ->sysfs_mutex
-        * This would ends up in a circular dependency with sysfs readdir path
-        * which does sysfs_mutex -> mm->mmap_sem
-        * This is fine because the reiserfs lock is useless in mount path,
-        * at least until we call journal_begin. We keep it for paranoid
-        * reasons.
-        */
-       reiserfs_write_unlock(sb);
        if (journal_init_dev(sb, journal, j_dev_name) != 0) {
-               reiserfs_write_lock(sb);
                reiserfs_warning(sb, "sh-462",
                                 "unable to initialize jornal device");
                goto free_and_return;
        }
-       reiserfs_write_lock(sb);
 
        rs = SB_DISK_SUPER_BLOCK(sb);
 
@@ -2829,9 +2805,7 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        journal->j_mount_id = 10;
        journal->j_state = 0;
        atomic_set(&(journal->j_jlock), 0);
-       reiserfs_write_unlock(sb);
        journal->j_cnode_free_list = allocate_cnodes(num_cnodes);
-       reiserfs_write_lock(sb);
        journal->j_cnode_free_orig = journal->j_cnode_free_list;
        journal->j_cnode_free = journal->j_cnode_free_list ? num_cnodes : 0;
        journal->j_cnode_used = 0;
@@ -2848,24 +2822,37 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
 
        init_journal_hash(sb);
        jl = journal->j_current_jl;
+
+       /*
+        * get_list_bitmap() may call flush_commit_list() which
+        * requires the lock. Calling flush_commit_list() shouldn't happen
+        * this early but I like to be paranoid.
+        */
+       reiserfs_write_lock(sb);
        jl->j_list_bitmap = get_list_bitmap(sb, jl);
+       reiserfs_write_unlock(sb);
        if (!jl->j_list_bitmap) {
                reiserfs_warning(sb, "journal-2005",
                                 "get_list_bitmap failed for journal list 0");
                goto free_and_return;
        }
-       if (journal_read(sb) < 0) {
+
+       /*
+        * Journal_read needs to be inspected in order to push down
+        * the lock further inside (or even remove it).
+        */
+       reiserfs_write_lock(sb);
+       ret = journal_read(sb);
+       reiserfs_write_unlock(sb);
+       if (ret < 0) {
                reiserfs_warning(sb, "reiserfs-2006",
                                 "Replay Failure, unable to mount");
                goto free_and_return;
        }
 
        reiserfs_mounted_fs_count++;
-       if (reiserfs_mounted_fs_count <= 1) {
-               reiserfs_write_unlock(sb);
+       if (reiserfs_mounted_fs_count <= 1)
                commit_wq = alloc_workqueue("reiserfs", WQ_MEM_RECLAIM, 0);
-               reiserfs_write_lock(sb);
-       }
 
        INIT_DELAYED_WORK(&journal->j_work, flush_async_commits);
        journal->j_work_sb = sb;
@@ -2896,14 +2883,13 @@ int journal_transaction_should_end(struct reiserfs_transaction_handle *th,
            journal->j_cnode_free < (journal->j_trans_max * 3)) {
                return 1;
        }
-       /* protected by the BKL here */
+
        journal->j_len_alloc += new_alloc;
        th->t_blocks_allocated += new_alloc ;
        return 0;
 }
 
-/* this must be called inside a transaction, and requires the
-** kernel_lock to be held
+/* this must be called inside a transaction
 */
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th)
 {
@@ -2914,8 +2900,7 @@ void reiserfs_block_writes(struct reiserfs_transaction_handle *th)
        return;
 }
 
-/* this must be called without a transaction started, and does not
-** require BKL
+/* this must be called without a transaction started
 */
 void reiserfs_allow_writes(struct super_block *s)
 {
@@ -2924,8 +2909,7 @@ void reiserfs_allow_writes(struct super_block *s)
        wake_up(&journal->j_join_wait);
 }
 
-/* this must be called without a transaction started, and does not
-** require BKL
+/* this must be called without a transaction started
 */
 void reiserfs_wait_on_write_block(struct super_block *s)
 {
index 1d42e707d5fadc0e604beecf42085c168e628274..e12d8b97cd4dbf3c4c7dc249d42c66a8aeadc4bb 100644 (file)
@@ -1519,9 +1519,7 @@ static int read_super_block(struct super_block *s, int offset)
 static int reread_meta_blocks(struct super_block *s)
 {
        ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
-       reiserfs_write_unlock(s);
        wait_on_buffer(SB_BUFFER_WITH_SB(s));
-       reiserfs_write_lock(s);
        if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
                reiserfs_warning(s, "reiserfs-2504", "error reading the super");
                return 1;
@@ -1746,22 +1744,11 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        mutex_init(&REISERFS_SB(s)->lock);
        REISERFS_SB(s)->lock_depth = -1;
 
-       /*
-        * This function is called with the bkl, which also was the old
-        * locking used here.
-        * do_journal_begin() will soon check if we hold the lock (ie: was the
-        * bkl). This is likely because do_journal_begin() has several another
-        * callers because at this time, it doesn't seem to be necessary to
-        * protect against anything.
-        * Anyway, let's be conservative and lock for now.
-        */
-       reiserfs_write_lock(s);
-
        jdev_name = NULL;
        if (reiserfs_parse_options
            (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
             &commit_max_age, qf_names, &qfmt) == 0) {
-               goto error;
+               goto error_unlocked;
        }
        if (jdev_name && jdev_name[0]) {
                REISERFS_SB(s)->s_jdev = kstrdup(jdev_name, GFP_KERNEL);
@@ -1777,7 +1764,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 
        if (blocks) {
                SWARN(silent, s, "jmacd-7", "resize option for remount only");
-               goto error;
+               goto error_unlocked;
        }
 
        /* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
@@ -1787,7 +1774,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
                SWARN(silent, s, "sh-2021", "can not find reiserfs on %s",
                      reiserfs_bdevname(s));
-               goto error;
+               goto error_unlocked;
        }
 
        rs = SB_DISK_SUPER_BLOCK(s);
@@ -1803,7 +1790,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                      "or increase size of your LVM partition");
                SWARN(silent, s, "", "Or may be you forgot to "
                      "reboot after fdisk when it told you to");
-               goto error;
+               goto error_unlocked;
        }
 
        sbi->s_mount_state = SB_REISERFS_STATE(s);
@@ -1811,8 +1798,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 
        if ((errval = reiserfs_init_bitmap_cache(s))) {
                SWARN(silent, s, "jmacd-8", "unable to read bitmap");
-               goto error;
+               goto error_unlocked;
        }
+
        errval = -EINVAL;
 #ifdef CONFIG_REISERFS_CHECK
        SWARN(silent, s, "", "CONFIG_REISERFS_CHECK is set ON");
@@ -1835,24 +1823,26 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        if (reiserfs_barrier_flush(s)) {
                printk("reiserfs: using flush barriers\n");
        }
+
        // set_device_ro(s->s_dev, 1) ;
        if (journal_init(s, jdev_name, old_format, commit_max_age)) {
                SWARN(silent, s, "sh-2022",
                      "unable to initialize journal space");
-               goto error;
+               goto error_unlocked;
        } else {
                jinit_done = 1; /* once this is set, journal_release must be called
                                 ** if we error out of the mount
                                 */
        }
+
        if (reread_meta_blocks(s)) {
                SWARN(silent, s, "jmacd-9",
                      "unable to reread meta blocks after journal init");
-               goto error;
+               goto error_unlocked;
        }
 
        if (replay_only(s))
-               goto error;
+               goto error_unlocked;
 
        if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
                SWARN(silent, s, "clm-7000",
@@ -1866,9 +1856,19 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
                         reiserfs_init_locked_inode, (void *)(&args));
        if (!root_inode) {
                SWARN(silent, s, "jmacd-10", "get root inode failed");
-               goto error;
+               goto error_unlocked;
        }
 
+       /*
+        * This path assumed to be called with the BKL in the old times.
+        * Now we have inherited the big reiserfs lock from it and many
+        * reiserfs helpers called in the mount path and elsewhere require
+        * this lock to be held even if it's not always necessary. Let's be
+        * conservative and hold it early. The window can be reduced after
+        * careful review of the code.
+        */
+       reiserfs_write_lock(s);
+
        if (root_inode->i_state & I_NEW) {
                reiserfs_read_locked_inode(root_inode, &args);
                unlock_new_inode(root_inode);
@@ -1995,12 +1995,16 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        return (0);
 
 error:
-       if (jinit_done) {       /* kill the commit thread, free journal ram */
+       reiserfs_write_unlock(s);
+
+error_unlocked:
+       /* kill the commit thread, free journal ram */
+       if (jinit_done) {
+               reiserfs_write_lock(s);
                journal_release_error(NULL, s);
+               reiserfs_write_unlock(s);
        }
 
-       reiserfs_write_unlock(s);
-
        reiserfs_free_bitmap_cache(s);
        if (SB_BUFFER_WITH_SB(s))
                brelse(SB_BUFFER_WITH_SB(s));
index f744be98cd5abc8dd6d93cf4a699981491f8e811..af0b738025929b1c18ac884734131ea5e843e40c 100644 (file)
@@ -70,11 +70,15 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
        spin_lock(&cache->lock);
 
        while (1) {
-               for (i = 0; i < cache->entries; i++)
-                       if (cache->entry[i].block == block)
+               for (i = cache->curr_blk, n = 0; n < cache->entries; n++) {
+                       if (cache->entry[i].block == block) {
+                               cache->curr_blk = i;
                                break;
+                       }
+                       i = (i + 1) % cache->entries;
+               }
 
-               if (i == cache->entries) {
+               if (n == cache->entries) {
                        /*
                         * Block not in cache, if all cache entries are used
                         * go to sleep waiting for one to become available.
@@ -245,6 +249,7 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries,
                goto cleanup;
        }
 
+       cache->curr_blk = 0;
        cache->next_blk = 0;
        cache->unused = entries;
        cache->entries = entries;
@@ -332,17 +337,20 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
                u64 *block, int *offset, int length)
 {
        struct squashfs_sb_info *msblk = sb->s_fs_info;
-       int bytes, copied = length;
+       int bytes, res = length;
        struct squashfs_cache_entry *entry;
 
        TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
 
        while (length) {
                entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
-               if (entry->error)
-                       return entry->error;
-               else if (*offset >= entry->length)
-                       return -EIO;
+               if (entry->error) {
+                       res = entry->error;
+                       goto error;
+               } else if (*offset >= entry->length) {
+                       res = -EIO;
+                       goto error;
+               }
 
                bytes = squashfs_copy_data(buffer, entry, *offset, length);
                if (buffer)
@@ -358,7 +366,11 @@ int squashfs_read_metadata(struct super_block *sb, void *buffer,
                squashfs_cache_put(entry);
        }
 
-       return copied;
+       return res;
+
+error:
+       squashfs_cache_put(entry);
+       return res;
 }
 
 
index fd7b3b3bda136fa720c75421b3551815417affd7..81afbccfa8432ba49a644a16c2c0a0526da31ea5 100644 (file)
@@ -208,8 +208,8 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                inode->i_op = &squashfs_inode_ops;
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;
-               inode->i_blocks = ((inode->i_size -
-                               le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
+               inode->i_blocks = (inode->i_size -
+                               le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
 
                squashfs_i(inode)->fragment_block = frag_blk;
                squashfs_i(inode)->fragment_size = frag_size;
index 651f0b31d2966318bfd5ec7ce6ee4bd152486c8e..52934a22f29665a00f082b24aa57ce915e875913 100644 (file)
@@ -28,6 +28,7 @@
 struct squashfs_cache {
        char                    *name;
        int                     entries;
+       int                     curr_blk;
        int                     next_blk;
        int                     num_waiters;
        int                     unused;
index d0858c2d9a47f7d4d38f131b14a1be7bf4c5f406..ecaa2f7bdb8f16ebac1a00896cc9d1a870351788 100644 (file)
@@ -290,7 +290,7 @@ handle_fragments:
 
 check_directory_table:
        /* Sanity check directory_table */
-       if (msblk->directory_table >= next_table) {
+       if (msblk->directory_table > next_table) {
                err = -EINVAL;
                goto failed_mount;
        }
index b09ba2dd8b625efc12130e7a20572560072d8b3b..f922cbacdb96e3e6f4f238cf7360079162452147 100644 (file)
@@ -38,9 +38,6 @@
 
 DEFINE_SPINLOCK(dbg_lock);
 
-static char dbg_key_buf0[128];
-static char dbg_key_buf1[128];
-
 static const char *get_key_fmt(int fmt)
 {
        switch (fmt) {
@@ -103,8 +100,8 @@ static const char *get_dent_type(int type)
        }
 }
 
-static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
-                       char *buffer)
+const char *dbg_snprintf_key(const struct ubifs_info *c,
+                            const union ubifs_key *key, char *buffer, int len)
 {
        char *p = buffer;
        int type = key_type(c, key);
@@ -112,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
        if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
                switch (type) {
                case UBIFS_INO_KEY:
-                       sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
-                              get_key_type(type));
+                       len -= snprintf(p, len, "(%lu, %s)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type));
                        break;
                case UBIFS_DENT_KEY:
                case UBIFS_XENT_KEY:
-                       sprintf(p, "(%lu, %s, %#08x)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type), key_hash(c, key));
+                       len -= snprintf(p, len, "(%lu, %s, %#08x)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type), key_hash(c, key));
                        break;
                case UBIFS_DATA_KEY:
-                       sprintf(p, "(%lu, %s, %u)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type), key_block(c, key));
+                       len -= snprintf(p, len, "(%lu, %s, %u)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type), key_block(c, key));
                        break;
                case UBIFS_TRUN_KEY:
-                       sprintf(p, "(%lu, %s)",
-                               (unsigned long)key_inum(c, key),
-                               get_key_type(type));
+                       len -= snprintf(p, len, "(%lu, %s)",
+                                       (unsigned long)key_inum(c, key),
+                                       get_key_type(type));
                        break;
                default:
-                       sprintf(p, "(bad key type: %#08x, %#08x)",
-                               key->u32[0], key->u32[1]);
+                       len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
+                                       key->u32[0], key->u32[1]);
                }
        } else
-               sprintf(p, "bad key format %d", c->key_fmt);
-}
-
-const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
-{
-       /* dbg_lock must be held */
-       sprintf_key(c, key, dbg_key_buf0);
-       return dbg_key_buf0;
-}
-
-const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
-{
-       /* dbg_lock must be held */
-       sprintf_key(c, key, dbg_key_buf1);
-       return dbg_key_buf1;
+               len -= snprintf(p, len, "bad key format %d", c->key_fmt);
+       ubifs_assert(len > 0);
+       return p;
 }
 
 const char *dbg_ntype(int type)
@@ -319,6 +305,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
        int i, n;
        union ubifs_key key;
        const struct ubifs_ch *ch = node;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        if (dbg_is_tst_rcvry(c))
                return;
@@ -474,7 +461,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                const struct ubifs_ino_node *ino = node;
 
                key_read(c, &ino->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
                       (unsigned long long)le64_to_cpu(ino->creat_sqnum));
                printk(KERN_DEBUG "\tsize           %llu\n",
@@ -517,7 +505,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int nlen = le16_to_cpu(dent->nlen);
 
                key_read(c, &dent->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tinum           %llu\n",
                       (unsigned long long)le64_to_cpu(dent->inum));
                printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
@@ -541,7 +530,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
                key_read(c, &dn->key, &key);
-               printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+               printk(KERN_DEBUG "\tkey            %s\n",
+                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
                printk(KERN_DEBUG "\tsize           %u\n",
                       le32_to_cpu(dn->size));
                printk(KERN_DEBUG "\tcompr_typ      %d\n",
@@ -582,7 +572,9 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                        key_read(c, &br->key, &key);
                        printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
                               i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
-                              le32_to_cpu(br->len), DBGKEY(&key));
+                              le32_to_cpu(br->len),
+                              dbg_snprintf_key(c, &key, key_buf,
+                                               DBG_KEY_BUF_LEN));
                }
                break;
        }
@@ -934,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
 {
        int n;
        const struct ubifs_zbranch *zbr;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        spin_lock(&dbg_lock);
        if (znode->parent)
@@ -958,12 +951,16 @@ void dbg_dump_znode(const struct ubifs_info *c,
                        printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
-                                         DBGKEY(&zbr->key));
+                                         dbg_snprintf_key(c, &zbr->key,
+                                                          key_buf,
+                                                          DBG_KEY_BUF_LEN));
                else
                        printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
                                          "%s\n", n, zbr->znode, zbr->lnum,
                                          zbr->offs, zbr->len,
-                                         DBGKEY(&zbr->key));
+                                         dbg_snprintf_key(c, &zbr->key,
+                                                          key_buf,
+                                                          DBG_KEY_BUF_LEN));
        }
        spin_unlock(&dbg_lock);
 }
@@ -1260,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        int err, nlen1, nlen2, cmp;
        struct ubifs_dent_node *dent1, *dent2;
        union ubifs_key key;
+       char key_buf[DBG_KEY_BUF_LEN];
 
        ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
        dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
@@ -1290,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        key_read(c, &dent1->key, &key);
        if (keys_cmp(c, &zbr1->key, &key)) {
                dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
+                       zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+                                                    DBG_KEY_BUF_LEN));
                dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr1->key));
+                       dbg_snprintf_key(c, &zbr1->key, key_buf,
+                                        DBG_KEY_BUF_LEN));
                dbg_dump_node(c, dent1);
                goto out_free;
        }
@@ -1300,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
        key_read(c, &dent2->key, &key);
        if (keys_cmp(c, &zbr2->key, &key)) {
                dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
-                       zbr1->offs, DBGKEY(&key));
+                       zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+                                                    DBG_KEY_BUF_LEN));
                dbg_err("but it should have key %s according to tnc",
-                       DBGKEY(&zbr2->key));
+                       dbg_snprintf_key(c, &zbr2->key, key_buf,
+                                        DBG_KEY_BUF_LEN));
                dbg_dump_node(c, dent2);
                goto out_free;
        }
@@ -1319,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
                dbg_err("2 xent/dent nodes with the same name");
        else
                dbg_err("bad order of colliding key %s",
-                       DBGKEY(&key));
+                       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 
        ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
        dbg_dump_node(c, dent1);
index 8d9c46810189a1db050d047a11b521c8fe145dba..307ab1d23f7599f6493193cb570c8c810d85a23e 100644 (file)
@@ -169,40 +169,39 @@ struct ubifs_global_debug_info {
        spin_unlock(&dbg_lock);                                                \
 } while (0)
 
-const char *dbg_key_str0(const struct ubifs_info *c,
-                        const union ubifs_key *key);
-const char *dbg_key_str1(const struct ubifs_info *c,
-                        const union ubifs_key *key);
-
-/*
- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
- * macros.
- */
-#define DBGKEY(key) dbg_key_str0(c, (key))
-#define DBGKEY1(key) dbg_key_str1(c, (key))
-
-extern spinlock_t dbg_lock;
-
-#define ubifs_dbg_msg(type, fmt, ...) do {                        \
-       spin_lock(&dbg_lock);                                     \
-       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
-       spin_unlock(&dbg_lock);                                   \
+#define ubifs_dbg_msg(type, fmt, ...) \
+       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
+
+#define DBG_KEY_BUF_LEN 32
+#define ubifs_dbg_msg_key(type, key, fmt, ...) do {                            \
+       char __tmp_key_buf[DBG_KEY_BUF_LEN];                                   \
+       pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__,             \
+                dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN));    \
 } while (0)
 
 /* Just a debugging messages not related to any specific UBIFS subsystem */
-#define dbg_msg(fmt, ...)   ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                                      \
+       printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
+              __func__, ##__VA_ARGS__)
+
 /* General messages */
 #define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Additional journal messages */
 #define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
+#define dbg_jnlk(key, fmt, ...) \
+       ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__)
 /* Additional TNC messages */
 #define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
+#define dbg_tnck(key, fmt, ...) \
+       ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__)
 /* Additional lprops messages */
 #define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
 /* Additional LEB find messages */
 #define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
 /* Additional mount messages */
 #define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
+#define dbg_mntk(key, fmt, ...) \
+       ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__)
 /* Additional I/O messages */
 #define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
 /* Additional commit messages */
@@ -218,6 +217,7 @@ extern spinlock_t dbg_lock;
 /* Additional recovery messages */
 #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
+extern spinlock_t dbg_lock;
 extern struct ubifs_global_debug_info ubifs_dbg;
 
 static inline int dbg_is_chk_gen(const struct ubifs_info *c)
@@ -258,6 +258,8 @@ const char *dbg_cstate(int cmt_state);
 const char *dbg_jhead(int jhead);
 const char *dbg_get_key_dump(const struct ubifs_info *c,
                             const union ubifs_key *key);
+const char *dbg_snprintf_key(const struct ubifs_info *c,
+                            const union ubifs_key *key, char *buffer, int len);
 void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
 void dbg_dump_node(const struct ubifs_info *c, const void *node);
 void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
@@ -368,6 +370,10 @@ static inline const char *dbg_jhead(int jhead)                    { return ""; }
 static inline const char *
 dbg_get_key_dump(const struct ubifs_info *c,
                 const union ubifs_key *key)                      { return ""; }
+static inline const char *
+dbg_snprintf_key(const struct ubifs_info *c,
+                const union ubifs_key *key, char *buffer,
+                int len)                                         { return ""; }
 static inline void dbg_dump_inode(struct ubifs_info *c,
                                  const struct inode *inode)      { return; }
 static inline void dbg_dump_node(const struct ubifs_info *c,
index cef0460f4c54651bbe5c432d8fc4e3307ee45d07..2f438ab2e7a2730f2dfff7498ad8c3301f425479 100644 (file)
@@ -697,9 +697,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
        int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
        struct ubifs_inode *ui = ubifs_inode(inode);
 
-       dbg_jnl("ino %lu, blk %u, len %d, key %s",
-               (unsigned long)key_inum(c, key), key_block(c, key), len,
-               DBGKEY(key));
+       dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
+               (unsigned long)key_inum(c, key), key_block(c, key), len);
        ubifs_assert(len <= UBIFS_BLOCK_SIZE);
 
        data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
@@ -1177,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
                dn = (void *)trun + UBIFS_TRUN_NODE_SZ;
                blk = new_size >> UBIFS_BLOCK_SHIFT;
                data_key_init(c, &key, inum, blk);
-               dbg_jnl("last block key %s", DBGKEY(&key));
+               dbg_jnlk(&key, "last block key ");
                err = ubifs_tnc_lookup(c, &key, dn);
                if (err == -ENOENT)
                        dlen = 0; /* Not found (so it is a hole) */
index 6189c74d97f03ef6ba3eafc19fc1a8924b42d4b9..66d59d0a14029ebc8b1fa3bb2d0ecfad38199e66 100644 (file)
@@ -1986,12 +1986,11 @@ again:
 
                                if (path[h].in_tree)
                                        continue;
-                               nnode = kmalloc(sz, GFP_NOFS);
+                               nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
                                if (!nnode) {
                                        err = -ENOMEM;
                                        goto out;
                                }
-                               memcpy(nnode, &path[h].nnode, sz);
                                parent = nnode->parent;
                                parent->nbranch[nnode->iip].nnode = nnode;
                                path[h].ptr.nnode = nnode;
@@ -2004,12 +2003,11 @@ again:
                                const size_t sz = sizeof(struct ubifs_pnode);
                                struct ubifs_nnode *parent;
 
-                               pnode = kmalloc(sz, GFP_NOFS);
+                               pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
                                if (!pnode) {
                                        err = -ENOMEM;
                                        goto out;
                                }
-                               memcpy(pnode, &path[h].pnode, sz);
                                parent = pnode->parent;
                                parent->nbranch[pnode->iip].pnode = pnode;
                                path[h].ptr.pnode = pnode;
index ccabaf1164b333a1fd276a2fff5beabdaa0bda1d..b007637f040662b836d98e15ec9143ad5c05cf3f 100644 (file)
@@ -221,8 +221,8 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 {
        int err;
 
-       dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum,
-               r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key));
+       dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
+                r->lnum, r->offs, r->len, r->deletion, r->sqnum);
 
        /* Set c->replay_sqnum to help deal with dangling branches. */
        c->replay_sqnum = r->sqnum;
@@ -361,7 +361,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
 {
        struct replay_entry *r;
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+       dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
 
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
@@ -409,7 +409,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
        struct replay_entry *r;
        char *nbuf;
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+       dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
index 066738647685ba8ad2d371060bfd226e12020e3b..16ad84d8402f31a5729f86c3b15f20a129f49efd 100644 (file)
@@ -344,12 +344,11 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                return err;
        }
 
-       lnc_node = kmalloc(zbr->len, GFP_NOFS);
+       lnc_node = kmemdup(node, zbr->len, GFP_NOFS);
        if (!lnc_node)
                /* We don't have to have the cache, so no error */
                return 0;
 
-       memcpy(lnc_node, node, zbr->len);
        zbr->leaf = lnc_node;
        return 0;
 }
@@ -506,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
 {
        int ret;
 
-       dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
+       dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
 
        ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
                            zbr->offs);
@@ -520,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
                        ret = 0;
        }
        if (ret == 0 && c->replaying)
-               dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
-                       zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
+               dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ",
+                       zbr->lnum, zbr->offs, zbr->len);
        return ret;
 }
 
@@ -996,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c,
        if (adding || !o_znode)
                return 0;
 
-       dbg_mnt("dangling match LEB %d:%d len %d %s",
+       dbg_mntk(key, "dangling match LEB %d:%d len %d key ",
                o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
-               o_znode->zbranch[o_n].len, DBGKEY(key));
+               o_znode->zbranch[o_n].len);
        *zn = o_znode;
        *n = o_n;
        return 1;
@@ -1180,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
        unsigned long time = get_seconds();
 
-       dbg_tnc("search key %s", DBGKEY(key));
+       dbg_tnck(key, "search key ");
        ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
 
        znode = c->zroot.znode;
@@ -1316,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
        unsigned long time = get_seconds();
 
-       dbg_tnc("search and dirty key %s", DBGKEY(key));
+       dbg_tnck(key, "search and dirty key ");
 
        znode = c->zroot.znode;
        if (unlikely(!znode)) {
@@ -1723,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
        if (!keys_eq(c, &zbr->key, &key1)) {
                ubifs_err("bad key in node at LEB %d:%d",
                          zbr->lnum, zbr->offs);
-               dbg_tnc("looked for key %s found node's key %s",
-                       DBGKEY(&zbr->key), DBGKEY1(&key1));
+               dbg_tnck(&zbr->key, "looked for key ");
+               dbg_tnck(&key1, "found node's key ");
                goto out_err;
        }
 
@@ -1777,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
                ubifs_err("failed to read from LEB %d:%d, error %d",
                          lnum, offs, err);
                dbg_dump_stack();
-               dbg_tnc("key %s", DBGKEY(&bu->key));
+               dbg_tnck(&bu->key, "key ");
                return err;
        }
 
@@ -1812,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
        int found, n, err;
        struct ubifs_znode *znode;
 
-       dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
+       dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
        mutex_lock(&c->tnc_mutex);
        found = ubifs_lookup_level0(c, key, &znode, &n);
        if (!found) {
@@ -1986,8 +1985,7 @@ again:
        zp = znode->parent;
        if (znode->child_cnt < c->fanout) {
                ubifs_assert(n != c->fanout);
-               dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
-                       DBGKEY(key));
+               dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
 
                insert_zbranch(znode, zbr, n);
 
@@ -2002,7 +2000,7 @@ again:
         * Unfortunately, @znode does not have more empty slots and we have to
         * split it.
         */
-       dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
+       dbg_tnck(key, "splitting level %d, key ", znode->level);
 
        if (znode->alt)
                /*
@@ -2096,7 +2094,7 @@ do_split:
        }
 
        /* Insert new key and branch */
-       dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
+       dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
 
        insert_zbranch(zi, zbr, n);
 
@@ -2172,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
+       dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (!found) {
                struct ubifs_zbranch zbr;
@@ -2221,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
-               old_offs, lnum, offs, len, DBGKEY(key));
+       dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
+                old_offs, lnum, offs, len);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2304,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
-               DBGKEY(key));
+       dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
+                lnum, offs, nm->len, nm->name);
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2398,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
        /* Delete without merge for now */
        ubifs_assert(znode->level == 0);
        ubifs_assert(n >= 0 && n < c->fanout);
-       dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
+       dbg_tnck(&znode->zbranch[n].key, "deleting key ");
 
        zbr = &znode->zbranch[n];
        lnc_free(zbr);
@@ -2508,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("key %s", DBGKEY(key));
+       dbg_tnck(key, "key ");
        found = lookup_level0_dirty(c, key, &znode, &n);
        if (found < 0) {
                err = found;
@@ -2539,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
        struct ubifs_znode *znode;
 
        mutex_lock(&c->tnc_mutex);
-       dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
+       dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
        err = lookup_level0_dirty(c, key, &znode, &n);
        if (err < 0)
                goto out_unlock;
@@ -2654,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
                                dbg_dump_znode(c, znode);
                                goto out_unlock;
                        }
-                       dbg_tnc("removing %s", DBGKEY(key));
+                       dbg_tnck(key, "removing key ");
                }
                if (k) {
                        for (i = n + 1 + k; i < znode->child_cnt; i++)
@@ -2774,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
        struct ubifs_zbranch *zbr;
        union ubifs_key *dkey;
 
-       dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
+       dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
        ubifs_assert(is_hash_key(c, key));
 
        mutex_lock(&c->tnc_mutex);
@@ -3333,9 +3331,9 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
 
 out_dump:
        block = key_block(c, key);
-       ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
-                 "(data key %s)", (unsigned long)inode->i_ino, size,
-                 ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
+       ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
+                 (unsigned long)inode->i_ino, size,
+                 ((loff_t)block) << UBIFS_BLOCK_SHIFT);
        mutex_unlock(&c->tnc_mutex);
        dbg_dump_inode(c, inode);
        dbg_dump_stack();
index b48db999903e6d34b40c5066a9f30844723b70f8..dc28fe6ec07a31bff2471bd731ed828363f85062 100644 (file)
@@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
                case UBIFS_XENT_KEY:
                        break;
                default:
-                       dbg_msg("bad key type at slot %d: %s", i,
-                               DBGKEY(&zbr->key));
+                       dbg_msg("bad key type at slot %d: %d",
+                               i, key_type(c, &zbr->key));
                        err = 3;
                        goto out_dump;
                }
@@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
                                      zbr->offs);
 
        if (err) {
-               dbg_tnc("key %s", DBGKEY(key));
+               dbg_tnck(key, "key ");
                return err;
        }
 
@@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
        if (!keys_eq(c, key, &key1)) {
                ubifs_err("bad key in node at LEB %d:%d",
                          zbr->lnum, zbr->offs);
-               dbg_tnc("looked for key %s found node's key %s",
-                       DBGKEY(key), DBGKEY1(&key1));
+               dbg_tnck(key, "looked for key ");
+               dbg_tnck(&key1, "but found node's key ");
                dbg_dump_node(c, node);
                return -EINVAL;
        }
index bf18f7a04544b28bb0fd989e33065ee17bb7a95e..85b2722687545b0e3299d7bdc0275ebe9fb2d2e2 100644 (file)
@@ -138,12 +138,11 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
        ui = ubifs_inode(inode);
        ui->xattr = 1;
        ui->flags |= UBIFS_XATTR_FL;
-       ui->data = kmalloc(size, GFP_NOFS);
+       ui->data = kmemdup(value, size, GFP_NOFS);
        if (!ui->data) {
                err = -ENOMEM;
                goto out_free;
        }
-       memcpy(ui->data, value, size);
        inode->i_size = ui->ui_size = size;
        ui->data_len = size;
 
@@ -204,12 +203,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
                return err;
 
        kfree(ui->data);
-       ui->data = kmalloc(size, GFP_NOFS);
+       ui->data = kmemdup(value, size, GFP_NOFS);
        if (!ui->data) {
                err = -ENOMEM;
                goto out_free;
        }
-       memcpy(ui->data, value, size);
        inode->i_size = ui->ui_size = size;
        ui->data_len = size;
 
index 912088773a69ef55b5313d7a6ccd5acebbc1de36..448303bdb85fd8009fdb6a6367fa9f2ed69b80ba 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm-generic/iomap.h>
 #endif
 
+#include <asm-generic/pci_iomap.h>
+
 #ifndef mmiowb
 #define mmiowb() do {} while (0)
 #endif
@@ -283,9 +285,7 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len)
 #define __io_virt(x) ((void __force *) (x))
 
 #ifndef CONFIG_GENERIC_IOMAP
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
 {
 }
@@ -327,7 +327,7 @@ static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
 #define ioremap_wc ioremap_nocache
 #endif
 
-static inline void iounmap(void *addr)
+static inline void iounmap(void __iomem *addr)
 {
 }
 #endif /* CONFIG_MMU */
index 98dcd76ce836db71243b031a2bdfc301627d7a03..8a3d4fde26040600f7ddb9d7c3e67a4807b265ff 100644 (file)
@@ -67,18 +67,15 @@ extern void ioport_unmap(void __iomem *);
 #endif
 
 #ifdef CONFIG_PCI
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+/* Destroy a virtual mapping cookie for a PCI BAR (memory or IO) */
 struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 #else
 struct pci_dev;
-static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
-{
-       return NULL;
-}
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 { }
 #endif
 
+#include <asm-generic/pci_iomap.h>
+
 #endif
index 351889d1de19282fdb10155d06d32301d148ba13..37d1fe28960a8ae7d82b2f804008b444c7fde556 100644 (file)
@@ -71,10 +71,14 @@ extern unsigned long memory_end;
 #define PAGE_OFFSET            (0)
 #endif
 
+#ifndef ARCH_PFN_OFFSET
+#define ARCH_PFN_OFFSET                (PAGE_OFFSET >> PAGE_SHIFT)
+#endif
+
 #ifndef __ASSEMBLY__
 
-#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
-#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long) (x)))
+#define __pa(x) ((unsigned long) (x))
 
 #define virt_to_pfn(kaddr)     (__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_to_virt(pfn)       __va((pfn) << PAGE_SHIFT)
@@ -86,7 +90,7 @@ extern unsigned long memory_end;
 #define page_to_phys(page)      ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 #endif
 
-#define pfn_valid(pfn)         ((pfn) < max_mapnr)
+#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
 
 #define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
                                ((void *)(kaddr) < (void *)memory_end))
diff --git a/include/asm-generic/pci_iomap.h b/include/asm-generic/pci_iomap.h
new file mode 100644 (file)
index 0000000..8de4b73
--- /dev/null
@@ -0,0 +1,25 @@
+/* Generic I/O port emulation, based on MN10300 code
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef __ASM_GENERIC_PCI_IOMAP_H
+#define __ASM_GENERIC_PCI_IOMAP_H
+
+struct pci_dev;
+#ifdef CONFIG_PCI
+/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+#else
+static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+       return NULL;
+}
+#endif
+
+#endif /* __ASM_GENERIC_IO_H */
index e58fa777fa09abe91831026852bfe21bdfa4f8d4..f96a5b58a975c6ccc1ebadecf746f84dd47a38ea 100644 (file)
@@ -139,6 +139,20 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
                __tlb_remove_tlb_entry(tlb, ptep, address);     \
        } while (0)
 
+/**
+ * tlb_remove_pmd_tlb_entry - remember a pmd mapping for later tlb invalidation
+ * This is a nop so far, because only x86 needs it.
+ */
+#ifndef __tlb_remove_pmd_tlb_entry
+#define __tlb_remove_pmd_tlb_entry(tlb, pmdp, address) do {} while (0)
+#endif
+
+#define tlb_remove_pmd_tlb_entry(tlb, pmdp, address)           \
+       do {                                                    \
+               tlb->need_flush = 1;                            \
+               __tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \
+       } while (0)
+
 #define pte_free_tlb(tlb, ptep, address)                       \
        do {                                                    \
                tlb->need_flush = 1;                            \
index ac68c999b6c2165bbba9bea374505cbc60f5abf9..9788568f79782befb0be7cf29d148220f9c898c4 100644 (file)
@@ -289,9 +289,14 @@ strncpy_from_user(char *dst, const char __user *src, long count)
  * Return 0 on exception, a value greater than N if too long
  */
 #ifndef __strnlen_user
-#define __strnlen_user strnlen
+#define __strnlen_user(s, n) (strnlen((s), (n)) + 1)
 #endif
 
+/*
+ * Unlike strnlen, strnlen_user includes the nul terminator in
+ * its returned count. Callers should check for a returned value
+ * greater than N as an indication the string is too long.
+ */
 static inline long strnlen_user(const char __user *src, long n)
 {
        if (!access_ok(VERIFY_READ, src, 1))
index ecc721def10c8ae2a6ba4dee6fead57d20af48f0..418d270e18063517750f39c68490f56fb7cd24c3 100644 (file)
@@ -134,6 +134,7 @@ struct crypto_template *crypto_lookup_template(const char *name);
 
 int crypto_register_instance(struct crypto_template *tmpl,
                             struct crypto_instance *inst);
+int crypto_unregister_instance(struct crypto_alg *alg);
 
 int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
                      struct crypto_instance *inst, u32 mask);
diff --git a/include/crypto/lrw.h b/include/crypto/lrw.h
new file mode 100644 (file)
index 0000000..25a2c87
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _CRYPTO_LRW_H
+#define _CRYPTO_LRW_H
+
+#include <crypto/b128ops.h>
+
+struct scatterlist;
+struct gf128mul_64k;
+struct blkcipher_desc;
+
+#define LRW_BLOCK_SIZE 16
+
+struct lrw_table_ctx {
+       /* optimizes multiplying a random (non incrementing, as at the
+        * start of a new sector) value with key2, we could also have
+        * used 4k optimization tables or no optimization at all. In the
+        * latter case we would have to store key2 here */
+       struct gf128mul_64k *table;
+       /* stores:
+        *  key2*{ 0,0,...0,0,0,0,1 }, key2*{ 0,0,...0,0,0,1,1 },
+        *  key2*{ 0,0,...0,0,1,1,1 }, key2*{ 0,0,...0,1,1,1,1 }
+        *  key2*{ 0,0,...1,1,1,1,1 }, etc
+        * needed for optimized multiplication of incrementing values
+        * with key2 */
+       be128 mulinc[128];
+};
+
+int lrw_init_table(struct lrw_table_ctx *ctx, const u8 *tweak);
+void lrw_free_table(struct lrw_table_ctx *ctx);
+
+struct lrw_crypt_req {
+       be128 *tbuf;
+       unsigned int tbuflen;
+
+       struct lrw_table_ctx *table_ctx;
+       void *crypt_ctx;
+       void (*crypt_fn)(void *ctx, u8 *blks, unsigned int nbytes);
+};
+
+int lrw_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+             struct scatterlist *src, unsigned int nbytes,
+             struct lrw_crypt_req *req);
+
+#endif  /* _CRYPTO_LRW_H */
diff --git a/include/crypto/serpent.h b/include/crypto/serpent.h
new file mode 100644 (file)
index 0000000..b7e0941
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Common values for serpent algorithms
+ */
+
+#ifndef _CRYPTO_SERPENT_H
+#define _CRYPTO_SERPENT_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define SERPENT_MIN_KEY_SIZE             0
+#define SERPENT_MAX_KEY_SIZE            32
+#define SERPENT_EXPKEY_WORDS           132
+#define SERPENT_BLOCK_SIZE              16
+
+struct serpent_ctx {
+       u32 expkey[SERPENT_EXPKEY_WORDS];
+};
+
+int __serpent_setkey(struct serpent_ctx *ctx, const u8 *key,
+                    unsigned int keylen);
+int serpent_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen);
+
+void __serpent_encrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src);
+void __serpent_decrypt(struct serpent_ctx *ctx, u8 *dst, const u8 *src);
+
+#endif
index c408522595c6855ff517e966ea16bf4c9cff19ac..095c901a8af3c155e44f123f2ea043edd0615f66 100644 (file)
@@ -17,6 +17,8 @@ struct twofish_ctx {
        u32 s[4][256], w[8], k[32];
 };
 
+int __twofish_setkey(struct twofish_ctx *ctx, const u8 *key,
+                    unsigned int key_len, u32 *flags);
 int twofish_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len);
 
 #endif
diff --git a/include/crypto/xts.h b/include/crypto/xts.h
new file mode 100644 (file)
index 0000000..72c09eb
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _CRYPTO_XTS_H
+#define _CRYPTO_XTS_H
+
+#include <crypto/b128ops.h>
+
+struct scatterlist;
+struct blkcipher_desc;
+
+#define XTS_BLOCK_SIZE 16
+
+struct xts_crypt_req {
+       be128 *tbuf;
+       unsigned int tbuflen;
+
+       void *tweak_ctx;
+       void (*tweak_fn)(void *ctx, u8* dst, const u8* src);
+       void *crypt_ctx;
+       void (*crypt_fn)(void *ctx, u8 *blks, unsigned int nbytes);
+};
+
+#define XTS_TWEAK_CAST(x) ((void (*)(void *, u8*, const u8*))(x))
+
+int xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+             struct scatterlist *src, unsigned int nbytes,
+             struct xts_crypt_req *req);
+
+#endif  /* _CRYPTO_XTS_H */
index 63e4fce6728829bb98c9630220fc75f21d19814e..4cd4be26722c14fb58d7f86f0a2a4988798cda68 100644 (file)
@@ -453,7 +453,7 @@ struct drm_encoder_funcs {
 #define DRM_CONNECTOR_MAX_UMODES 16
 #define DRM_CONNECTOR_MAX_PROPERTY 16
 #define DRM_CONNECTOR_LEN 32
-#define DRM_CONNECTOR_MAX_ENCODER 2
+#define DRM_CONNECTOR_MAX_ENCODER 3
 
 /**
  * drm_encoder - central DRM encoder structure
index 21114810c7c0b687afa01f188e50d99bdbdafecb..0101e9c17fa1ec022c75f3655646c16aca9dd948 100644 (file)
@@ -30,6 +30,7 @@ struct dma_chan;
  * @cd_invert: true if the gpio_cd pin value is active low
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
+ * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
  * @dma_filter: function used to select an appropriate RX and TX
  * DMA channel to be used for DMA, if and only if you're deploying the
  * generic DMA engine
@@ -52,6 +53,7 @@ struct mmci_platform_data {
        int     gpio_cd;
        bool    cd_invert;
        unsigned long capabilities;
+       unsigned long capabilities2;
        bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
        void *dma_rx_param;
        void *dma_tx_param;
index dfadc96e9d63851c334885f0ec7761c8d6cfe3ff..2f4079175afb81f80f641e28da9b1145b5415bae 100644 (file)
@@ -29,6 +29,7 @@
    the kernel context */
 #define __cold                 __attribute__((__cold__))
 
+#define __linktime_error(message) __attribute__((__error__(message)))
 
 #if __GNUC_MINOR__ >= 5
 /*
index 320d6c94ff848d5db94fb1fd76576501a88e9a3a..4a243546d142b3e0264b115332bf73e354aa0fdf 100644 (file)
@@ -293,7 +293,9 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 #ifndef __compiletime_error
 # define __compiletime_error(message)
 #endif
-
+#ifndef __linktime_error
+# define __linktime_error(message)
+#endif
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
  * is also forbidden from reordering successive instances of ACCESS_ONCE(),
index 5c4abce94ad1665803c79fd61a501e6969477029..b936763f2236be16254d23380e49d99f08f82dc4 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/kexec.h>
 #include <linux/device.h>
 #include <linux/proc_fs.h>
+#include <linux/elf.h>
 
 #define ELFCORE_ADDR_MAX       (-1ULL)
 #define ELFCORE_ADDR_ERR       (-2ULL)
index a47bda5f76db125288898fb1aea2f098bc2dfa42..d64a55b23afda64f4b490ef475e092edcf3c32b7 100644 (file)
@@ -203,6 +203,7 @@ struct dentry_operations {
 
 #define DCACHE_CANT_MOUNT      0x0100
 #define DCACHE_GENOCIDE                0x0200
+#define DCACHE_SHRINK_LIST     0x0400
 
 #define DCACHE_NFSFS_RENAMED   0x1000
      /* this dentry has been "silly renamed" and has to be deleted on the last
@@ -241,6 +242,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
 extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
 extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
 extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
+extern struct dentry *d_find_any_alias(struct inode *inode);
 extern struct dentry * d_obtain_alias(struct inode *);
 extern void shrink_dcache_sb(struct super_block *);
 extern void shrink_dcache_parent(struct dentry *);
diff --git a/include/linux/digsig.h b/include/linux/digsig.h
new file mode 100644 (file)
index 0000000..efae755
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Intel Corporation
+ *
+ * Author:
+ * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ *                 <dmitry.kasatkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ */
+
+#ifndef _DIGSIG_H
+#define _DIGSIG_H
+
+#include <linux/key.h>
+
+enum pubkey_algo {
+       PUBKEY_ALGO_RSA,
+       PUBKEY_ALGO_MAX,
+};
+
+enum digest_algo {
+       DIGEST_ALGO_SHA1,
+       DIGEST_ALGO_SHA256,
+       DIGEST_ALGO_MAX
+};
+
+struct pubkey_hdr {
+       uint8_t         version;        /* key format version */
+       time_t          timestamp;      /* key made, always 0 for now */
+       uint8_t         algo;
+       uint8_t         nmpi;
+       char            mpi[0];
+} __packed;
+
+struct signature_hdr {
+       uint8_t         version;        /* signature format version */
+       time_t          timestamp;      /* signature made */
+       uint8_t         algo;
+       uint8_t         hash;
+       uint8_t         keyid[8];
+       uint8_t         nmpi;
+       char            mpi[0];
+} __packed;
+
+#if defined(CONFIG_DIGSIG) || defined(CONFIG_DIGSIG_MODULE)
+
+int digsig_verify(struct key *keyring, const char *sig, int siglen,
+                                       const char *digest, int digestlen);
+
+#else
+
+static inline int digsig_verify(struct key *keyring, const char *sig,
+                               int siglen, const char *digest, int digestlen)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_DIGSIG */
+
+#endif /* _DIGSIG_H */
index d4e02f5353a080ae03bf2233eea266dcad5c36ba..6c7f6e9546c7fde54a88228ebc52144e6bd27692 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2011 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -74,15 +74,76 @@ struct dlm_lksb {
 
 #ifdef __KERNEL__
 
+struct dlm_slot {
+       int nodeid; /* 1 to MAX_INT */
+       int slot;   /* 1 to MAX_INT */
+};
+
+/*
+ * recover_prep: called before the dlm begins lock recovery.
+ *   Notfies lockspace user that locks from failed members will be granted.
+ * recover_slot: called after recover_prep and before recover_done.
+ *   Identifies a failed lockspace member.
+ * recover_done: called after the dlm completes lock recovery.
+ *   Identifies lockspace members and lockspace generation number.
+ */
+
+struct dlm_lockspace_ops {
+       void (*recover_prep) (void *ops_arg);
+       void (*recover_slot) (void *ops_arg, struct dlm_slot *slot);
+       void (*recover_done) (void *ops_arg, struct dlm_slot *slots,
+                             int num_slots, int our_slot, uint32_t generation);
+};
+
 /*
  * dlm_new_lockspace
  *
- * Starts a lockspace with the given name.  If the named lockspace exists in
- * the cluster, the calling node joins it.
+ * Create/join a lockspace.
+ *
+ * name: lockspace name, null terminated, up to DLM_LOCKSPACE_LEN (not
+ *   including terminating null).
+ *
+ * cluster: cluster name, null terminated, up to DLM_LOCKSPACE_LEN (not
+ *   including terminating null).  Optional.  When cluster is null, it
+ *   is not used.  When set, dlm_new_lockspace() returns -EBADR if cluster
+ *   is not equal to the dlm cluster name.
+ *
+ * flags:
+ * DLM_LSFL_NODIR
+ *   The dlm should not use a resource directory, but statically assign
+ *   resource mastery to nodes based on the name hash that is otherwise
+ *   used to select the directory node.  Must be the same on all nodes.
+ * DLM_LSFL_TIMEWARN
+ *   The dlm should emit netlink messages if locks have been waiting
+ *   for a configurable amount of time.  (Unused.)
+ * DLM_LSFL_FS
+ *   The lockspace user is in the kernel (i.e. filesystem).  Enables
+ *   direct bast/cast callbacks.
+ * DLM_LSFL_NEWEXCL
+ *   dlm_new_lockspace() should return -EEXIST if the lockspace exists.
+ *
+ * lvblen: length of lvb in bytes.  Must be multiple of 8.
+ *   dlm_new_lockspace() returns an error if this does not match
+ *   what other nodes are using.
+ *
+ * ops: callbacks that indicate lockspace recovery points so the
+ *   caller can coordinate its recovery and know lockspace members.
+ *   This is only used by the initial dlm_new_lockspace() call.
+ *   Optional.
+ *
+ * ops_arg: arg for ops callbacks.
+ *
+ * ops_result: tells caller if the ops callbacks (if provided) will
+ *   be used or not.  0: will be used, -EXXX will not be used.
+ *   -EOPNOTSUPP: the dlm does not have recovery_callbacks enabled.
+ *
+ * lockspace: handle for dlm functions
  */
 
-int dlm_new_lockspace(const char *name, int namelen,
-                     dlm_lockspace_t **lockspace, uint32_t flags, int lvblen);
+int dlm_new_lockspace(const char *name, const char *cluster,
+                     uint32_t flags, int lvblen,
+                     const struct dlm_lockspace_ops *ops, void *ops_arg,
+                     int *ops_result, dlm_lockspace_t **lockspace);
 
 /*
  * dlm_release_lockspace
index 2362a0bc7f0dbfe0c4cb7df2e31ef769ebcbdacc..37c300712e025c2138f8627033b82ff9584683c6 100644 (file)
@@ -109,6 +109,14 @@ typedef struct {
        u32 imagesize;
 } efi_capsule_header_t;
 
+/*
+ * Allocation types for calls to boottime->allocate_pages.
+ */
+#define EFI_ALLOCATE_ANY_PAGES         0
+#define EFI_ALLOCATE_MAX_ADDRESS       1
+#define EFI_ALLOCATE_ADDRESS           2
+#define EFI_MAX_ALLOCATE_TYPE          3
+
 typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg);
 
 /*
@@ -138,6 +146,57 @@ typedef struct {
        u8 sets_to_zero;
 } efi_time_cap_t;
 
+/*
+ * EFI Boot Services table
+ */
+typedef struct {
+       efi_table_hdr_t hdr;
+       void *raise_tpl;
+       void *restore_tpl;
+       void *allocate_pages;
+       void *free_pages;
+       void *get_memory_map;
+       void *allocate_pool;
+       void *free_pool;
+       void *create_event;
+       void *set_timer;
+       void *wait_for_event;
+       void *signal_event;
+       void *close_event;
+       void *check_event;
+       void *install_protocol_interface;
+       void *reinstall_protocol_interface;
+       void *uninstall_protocol_interface;
+       void *handle_protocol;
+       void *__reserved;
+       void *register_protocol_notify;
+       void *locate_handle;
+       void *locate_device_path;
+       void *install_configuration_table;
+       void *load_image;
+       void *start_image;
+       void *exit;
+       void *unload_image;
+       void *exit_boot_services;
+       void *get_next_monotonic_count;
+       void *stall;
+       void *set_watchdog_timer;
+       void *connect_controller;
+       void *disconnect_controller;
+       void *open_protocol;
+       void *close_protocol;
+       void *open_protocol_information;
+       void *protocols_per_handle;
+       void *locate_handle_buffer;
+       void *locate_protocol;
+       void *install_multiple_protocol_interfaces;
+       void *uninstall_multiple_protocol_interfaces;
+       void *calculate_crc32;
+       void *copy_mem;
+       void *set_mem;
+       void *create_event_ex;
+} efi_boot_services_t;
+
 /*
  * Types and defines for EFI ResetSystem
  */
@@ -236,6 +295,24 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
 #define LINUX_EFI_CRASH_GUID \
     EFI_GUID(  0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 )
 
+#define LOADED_IMAGE_PROTOCOL_GUID \
+    EFI_GUID(  0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
+#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
+    EFI_GUID(  0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a )
+
+#define EFI_UGA_PROTOCOL_GUID \
+    EFI_GUID(  0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 )
+
+#define EFI_PCI_IO_PROTOCOL_GUID \
+    EFI_GUID(  0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x2, 0x9a )
+
+#define EFI_FILE_INFO_ID \
+    EFI_GUID(  0x9576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
+#define EFI_FILE_SYSTEM_GUID \
+    EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
 typedef struct {
        efi_guid_t guid;
        unsigned long table;
@@ -261,7 +338,7 @@ typedef struct {
        unsigned long stderr_handle;
        unsigned long stderr;
        efi_runtime_services_t *runtime;
-       unsigned long boottime;
+       efi_boot_services_t *boottime;
        unsigned long nr_tables;
        unsigned long tables;
 } efi_system_table_t;
@@ -275,6 +352,56 @@ struct efi_memory_map {
        unsigned long desc_size;
 };
 
+typedef struct {
+       u32 revision;
+       void *parent_handle;
+       efi_system_table_t *system_table;
+       void *device_handle;
+       void *file_path;
+       void *reserved;
+       u32 load_options_size;
+       void *load_options;
+       void *image_base;
+       __aligned_u64 image_size;
+       unsigned int image_code_type;
+       unsigned int image_data_type;
+       unsigned long unload;
+} efi_loaded_image_t;
+
+typedef struct {
+       u64 revision;
+       void *open_volume;
+} efi_file_io_interface_t;
+
+typedef struct {
+       u64 size;
+       u64 file_size;
+       u64 phys_size;
+       efi_time_t create_time;
+       efi_time_t last_access_time;
+       efi_time_t modification_time;
+       __aligned_u64 attribute;
+       efi_char16_t filename[1];
+} efi_file_info_t;
+
+typedef struct {
+       u64 revision;
+       void *open;
+       void *close;
+       void *delete;
+       void *read;
+       void *write;
+       void *get_position;
+       void *set_position;
+       void *get_info;
+       void *set_info;
+       void *flush;
+} efi_file_handle_t;
+
+#define EFI_FILE_MODE_READ     0x0000000000000001
+#define EFI_FILE_MODE_WRITE    0x0000000000000002
+#define EFI_FILE_MODE_CREATE   0x8000000000000000
+
 #define EFI_INVALID_TABLE_ADDR         (~0UL)
 
 /*
@@ -384,6 +511,13 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
 #define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
 
+/*
+ * The type of search to perform when calling boottime->locate_handle
+ */
+#define EFI_LOCATE_ALL_HANDLES                 0
+#define EFI_LOCATE_BY_REGISTER_NOTIFY          1
+#define EFI_LOCATE_BY_PROTOCOL                 2
+
 /*
  * EFI Device Path information
  */
index 18bea78fe47b3e5ce97f98bac45fd6e1e6acd785..8e2b7bac437869d8058427d513115e457a57752d 100644 (file)
@@ -33,6 +33,7 @@
 #define EM_H8_300      46      /* Renesas H8/300,300H,H8S */
 #define EM_MN10300     89      /* Panasonic/MEI MN10300, AM33 */
 #define EM_BLACKFIN     106     /* ADI Blackfin Processor */
+#define EM_TI_C6000    140     /* TI C6X DSPs */
 #define EM_FRV         0x5441  /* Fujitsu FR-V */
 #define EM_AVR32       0x18ad  /* Atmel AVR32 */
 
index f362733186a5a6f4a1657b0a85ee32e158095ed2..657ab55beda014c15b33833e84dc7e1496d06abf 100644 (file)
@@ -61,6 +61,7 @@ struct file;
 static inline void eventpoll_init_file(struct file *file)
 {
        INIT_LIST_HEAD(&file->f_ep_links);
+       INIT_LIST_HEAD(&file->f_tfile_llink);
 }
 
 
index 7aacf31418fed291df3591c07ef252a26aa4c62c..4bc8169fb5a1edd97b5cc0a6703126d15596add6 100644 (file)
@@ -525,6 +525,7 @@ enum positive_aop_returns {
 struct page;
 struct address_space;
 struct writeback_control;
+enum migrate_mode;
 
 struct iov_iter {
        const struct iovec *iov;
@@ -609,9 +610,12 @@ struct address_space_operations {
                        loff_t offset, unsigned long nr_segs);
        int (*get_xip_mem)(struct address_space *, pgoff_t, int,
                                                void **, unsigned long *);
-       /* migrate the contents of a page to the specified target */
+       /*
+        * migrate the contents of a page to the specified target. If sync
+        * is false, it must not block.
+        */
        int (*migratepage) (struct address_space *,
-                       struct page *, struct page *);
+                       struct page *, struct page *, enum migrate_mode);
        int (*launder_page) (struct page *);
        int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
                                        unsigned long);
@@ -656,6 +660,7 @@ struct address_space {
         * must be enforced here for CRIS, to let the least significant bit
         * of struct page's "mapping" pointer be used for PAGE_MAPPING_ANON.
         */
+struct request_queue;
 
 struct block_device {
        dev_t                   bd_dev;  /* not a kdev_t - it's a search key */
@@ -678,6 +683,7 @@ struct block_device {
        unsigned                bd_part_count;
        int                     bd_invalidated;
        struct gendisk *        bd_disk;
+       struct request_queue *  bd_queue;
        struct list_head        bd_list;
        /*
         * Private data.  You must have bd_claim'ed the block_device
@@ -1001,6 +1007,7 @@ struct file {
 #ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
+       struct list_head        f_tfile_llink;
 #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
 #ifdef CONFIG_DEBUG_WRITECOUNT
@@ -2536,7 +2543,8 @@ extern int generic_check_addressable(unsigned, u64);
 
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
-                               struct page *, struct page *);
+                               struct page *, struct page *,
+                               enum migrate_mode);
 #else
 #define buffer_migrate_page NULL
 #endif
index 464cff52686092c0f862f551b2db53ed3050b629..8ba2c9460b28fb90bfee024aa8f73601f6c4cf68 100644 (file)
  *
  * 7.17
  *  - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
+ *
+ * 7.18
+ *  - add FUSE_IOCTL_DIR flag
+ *  - add FUSE_NOTIFY_DELETE
  */
 
 #ifndef _LINUX_FUSE_H
@@ -81,7 +85,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 17
+#define FUSE_KERNEL_MINOR_VERSION 18
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -214,6 +218,7 @@ struct fuse_file_lock {
  * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
  * FUSE_IOCTL_RETRY: retry with new iovecs
  * FUSE_IOCTL_32BIT: 32bit ioctl
+ * FUSE_IOCTL_DIR: is a directory
  *
  * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
  */
@@ -221,6 +226,7 @@ struct fuse_file_lock {
 #define FUSE_IOCTL_UNRESTRICTED        (1 << 1)
 #define FUSE_IOCTL_RETRY       (1 << 2)
 #define FUSE_IOCTL_32BIT       (1 << 3)
+#define FUSE_IOCTL_DIR         (1 << 4)
 
 #define FUSE_IOCTL_MAX_IOV     256
 
@@ -283,6 +289,7 @@ enum fuse_notify_code {
        FUSE_NOTIFY_INVAL_ENTRY = 3,
        FUSE_NOTIFY_STORE = 4,
        FUSE_NOTIFY_RETRIEVE = 5,
+       FUSE_NOTIFY_DELETE = 6,
        FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -606,6 +613,13 @@ struct fuse_notify_inval_entry_out {
        __u32   padding;
 };
 
+struct fuse_notify_delete_out {
+       __u64   parent;
+       __u64   child;
+       __u32   namelen;
+       __u32   padding;
+};
+
 struct fuse_notify_store_out {
        __u64   nodeid;
        __u64   offset;
index 3a76faf6a3ee82cd20f82d36208c6f50c8f29685..581e74b7df95e3d063bbbcaece35aafe60fad774 100644 (file)
@@ -36,6 +36,7 @@ struct vm_area_struct;
 #endif
 #define ___GFP_NO_KSWAPD       0x400000u
 #define ___GFP_OTHER_NODE      0x800000u
+#define ___GFP_WRITE           0x1000000u
 
 /*
  * GFP bitmasks..
@@ -85,6 +86,7 @@ struct vm_area_struct;
 
 #define __GFP_NO_KSWAPD        ((__force gfp_t)___GFP_NO_KSWAPD)
 #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
+#define __GFP_WRITE    ((__force gfp_t)___GFP_WRITE)   /* Allocator intends to dirty page */
 
 /*
  * This may seem redundant, but it's a way of annotating false positives vs.
@@ -92,7 +94,7 @@ struct vm_area_struct;
  */
 #define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
 
-#define __GFP_BITS_SHIFT 24    /* Room for N __GFP_FOO bits */
+#define __GFP_BITS_SHIFT 25    /* Room for N __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /* This equals 0, but use constants in case they ever change */
@@ -313,7 +315,7 @@ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
 static inline struct page *alloc_pages_exact_node(int nid, gfp_t gfp_mask,
                                                unsigned int order)
 {
-       VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
+       VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES || !node_online(nid));
 
        return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
 }
@@ -358,6 +360,7 @@ void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask);
 extern void __free_pages(struct page *page, unsigned int order);
 extern void free_pages(unsigned long addr, unsigned int order);
 extern void free_hot_cold_page(struct page *page, int cold);
+extern void free_hot_cold_page_list(struct list_head *list, int cold);
 
 #define __free_page(page) __free_pages((page), 0)
 #define free_page(addr) free_pages((addr), 0)
@@ -367,9 +370,25 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
 void drain_all_pages(void);
 void drain_local_pages(void *dummy);
 
+/*
+ * gfp_allowed_mask is set to GFP_BOOT_MASK during early boot to restrict what
+ * GFP flags are used before interrupts are enabled. Once interrupts are
+ * enabled, it is set to __GFP_BITS_MASK while the system is running. During
+ * hibernation, it is used by PM to avoid I/O during memory allocation while
+ * devices are suspended.
+ */
 extern gfp_t gfp_allowed_mask;
 
 extern void pm_restrict_gfp_mask(void);
 extern void pm_restore_gfp_mask(void);
 
+#ifdef CONFIG_PM_SLEEP
+extern bool pm_suspended_storage(void);
+#else
+static inline bool pm_suspended_storage(void)
+{
+       return false;
+}
+#endif /* CONFIG_PM_SLEEP */
+
 #endif /* __LINUX_GFP_H */
index 4f4462974c142cd47e00eddabf4e8d64802a72f3..b148087f49a62921d40b66b39224d33239047626 100644 (file)
@@ -22,6 +22,8 @@
 #define GFS2_LIVE_LOCK         1
 #define GFS2_TRANS_LOCK                2
 #define GFS2_RENAME_LOCK       3
+#define GFS2_CONTROL_LOCK      4
+#define GFS2_MOUNTED_LOCK      5
 
 /* Format numbers for various metadata types */
 
index a9ace9c32507e31a851bcd719d0a56759b3a4428..1b921299abc420f1e258b614aa319964cd98942c 100644 (file)
@@ -18,7 +18,7 @@ extern struct page *follow_trans_huge_pmd(struct mm_struct *mm,
                                          unsigned int flags);
 extern int zap_huge_pmd(struct mmu_gather *tlb,
                        struct vm_area_struct *vma,
-                       pmd_t *pmd);
+                       pmd_t *pmd, unsigned long addr);
 extern int mincore_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        unsigned long addr, unsigned long end,
                        unsigned char *vec);
index 114c0f6fc63d8f7c818f79459995c6844736993a..78d3465251d6cd8e38e47903622cd0e3bad9e42d 100644 (file)
@@ -652,10 +652,12 @@ struct twl4030_power_data {
        unsigned num;
        struct twl4030_resconfig *resource_config;
 #define TWL4030_RESCONFIG_UNDEF        ((u8)-1)
+       bool use_poweroff;      /* Board is wired for TWL poweroff */
 };
 
 extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
+extern void twl4030_power_off(void);
 
 struct twl4030_codec_data {
        unsigned int digimic_delay; /* in ms */
index 34e8d52c192509ec3908bd74376410f7170a8628..f1362b5447fcbcf6935e49aec748675562eb0b12 100644 (file)
@@ -22,7 +22,7 @@ struct inet_diag_sockid {
 
 /* Request structure */
 
-struct inet_diag_req_compat {
+struct inet_diag_req {
        __u8    idiag_family;           /* Family of addresses. */
        __u8    idiag_src_len;
        __u8    idiag_dst_len;
@@ -34,7 +34,7 @@ struct inet_diag_req_compat {
        __u32   idiag_dbs;              /* Tables to dump (NI) */
 };
 
-struct inet_diag_req {
+struct inet_diag_req_v2 {
        __u8    sdiag_family;
        __u8    sdiag_protocol;
        __u8    idiag_ext;
@@ -143,12 +143,12 @@ struct netlink_callback;
 struct inet_diag_handler {
        void                    (*dump)(struct sk_buff *skb,
                                        struct netlink_callback *cb,
-                                       struct inet_diag_req *r,
+                                       struct inet_diag_req_v2 *r,
                                        struct nlattr *bc);
 
        int                     (*dump_one)(struct sk_buff *in_skb,
                                        const struct nlmsghdr *nlh,
-                                       struct inet_diag_req *req);
+                                       struct inet_diag_req_v2 *req);
 
        void                    (*idiag_get_info)(struct sock *sk,
                                                  struct inet_diag_msg *r,
@@ -158,15 +158,15 @@ struct inet_diag_handler {
 
 struct inet_connection_sock;
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh);
 void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *r,
+               struct netlink_callback *cb, struct inet_diag_req_v2 *r,
                struct nlattr *bc);
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
                struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req);
+               struct inet_diag_req_v2 *req);
 
 int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk);
 
index 2092ea21e469eeeaa415a885ead161fed0ac7d38..5557baefed60b5f5bb3dd0984bbbe7f2e0a4c8fc 100644 (file)
@@ -1151,6 +1151,7 @@ extern int        jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t);
 extern int     jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t);
 extern void    jbd2_journal_clear_revoke(journal_t *);
 extern void    jbd2_journal_switch_revoke_table(journal_t *journal);
+extern void    jbd2_clear_buffer_revoked_flags(journal_t *journal);
 
 /*
  * The log thread user interface:
index e8b1597b5cf2592b85157674b1d1fcbd555d309a..e8343422240a8ca981dbd5b5971ccef6c30d1382 100644 (file)
@@ -185,16 +185,17 @@ static inline void might_fault(void)
 
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(int state);
-NORET_TYPE void panic(const char * fmt, ...)
-       __attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
+__printf(1, 2)
+void panic(const char *fmt, ...)
+       __noreturn __cold;
 extern void oops_enter(void);
 extern void oops_exit(void);
 void print_oops_end_marker(void);
 extern int oops_may_print(void);
-NORET_TYPE void do_exit(long error_code)
-       ATTRIB_NORET;
-NORET_TYPE void complete_and_exit(struct completion *, long)
-       ATTRIB_NORET;
+void do_exit(long error_code)
+       __noreturn;
+void complete_and_exit(struct completion *, long)
+       __noreturn;
 
 /* Internal, do not use. */
 int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res);
@@ -341,6 +342,7 @@ extern int panic_timeout;
 extern int panic_on_oops;
 extern int panic_on_unrecovered_nmi;
 extern int panic_on_io_nmi;
+extern int sysctl_panic_on_stackoverflow;
 extern const char *print_tainted(void);
 extern void add_taint(unsigned flag);
 extern int test_taint(unsigned flag);
@@ -665,6 +667,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
 #define BUILD_BUG_ON_ZERO(e) (0)
 #define BUILD_BUG_ON_NULL(e) ((void*)0)
 #define BUILD_BUG_ON(condition)
+#define BUILD_BUG() (0)
 #else /* __CHECKER__ */
 
 /* Force a compilation error if a constant expression is not a power of 2 */
@@ -703,6 +706,21 @@ extern int __build_bug_on_failed;
                if (condition) __build_bug_on_failed = 1;       \
        } while(0)
 #endif
+
+/**
+ * BUILD_BUG - break compile if used.
+ *
+ * If you have some code that you expect the compiler to eliminate at
+ * build time, you should use BUILD_BUG to detect if it is
+ * unexpectedly used.
+ */
+#define BUILD_BUG()                                            \
+       do {                                                    \
+               extern void __build_bug_failed(void)            \
+                       __linktime_error("BUILD_BUG failed");   \
+               __build_bug_failed();                           \
+       } while (0)
+
 #endif /* __CHECKER__ */
 
 /* Trap pasters of __FUNCTION__ at compile-time */
index 9efd081bb31e19b23f98935b9673dd89b53924af..39e3c082c49d489a32ab781e080b28236661877f 100644 (file)
@@ -92,6 +92,7 @@ struct key_type {
 
        /* internal fields */
        struct list_head        link;           /* link in types list */
+       struct lock_class_key   lock_class;     /* key->sem lock class */
 };
 
 extern struct key_type key_type_keyring;
index ee0c952188de2c99281fd7567f701893e90a47dd..fee66317e071547a4a75e0b90b61399b97249ed2 100644 (file)
@@ -18,7 +18,6 @@
 enum kmsg_dump_reason {
        KMSG_DUMP_OOPS,
        KMSG_DUMP_PANIC,
-       KMSG_DUMP_KEXEC,
        KMSG_DUMP_RESTART,
        KMSG_DUMP_HALT,
        KMSG_DUMP_POWEROFF,
diff --git a/include/linux/leds-tca6507.h b/include/linux/leds-tca6507.h
new file mode 100644 (file)
index 0000000..dcabf4f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * TCA6507 LED chip driver.
+ *
+ * Copyright (C) 2011 Neil Brown <neil@brown.name>
+ *
+ * This program is free software; you can 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 __LINUX_TCA6507_H
+#define __LINUX_TCA6507_H
+#include <linux/leds.h>
+
+struct tca6507_platform_data {
+       struct led_platform_data leds;
+#ifdef CONFIG_GPIOLIB
+       int gpio_base;
+       void (*setup)(unsigned gpio_base, unsigned ngpio);
+#endif
+};
+
+#define        TCA6507_MAKE_GPIO 1
+#endif /* __LINUX_TCA6507_H*/
index 3f46aedea42fbb5024f8e9896e380d0051c74132..807f1e5332267e6bd776f9591f106b723e1c02ab 100644 (file)
@@ -88,8 +88,4 @@
 
 #endif
 
-#define NORET_TYPE    /**/
-#define ATTRIB_NORET  __attribute__((noreturn))
-#define NORET_AND     noreturn,
-
 #endif
diff --git a/include/linux/lp8727.h b/include/linux/lp8727.h
new file mode 100755 (executable)
index 0000000..d21fa28
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *                     Copyright (C) 2011 National Semiconductor
+ *
+ * This program is free software; you can 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 _LP8727_H
+#define _LP8727_H
+
+enum lp8727_eoc_level {
+       EOC_5P,
+       EOC_10P,
+       EOC_16P,
+       EOC_20P,
+       EOC_25P,
+       EOC_33P,
+       EOC_50P,
+};
+
+enum lp8727_ichg {
+       ICHG_90mA,
+       ICHG_100mA,
+       ICHG_400mA,
+       ICHG_450mA,
+       ICHG_500mA,
+       ICHG_600mA,
+       ICHG_700mA,
+       ICHG_800mA,
+       ICHG_900mA,
+       ICHG_1000mA,
+};
+
+struct lp8727_chg_param {
+       /* end of charge level setting */
+       enum lp8727_eoc_level eoc_level;
+       /* charging current */
+       enum lp8727_ichg ichg;
+};
+
+struct lp8727_platform_data {
+       u8 (*get_batt_present)(void);
+       u16 (*get_batt_level)(void);
+       u8 (*get_batt_capacity)(void);
+       u8 (*get_batt_temp)(void);
+       struct lp8727_chg_param ac;
+       struct lp8727_chg_param usb;
+};
+
+#endif
index f944591765eba3be0904bc820c4063c3c73183fd..4d34356fe644ee5dca447071829ae06ab68eeb60 100644 (file)
@@ -32,13 +32,11 @@ enum mem_cgroup_page_stat_item {
        MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */
 };
 
-extern unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z,
-                                       struct mem_cgroup *mem_cont,
-                                       int active, int file);
+struct mem_cgroup_reclaim_cookie {
+       struct zone *zone;
+       int priority;
+       unsigned int generation;
+};
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 /*
@@ -56,20 +54,21 @@ extern int mem_cgroup_newpage_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask);
 /* for swap handling */
 extern int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
-               struct page *page, gfp_t mask, struct mem_cgroup **ptr);
+               struct page *page, gfp_t mask, struct mem_cgroup **memcgp);
 extern void mem_cgroup_commit_charge_swapin(struct page *page,
-                                       struct mem_cgroup *ptr);
-extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr);
+                                       struct mem_cgroup *memcg);
+extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg);
 
 extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                        gfp_t gfp_mask);
-extern void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_rotate_reclaimable_page(struct page *page);
-extern void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru);
-extern void mem_cgroup_del_lru(struct page *page);
-extern void mem_cgroup_move_lists(struct page *page,
-                                 enum lru_list from, enum lru_list to);
+
+struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
+struct lruvec *mem_cgroup_lru_add_list(struct zone *, struct page *,
+                                      enum lru_list);
+void mem_cgroup_lru_del_list(struct page *, enum lru_list);
+void mem_cgroup_lru_del(struct page *);
+struct lruvec *mem_cgroup_lru_move_lists(struct zone *, struct page *,
+                                        enum lru_list, enum lru_list);
 
 /* For coalescing uncharge for reducing memcg' overhead*/
 extern void mem_cgroup_uncharge_start(void);
@@ -102,10 +101,15 @@ extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg);
 
 extern int
 mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask);
+       struct page *newpage, struct mem_cgroup **memcgp, gfp_t gfp_mask);
 extern void mem_cgroup_end_migration(struct mem_cgroup *memcg,
        struct page *oldpage, struct page *newpage, bool migration_ok);
 
+struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
+                                  struct mem_cgroup *,
+                                  struct mem_cgroup_reclaim_cookie *);
+void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
+
 /*
  * For memory reclaim.
  */
@@ -122,7 +126,10 @@ struct zone_reclaim_stat*
 mem_cgroup_get_reclaim_stat_from_page(struct page *page);
 extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
                                        struct task_struct *p);
+extern void mem_cgroup_replace_page_cache(struct page *oldpage,
+                                       struct page *newpage);
 
+extern void mem_cgroup_reset_owner(struct page *page);
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
 extern int do_swap_account;
 #endif
@@ -157,7 +164,7 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg);
 
 void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
+void mem_cgroup_split_huge_fixup(struct page *head);
 #endif
 
 #ifdef CONFIG_DEBUG_VM
@@ -180,17 +187,17 @@ static inline int mem_cgroup_cache_charge(struct page *page,
 }
 
 static inline int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
-               struct page *page, gfp_t gfp_mask, struct mem_cgroup **ptr)
+               struct page *page, gfp_t gfp_mask, struct mem_cgroup **memcgp)
 {
        return 0;
 }
 
 static inline void mem_cgroup_commit_charge_swapin(struct page *page,
-                                         struct mem_cgroup *ptr)
+                                         struct mem_cgroup *memcg)
 {
 }
 
-static inline void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *ptr)
+static inline void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg)
 {
 }
 
@@ -210,33 +217,33 @@ static inline void mem_cgroup_uncharge_cache_page(struct page *page)
 {
 }
 
-static inline void mem_cgroup_add_lru_list(struct page *page, int lru)
-{
-}
-
-static inline void mem_cgroup_del_lru_list(struct page *page, int lru)
+static inline struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
+                                                   struct mem_cgroup *memcg)
 {
-       return ;
+       return &zone->lruvec;
 }
 
-static inline void mem_cgroup_rotate_reclaimable_page(struct page *page)
+static inline struct lruvec *mem_cgroup_lru_add_list(struct zone *zone,
+                                                    struct page *page,
+                                                    enum lru_list lru)
 {
-       return ;
+       return &zone->lruvec;
 }
 
-static inline void mem_cgroup_rotate_lru_list(struct page *page, int lru)
+static inline void mem_cgroup_lru_del_list(struct page *page, enum lru_list lru)
 {
-       return ;
 }
 
-static inline void mem_cgroup_del_lru(struct page *page)
+static inline void mem_cgroup_lru_del(struct page *page)
 {
-       return ;
 }
 
-static inline void
-mem_cgroup_move_lists(struct page *page, enum lru_list from, enum lru_list to)
+static inline struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
+                                                      struct page *page,
+                                                      enum lru_list from,
+                                                      enum lru_list to)
 {
+       return &zone->lruvec;
 }
 
 static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
@@ -269,7 +276,7 @@ static inline struct cgroup_subsys_state
 
 static inline int
 mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
-       struct mem_cgroup **ptr, gfp_t gfp_mask)
+       struct mem_cgroup **memcgp, gfp_t gfp_mask)
 {
        return 0;
 }
@@ -279,6 +286,19 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg,
 {
 }
 
+static inline struct mem_cgroup *
+mem_cgroup_iter(struct mem_cgroup *root,
+               struct mem_cgroup *prev,
+               struct mem_cgroup_reclaim_cookie *reclaim)
+{
+       return NULL;
+}
+
+static inline void mem_cgroup_iter_break(struct mem_cgroup *root,
+                                        struct mem_cgroup *prev)
+{
+}
+
 static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *memcg)
 {
        return 0;
@@ -360,8 +380,7 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
        return 0;
 }
 
-static inline void mem_cgroup_split_huge_fixup(struct page *head,
-                                               struct page *tail)
+static inline void mem_cgroup_split_huge_fixup(struct page *head)
 {
 }
 
@@ -369,6 +388,14 @@ static inline
 void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
 {
 }
+static inline void mem_cgroup_replace_page_cache(struct page *oldpage,
+                               struct page *newpage)
+{
+}
+
+static inline void mem_cgroup_reset_owner(struct page *page)
+{
+}
 #endif /* CONFIG_CGROUP_MEM_CONT */
 
 #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM)
index 7978eec1b7d9964420c2e854afba51a8f9cbf8f5..7c727a90d70da6229afeb9c9cf7c8601841863e2 100644 (file)
@@ -164,11 +164,11 @@ static inline void mpol_get(struct mempolicy *pol)
                atomic_inc(&pol->refcnt);
 }
 
-extern int __mpol_equal(struct mempolicy *a, struct mempolicy *b);
-static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)
+extern bool __mpol_equal(struct mempolicy *a, struct mempolicy *b);
+static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
        if (a == b)
-               return 1;
+               return true;
        return __mpol_equal(a, b);
 }
 
@@ -257,9 +257,9 @@ static inline int vma_migratable(struct vm_area_struct *vma)
 
 struct mempolicy {};
 
-static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)
+static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
-       return 1;
+       return true;
 }
 
 static inline void mpol_put(struct mempolicy *p)
index 63b4fb8e3b6f9aac05faef4534755a55dffc8733..92be3476c9f5560d8623ac5cae738e1471525f22 100644 (file)
@@ -297,10 +297,11 @@ enum {
 
 struct pm860x_chip {
        struct device           *dev;
-       struct mutex            io_lock;
        struct mutex            irq_lock;
        struct i2c_client       *client;
        struct i2c_client       *companion;     /* companion chip client */
+       struct regmap           *regmap;
+       struct regmap           *regmap_companion;
 
        int                     buck3_double;   /* DVC ramp slope double */
        unsigned short          companion_addr;
diff --git a/include/linux/mfd/ab5500/ab5500.h b/include/linux/mfd/ab5500/ab5500.h
deleted file mode 100644 (file)
index a720051..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson 2011
- *
- * License Terms: GNU General Public License v2
- */
-#ifndef MFD_AB5500_H
-#define MFD_AB5500_H
-
-#include <linux/device.h>
-
-enum ab5500_devid {
-       AB5500_DEVID_ADC,
-       AB5500_DEVID_LEDS,
-       AB5500_DEVID_POWER,
-       AB5500_DEVID_REGULATORS,
-       AB5500_DEVID_SIM,
-       AB5500_DEVID_RTC,
-       AB5500_DEVID_CHARGER,
-       AB5500_DEVID_FUELGAUGE,
-       AB5500_DEVID_VIBRATOR,
-       AB5500_DEVID_CODEC,
-       AB5500_DEVID_USB,
-       AB5500_DEVID_OTP,
-       AB5500_DEVID_VIDEO,
-       AB5500_DEVID_DBIECI,
-       AB5500_DEVID_ONSWA,
-       AB5500_NUM_DEVICES,
-};
-
-enum ab5500_banks {
-       AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP = 0,
-       AB5500_BANK_VDDDIG_IO_I2C_CLK_TST = 1,
-       AB5500_BANK_VDENC = 2,
-       AB5500_BANK_SIM_USBSIM  = 3,
-       AB5500_BANK_LED = 4,
-       AB5500_BANK_ADC  = 5,
-       AB5500_BANK_RTC  = 6,
-       AB5500_BANK_STARTUP  = 7,
-       AB5500_BANK_DBI_ECI  = 8,
-       AB5500_BANK_CHG  = 9,
-       AB5500_BANK_FG_BATTCOM_ACC = 10,
-       AB5500_BANK_USB = 11,
-       AB5500_BANK_IT = 12,
-       AB5500_BANK_VIBRA = 13,
-       AB5500_BANK_AUDIO_HEADSETUSB = 14,
-       AB5500_NUM_BANKS = 15,
-};
-
-enum ab5500_banks_addr {
-       AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP = 0x4A,
-       AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST = 0x4B,
-       AB5500_ADDR_VDENC = 0x06,
-       AB5500_ADDR_SIM_USBSIM  = 0x04,
-       AB5500_ADDR_LED = 0x10,
-       AB5500_ADDR_ADC  = 0x0A,
-       AB5500_ADDR_RTC  = 0x0F,
-       AB5500_ADDR_STARTUP  = 0x03,
-       AB5500_ADDR_DBI_ECI  = 0x07,
-       AB5500_ADDR_CHG  = 0x0B,
-       AB5500_ADDR_FG_BATTCOM_ACC = 0x0C,
-       AB5500_ADDR_USB = 0x05,
-       AB5500_ADDR_IT = 0x0E,
-       AB5500_ADDR_VIBRA = 0x02,
-       AB5500_ADDR_AUDIO_HEADSETUSB = 0x0D,
-};
-
-/*
- * Interrupt register offsets
- * Bank : 0x0E
- */
-#define AB5500_IT_SOURCE0_REG          0x20
-#define AB5500_IT_SOURCE1_REG          0x21
-#define AB5500_IT_SOURCE2_REG          0x22
-#define AB5500_IT_SOURCE3_REG          0x23
-#define AB5500_IT_SOURCE4_REG          0x24
-#define AB5500_IT_SOURCE5_REG          0x25
-#define AB5500_IT_SOURCE6_REG          0x26
-#define AB5500_IT_SOURCE7_REG          0x27
-#define AB5500_IT_SOURCE8_REG          0x28
-#define AB5500_IT_SOURCE9_REG          0x29
-#define AB5500_IT_SOURCE10_REG         0x2A
-#define AB5500_IT_SOURCE11_REG         0x2B
-#define AB5500_IT_SOURCE12_REG         0x2C
-#define AB5500_IT_SOURCE13_REG         0x2D
-#define AB5500_IT_SOURCE14_REG         0x2E
-#define AB5500_IT_SOURCE15_REG         0x2F
-#define AB5500_IT_SOURCE16_REG         0x30
-#define AB5500_IT_SOURCE17_REG         0x31
-#define AB5500_IT_SOURCE18_REG         0x32
-#define AB5500_IT_SOURCE19_REG         0x33
-#define AB5500_IT_SOURCE20_REG         0x34
-#define AB5500_IT_SOURCE21_REG         0x35
-#define AB5500_IT_SOURCE22_REG         0x36
-#define AB5500_IT_SOURCE23_REG         0x37
-
-#define AB5500_NUM_IRQ_REGS            23
-
-/**
- * struct ab5500
- * @access_mutex: lock out concurrent accesses to the AB registers
- * @dev: a pointer to the device struct for this chip driver
- * @ab5500_irq: the analog baseband irq
- * @irq_base: the platform configuration irq base for subdevices
- * @chip_name: name of this chip variant
- * @chip_id: 8 bit chip ID for this chip variant
- * @irq_lock: a lock to protect the mask
- * @abb_events: a local bit mask of the prcmu wakeup events
- * @event_mask: a local copy of the mask event registers
- * @last_event_mask: a copy of the last event_mask written to hardware
- * @startup_events: a copy of the first reading of the event registers
- * @startup_events_read: whether the first events have been read
- */
-struct ab5500 {
-       struct mutex access_mutex;
-       struct device *dev;
-       unsigned int ab5500_irq;
-       unsigned int irq_base;
-       char chip_name[32];
-       u8 chip_id;
-       struct mutex irq_lock;
-       u32 abb_events;
-       u8 mask[AB5500_NUM_IRQ_REGS];
-       u8 oldmask[AB5500_NUM_IRQ_REGS];
-       u8 startup_events[AB5500_NUM_IRQ_REGS];
-       bool startup_events_read;
-#ifdef CONFIG_DEBUG_FS
-       unsigned int debug_bank;
-       unsigned int debug_address;
-#endif
-};
-
-struct ab5500_platform_data {
-       struct {unsigned int base; unsigned int count; } irq;
-       void *dev_data[AB5500_NUM_DEVICES];
-       struct abx500_init_settings *init_settings;
-       unsigned int init_settings_sz;
-       bool pm_power_off;
-};
-
-#endif /* MFD_AB5500_H */
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
deleted file mode 100644 (file)
index 838c6b4..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- */
-#ifndef MFD_AB8500_H
-#define MFD_AB8500_H
-
-#include <linux/device.h>
-
-/*
- * AB8500 bank addresses
- */
-#define AB8500_SYS_CTRL1_BLOCK 0x1
-#define AB8500_SYS_CTRL2_BLOCK 0x2
-#define AB8500_REGU_CTRL1      0x3
-#define AB8500_REGU_CTRL2      0x4
-#define AB8500_USB             0x5
-#define AB8500_TVOUT           0x6
-#define AB8500_DBI             0x7
-#define AB8500_ECI_AV_ACC      0x8
-#define AB8500_RESERVED                0x9
-#define AB8500_GPADC           0xA
-#define AB8500_CHARGER         0xB
-#define AB8500_GAS_GAUGE       0xC
-#define AB8500_AUDIO           0xD
-#define AB8500_INTERRUPT       0xE
-#define AB8500_RTC             0xF
-#define AB8500_MISC            0x10
-#define AB8500_DEVELOPMENT     0x11
-#define AB8500_DEBUG           0x12
-#define AB8500_PROD_TEST       0x13
-#define AB8500_OTP_EMUL                0x15
-
-/*
- * Interrupts
- */
-
-#define AB8500_INT_MAIN_EXT_CH_NOT_OK  0
-#define AB8500_INT_UN_PLUG_TV_DET      1
-#define AB8500_INT_PLUG_TV_DET         2
-#define AB8500_INT_TEMP_WARM           3
-#define AB8500_INT_PON_KEY2DB_F                4
-#define AB8500_INT_PON_KEY2DB_R                5
-#define AB8500_INT_PON_KEY1DB_F                6
-#define AB8500_INT_PON_KEY1DB_R                7
-#define AB8500_INT_BATT_OVV            8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET  10
-#define AB8500_INT_MAIN_CH_PLUG_DET    11
-#define AB8500_INT_USB_ID_DET_F                12
-#define AB8500_INT_USB_ID_DET_R                13
-#define AB8500_INT_VBUS_DET_F          14
-#define AB8500_INT_VBUS_DET_R          15
-#define AB8500_INT_VBUS_CH_DROP_END    16
-#define AB8500_INT_RTC_60S             17
-#define AB8500_INT_RTC_ALARM           18
-#define AB8500_INT_BAT_CTRL_INDB       20
-#define AB8500_INT_CH_WD_EXP           21
-#define AB8500_INT_VBUS_OVV            22
-#define AB8500_INT_MAIN_CH_DROP_END    23
-#define AB8500_INT_CCN_CONV_ACC                24
-#define AB8500_INT_INT_AUD             25
-#define AB8500_INT_CCEOC               26
-#define AB8500_INT_CC_INT_CALIB                27
-#define AB8500_INT_LOW_BAT_F           28
-#define AB8500_INT_LOW_BAT_R           29
-#define AB8500_INT_BUP_CHG_NOT_OK      30
-#define AB8500_INT_BUP_CHG_OK          31
-#define AB8500_INT_GP_HW_ADC_CONV_END  32
-#define AB8500_INT_ACC_DETECT_1DB_F    33
-#define AB8500_INT_ACC_DETECT_1DB_R    34
-#define AB8500_INT_ACC_DETECT_22DB_F   35
-#define AB8500_INT_ACC_DETECT_22DB_R   36
-#define AB8500_INT_ACC_DETECT_21DB_F   37
-#define AB8500_INT_ACC_DETECT_21DB_R   38
-#define AB8500_INT_GP_SW_ADC_CONV_END  39
-#define AB8500_INT_GPIO6R              40
-#define AB8500_INT_GPIO7R              41
-#define AB8500_INT_GPIO8R              42
-#define AB8500_INT_GPIO9R              43
-#define AB8500_INT_GPIO10R             44
-#define AB8500_INT_GPIO11R             45
-#define AB8500_INT_GPIO12R             46
-#define AB8500_INT_GPIO13R             47
-#define AB8500_INT_GPIO24R             48
-#define AB8500_INT_GPIO25R             49
-#define AB8500_INT_GPIO36R             50
-#define AB8500_INT_GPIO37R             51
-#define AB8500_INT_GPIO38R             52
-#define AB8500_INT_GPIO39R             53
-#define AB8500_INT_GPIO40R             54
-#define AB8500_INT_GPIO41R             55
-#define AB8500_INT_GPIO6F              56
-#define AB8500_INT_GPIO7F              57
-#define AB8500_INT_GPIO8F              58
-#define AB8500_INT_GPIO9F              59
-#define AB8500_INT_GPIO10F             60
-#define AB8500_INT_GPIO11F             61
-#define AB8500_INT_GPIO12F             62
-#define AB8500_INT_GPIO13F             63
-#define AB8500_INT_GPIO24F             64
-#define AB8500_INT_GPIO25F             65
-#define AB8500_INT_GPIO36F             66
-#define AB8500_INT_GPIO37F             67
-#define AB8500_INT_GPIO38F             68
-#define AB8500_INT_GPIO39F             69
-#define AB8500_INT_GPIO40F             70
-#define AB8500_INT_GPIO41F             71
-#define AB8500_INT_ADP_SOURCE_ERROR    72
-#define AB8500_INT_ADP_SINK_ERROR      73
-#define AB8500_INT_ADP_PROBE_PLUG      74
-#define AB8500_INT_ADP_PROBE_UNPLUG    75
-#define AB8500_INT_ADP_SENSE_OFF       76
-#define AB8500_INT_USB_PHY_POWER_ERR   78
-#define AB8500_INT_USB_LINK_STATUS     79
-#define AB8500_INT_BTEMP_LOW           80
-#define AB8500_INT_BTEMP_LOW_MEDIUM    81
-#define AB8500_INT_BTEMP_MEDIUM_HIGH   82
-#define AB8500_INT_BTEMP_HIGH          83
-#define AB8500_INT_USB_CHARGER_NOT_OK  89
-#define AB8500_INT_ID_WAKEUP_R         90
-#define AB8500_INT_ID_DET_R1R          92
-#define AB8500_INT_ID_DET_R2R          93
-#define AB8500_INT_ID_DET_R3R          94
-#define AB8500_INT_ID_DET_R4R          95
-#define AB8500_INT_ID_WAKEUP_F         96
-#define AB8500_INT_ID_DET_R1F          98
-#define AB8500_INT_ID_DET_R2F          99
-#define AB8500_INT_ID_DET_R3F          100
-#define AB8500_INT_ID_DET_R4F          101
-#define AB8500_INT_USB_CHG_DET_DONE    102
-#define AB8500_INT_USB_CH_TH_PROT_F    104
-#define AB8500_INT_USB_CH_TH_PROT_R    105
-#define AB8500_INT_MAIN_CH_TH_PROT_F   106
-#define AB8500_INT_MAIN_CH_TH_PROT_R   107
-#define AB8500_INT_USB_CHARGER_NOT_OKF 111
-
-#define AB8500_NR_IRQS                 112
-#define AB8500_NUM_IRQ_REGS            14
-
-/**
- * struct ab8500 - ab8500 internal structure
- * @dev: parent device
- * @lock: read/write operations lock
- * @irq_lock: genirq bus lock
- * @irq: irq line
- * @chip_id: chip revision id
- * @write: register write
- * @read: register read
- * @rx_buf: rx buf for SPI
- * @tx_buf: tx buf for SPI
- * @mask: cache of IRQ regs for bus lock
- * @oldmask: cache of previous IRQ regs for bus lock
- */
-struct ab8500 {
-       struct device   *dev;
-       struct mutex    lock;
-       struct mutex    irq_lock;
-
-       int             irq_base;
-       int             irq;
-       u8              chip_id;
-
-       int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
-       int (*read) (struct ab8500 *a8500, u16 addr);
-
-       unsigned long   tx_buf[4];
-       unsigned long   rx_buf[4];
-
-       u8 mask[AB8500_NUM_IRQ_REGS];
-       u8 oldmask[AB8500_NUM_IRQ_REGS];
-};
-
-struct regulator_reg_init;
-struct regulator_init_data;
-struct ab8500_gpio_platform_data;
-
-/**
- * struct ab8500_platform_data - AB8500 platform data
- * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
- * @init: board-specific initialization after detection of ab8500
- * @num_regulator_reg_init: number of regulator init registers
- * @regulator_reg_init: regulator init registers
- * @num_regulator: number of regulators
- * @regulator: machine-specific constraints for regulators
- */
-struct ab8500_platform_data {
-       int irq_base;
-       void (*init) (struct ab8500 *);
-       int num_regulator_reg_init;
-       struct ab8500_regulator_reg_init *regulator_reg_init;
-       int num_regulator;
-       struct regulator_init_data *regulator;
-       struct ab8500_gpio_platform_data *gpio;
-};
-
-extern int __devinit ab8500_init(struct ab8500 *ab8500);
-extern int __devexit ab8500_exit(struct ab8500 *ab8500);
-
-#endif /* MFD_AB8500_H */
diff --git a/include/linux/mfd/ab8500/gpadc.h b/include/linux/mfd/ab8500/gpadc.h
deleted file mode 100644 (file)
index 2529667..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 ST-Ericsson SA
- * Licensed under GPLv2.
- *
- * Author: Arun R Murthy <arun.murthy@stericsson.com>
- * Author: Daniel Willerud <daniel.willerud@stericsson.com>
- */
-
-#ifndef        _AB8500_GPADC_H
-#define _AB8500_GPADC_H
-
-/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
-#define BAT_CTRL       0x01
-#define BTEMP_BALL     0x02
-#define MAIN_CHARGER_V 0x03
-#define ACC_DETECT1    0x04
-#define ACC_DETECT2    0x05
-#define ADC_AUX1       0x06
-#define ADC_AUX2       0x07
-#define MAIN_BAT_V     0x08
-#define VBUS_V         0x09
-#define MAIN_CHARGER_C 0x0A
-#define USB_CHARGER_C  0x0B
-#define BK_BAT_V       0x0C
-#define DIE_TEMP       0x0D
-
-struct ab8500_gpadc;
-
-struct ab8500_gpadc *ab8500_gpadc_get(char *name);
-int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel);
-int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel);
-int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
-    u8 channel, int ad_value);
-
-#endif /* _AB8500_GPADC_H */
diff --git a/include/linux/mfd/ab8500/gpio.h b/include/linux/mfd/ab8500/gpio.h
deleted file mode 100644 (file)
index 488a8c9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright ST-Ericsson 2010.
- *
- * Author: Bibek Basu <bibek.basu@stericsson.com>
- * Licensed under GPLv2.
- */
-
-#ifndef _AB8500_GPIO_H
-#define _AB8500_GPIO_H
-
-/*
- * Platform data to register a block: only the initial gpio/irq number.
- */
-
-struct ab8500_gpio_platform_data {
-       int gpio_base;
-       u32 irq_base;
-       u8  config_reg[7];
-};
-
-#endif /* _AB8500_GPIO_H */
diff --git a/include/linux/mfd/ab8500/sysctrl.h b/include/linux/mfd/ab8500/sysctrl.h
deleted file mode 100644 (file)
index 10da029..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
- * License terms: GNU General Public License (GPL) version 2
- */
-#ifndef __AB8500_SYSCTRL_H
-#define __AB8500_SYSCTRL_H
-
-#include <linux/bitops.h>
-
-#ifdef CONFIG_AB8500_CORE
-
-int ab8500_sysctrl_read(u16 reg, u8 *value);
-int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
-
-#else
-
-static inline int ab8500_sysctrl_read(u16 reg, u8 *value)
-{
-       return 0;
-}
-
-static inline int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
-{
-       return 0;
-}
-
-#endif /* CONFIG_AB8500_CORE */
-
-static inline int ab8500_sysctrl_set(u16 reg, u8 bits)
-{
-       return ab8500_sysctrl_write(reg, bits, bits);
-}
-
-static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
-{
-       return ab8500_sysctrl_write(reg, bits, 0);
-}
-
-/* Registers */
-#define AB8500_TURNONSTATUS            0x100
-#define AB8500_RESETSTATUS             0x101
-#define AB8500_PONKEY1PRESSSTATUS      0x102
-#define AB8500_SYSCLKREQSTATUS         0x142
-#define AB8500_STW4500CTRL1            0x180
-#define AB8500_STW4500CTRL2            0x181
-#define AB8500_STW4500CTRL3            0x200
-#define AB8500_MAINWDOGCTRL            0x201
-#define AB8500_MAINWDOGTIMER           0x202
-#define AB8500_LOWBAT                  0x203
-#define AB8500_BATTOK                  0x204
-#define AB8500_SYSCLKTIMER             0x205
-#define AB8500_SMPSCLKCTRL             0x206
-#define AB8500_SMPSCLKSEL1             0x207
-#define AB8500_SMPSCLKSEL2             0x208
-#define AB8500_SMPSCLKSEL3             0x209
-#define AB8500_SYSULPCLKCONF           0x20A
-#define AB8500_SYSULPCLKCTRL1          0x20B
-#define AB8500_SYSCLKCTRL              0x20C
-#define AB8500_SYSCLKREQ1VALID         0x20D
-#define AB8500_SYSTEMCTRLSUP           0x20F
-#define AB8500_SYSCLKREQ1RFCLKBUF      0x210
-#define AB8500_SYSCLKREQ2RFCLKBUF      0x211
-#define AB8500_SYSCLKREQ3RFCLKBUF      0x212
-#define AB8500_SYSCLKREQ4RFCLKBUF      0x213
-#define AB8500_SYSCLKREQ5RFCLKBUF      0x214
-#define AB8500_SYSCLKREQ6RFCLKBUF      0x215
-#define AB8500_SYSCLKREQ7RFCLKBUF      0x216
-#define AB8500_SYSCLKREQ8RFCLKBUF      0x217
-#define AB8500_DITHERCLKCTRL           0x220
-#define AB8500_SWATCTRL                        0x230
-#define AB8500_HIQCLKCTRL              0x232
-#define AB8500_VSIMSYSCLKCTRL          0x233
-
-/* Bits */
-#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
-#define AB8500_TURNONSTATUS_PONKEY1DBF BIT(1)
-#define AB8500_TURNONSTATUS_PONKEY2DBF BIT(2)
-#define AB8500_TURNONSTATUS_RTCALARM BIT(3)
-#define AB8500_TURNONSTATUS_MAINCHDET BIT(4)
-#define AB8500_TURNONSTATUS_VBUSDET BIT(5)
-#define AB8500_TURNONSTATUS_USBIDDETECT BIT(6)
-
-#define AB8500_RESETSTATUS_RESETN4500NSTATUS BIT(0)
-#define AB8500_RESETSTATUS_SWRESETN4500NSTATUS BIT(2)
-
-#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_MASK 0x7F
-#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_SHIFT 0
-
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ1STATUS BIT(0)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ2STATUS BIT(1)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ3STATUS BIT(2)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ4STATUS BIT(3)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ5STATUS BIT(4)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ6STATUS BIT(5)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ7STATUS BIT(6)
-#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ8STATUS BIT(7)
-
-#define AB8500_STW4500CTRL1_SWOFF BIT(0)
-#define AB8500_STW4500CTRL1_SWRESET4500N BIT(1)
-#define AB8500_STW4500CTRL1_THDB8500SWOFF BIT(2)
-
-#define AB8500_STW4500CTRL2_RESETNVAUX1VALID BIT(0)
-#define AB8500_STW4500CTRL2_RESETNVAUX2VALID BIT(1)
-#define AB8500_STW4500CTRL2_RESETNVAUX3VALID BIT(2)
-#define AB8500_STW4500CTRL2_RESETNVMODVALID BIT(3)
-#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY1VALID BIT(4)
-#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY2VALID BIT(5)
-#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY3VALID BIT(6)
-#define AB8500_STW4500CTRL2_RESETNVSMPS1VALID BIT(7)
-
-#define AB8500_STW4500CTRL3_CLK32KOUT2DIS BIT(0)
-#define AB8500_STW4500CTRL3_RESETAUDN BIT(1)
-#define AB8500_STW4500CTRL3_RESETDENCN BIT(2)
-#define AB8500_STW4500CTRL3_THSDENA BIT(3)
-
-#define AB8500_MAINWDOGCTRL_MAINWDOGENA BIT(0)
-#define AB8500_MAINWDOGCTRL_MAINWDOGKICK BIT(1)
-#define AB8500_MAINWDOGCTRL_WDEXPTURNONVALID BIT(4)
-
-#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_MASK 0x7F
-#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_SHIFT 0
-
-#define AB8500_LOWBAT_LOWBATENA BIT(0)
-#define AB8500_LOWBAT_LOWBAT_MASK 0x7E
-#define AB8500_LOWBAT_LOWBAT_SHIFT 1
-
-#define AB8500_BATTOK_BATTOKSEL0THF_MASK 0x0F
-#define AB8500_BATTOK_BATTOKSEL0THF_SHIFT 0
-#define AB8500_BATTOK_BATTOKSEL1THF_MASK 0xF0
-#define AB8500_BATTOK_BATTOKSEL1THF_SHIFT 4
-
-#define AB8500_SYSCLKTIMER_SYSCLKTIMER_MASK 0x0F
-#define AB8500_SYSCLKTIMER_SYSCLKTIMER_SHIFT 0
-#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_MASK 0xF0
-#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_SHIFT 4
-
-#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_MASK 0x03
-#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_SHIFT 0
-#define AB8500_SMPSCLKCTRL_3M2CLKINTENA BIT(2)
-
-#define AB8500_SMPSCLKSEL1_VARMCLKSEL_MASK 0x07
-#define AB8500_SMPSCLKSEL1_VARMCLKSEL_SHIFT 0
-#define AB8500_SMPSCLKSEL1_VAPECLKSEL_MASK 0x38
-#define AB8500_SMPSCLKSEL1_VAPECLKSEL_SHIFT 3
-
-#define AB8500_SMPSCLKSEL2_VMODCLKSEL_MASK 0x07
-#define AB8500_SMPSCLKSEL2_VMODCLKSEL_SHIFT 0
-#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_MASK 0x38
-#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_SHIFT 3
-
-#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_MASK 0x07
-#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_SHIFT 0
-#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_MASK 0x38
-#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_SHIFT 3
-
-#define AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK 0x03
-#define AB8500_SYSULPCLKCONF_ULPCLKCONF_SHIFT 0
-#define AB8500_SYSULPCLKCONF_CLK27MHZSTRE BIT(2)
-#define AB8500_SYSULPCLKCONF_TVOUTCLKDELN BIT(3)
-#define AB8500_SYSULPCLKCONF_TVOUTCLKINV BIT(4)
-#define AB8500_SYSULPCLKCONF_ULPCLKSTRE BIT(5)
-#define AB8500_SYSULPCLKCONF_CLK27MHZBUFENA BIT(6)
-#define AB8500_SYSULPCLKCONF_CLK27MHZPDENA BIT(7)
-
-#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK 0x03
-#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT 0
-#define AB8500_SYSULPCLKCTRL1_ULPCLKREQ BIT(2)
-#define AB8500_SYSULPCLKCTRL1_4500SYSCLKREQ BIT(3)
-#define AB8500_SYSULPCLKCTRL1_AUDIOCLKENA BIT(4)
-#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ BIT(5)
-#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ BIT(6)
-#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ BIT(7)
-
-#define AB8500_SYSCLKCTRL_TVOUTPLLENA BIT(0)
-#define AB8500_SYSCLKCTRL_TVOUTCLKENA BIT(1)
-#define AB8500_SYSCLKCTRL_USBCLKENA BIT(2)
-
-#define AB8500_SYSCLKREQ1VALID_SYSCLKREQ1VALID BIT(0)
-#define AB8500_SYSCLKREQ1VALID_ULPCLKREQ1VALID BIT(1)
-#define AB8500_SYSCLKREQ1VALID_USBSYSCLKREQ1VALID BIT(2)
-
-#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_MASK 0x03
-#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_SHIFT 0
-#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_MASK 0x0C
-#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_SHIFT 2
-#define AB8500_SYSTEMCTRLSUP_INTDB8500NOD BIT(4)
-
-#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF4 BIT(4)
-
-#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF2 BIT(2)
-#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF3 BIT(3)
-#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF4 BIT(4)
-
-#define AB8500_DITHERCLKCTRL_VARMDITHERENA BIT(0)
-#define AB8500_DITHERCLKCTRL_VSMPS3DITHERENA BIT(1)
-#define AB8500_DITHERCLKCTRL_VSMPS1DITHERENA BIT(2)
-#define AB8500_DITHERCLKCTRL_VSMPS2DITHERENA BIT(3)
-#define AB8500_DITHERCLKCTRL_VMODDITHERENA BIT(4)
-#define AB8500_DITHERCLKCTRL_VAPEDITHERENA BIT(5)
-#define AB8500_DITHERCLKCTRL_DITHERDEL_MASK 0xC0
-#define AB8500_DITHERCLKCTRL_DITHERDEL_SHIFT 6
-
-#define AB8500_SWATCTRL_UPDATERF BIT(0)
-#define AB8500_SWATCTRL_SWATENABLE BIT(1)
-#define AB8500_SWATCTRL_RFOFFTIMER_MASK 0x1C
-#define AB8500_SWATCTRL_RFOFFTIMER_SHIFT 2
-#define AB8500_SWATCTRL_SWATBIT5 BIT(6)
-
-#define AB8500_HIQCLKCTRL_SYSCLKREQ1HIQENAVALID BIT(0)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ2HIQENAVALID BIT(1)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ3HIQENAVALID BIT(2)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ4HIQENAVALID BIT(3)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ5HIQENAVALID BIT(4)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ6HIQENAVALID BIT(5)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ7HIQENAVALID BIT(6)
-#define AB8500_HIQCLKCTRL_SYSCLKREQ8HIQENAVALID BIT(7)
-
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ1VALID BIT(0)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ2VALID BIT(1)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ3VALID BIT(2)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ4VALID BIT(3)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ5VALID BIT(4)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ6VALID BIT(5)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
-#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
-
-#endif /* __AB8500_SYSCTRL_H */
diff --git a/include/linux/mfd/abx500/ab5500.h b/include/linux/mfd/abx500/ab5500.h
new file mode 100644 (file)
index 0000000..a720051
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) ST-Ericsson 2011
+ *
+ * License Terms: GNU General Public License v2
+ */
+#ifndef MFD_AB5500_H
+#define MFD_AB5500_H
+
+#include <linux/device.h>
+
+enum ab5500_devid {
+       AB5500_DEVID_ADC,
+       AB5500_DEVID_LEDS,
+       AB5500_DEVID_POWER,
+       AB5500_DEVID_REGULATORS,
+       AB5500_DEVID_SIM,
+       AB5500_DEVID_RTC,
+       AB5500_DEVID_CHARGER,
+       AB5500_DEVID_FUELGAUGE,
+       AB5500_DEVID_VIBRATOR,
+       AB5500_DEVID_CODEC,
+       AB5500_DEVID_USB,
+       AB5500_DEVID_OTP,
+       AB5500_DEVID_VIDEO,
+       AB5500_DEVID_DBIECI,
+       AB5500_DEVID_ONSWA,
+       AB5500_NUM_DEVICES,
+};
+
+enum ab5500_banks {
+       AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP = 0,
+       AB5500_BANK_VDDDIG_IO_I2C_CLK_TST = 1,
+       AB5500_BANK_VDENC = 2,
+       AB5500_BANK_SIM_USBSIM  = 3,
+       AB5500_BANK_LED = 4,
+       AB5500_BANK_ADC  = 5,
+       AB5500_BANK_RTC  = 6,
+       AB5500_BANK_STARTUP  = 7,
+       AB5500_BANK_DBI_ECI  = 8,
+       AB5500_BANK_CHG  = 9,
+       AB5500_BANK_FG_BATTCOM_ACC = 10,
+       AB5500_BANK_USB = 11,
+       AB5500_BANK_IT = 12,
+       AB5500_BANK_VIBRA = 13,
+       AB5500_BANK_AUDIO_HEADSETUSB = 14,
+       AB5500_NUM_BANKS = 15,
+};
+
+enum ab5500_banks_addr {
+       AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP = 0x4A,
+       AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST = 0x4B,
+       AB5500_ADDR_VDENC = 0x06,
+       AB5500_ADDR_SIM_USBSIM  = 0x04,
+       AB5500_ADDR_LED = 0x10,
+       AB5500_ADDR_ADC  = 0x0A,
+       AB5500_ADDR_RTC  = 0x0F,
+       AB5500_ADDR_STARTUP  = 0x03,
+       AB5500_ADDR_DBI_ECI  = 0x07,
+       AB5500_ADDR_CHG  = 0x0B,
+       AB5500_ADDR_FG_BATTCOM_ACC = 0x0C,
+       AB5500_ADDR_USB = 0x05,
+       AB5500_ADDR_IT = 0x0E,
+       AB5500_ADDR_VIBRA = 0x02,
+       AB5500_ADDR_AUDIO_HEADSETUSB = 0x0D,
+};
+
+/*
+ * Interrupt register offsets
+ * Bank : 0x0E
+ */
+#define AB5500_IT_SOURCE0_REG          0x20
+#define AB5500_IT_SOURCE1_REG          0x21
+#define AB5500_IT_SOURCE2_REG          0x22
+#define AB5500_IT_SOURCE3_REG          0x23
+#define AB5500_IT_SOURCE4_REG          0x24
+#define AB5500_IT_SOURCE5_REG          0x25
+#define AB5500_IT_SOURCE6_REG          0x26
+#define AB5500_IT_SOURCE7_REG          0x27
+#define AB5500_IT_SOURCE8_REG          0x28
+#define AB5500_IT_SOURCE9_REG          0x29
+#define AB5500_IT_SOURCE10_REG         0x2A
+#define AB5500_IT_SOURCE11_REG         0x2B
+#define AB5500_IT_SOURCE12_REG         0x2C
+#define AB5500_IT_SOURCE13_REG         0x2D
+#define AB5500_IT_SOURCE14_REG         0x2E
+#define AB5500_IT_SOURCE15_REG         0x2F
+#define AB5500_IT_SOURCE16_REG         0x30
+#define AB5500_IT_SOURCE17_REG         0x31
+#define AB5500_IT_SOURCE18_REG         0x32
+#define AB5500_IT_SOURCE19_REG         0x33
+#define AB5500_IT_SOURCE20_REG         0x34
+#define AB5500_IT_SOURCE21_REG         0x35
+#define AB5500_IT_SOURCE22_REG         0x36
+#define AB5500_IT_SOURCE23_REG         0x37
+
+#define AB5500_NUM_IRQ_REGS            23
+
+/**
+ * struct ab5500
+ * @access_mutex: lock out concurrent accesses to the AB registers
+ * @dev: a pointer to the device struct for this chip driver
+ * @ab5500_irq: the analog baseband irq
+ * @irq_base: the platform configuration irq base for subdevices
+ * @chip_name: name of this chip variant
+ * @chip_id: 8 bit chip ID for this chip variant
+ * @irq_lock: a lock to protect the mask
+ * @abb_events: a local bit mask of the prcmu wakeup events
+ * @event_mask: a local copy of the mask event registers
+ * @last_event_mask: a copy of the last event_mask written to hardware
+ * @startup_events: a copy of the first reading of the event registers
+ * @startup_events_read: whether the first events have been read
+ */
+struct ab5500 {
+       struct mutex access_mutex;
+       struct device *dev;
+       unsigned int ab5500_irq;
+       unsigned int irq_base;
+       char chip_name[32];
+       u8 chip_id;
+       struct mutex irq_lock;
+       u32 abb_events;
+       u8 mask[AB5500_NUM_IRQ_REGS];
+       u8 oldmask[AB5500_NUM_IRQ_REGS];
+       u8 startup_events[AB5500_NUM_IRQ_REGS];
+       bool startup_events_read;
+#ifdef CONFIG_DEBUG_FS
+       unsigned int debug_bank;
+       unsigned int debug_address;
+#endif
+};
+
+struct ab5500_platform_data {
+       struct {unsigned int base; unsigned int count; } irq;
+       void *dev_data[AB5500_NUM_DEVICES];
+       struct abx500_init_settings *init_settings;
+       unsigned int init_settings_sz;
+       bool pm_power_off;
+};
+
+#endif /* MFD_AB5500_H */
diff --git a/include/linux/mfd/abx500/ab8500-gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h
new file mode 100644 (file)
index 0000000..2529667
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Licensed under GPLv2.
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ */
+
+#ifndef        _AB8500_GPADC_H
+#define _AB8500_GPADC_H
+
+/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
+#define BAT_CTRL       0x01
+#define BTEMP_BALL     0x02
+#define MAIN_CHARGER_V 0x03
+#define ACC_DETECT1    0x04
+#define ACC_DETECT2    0x05
+#define ADC_AUX1       0x06
+#define ADC_AUX2       0x07
+#define MAIN_BAT_V     0x08
+#define VBUS_V         0x09
+#define MAIN_CHARGER_C 0x0A
+#define USB_CHARGER_C  0x0B
+#define BK_BAT_V       0x0C
+#define DIE_TEMP       0x0D
+
+struct ab8500_gpadc;
+
+struct ab8500_gpadc *ab8500_gpadc_get(char *name);
+int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel);
+int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel);
+int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
+    u8 channel, int ad_value);
+
+#endif /* _AB8500_GPADC_H */
diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h
new file mode 100644 (file)
index 0000000..488a8c9
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright ST-Ericsson 2010.
+ *
+ * Author: Bibek Basu <bibek.basu@stericsson.com>
+ * Licensed under GPLv2.
+ */
+
+#ifndef _AB8500_GPIO_H
+#define _AB8500_GPIO_H
+
+/*
+ * Platform data to register a block: only the initial gpio/irq number.
+ */
+
+struct ab8500_gpio_platform_data {
+       int gpio_base;
+       u32 irq_base;
+       u8  config_reg[7];
+};
+
+#endif /* _AB8500_GPIO_H */
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
new file mode 100644 (file)
index 0000000..10da029
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __AB8500_SYSCTRL_H
+#define __AB8500_SYSCTRL_H
+
+#include <linux/bitops.h>
+
+#ifdef CONFIG_AB8500_CORE
+
+int ab8500_sysctrl_read(u16 reg, u8 *value);
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
+
+#else
+
+static inline int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+       return 0;
+}
+
+static inline int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+       return 0;
+}
+
+#endif /* CONFIG_AB8500_CORE */
+
+static inline int ab8500_sysctrl_set(u16 reg, u8 bits)
+{
+       return ab8500_sysctrl_write(reg, bits, bits);
+}
+
+static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
+{
+       return ab8500_sysctrl_write(reg, bits, 0);
+}
+
+/* Registers */
+#define AB8500_TURNONSTATUS            0x100
+#define AB8500_RESETSTATUS             0x101
+#define AB8500_PONKEY1PRESSSTATUS      0x102
+#define AB8500_SYSCLKREQSTATUS         0x142
+#define AB8500_STW4500CTRL1            0x180
+#define AB8500_STW4500CTRL2            0x181
+#define AB8500_STW4500CTRL3            0x200
+#define AB8500_MAINWDOGCTRL            0x201
+#define AB8500_MAINWDOGTIMER           0x202
+#define AB8500_LOWBAT                  0x203
+#define AB8500_BATTOK                  0x204
+#define AB8500_SYSCLKTIMER             0x205
+#define AB8500_SMPSCLKCTRL             0x206
+#define AB8500_SMPSCLKSEL1             0x207
+#define AB8500_SMPSCLKSEL2             0x208
+#define AB8500_SMPSCLKSEL3             0x209
+#define AB8500_SYSULPCLKCONF           0x20A
+#define AB8500_SYSULPCLKCTRL1          0x20B
+#define AB8500_SYSCLKCTRL              0x20C
+#define AB8500_SYSCLKREQ1VALID         0x20D
+#define AB8500_SYSTEMCTRLSUP           0x20F
+#define AB8500_SYSCLKREQ1RFCLKBUF      0x210
+#define AB8500_SYSCLKREQ2RFCLKBUF      0x211
+#define AB8500_SYSCLKREQ3RFCLKBUF      0x212
+#define AB8500_SYSCLKREQ4RFCLKBUF      0x213
+#define AB8500_SYSCLKREQ5RFCLKBUF      0x214
+#define AB8500_SYSCLKREQ6RFCLKBUF      0x215
+#define AB8500_SYSCLKREQ7RFCLKBUF      0x216
+#define AB8500_SYSCLKREQ8RFCLKBUF      0x217
+#define AB8500_DITHERCLKCTRL           0x220
+#define AB8500_SWATCTRL                        0x230
+#define AB8500_HIQCLKCTRL              0x232
+#define AB8500_VSIMSYSCLKCTRL          0x233
+
+/* Bits */
+#define AB8500_TURNONSTATUS_PORNVBAT BIT(0)
+#define AB8500_TURNONSTATUS_PONKEY1DBF BIT(1)
+#define AB8500_TURNONSTATUS_PONKEY2DBF BIT(2)
+#define AB8500_TURNONSTATUS_RTCALARM BIT(3)
+#define AB8500_TURNONSTATUS_MAINCHDET BIT(4)
+#define AB8500_TURNONSTATUS_VBUSDET BIT(5)
+#define AB8500_TURNONSTATUS_USBIDDETECT BIT(6)
+
+#define AB8500_RESETSTATUS_RESETN4500NSTATUS BIT(0)
+#define AB8500_RESETSTATUS_SWRESETN4500NSTATUS BIT(2)
+
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_MASK 0x7F
+#define AB8500_PONKEY1PRESSSTATUS_PONKEY1PRESSTIME_SHIFT 0
+
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ1STATUS BIT(0)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ2STATUS BIT(1)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ3STATUS BIT(2)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ4STATUS BIT(3)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ5STATUS BIT(4)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ6STATUS BIT(5)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ7STATUS BIT(6)
+#define AB8500_SYSCLKREQSTATUS_SYSCLKREQ8STATUS BIT(7)
+
+#define AB8500_STW4500CTRL1_SWOFF BIT(0)
+#define AB8500_STW4500CTRL1_SWRESET4500N BIT(1)
+#define AB8500_STW4500CTRL1_THDB8500SWOFF BIT(2)
+
+#define AB8500_STW4500CTRL2_RESETNVAUX1VALID BIT(0)
+#define AB8500_STW4500CTRL2_RESETNVAUX2VALID BIT(1)
+#define AB8500_STW4500CTRL2_RESETNVAUX3VALID BIT(2)
+#define AB8500_STW4500CTRL2_RESETNVMODVALID BIT(3)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY1VALID BIT(4)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY2VALID BIT(5)
+#define AB8500_STW4500CTRL2_RESETNVEXTSUPPLY3VALID BIT(6)
+#define AB8500_STW4500CTRL2_RESETNVSMPS1VALID BIT(7)
+
+#define AB8500_STW4500CTRL3_CLK32KOUT2DIS BIT(0)
+#define AB8500_STW4500CTRL3_RESETAUDN BIT(1)
+#define AB8500_STW4500CTRL3_RESETDENCN BIT(2)
+#define AB8500_STW4500CTRL3_THSDENA BIT(3)
+
+#define AB8500_MAINWDOGCTRL_MAINWDOGENA BIT(0)
+#define AB8500_MAINWDOGCTRL_MAINWDOGKICK BIT(1)
+#define AB8500_MAINWDOGCTRL_WDEXPTURNONVALID BIT(4)
+
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_MASK 0x7F
+#define AB8500_MAINWDOGTIMER_MAINWDOGTIMER_SHIFT 0
+
+#define AB8500_LOWBAT_LOWBATENA BIT(0)
+#define AB8500_LOWBAT_LOWBAT_MASK 0x7E
+#define AB8500_LOWBAT_LOWBAT_SHIFT 1
+
+#define AB8500_BATTOK_BATTOKSEL0THF_MASK 0x0F
+#define AB8500_BATTOK_BATTOKSEL0THF_SHIFT 0
+#define AB8500_BATTOK_BATTOKSEL1THF_MASK 0xF0
+#define AB8500_BATTOK_BATTOKSEL1THF_SHIFT 4
+
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_MASK 0x0F
+#define AB8500_SYSCLKTIMER_SYSCLKTIMER_SHIFT 0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_MASK 0xF0
+#define AB8500_SYSCLKTIMER_SYSCLKTIMERADJ_SHIFT 4
+
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_MASK 0x03
+#define AB8500_SMPSCLKCTRL_SMPSCLKINTSEL_SHIFT 0
+#define AB8500_SMPSCLKCTRL_3M2CLKINTENA BIT(2)
+
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL1_VARMCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL1_VAPECLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL2_VMODCLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL2_VSMPS1CLKSEL_SHIFT 3
+
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_MASK 0x07
+#define AB8500_SMPSCLKSEL3_VSMPS2CLKSEL_SHIFT 0
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_MASK 0x38
+#define AB8500_SMPSCLKSEL3_VSMPS3CLKSEL_SHIFT 3
+
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_MASK 0x03
+#define AB8500_SYSULPCLKCONF_ULPCLKCONF_SHIFT 0
+#define AB8500_SYSULPCLKCONF_CLK27MHZSTRE BIT(2)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKDELN BIT(3)
+#define AB8500_SYSULPCLKCONF_TVOUTCLKINV BIT(4)
+#define AB8500_SYSULPCLKCONF_ULPCLKSTRE BIT(5)
+#define AB8500_SYSULPCLKCONF_CLK27MHZBUFENA BIT(6)
+#define AB8500_SYSULPCLKCONF_CLK27MHZPDENA BIT(7)
+
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK 0x03
+#define AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT 0
+#define AB8500_SYSULPCLKCTRL1_ULPCLKREQ BIT(2)
+#define AB8500_SYSULPCLKCTRL1_4500SYSCLKREQ BIT(3)
+#define AB8500_SYSULPCLKCTRL1_AUDIOCLKENA BIT(4)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ BIT(5)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ BIT(6)
+#define AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ BIT(7)
+
+#define AB8500_SYSCLKCTRL_TVOUTPLLENA BIT(0)
+#define AB8500_SYSCLKCTRL_TVOUTCLKENA BIT(1)
+#define AB8500_SYSCLKCTRL_USBCLKENA BIT(2)
+
+#define AB8500_SYSCLKREQ1VALID_SYSCLKREQ1VALID BIT(0)
+#define AB8500_SYSCLKREQ1VALID_ULPCLKREQ1VALID BIT(1)
+#define AB8500_SYSCLKREQ1VALID_USBSYSCLKREQ1VALID BIT(2)
+
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_MASK 0x03
+#define AB8500_SYSTEMCTRLSUP_EXTSUP12LPNCLKSEL_SHIFT 0
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_MASK 0x0C
+#define AB8500_SYSTEMCTRLSUP_EXTSUP3LPNCLKSEL_SHIFT 2
+#define AB8500_SYSTEMCTRLSUP_INTDB8500NOD BIT(4)
+
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ1RFCLKBUF_SYSCLKREQ1RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ2RFCLKBUF_SYSCLKREQ2RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ3RFCLKBUF_SYSCLKREQ3RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ4RFCLKBUF_SYSCLKREQ4RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ5RFCLKBUF_SYSCLKREQ5RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ6RFCLKBUF_SYSCLKREQ6RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ7RFCLKBUF_SYSCLKREQ7RFCLKBUF4 BIT(4)
+
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF2 BIT(2)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF3 BIT(3)
+#define AB8500_SYSCLKREQ8RFCLKBUF_SYSCLKREQ8RFCLKBUF4 BIT(4)
+
+#define AB8500_DITHERCLKCTRL_VARMDITHERENA BIT(0)
+#define AB8500_DITHERCLKCTRL_VSMPS3DITHERENA BIT(1)
+#define AB8500_DITHERCLKCTRL_VSMPS1DITHERENA BIT(2)
+#define AB8500_DITHERCLKCTRL_VSMPS2DITHERENA BIT(3)
+#define AB8500_DITHERCLKCTRL_VMODDITHERENA BIT(4)
+#define AB8500_DITHERCLKCTRL_VAPEDITHERENA BIT(5)
+#define AB8500_DITHERCLKCTRL_DITHERDEL_MASK 0xC0
+#define AB8500_DITHERCLKCTRL_DITHERDEL_SHIFT 6
+
+#define AB8500_SWATCTRL_UPDATERF BIT(0)
+#define AB8500_SWATCTRL_SWATENABLE BIT(1)
+#define AB8500_SWATCTRL_RFOFFTIMER_MASK 0x1C
+#define AB8500_SWATCTRL_RFOFFTIMER_SHIFT 2
+#define AB8500_SWATCTRL_SWATBIT5 BIT(6)
+
+#define AB8500_HIQCLKCTRL_SYSCLKREQ1HIQENAVALID BIT(0)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ2HIQENAVALID BIT(1)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ3HIQENAVALID BIT(2)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ4HIQENAVALID BIT(3)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ5HIQENAVALID BIT(4)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ6HIQENAVALID BIT(5)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ7HIQENAVALID BIT(6)
+#define AB8500_HIQCLKCTRL_SYSCLKREQ8HIQENAVALID BIT(7)
+
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ1VALID BIT(0)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ2VALID BIT(1)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ3VALID BIT(2)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ4VALID BIT(3)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ5VALID BIT(4)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ6VALID BIT(5)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ7VALID BIT(6)
+#define AB8500_VSIMSYSCLKCTRL_VSIMSYSCLKREQ8VALID BIT(7)
+
+#endif /* __AB8500_SYSCTRL_H */
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
new file mode 100644 (file)
index 0000000..838c6b4
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ */
+#ifndef MFD_AB8500_H
+#define MFD_AB8500_H
+
+#include <linux/device.h>
+
+/*
+ * AB8500 bank addresses
+ */
+#define AB8500_SYS_CTRL1_BLOCK 0x1
+#define AB8500_SYS_CTRL2_BLOCK 0x2
+#define AB8500_REGU_CTRL1      0x3
+#define AB8500_REGU_CTRL2      0x4
+#define AB8500_USB             0x5
+#define AB8500_TVOUT           0x6
+#define AB8500_DBI             0x7
+#define AB8500_ECI_AV_ACC      0x8
+#define AB8500_RESERVED                0x9
+#define AB8500_GPADC           0xA
+#define AB8500_CHARGER         0xB
+#define AB8500_GAS_GAUGE       0xC
+#define AB8500_AUDIO           0xD
+#define AB8500_INTERRUPT       0xE
+#define AB8500_RTC             0xF
+#define AB8500_MISC            0x10
+#define AB8500_DEVELOPMENT     0x11
+#define AB8500_DEBUG           0x12
+#define AB8500_PROD_TEST       0x13
+#define AB8500_OTP_EMUL                0x15
+
+/*
+ * Interrupts
+ */
+
+#define AB8500_INT_MAIN_EXT_CH_NOT_OK  0
+#define AB8500_INT_UN_PLUG_TV_DET      1
+#define AB8500_INT_PLUG_TV_DET         2
+#define AB8500_INT_TEMP_WARM           3
+#define AB8500_INT_PON_KEY2DB_F                4
+#define AB8500_INT_PON_KEY2DB_R                5
+#define AB8500_INT_PON_KEY1DB_F                6
+#define AB8500_INT_PON_KEY1DB_R                7
+#define AB8500_INT_BATT_OVV            8
+#define AB8500_INT_MAIN_CH_UNPLUG_DET  10
+#define AB8500_INT_MAIN_CH_PLUG_DET    11
+#define AB8500_INT_USB_ID_DET_F                12
+#define AB8500_INT_USB_ID_DET_R                13
+#define AB8500_INT_VBUS_DET_F          14
+#define AB8500_INT_VBUS_DET_R          15
+#define AB8500_INT_VBUS_CH_DROP_END    16
+#define AB8500_INT_RTC_60S             17
+#define AB8500_INT_RTC_ALARM           18
+#define AB8500_INT_BAT_CTRL_INDB       20
+#define AB8500_INT_CH_WD_EXP           21
+#define AB8500_INT_VBUS_OVV            22
+#define AB8500_INT_MAIN_CH_DROP_END    23
+#define AB8500_INT_CCN_CONV_ACC                24
+#define AB8500_INT_INT_AUD             25
+#define AB8500_INT_CCEOC               26
+#define AB8500_INT_CC_INT_CALIB                27
+#define AB8500_INT_LOW_BAT_F           28
+#define AB8500_INT_LOW_BAT_R           29
+#define AB8500_INT_BUP_CHG_NOT_OK      30
+#define AB8500_INT_BUP_CHG_OK          31
+#define AB8500_INT_GP_HW_ADC_CONV_END  32
+#define AB8500_INT_ACC_DETECT_1DB_F    33
+#define AB8500_INT_ACC_DETECT_1DB_R    34
+#define AB8500_INT_ACC_DETECT_22DB_F   35
+#define AB8500_INT_ACC_DETECT_22DB_R   36
+#define AB8500_INT_ACC_DETECT_21DB_F   37
+#define AB8500_INT_ACC_DETECT_21DB_R   38
+#define AB8500_INT_GP_SW_ADC_CONV_END  39
+#define AB8500_INT_GPIO6R              40
+#define AB8500_INT_GPIO7R              41
+#define AB8500_INT_GPIO8R              42
+#define AB8500_INT_GPIO9R              43
+#define AB8500_INT_GPIO10R             44
+#define AB8500_INT_GPIO11R             45
+#define AB8500_INT_GPIO12R             46
+#define AB8500_INT_GPIO13R             47
+#define AB8500_INT_GPIO24R             48
+#define AB8500_INT_GPIO25R             49
+#define AB8500_INT_GPIO36R             50
+#define AB8500_INT_GPIO37R             51
+#define AB8500_INT_GPIO38R             52
+#define AB8500_INT_GPIO39R             53
+#define AB8500_INT_GPIO40R             54
+#define AB8500_INT_GPIO41R             55
+#define AB8500_INT_GPIO6F              56
+#define AB8500_INT_GPIO7F              57
+#define AB8500_INT_GPIO8F              58
+#define AB8500_INT_GPIO9F              59
+#define AB8500_INT_GPIO10F             60
+#define AB8500_INT_GPIO11F             61
+#define AB8500_INT_GPIO12F             62
+#define AB8500_INT_GPIO13F             63
+#define AB8500_INT_GPIO24F             64
+#define AB8500_INT_GPIO25F             65
+#define AB8500_INT_GPIO36F             66
+#define AB8500_INT_GPIO37F             67
+#define AB8500_INT_GPIO38F             68
+#define AB8500_INT_GPIO39F             69
+#define AB8500_INT_GPIO40F             70
+#define AB8500_INT_GPIO41F             71
+#define AB8500_INT_ADP_SOURCE_ERROR    72
+#define AB8500_INT_ADP_SINK_ERROR      73
+#define AB8500_INT_ADP_PROBE_PLUG      74
+#define AB8500_INT_ADP_PROBE_UNPLUG    75
+#define AB8500_INT_ADP_SENSE_OFF       76
+#define AB8500_INT_USB_PHY_POWER_ERR   78
+#define AB8500_INT_USB_LINK_STATUS     79
+#define AB8500_INT_BTEMP_LOW           80
+#define AB8500_INT_BTEMP_LOW_MEDIUM    81
+#define AB8500_INT_BTEMP_MEDIUM_HIGH   82
+#define AB8500_INT_BTEMP_HIGH          83
+#define AB8500_INT_USB_CHARGER_NOT_OK  89
+#define AB8500_INT_ID_WAKEUP_R         90
+#define AB8500_INT_ID_DET_R1R          92
+#define AB8500_INT_ID_DET_R2R          93
+#define AB8500_INT_ID_DET_R3R          94
+#define AB8500_INT_ID_DET_R4R          95
+#define AB8500_INT_ID_WAKEUP_F         96
+#define AB8500_INT_ID_DET_R1F          98
+#define AB8500_INT_ID_DET_R2F          99
+#define AB8500_INT_ID_DET_R3F          100
+#define AB8500_INT_ID_DET_R4F          101
+#define AB8500_INT_USB_CHG_DET_DONE    102
+#define AB8500_INT_USB_CH_TH_PROT_F    104
+#define AB8500_INT_USB_CH_TH_PROT_R    105
+#define AB8500_INT_MAIN_CH_TH_PROT_F   106
+#define AB8500_INT_MAIN_CH_TH_PROT_R   107
+#define AB8500_INT_USB_CHARGER_NOT_OKF 111
+
+#define AB8500_NR_IRQS                 112
+#define AB8500_NUM_IRQ_REGS            14
+
+/**
+ * struct ab8500 - ab8500 internal structure
+ * @dev: parent device
+ * @lock: read/write operations lock
+ * @irq_lock: genirq bus lock
+ * @irq: irq line
+ * @chip_id: chip revision id
+ * @write: register write
+ * @read: register read
+ * @rx_buf: rx buf for SPI
+ * @tx_buf: tx buf for SPI
+ * @mask: cache of IRQ regs for bus lock
+ * @oldmask: cache of previous IRQ regs for bus lock
+ */
+struct ab8500 {
+       struct device   *dev;
+       struct mutex    lock;
+       struct mutex    irq_lock;
+
+       int             irq_base;
+       int             irq;
+       u8              chip_id;
+
+       int (*write) (struct ab8500 *a8500, u16 addr, u8 data);
+       int (*read) (struct ab8500 *a8500, u16 addr);
+
+       unsigned long   tx_buf[4];
+       unsigned long   rx_buf[4];
+
+       u8 mask[AB8500_NUM_IRQ_REGS];
+       u8 oldmask[AB8500_NUM_IRQ_REGS];
+};
+
+struct regulator_reg_init;
+struct regulator_init_data;
+struct ab8500_gpio_platform_data;
+
+/**
+ * struct ab8500_platform_data - AB8500 platform data
+ * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
+ * @init: board-specific initialization after detection of ab8500
+ * @num_regulator_reg_init: number of regulator init registers
+ * @regulator_reg_init: regulator init registers
+ * @num_regulator: number of regulators
+ * @regulator: machine-specific constraints for regulators
+ */
+struct ab8500_platform_data {
+       int irq_base;
+       void (*init) (struct ab8500 *);
+       int num_regulator_reg_init;
+       struct ab8500_regulator_reg_init *regulator_reg_init;
+       int num_regulator;
+       struct regulator_init_data *regulator;
+       struct ab8500_gpio_platform_data *gpio;
+};
+
+extern int __devinit ab8500_init(struct ab8500 *ab8500);
+extern int __devexit ab8500_exit(struct ab8500 *ab8500);
+
+#endif /* MFD_AB8500_H */
index 5259dfe8c58567937ef5f7e96ebbf86850c28428..15b2392a56fbe4419c1caeb3986138249b2bc07b 100644 (file)
@@ -167,9 +167,6 @@ enum {
        MAX8925_IRQ_VCHG_DC_OVP,
        MAX8925_IRQ_VCHG_DC_F,
        MAX8925_IRQ_VCHG_DC_R,
-       MAX8925_IRQ_VCHG_USB_OVP,
-       MAX8925_IRQ_VCHG_USB_F,
-       MAX8925_IRQ_VCHG_USB_R,
        MAX8925_IRQ_VCHG_THM_OK_R,
        MAX8925_IRQ_VCHG_THM_OK_F,
        MAX8925_IRQ_VCHG_SYSLOW_F,
@@ -206,6 +203,8 @@ struct max8925_chip {
        int                     irq_base;
        int                     core_irq;
        int                     tsc_irq;
+
+       unsigned int            wakeup_flag;
 };
 
 struct max8925_backlight_pdata {
@@ -223,6 +222,10 @@ struct max8925_power_pdata {
        unsigned        batt_detect:1;
        unsigned        topoff_threshold:2;
        unsigned        fast_charge:3;  /* charge current */
+       unsigned        no_temp_support:1; /* set if no temperature detect */
+       unsigned        no_insert_detect:1; /* set if no ac insert detect */
+       char            **supplied_to;
+       int             num_supplicants;
 };
 
 /*
index 0bbd13dbe336bdbbcbb86b2caf9453feac4009fd..fff590521e5045beced56e80f207fcd178a9fa99 100644 (file)
@@ -77,6 +77,82 @@ struct max8997_regulator_data {
        struct regulator_init_data *initdata;
 };
 
+enum max8997_muic_usb_type {
+       MAX8997_USB_HOST,
+       MAX8997_USB_DEVICE,
+};
+
+enum max8997_muic_charger_type {
+       MAX8997_CHARGER_TYPE_NONE = 0,
+       MAX8997_CHARGER_TYPE_USB,
+       MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT,
+       MAX8997_CHARGER_TYPE_DEDICATED_CHG,
+       MAX8997_CHARGER_TYPE_500MA,
+       MAX8997_CHARGER_TYPE_1A,
+       MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7,
+};
+
+struct max8997_muic_reg_data {
+       u8 addr;
+       u8 data;
+};
+
+/**
+ * struct max8997_muic_platform_data
+ * @usb_callback: callback function for USB
+ *               inform callee of USB type (HOST or DEVICE)
+ *               and attached state(true or false)
+ * @charger_callback: callback function for charger
+ *               inform callee of charger_type
+ *               and attached state(true or false)
+ * @deskdock_callback: callback function for desk dock
+ *               inform callee of attached state(true or false)
+ * @cardock_callback: callback function for car dock
+ *               inform callee of attached state(true or false)
+ * @mhl_callback: callback function for MHL (Mobile High-definition Link)
+ *               inform callee of attached state(true or false)
+ * @uart_callback: callback function for JIG UART
+ *                inform callee of attached state(true or false)
+ * @init_data: array of max8997_muic_reg_data
+ *            used for initializing registers of MAX8997 MUIC device
+ * @num_init_data: array size of init_data
+ */
+struct max8997_muic_platform_data {
+       void (*usb_callback)(enum max8997_muic_usb_type usb_type,
+               bool attached);
+       void (*charger_callback)(bool attached,
+               enum max8997_muic_charger_type charger_type);
+       void (*deskdock_callback) (bool attached);
+       void (*cardock_callback) (bool attached);
+       void (*mhl_callback) (bool attached);
+       void (*uart_callback) (bool attached);
+
+       struct max8997_muic_reg_data *init_data;
+       int num_init_data;
+};
+
+enum max8997_led_mode {
+       MAX8997_NONE,
+       MAX8997_FLASH_MODE,
+       MAX8997_MOVIE_MODE,
+       MAX8997_FLASH_PIN_CONTROL_MODE,
+       MAX8997_MOVIE_PIN_CONTROL_MODE,
+};
+
+/**
+ *  struct max8997_led_platform_data
+ *  The number of LED devices for MAX8997 is two
+ *  @mode: LED mode for each LED device
+ *  @brightness: initial brightness for each LED device
+ *     range:
+ *     [0 - 31]: MAX8997_FLASH_MODE and MAX8997_FLASH_PIN_CONTROL_MODE
+ *     [0 - 15]: MAX8997_MOVIE_MODE and MAX8997_MOVIE_PIN_CONTROL_MODE
+ */
+struct max8997_led_platform_data {
+       enum max8997_led_mode mode[2];
+       u8 brightness[2];
+};
+
 struct max8997_platform_data {
        /* IRQ */
        int irq_base;
@@ -113,10 +189,13 @@ struct max8997_platform_data {
        /* charge Full Timeout */
        int timeout; /* 0 (no timeout), 5, 6, 7 hours */
 
-       /* MUIC: Not implemented */
+       /* ---- MUIC ---- */
+       struct max8997_muic_platform_data *muic_pdata;
+
        /* HAPTIC: Not implemented */
        /* RTC: Not implemented */
-       /* Flash: Not implemented */
+       /* ---- LED ---- */
+       struct max8997_led_platform_data *led_pdata;
 };
 
 #endif /* __LINUX_MFD_MAX8998_H */
index a98e2a316d1f2e4235cc628e52b44058112ab976..b86ee45c8b03fc1b57f233543bbd0f0859167532 100644 (file)
@@ -174,6 +174,9 @@ struct mc13xxx_platform_data {
 #define MC13XXX_ADC_MODE_MULT_CHAN     3
 
 #define MC13XXX_ADC0           43
+#define MC13XXX_ADC0_LICELLCON         (1 << 0)
+#define MC13XXX_ADC0_CHRGICON          (1 << 1)
+#define MC13XXX_ADC0_BATICON           (1 << 2)
 #define MC13XXX_ADC0_ADREFEN           (1 << 10)
 #define MC13XXX_ADC0_TSMOD0            (1 << 12)
 #define MC13XXX_ADC0_TSMOD1            (1 << 13)
@@ -185,4 +188,9 @@ struct mc13xxx_platform_data {
                                        MC13XXX_ADC0_TSMOD1 | \
                                        MC13XXX_ADC0_TSMOD2)
 
+#define MC13XXX_ADC0_CONFIG_MASK       (MC13XXX_ADC0_TSMOD_MASK | \
+                                       MC13XXX_ADC0_LICELLCON | \
+                                       MC13XXX_ADC0_CHRGICON | \
+                                       MC13XXX_ADC0_BATICON)
+
 #endif /* ifndef __LINUX_MFD_MC13XXX_H */
index ee496708e38b9a0de245a3c9f59d67377dc6fd59..1515e64e3663abd1a557e339c0eb57d6f13d8117 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef MCP_H
 #define MCP_H
 
+#include <linux/mod_devicetable.h>
 #include <mach/dma.h>
 
 struct mcp_ops;
@@ -26,7 +27,7 @@ struct mcp {
        dma_device_t    dma_telco_rd;
        dma_device_t    dma_telco_wr;
        struct device   attached_device;
-       int             gpio_base;
+       const char      *codec;
 };
 
 struct mcp_ops {
@@ -44,10 +45,11 @@ void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
 unsigned int mcp_reg_read(struct mcp *, unsigned int);
 void mcp_enable(struct mcp *);
 void mcp_disable(struct mcp *);
+const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp);
 #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
 
 struct mcp *mcp_host_alloc(struct device *, size_t);
-int mcp_host_register(struct mcp *);
+int mcp_host_register(struct mcp *, void *);
 void mcp_host_unregister(struct mcp *);
 
 struct mcp_driver {
@@ -56,6 +58,7 @@ struct mcp_driver {
        void (*remove)(struct mcp *);
        int (*suspend)(struct mcp *, pm_message_t);
        int (*resume)(struct mcp *);
+       const struct mcp_device_id *id_table;
 };
 
 int mcp_driver_register(struct mcp_driver *);
diff --git a/include/linux/mfd/s5m87xx/s5m-core.h b/include/linux/mfd/s5m87xx/s5m-core.h
new file mode 100644 (file)
index 0000000..a7480b5
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * s5m-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M_CORE_H
+#define __LINUX_MFD_S5M_CORE_H
+
+#define NUM_IRQ_REGS   4
+
+enum s5m_device_type {
+       S5M8751X,
+       S5M8763X,
+       S5M8767X,
+};
+
+/* S5M8767 registers */
+enum s5m8767_reg {
+       S5M8767_REG_ID,
+       S5M8767_REG_INT1,
+       S5M8767_REG_INT2,
+       S5M8767_REG_INT3,
+       S5M8767_REG_INT1M,
+       S5M8767_REG_INT2M,
+       S5M8767_REG_INT3M,
+       S5M8767_REG_STATUS1,
+       S5M8767_REG_STATUS2,
+       S5M8767_REG_STATUS3,
+       S5M8767_REG_CTRL1,
+       S5M8767_REG_CTRL2,
+       S5M8767_REG_LOWBAT1,
+       S5M8767_REG_LOWBAT2,
+       S5M8767_REG_BUCHG,
+       S5M8767_REG_DVSRAMP,
+       S5M8767_REG_DVSTIMER2 = 0x10,
+       S5M8767_REG_DVSTIMER3,
+       S5M8767_REG_DVSTIMER4,
+       S5M8767_REG_LDO1,
+       S5M8767_REG_LDO2,
+       S5M8767_REG_LDO3,
+       S5M8767_REG_LDO4,
+       S5M8767_REG_LDO5,
+       S5M8767_REG_LDO6,
+       S5M8767_REG_LDO7,
+       S5M8767_REG_LDO8,
+       S5M8767_REG_LDO9,
+       S5M8767_REG_LDO10,
+       S5M8767_REG_LDO11,
+       S5M8767_REG_LDO12,
+       S5M8767_REG_LDO13,
+       S5M8767_REG_LDO14 = 0x20,
+       S5M8767_REG_LDO15,
+       S5M8767_REG_LDO16,
+       S5M8767_REG_LDO17,
+       S5M8767_REG_LDO18,
+       S5M8767_REG_LDO19,
+       S5M8767_REG_LDO20,
+       S5M8767_REG_LDO21,
+       S5M8767_REG_LDO22,
+       S5M8767_REG_LDO23,
+       S5M8767_REG_LDO24,
+       S5M8767_REG_LDO25,
+       S5M8767_REG_LDO26,
+       S5M8767_REG_LDO27,
+       S5M8767_REG_LDO28,
+       S5M8767_REG_UVLO = 0x31,
+       S5M8767_REG_BUCK1CTRL1,
+       S5M8767_REG_BUCK1CTRL2,
+       S5M8767_REG_BUCK2CTRL,
+       S5M8767_REG_BUCK2DVS1,
+       S5M8767_REG_BUCK2DVS2,
+       S5M8767_REG_BUCK2DVS3,
+       S5M8767_REG_BUCK2DVS4,
+       S5M8767_REG_BUCK2DVS5,
+       S5M8767_REG_BUCK2DVS6,
+       S5M8767_REG_BUCK2DVS7,
+       S5M8767_REG_BUCK2DVS8,
+       S5M8767_REG_BUCK3CTRL,
+       S5M8767_REG_BUCK3DVS1,
+       S5M8767_REG_BUCK3DVS2,
+       S5M8767_REG_BUCK3DVS3,
+       S5M8767_REG_BUCK3DVS4,
+       S5M8767_REG_BUCK3DVS5,
+       S5M8767_REG_BUCK3DVS6,
+       S5M8767_REG_BUCK3DVS7,
+       S5M8767_REG_BUCK3DVS8,
+       S5M8767_REG_BUCK4CTRL,
+       S5M8767_REG_BUCK4DVS1,
+       S5M8767_REG_BUCK4DVS2,
+       S5M8767_REG_BUCK4DVS3,
+       S5M8767_REG_BUCK4DVS4,
+       S5M8767_REG_BUCK4DVS5,
+       S5M8767_REG_BUCK4DVS6,
+       S5M8767_REG_BUCK4DVS7,
+       S5M8767_REG_BUCK4DVS8,
+       S5M8767_REG_BUCK5CTRL1,
+       S5M8767_REG_BUCK5CTRL2,
+       S5M8767_REG_BUCK5CTRL3,
+       S5M8767_REG_BUCK5CTRL4,
+       S5M8767_REG_BUCK5CTRL5,
+       S5M8767_REG_BUCK6CTRL1,
+       S5M8767_REG_BUCK6CTRL2,
+       S5M8767_REG_BUCK7CTRL1,
+       S5M8767_REG_BUCK7CTRL2,
+       S5M8767_REG_BUCK8CTRL1,
+       S5M8767_REG_BUCK8CTRL2,
+       S5M8767_REG_BUCK9CTRL1,
+       S5M8767_REG_BUCK9CTRL2,
+       S5M8767_REG_LDO1CTRL,
+       S5M8767_REG_LDO2_1CTRL,
+       S5M8767_REG_LDO2_2CTRL,
+       S5M8767_REG_LDO2_3CTRL,
+       S5M8767_REG_LDO2_4CTRL,
+       S5M8767_REG_LDO3CTRL,
+       S5M8767_REG_LDO4CTRL,
+       S5M8767_REG_LDO5CTRL,
+       S5M8767_REG_LDO6CTRL,
+       S5M8767_REG_LDO7CTRL,
+       S5M8767_REG_LDO8CTRL,
+       S5M8767_REG_LDO9CTRL,
+       S5M8767_REG_LDO10CTRL,
+       S5M8767_REG_LDO11CTRL,
+       S5M8767_REG_LDO12CTRL,
+       S5M8767_REG_LDO13CTRL,
+       S5M8767_REG_LDO14CTRL,
+       S5M8767_REG_LDO15CTRL,
+       S5M8767_REG_LDO16CTRL,
+       S5M8767_REG_LDO17CTRL,
+       S5M8767_REG_LDO18CTRL,
+       S5M8767_REG_LDO19CTRL,
+       S5M8767_REG_LDO20CTRL,
+       S5M8767_REG_LDO21CTRL,
+       S5M8767_REG_LDO22CTRL,
+       S5M8767_REG_LDO23CTRL,
+       S5M8767_REG_LDO24CTRL,
+       S5M8767_REG_LDO25CTRL,
+       S5M8767_REG_LDO26CTRL,
+       S5M8767_REG_LDO27CTRL,
+       S5M8767_REG_LDO28CTRL,
+};
+
+/* S5M8763 registers */
+enum s5m8763_reg {
+       S5M8763_REG_IRQ1,
+       S5M8763_REG_IRQ2,
+       S5M8763_REG_IRQ3,
+       S5M8763_REG_IRQ4,
+       S5M8763_REG_IRQM1,
+       S5M8763_REG_IRQM2,
+       S5M8763_REG_IRQM3,
+       S5M8763_REG_IRQM4,
+       S5M8763_REG_STATUS1,
+       S5M8763_REG_STATUS2,
+       S5M8763_REG_STATUSM1,
+       S5M8763_REG_STATUSM2,
+       S5M8763_REG_CHGR1,
+       S5M8763_REG_CHGR2,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE1,
+       S5M8763_REG_LDO_ACTIVE_DISCHARGE2,
+       S5M8763_REG_BUCK_ACTIVE_DISCHARGE3,
+       S5M8763_REG_ONOFF1,
+       S5M8763_REG_ONOFF2,
+       S5M8763_REG_ONOFF3,
+       S5M8763_REG_ONOFF4,
+       S5M8763_REG_BUCK1_VOLTAGE1,
+       S5M8763_REG_BUCK1_VOLTAGE2,
+       S5M8763_REG_BUCK1_VOLTAGE3,
+       S5M8763_REG_BUCK1_VOLTAGE4,
+       S5M8763_REG_BUCK2_VOLTAGE1,
+       S5M8763_REG_BUCK2_VOLTAGE2,
+       S5M8763_REG_BUCK3,
+       S5M8763_REG_BUCK4,
+       S5M8763_REG_LDO1_LDO2,
+       S5M8763_REG_LDO3,
+       S5M8763_REG_LDO4,
+       S5M8763_REG_LDO5,
+       S5M8763_REG_LDO6,
+       S5M8763_REG_LDO7,
+       S5M8763_REG_LDO7_LDO8,
+       S5M8763_REG_LDO9_LDO10,
+       S5M8763_REG_LDO11,
+       S5M8763_REG_LDO12,
+       S5M8763_REG_LDO13,
+       S5M8763_REG_LDO14,
+       S5M8763_REG_LDO15,
+       S5M8763_REG_LDO16,
+       S5M8763_REG_BKCHR,
+       S5M8763_REG_LBCNFG1,
+       S5M8763_REG_LBCNFG2,
+};
+
+enum s5m8767_irq {
+       S5M8767_IRQ_PWRR,
+       S5M8767_IRQ_PWRF,
+       S5M8767_IRQ_PWR1S,
+       S5M8767_IRQ_JIGR,
+       S5M8767_IRQ_JIGF,
+       S5M8767_IRQ_LOWBAT2,
+       S5M8767_IRQ_LOWBAT1,
+
+       S5M8767_IRQ_MRB,
+       S5M8767_IRQ_DVSOK2,
+       S5M8767_IRQ_DVSOK3,
+       S5M8767_IRQ_DVSOK4,
+
+       S5M8767_IRQ_RTC60S,
+       S5M8767_IRQ_RTCA1,
+       S5M8767_IRQ_RTCA2,
+       S5M8767_IRQ_SMPL,
+       S5M8767_IRQ_RTC1S,
+       S5M8767_IRQ_WTSR,
+
+       S5M8767_IRQ_NR,
+};
+
+#define S5M8767_IRQ_PWRR_MASK          (1 << 0)
+#define S5M8767_IRQ_PWRF_MASK          (1 << 1)
+#define S5M8767_IRQ_PWR1S_MASK         (1 << 3)
+#define S5M8767_IRQ_JIGR_MASK          (1 << 4)
+#define S5M8767_IRQ_JIGF_MASK          (1 << 5)
+#define S5M8767_IRQ_LOWBAT2_MASK       (1 << 6)
+#define S5M8767_IRQ_LOWBAT1_MASK       (1 << 7)
+
+#define S5M8767_IRQ_MRB_MASK           (1 << 2)
+#define S5M8767_IRQ_DVSOK2_MASK                (1 << 3)
+#define S5M8767_IRQ_DVSOK3_MASK                (1 << 4)
+#define S5M8767_IRQ_DVSOK4_MASK                (1 << 5)
+
+#define S5M8767_IRQ_RTC60S_MASK                (1 << 0)
+#define S5M8767_IRQ_RTCA1_MASK         (1 << 1)
+#define S5M8767_IRQ_RTCA2_MASK         (1 << 2)
+#define S5M8767_IRQ_SMPL_MASK          (1 << 3)
+#define S5M8767_IRQ_RTC1S_MASK         (1 << 4)
+#define S5M8767_IRQ_WTSR_MASK          (1 << 5)
+
+enum s5m8763_irq {
+       S5M8763_IRQ_DCINF,
+       S5M8763_IRQ_DCINR,
+       S5M8763_IRQ_JIGF,
+       S5M8763_IRQ_JIGR,
+       S5M8763_IRQ_PWRONF,
+       S5M8763_IRQ_PWRONR,
+
+       S5M8763_IRQ_WTSREVNT,
+       S5M8763_IRQ_SMPLEVNT,
+       S5M8763_IRQ_ALARM1,
+       S5M8763_IRQ_ALARM0,
+
+       S5M8763_IRQ_ONKEY1S,
+       S5M8763_IRQ_TOPOFFR,
+       S5M8763_IRQ_DCINOVPR,
+       S5M8763_IRQ_CHGRSTF,
+       S5M8763_IRQ_DONER,
+       S5M8763_IRQ_CHGFAULT,
+
+       S5M8763_IRQ_LOBAT1,
+       S5M8763_IRQ_LOBAT2,
+
+       S5M8763_IRQ_NR,
+};
+
+#define S5M8763_IRQ_DCINF_MASK         (1 << 2)
+#define S5M8763_IRQ_DCINR_MASK         (1 << 3)
+#define S5M8763_IRQ_JIGF_MASK          (1 << 4)
+#define S5M8763_IRQ_JIGR_MASK          (1 << 5)
+#define S5M8763_IRQ_PWRONF_MASK                (1 << 6)
+#define S5M8763_IRQ_PWRONR_MASK                (1 << 7)
+
+#define S5M8763_IRQ_WTSREVNT_MASK      (1 << 0)
+#define S5M8763_IRQ_SMPLEVNT_MASK      (1 << 1)
+#define S5M8763_IRQ_ALARM1_MASK                (1 << 2)
+#define S5M8763_IRQ_ALARM0_MASK                (1 << 3)
+
+#define S5M8763_IRQ_ONKEY1S_MASK       (1 << 0)
+#define S5M8763_IRQ_TOPOFFR_MASK       (1 << 2)
+#define S5M8763_IRQ_DCINOVPR_MASK      (1 << 3)
+#define S5M8763_IRQ_CHGRSTF_MASK       (1 << 4)
+#define S5M8763_IRQ_DONER_MASK         (1 << 5)
+#define S5M8763_IRQ_CHGFAULT_MASK      (1 << 7)
+
+#define S5M8763_IRQ_LOBAT1_MASK                (1 << 0)
+#define S5M8763_IRQ_LOBAT2_MASK                (1 << 1)
+
+#define S5M8763_ENRAMP                  (1 << 4)
+
+/**
+ * struct s5m87xx_dev - s5m87xx master device for sub-drivers
+ * @dev: master device of the chip (can be used to access platform data)
+ * @i2c: i2c client private data for regulator
+ * @rtc: i2c client private data for rtc
+ * @iolock: mutex for serializing io access
+ * @irqlock: mutex for buslock
+ * @irq_base: base IRQ number for s5m87xx, required for IRQs
+ * @irq: generic IRQ number for s5m87xx
+ * @ono: power onoff IRQ number for s5m87xx
+ * @irq_masks_cur: currently active value
+ * @irq_masks_cache: cached hardware value
+ * @type: indicate which s5m87xx "variant" is used
+ */
+struct s5m87xx_dev {
+       struct device *dev;
+       struct regmap *regmap;
+       struct i2c_client *i2c;
+       struct i2c_client *rtc;
+       struct mutex iolock;
+       struct mutex irqlock;
+
+       int device_type;
+       int irq_base;
+       int irq;
+       int ono;
+       u8 irq_masks_cur[NUM_IRQ_REGS];
+       u8 irq_masks_cache[NUM_IRQ_REGS];
+       int type;
+       bool wakeup;
+};
+
+int s5m_irq_init(struct s5m87xx_dev *s5m87xx);
+void s5m_irq_exit(struct s5m87xx_dev *s5m87xx);
+int s5m_irq_resume(struct s5m87xx_dev *s5m87xx);
+
+extern int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest);
+extern int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
+extern int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value);
+extern int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
+extern int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask);
+
+struct s5m_platform_data {
+       struct s5m_regulator_data       *regulators;
+       int                             device_type;
+       int                             num_regulators;
+
+       int                             irq_base;
+       int                             (*cfg_pmic_irq)(void);
+
+       int                             ono;
+       bool                            wakeup;
+       bool                            buck_voltage_lock;
+
+       int                             buck_gpios[3];
+       int                             buck2_voltage[8];
+       bool                            buck2_gpiodvs;
+       int                             buck3_voltage[8];
+       bool                            buck3_gpiodvs;
+       int                             buck4_voltage[8];
+       bool                            buck4_gpiodvs;
+
+       int                             buck_set1;
+       int                             buck_set2;
+       int                             buck_set3;
+       int                             buck2_enable;
+       int                             buck3_enable;
+       int                             buck4_enable;
+       int                             buck_default_idx;
+       int                             buck2_default_idx;
+       int                             buck3_default_idx;
+       int                             buck4_default_idx;
+
+       int                             buck_ramp_delay;
+       bool                            buck2_ramp_enable;
+       bool                            buck3_ramp_enable;
+       bool                            buck4_ramp_enable;
+};
+
+#endif /*  __LINUX_MFD_S5M_CORE_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-pmic.h b/include/linux/mfd/s5m87xx/s5m-pmic.h
new file mode 100644 (file)
index 0000000..a72a5d2
--- /dev/null
@@ -0,0 +1,100 @@
+/* s5m87xx.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_MFD_S5M_PMIC_H
+#define __LINUX_MFD_S5M_PMIC_H
+
+#include <linux/regulator/machine.h>
+
+/* S5M8767 regulator ids */
+enum s5m8767_regulators {
+       S5M8767_LDO1,
+       S5M8767_LDO2,
+       S5M8767_LDO3,
+       S5M8767_LDO4,
+       S5M8767_LDO5,
+       S5M8767_LDO6,
+       S5M8767_LDO7,
+       S5M8767_LDO8,
+       S5M8767_LDO9,
+       S5M8767_LDO10,
+       S5M8767_LDO11,
+       S5M8767_LDO12,
+       S5M8767_LDO13,
+       S5M8767_LDO14,
+       S5M8767_LDO15,
+       S5M8767_LDO16,
+       S5M8767_LDO17,
+       S5M8767_LDO18,
+       S5M8767_LDO19,
+       S5M8767_LDO20,
+       S5M8767_LDO21,
+       S5M8767_LDO22,
+       S5M8767_LDO23,
+       S5M8767_LDO24,
+       S5M8767_LDO25,
+       S5M8767_LDO26,
+       S5M8767_LDO27,
+       S5M8767_LDO28,
+       S5M8767_BUCK1,
+       S5M8767_BUCK2,
+       S5M8767_BUCK3,
+       S5M8767_BUCK4,
+       S5M8767_BUCK5,
+       S5M8767_BUCK6,
+       S5M8767_BUCK7,
+       S5M8767_BUCK8,
+       S5M8767_BUCK9,
+       S5M8767_AP_EN32KHZ,
+       S5M8767_CP_EN32KHZ,
+
+       S5M8767_REG_MAX,
+};
+
+/* S5M8763 regulator ids */
+enum s5m8763_regulators {
+       S5M8763_LDO1,
+       S5M8763_LDO2,
+       S5M8763_LDO3,
+       S5M8763_LDO4,
+       S5M8763_LDO5,
+       S5M8763_LDO6,
+       S5M8763_LDO7,
+       S5M8763_LDO8,
+       S5M8763_LDO9,
+       S5M8763_LDO10,
+       S5M8763_LDO11,
+       S5M8763_LDO12,
+       S5M8763_LDO13,
+       S5M8763_LDO14,
+       S5M8763_LDO15,
+       S5M8763_LDO16,
+       S5M8763_BUCK1,
+       S5M8763_BUCK2,
+       S5M8763_BUCK3,
+       S5M8763_BUCK4,
+       S5M8763_AP_EN32KHZ,
+       S5M8763_CP_EN32KHZ,
+       S5M8763_ENCHGVI,
+       S5M8763_ESAFEUSB1,
+       S5M8763_ESAFEUSB2,
+};
+
+/**
+ * s5m87xx_regulator_data - regulator data
+ * @id: regulator id
+ * @initdata: regulator init data (contraints, supplies, ...)
+ */
+struct s5m_regulator_data {
+       int                             id;
+       struct regulator_init_data      *initdata;
+};
+
+#endif /*  __LINUX_MFD_S5M_PMIC_H */
diff --git a/include/linux/mfd/s5m87xx/s5m-rtc.h b/include/linux/mfd/s5m87xx/s5m-rtc.h
new file mode 100644 (file)
index 0000000..6ce8da2
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * s5m-rtc.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *              http://www.samsung.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_S5M_RTC_H
+#define __LINUX_MFD_S5M_RTC_H
+
+enum s5m87xx_rtc_reg {
+       S5M87XX_RTC_SEC,
+       S5M87XX_RTC_MIN,
+       S5M87XX_RTC_HOUR,
+       S5M87XX_RTC_WEEKDAY,
+       S5M87XX_RTC_DATE,
+       S5M87XX_RTC_MONTH,
+       S5M87XX_RTC_YEAR1,
+       S5M87XX_RTC_YEAR2,
+       S5M87XX_ALARM0_SEC,
+       S5M87XX_ALARM0_MIN,
+       S5M87XX_ALARM0_HOUR,
+       S5M87XX_ALARM0_WEEKDAY,
+       S5M87XX_ALARM0_DATE,
+       S5M87XX_ALARM0_MONTH,
+       S5M87XX_ALARM0_YEAR1,
+       S5M87XX_ALARM0_YEAR2,
+       S5M87XX_ALARM1_SEC,
+       S5M87XX_ALARM1_MIN,
+       S5M87XX_ALARM1_HOUR,
+       S5M87XX_ALARM1_WEEKDAY,
+       S5M87XX_ALARM1_DATE,
+       S5M87XX_ALARM1_MONTH,
+       S5M87XX_ALARM1_YEAR1,
+       S5M87XX_ALARM1_YEAR2,
+       S5M87XX_ALARM0_CONF,
+       S5M87XX_ALARM1_CONF,
+       S5M87XX_RTC_STATUS,
+       S5M87XX_WTSR_SMPL_CNTL,
+       S5M87XX_RTC_UDR_CON,
+};
+
+#define RTC_I2C_ADDR           (0x0C >> 1)
+
+#define HOUR_12                        (1 << 7)
+#define HOUR_AMPM              (1 << 6)
+#define HOUR_PM                        (1 << 5)
+#define ALARM0_STATUS          (1 << 1)
+#define ALARM1_STATUS          (1 << 2)
+#define UPDATE_AD              (1 << 0)
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT           0
+#define BCD_EN_MASK            (1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT          1
+#define MODEL24_MASK           (1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT          0
+#define RTC_UDR_MASK           (1 << RTC_UDR_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT          6
+#define HOUR_PM_MASK           (1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT     7
+#define ALARM_ENABLE_MASK      (1 << ALARM_ENABLE_SHIFT)
+
+enum {
+       RTC_SEC = 0,
+       RTC_MIN,
+       RTC_HOUR,
+       RTC_WEEKDAY,
+       RTC_DATE,
+       RTC_MONTH,
+       RTC_YEAR1,
+       RTC_YEAR2,
+};
+
+#endif /*  __LINUX_MFD_S5M_RTC_H */
index be1af7c42e576ecd9881276401df8ee5a49d694f..ca1d7a3476004d6936c104a8a435dfd4ac4e5f52 100644 (file)
@@ -20,6 +20,8 @@ enum stmpe_block {
 };
 
 enum stmpe_partnum {
+       STMPE610,
+       STMPE801,
        STMPE811,
        STMPE1601,
        STMPE2401,
@@ -50,17 +52,20 @@ enum {
 
 
 struct stmpe_variant_info;
+struct stmpe_client_info;
 
 /**
  * struct stmpe - STMPE MFD structure
  * @lock: lock protecting I/O operations
  * @irq_lock: IRQ bus lock
  * @dev: device, mostly for dev_dbg()
- * @i2c: i2c client
+ * @client: client - i2c or spi
+ * @ci: client specific information
  * @partnum: part number
  * @variant: the detected STMPE model number
  * @regs: list of addresses of registers which are at different addresses on
  *       different variants.  Indexed by one of STMPE_IDX_*.
+ * @irq: irq number for stmpe
  * @irq_base: starting IRQ number for internal IRQs
  * @num_gpios: number of gpios, differs for variants
  * @ier: cache of IER registers for bus_lock
@@ -71,11 +76,13 @@ struct stmpe {
        struct mutex lock;
        struct mutex irq_lock;
        struct device *dev;
-       struct i2c_client *i2c;
+       void *client;
+       struct stmpe_client_info *ci;
        enum stmpe_partnum partnum;
        struct stmpe_variant_info *variant;
        const u8 *regs;
 
+       int irq;
        int irq_base;
        int num_gpios;
        u8 ier[2];
@@ -183,6 +190,9 @@ struct stmpe_ts_platform_data {
  * @autosleep_timeout: inactivity timeout in milliseconds for autosleep
  * @irq_base: base IRQ number.  %STMPE_NR_IRQS irqs will be used, or
  *           %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
+ * @irq_over_gpio: true if gpio is used to get irq
+ * @irq_gpio: gpio number over which irq will be requested (significant only if
+ *           irq_over_gpio is true)
  * @gpio: GPIO-specific platform data
  * @keypad: keypad-specific platform data
  * @ts: touchscreen-specific platform data
@@ -194,6 +204,8 @@ struct stmpe_platform_data {
        unsigned int irq_trigger;
        bool irq_invert_polarity;
        bool autosleep;
+       bool irq_over_gpio;
+       int irq_gpio;
        int autosleep_timeout;
 
        struct stmpe_gpio_platform_data *gpio;
index 4321f044d1e45e1ad5cdaf20eba1440427b1fb5e..bc19e5fb7ea8f1791960e961e7a9dab803f15a54 100644 (file)
 #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
 #define UCB_MODE_AUD_OFF_CAN   (1 << 13)
 
+struct ucb1x00_plat_data {
+       int             gpio_base;
+};
 
 struct ucb1x00_irq {
        void *devid;
@@ -116,7 +119,7 @@ struct ucb1x00 {
        unsigned int            irq;
        struct semaphore        adc_sem;
        spinlock_t              io_lock;
-       u16                     id;
+       const struct mcp_device_id *id;
        u16                     io_dir;
        u16                     io_out;
        u16                     adc_cr;
index f44bdb7273bd819b5c30b4dba7d808a4ad46e015..9eff2a351ec5cb77951e6bf64c902e14c78f40ce 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __MFD_WM8994_CORE_H__
 #define __MFD_WM8994_CORE_H__
 
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 
 enum wm8994_type {
@@ -55,6 +56,7 @@ struct wm8994 {
        struct mutex irq_lock;
 
        enum wm8994_type type;
+       int revision;
 
        struct device *dev;
        struct regmap *regmap;
@@ -65,13 +67,10 @@ struct wm8994 {
        int irq_base;
 
        int irq;
-       u16 irq_masks_cur[WM8994_NUM_IRQ_REGS];
-       u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
+       struct regmap_irq_chip_data *irq_data;
 
        /* Used over suspend/resume */
        bool suspended;
-       u16 ldo_regs[WM8994_NUM_LDO_REGS];
-       u16 gpio_regs[WM8994_NUM_GPIO_REGS];
 
        struct regulator_dev *dbvdd;
        int num_supplies;
index ea32f306dca6963c312fe4f4b4e3968233f68393..3fb1f407d5e6e36cf0c9cff31d222bff0258b91f 100644 (file)
@@ -23,7 +23,7 @@ struct wm8994_ldo_pdata {
        int enable;
 
        const char *supply;
-       struct regulator_init_data *init_data;
+       const struct regulator_init_data *init_data;
 };
 
 #define WM8994_CONFIGURE_GPIO 0x10000
@@ -113,6 +113,23 @@ struct wm8958_enh_eq_cfg {
        u16 regs[WM8958_ENH_EQ_REGS];
 };
 
+/**
+ * Microphone detection rates, used to tune response rates and power
+ * consumption for WM8958/WM1811 microphone detection.
+ *
+ * @sysclk: System clock rate to use this configuration for.
+ * @idle: True if this configuration should use when no accessory is detected,
+ *        false otherwise.
+ * @start: Value for MICD_BIAS_START_TIME register field (not shifted).
+ * @rate: Value for MICD_RATE register field (not shifted).
+ */
+struct wm8958_micd_rate {
+       int sysclk;
+       bool idle;
+       int start;
+       int rate;
+};
+
 struct wm8994_pdata {
        int gpio_base;
 
@@ -144,6 +161,9 @@ struct wm8994_pdata {
        int num_enh_eq_cfgs;
        struct wm8958_enh_eq_cfg *enh_eq_cfgs;
 
+       int num_micd_rates;
+       struct wm8958_micd_rate *micd_rates;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
@@ -168,12 +188,21 @@ struct wm8994_pdata {
        /* WM8958 microphone bias configuration */
        int micbias[2];
 
+       /* WM8958 microphone detection ranges */
+       u16 micd_lvl_sel;
+
        /* Disable the internal pull downs on the LDOs if they are
         * always driven (eg, connected to an always on supply or
         * GPIO that always drives an output.  If they float power
         * consumption will rise.
         */
        bool ldo_ena_always_driven;
+
+       /*
+        * SPKMODE must be pulled internally by the device on this
+        * system.
+        */
+       bool spkmode_pu;
 };
 
 #endif
index 83a9caec0e4311e72b3997130d1291030616537f..86e6a032a07833f3dbee4f8d399a6e63e61ef93a 100644 (file)
 #define WM8994_FLL1_CONTROL_3                   0x222
 #define WM8994_FLL1_CONTROL_4                   0x223
 #define WM8994_FLL1_CONTROL_5                   0x224
+#define WM8958_FLL1_EFS_1                       0x226
+#define WM8958_FLL1_EFS_2                       0x227
 #define WM8994_FLL2_CONTROL_1                   0x240
 #define WM8994_FLL2_CONTROL_2                   0x241
 #define WM8994_FLL2_CONTROL_3                   0x242
 #define WM8994_FLL2_CONTROL_4                   0x243
 #define WM8994_FLL2_CONTROL_5                   0x244
+#define WM8958_FLL2_EFS_1                       0x246
+#define WM8958_FLL2_EFS_2                       0x247
 #define WM8994_AIF1_CONTROL_1                   0x300
 #define WM8994_AIF1_CONTROL_2                   0x301
 #define WM8994_AIF1_MASTER_SLAVE                0x302
 #define WM8994_AIF2DAC_LRCLK                    0x315
 #define WM8994_AIF2DAC_DATA                     0x316
 #define WM8994_AIF2ADC_DATA                     0x317
+#define WM1811_AIF2TX_CONTROL                   0x318
 #define WM8958_AIF3_CONTROL_1                   0x320
 #define WM8958_AIF3_CONTROL_2                   0x321
 #define WM8958_AIF3DAC_DATA                     0x322
 #define WM8994_AIF1_DAC1_EQ_BAND_5_A            0x491
 #define WM8994_AIF1_DAC1_EQ_BAND_5_B            0x492
 #define WM8994_AIF1_DAC1_EQ_BAND_5_PG           0x493
+#define WM8994_AIF1_DAC1_EQ_BAND_1_C            0x494
 #define WM8994_AIF1_DAC2_EQ_GAINS_1             0x4A0
 #define WM8994_AIF1_DAC2_EQ_GAINS_2             0x4A1
 #define WM8994_AIF1_DAC2_EQ_BAND_1_A            0x4A2
 #define WM8994_AIF1_DAC2_EQ_BAND_5_A            0x4B1
 #define WM8994_AIF1_DAC2_EQ_BAND_5_B            0x4B2
 #define WM8994_AIF1_DAC2_EQ_BAND_5_PG           0x4B3
+#define WM8994_AIF1_DAC2_EQ_BAND_1_C            0x4B4
 #define WM8994_AIF2_ADC_LEFT_VOLUME             0x500
 #define WM8994_AIF2_ADC_RIGHT_VOLUME            0x501
 #define WM8994_AIF2_DAC_LEFT_VOLUME             0x502
 #define WM8994_AIF2_EQ_BAND_5_A                 0x591
 #define WM8994_AIF2_EQ_BAND_5_B                 0x592
 #define WM8994_AIF2_EQ_BAND_5_PG                0x593
+#define WM8994_AIF2_EQ_BAND_1_C                 0x594
 #define WM8994_DAC1_MIXER_VOLUMES               0x600
 #define WM8994_DAC1_LEFT_MIXER_ROUTING          0x601
 #define WM8994_DAC1_RIGHT_MIXER_ROUTING         0x602
 #define WM8994_GPIO_4                           0x703
 #define WM8994_GPIO_5                           0x704
 #define WM8994_GPIO_6                           0x705
+#define WM1811_JACKDET_CTRL                    0x705
 #define WM8994_GPIO_7                           0x706
 #define WM8994_GPIO_8                           0x707
 #define WM8994_GPIO_9                           0x708
 #define WM8958_DSP2_RELEASETIME                 0xA03
 #define WM8958_DSP2_VERMAJMIN                   0xA04
 #define WM8958_DSP2_VERBUILD                    0xA05
+#define WM8958_DSP2_TESTREG                     0xA06
+#define WM8958_DSP2_XORREG                      0xA07
+#define WM8958_DSP2_SHIFTMAXX                   0xA08
+#define WM8958_DSP2_SHIFTMAXY                   0xA09
+#define WM8958_DSP2_SHIFTMAXZ                   0xA0A
+#define WM8958_DSP2_SHIFTMAXEXTLO               0xA0B
+#define WM8958_DSP2_AESSELECT                   0xA0C
 #define WM8958_DSP2_EXECCONTROL                 0xA0D
+#define WM8958_DSP2_SAMPLEBREAK                 0xA0E
+#define WM8958_DSP2_COUNTBREAK                  0xA0F
+#define WM8958_DSP2_INTSTATUS                   0xA10
+#define WM8958_DSP2_EVENTSTATUS                 0xA11
+#define WM8958_DSP2_INTMASK                     0xA12
+#define WM8958_DSP2_CONFIGDWIDTH                0xA13
+#define WM8958_DSP2_CONFIGINSTR                 0xA14
+#define WM8958_DSP2_CONFIGDMEM                  0xA15
+#define WM8958_DSP2_CONFIGDELAYS                0xA16
+#define WM8958_DSP2_CONFIGNUMIO                 0xA17
+#define WM8958_DSP2_CONFIGEXTDEPTH              0xA18
+#define WM8958_DSP2_CONFIGMULTIPLIER            0xA19
+#define WM8958_DSP2_CONFIGCTRLDWIDTH            0xA1A
+#define WM8958_DSP2_CONFIGPIPELINE              0xA1B
+#define WM8958_DSP2_SHIFTMAXEXTHI               0xA1C
+#define WM8958_DSP2_SWVERSIONREG                0xA1D
+#define WM8958_DSP2_CONFIGXMEM                  0xA1E
+#define WM8958_DSP2_CONFIGYMEM                  0xA1F
+#define WM8958_DSP2_CONFIGZMEM                  0xA20
+#define WM8958_FW_BUILD_1                       0x2000
+#define WM8958_FW_BUILD_0                       0x2001
+#define WM8958_FW_ID_1                          0x2002
+#define WM8958_FW_ID_0                          0x2003
+#define WM8958_FW_MAJOR_1                       0x2004
+#define WM8958_FW_MAJOR_0                       0x2005
+#define WM8958_FW_MINOR_1                       0x2006
+#define WM8958_FW_MINOR_0                       0x2007
+#define WM8958_FW_PATCH_1                       0x2008
+#define WM8958_FW_PATCH_0                       0x2009
 #define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1     0x2200
 #define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_2     0x2201
 #define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_1     0x2202
 #define WM8958_MBC_B2_PG2_2                     0x242D
 #define WM8958_MBC_B1_PG2_1                     0x242E
 #define WM8958_MBC_B1_PG2_2                     0x242F
+#define WM8958_MBC_CROSSOVER_1                  0x2600
+#define WM8958_MBC_CROSSOVER_2                  0x2601
+#define WM8958_MBC_HPF_1                        0x2602
+#define WM8958_MBC_HPF_2                        0x2603
+#define WM8958_MBC_LPF_1                        0x2606
+#define WM8958_MBC_LPF_2                        0x2607
+#define WM8958_MBC_RMS_LIMIT_1                  0x260A
+#define WM8958_MBC_RMS_LIMIT_2                  0x260B
 #define WM8994_WRITE_SEQUENCER_0                0x3000
 #define WM8994_WRITE_SEQUENCER_1                0x3001
 #define WM8994_WRITE_SEQUENCER_2                0x3002
 /*
  * R57 (0x39) - AntiPOP (2)
  */
+#define WM1811_JACKDET_MODE_MASK                0x0180  /* JACKDET_MODE - [8:7] */
+#define WM1811_JACKDET_MODE_SHIFT                    7  /* JACKDET_MODE - [8:7] */
+#define WM1811_JACKDET_MODE_WIDTH                    2  /* JACKDET_MODE - [8:7] */
 #define WM8994_MICB2_DISCH                      0x0100  /* MICB2_DISCH */
 #define WM8994_MICB2_DISCH_MASK                 0x0100  /* MICB2_DISCH */
 #define WM8994_MICB2_DISCH_SHIFT                     8  /* MICB2_DISCH */
 /*
  * R548 (0x224) - FLL1 Control (5)
  */
+#define WM8958_FLL1_BYP                         0x8000  /* FLL1_BYP */
+#define WM8958_FLL1_BYP_MASK                    0x8000  /* FLL1_BYP */
+#define WM8958_FLL1_BYP_SHIFT                       15  /* FLL1_BYP */
+#define WM8958_FLL1_BYP_WIDTH                        1  /* FLL1_BYP */
 #define WM8994_FLL1_FRC_NCO_VAL_MASK            0x1F80  /* FLL1_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL1_FRC_NCO_VAL_SHIFT                7  /* FLL1_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL1_FRC_NCO_VAL_WIDTH                6  /* FLL1_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL1_REFCLK_SRC_SHIFT                 0  /* FLL1_REFCLK_SRC - [1:0] */
 #define WM8994_FLL1_REFCLK_SRC_WIDTH                 2  /* FLL1_REFCLK_SRC - [1:0] */
 
+/*
+ * R550 (0x226) - FLL1 EFS 1
+ */
+#define WM8958_FLL1_LAMBDA_MASK                 0xFFFF  /* FLL1_LAMBDA - [15:0] */
+#define WM8958_FLL1_LAMBDA_SHIFT                     0  /* FLL1_LAMBDA - [15:0] */
+#define WM8958_FLL1_LAMBDA_WIDTH                    16  /* FLL1_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL1 EFS 2
+ */
+#define WM8958_FLL1_LFSR_SEL_MASK               0x0006  /* FLL1_LFSR_SEL - [2:1] */
+#define WM8958_FLL1_LFSR_SEL_SHIFT                   1  /* FLL1_LFSR_SEL - [2:1] */
+#define WM8958_FLL1_LFSR_SEL_WIDTH                   2  /* FLL1_LFSR_SEL - [2:1] */
+#define WM8958_FLL1_EFS_ENA                     0x0001  /* FLL1_EFS_ENA */
+#define WM8958_FLL1_EFS_ENA_MASK                0x0001  /* FLL1_EFS_ENA */
+#define WM8958_FLL1_EFS_ENA_SHIFT                    0  /* FLL1_EFS_ENA */
+#define WM8958_FLL1_EFS_ENA_WIDTH                    1  /* FLL1_EFS_ENA */
+
 /*
  * R576 (0x240) - FLL2 Control (1)
  */
 /*
  * R580 (0x244) - FLL2 Control (5)
  */
+#define WM8958_FLL2_BYP                         0x8000  /* FLL2_BYP */
+#define WM8958_FLL2_BYP_MASK                    0x8000  /* FLL2_BYP */
+#define WM8958_FLL2_BYP_SHIFT                       15  /* FLL2_BYP */
+#define WM8958_FLL2_BYP_WIDTH                        1  /* FLL2_BYP */
 #define WM8994_FLL2_FRC_NCO_VAL_MASK            0x1F80  /* FLL2_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL2_FRC_NCO_VAL_SHIFT                7  /* FLL2_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL2_FRC_NCO_VAL_WIDTH                6  /* FLL2_FRC_NCO_VAL - [12:7] */
 #define WM8994_FLL2_REFCLK_SRC_SHIFT                 0  /* FLL2_REFCLK_SRC - [1:0] */
 #define WM8994_FLL2_REFCLK_SRC_WIDTH                 2  /* FLL2_REFCLK_SRC - [1:0] */
 
+/*
+ * R582 (0x246) - FLL2 EFS 1
+ */
+#define WM8958_FLL2_LAMBDA_MASK                 0xFFFF  /* FLL2_LAMBDA - [15:0] */
+#define WM8958_FLL2_LAMBDA_SHIFT                     0  /* FLL2_LAMBDA - [15:0] */
+#define WM8958_FLL2_LAMBDA_WIDTH                    16  /* FLL2_LAMBDA - [15:0] */
+
+/*
+ * R583 (0x247) - FLL2 EFS 2
+ */
+#define WM8958_FLL2_LFSR_SEL_MASK               0x0006  /* FLL2_LFSR_SEL - [2:1] */
+#define WM8958_FLL2_LFSR_SEL_SHIFT                   1  /* FLL2_LFSR_SEL - [2:1] */
+#define WM8958_FLL2_LFSR_SEL_WIDTH                   2  /* FLL2_LFSR_SEL - [2:1] */
+#define WM8958_FLL2_EFS_ENA                     0x0001  /* FLL2_EFS_ENA */
+#define WM8958_FLL2_EFS_ENA_MASK                0x0001  /* FLL2_EFS_ENA */
+#define WM8958_FLL2_EFS_ENA_SHIFT                    0  /* FLL2_EFS_ENA */
+#define WM8958_FLL2_EFS_ENA_WIDTH                    1  /* FLL2_EFS_ENA */
+
 /*
  * R768 (0x300) - AIF1 Control (1)
  */
 #define WM8994_STL_SEL_SHIFT                         0  /* STL_SEL */
 #define WM8994_STL_SEL_WIDTH                         1  /* STL_SEL */
 
+/*
+ * R1797 (0x705) - JACKDET Ctrl
+ */
+#define WM1811_JACKDET_DB                       0x0100  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_MASK                  0x0100  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_SHIFT                      8  /* JACKDET_DB */
+#define WM1811_JACKDET_DB_WIDTH                      1  /* JACKDET_DB */
+#define WM1811_JACKDET_LVL                      0x0040  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_MASK                 0x0040  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_SHIFT                     6  /* JACKDET_LVL */
+#define WM1811_JACKDET_LVL_WIDTH                     1  /* JACKDET_LVL */
+
 /*
  * R1824 (0x720) - Pull Control (1)
  */
index e39aeecfe9a21666a107bf02be780bacca1ba0f5..eaf867412f7adf26e96a3ad4eb3f002a418434e4 100644 (file)
@@ -6,18 +6,31 @@
 
 typedef struct page *new_page_t(struct page *, unsigned long private, int **);
 
+/*
+ * MIGRATE_ASYNC means never block
+ * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking
+ *     on most operations but not ->writepage as the potential stall time
+ *     is too significant
+ * MIGRATE_SYNC will block when migrating pages
+ */
+enum migrate_mode {
+       MIGRATE_ASYNC,
+       MIGRATE_SYNC_LIGHT,
+       MIGRATE_SYNC,
+};
+
 #ifdef CONFIG_MIGRATION
 #define PAGE_MIGRATION 1
 
 extern void putback_lru_pages(struct list_head *l);
 extern int migrate_page(struct address_space *,
-                       struct page *, struct page *);
+                       struct page *, struct page *, enum migrate_mode);
 extern int migrate_pages(struct list_head *l, new_page_t x,
                        unsigned long private, bool offlining,
-                       bool sync);
+                       enum migrate_mode mode);
 extern int migrate_huge_pages(struct list_head *l, new_page_t x,
                        unsigned long private, bool offlining,
-                       bool sync);
+                       enum migrate_mode mode);
 
 extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
@@ -36,10 +49,10 @@ extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 static inline void putback_lru_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, bool offlining,
-               bool sync) { return -ENOSYS; }
+               enum migrate_mode mode) { return -ENOSYS; }
 static inline int migrate_huge_pages(struct list_head *l, new_page_t x,
                unsigned long private, bool offlining,
-               bool sync) { return -ENOSYS; }
+               enum migrate_mode mode) { return -ENOSYS; }
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 static inline int migrate_prep_local(void) { return -ENOSYS; }
index 5d9b4c9813bdb7ae5700c3f078dc5629371c5f4d..17b27cd269c404e117416e468ca9853dd94d141b 100644 (file)
@@ -1482,6 +1482,18 @@ static inline unsigned long vma_pages(struct vm_area_struct *vma)
        return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
 }
 
+/* Look up the first VMA which exactly match the interval vm_start ... vm_end */
+static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm,
+                               unsigned long vm_start, unsigned long vm_end)
+{
+       struct vm_area_struct *vma = find_vma(mm, vm_start);
+
+       if (vma && (vma->vm_start != vm_start || vma->vm_end != vm_end))
+               vma = NULL;
+
+       return vma;
+}
+
 #ifdef CONFIG_MMU
 pgprot_t vm_get_page_prot(unsigned long vm_flags);
 #else
@@ -1528,23 +1540,13 @@ static inline void vm_stat_account(struct mm_struct *mm,
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
-extern int debug_pagealloc_enabled;
-
 extern void kernel_map_pages(struct page *page, int numpages, int enable);
-
-static inline void enable_debug_pagealloc(void)
-{
-       debug_pagealloc_enabled = 1;
-}
 #ifdef CONFIG_HIBERNATION
 extern bool kernel_page_present(struct page *page);
 #endif /* CONFIG_HIBERNATION */
 #else
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable) {}
-static inline void enable_debug_pagealloc(void)
-{
-}
 #ifdef CONFIG_HIBERNATION
 static inline bool kernel_page_present(struct page *page) { return true; }
 #endif /* CONFIG_HIBERNATION */
@@ -1618,5 +1620,22 @@ extern void copy_user_huge_page(struct page *dst, struct page *src,
                                unsigned int pages_per_huge_page);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+extern unsigned int _debug_guardpage_minorder;
+
+static inline unsigned int debug_guardpage_minorder(void)
+{
+       return _debug_guardpage_minorder;
+}
+
+static inline bool page_is_guard(struct page *page)
+{
+       return test_bit(PAGE_DEBUG_FLAG_GUARD, &page->debug_flags);
+}
+#else
+static inline unsigned int debug_guardpage_minorder(void) { return 0; }
+static inline bool page_is_guard(struct page *page) { return false; }
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 8f7d24712dc115790269442be6f8c245d4cf6145..227fd3e9a9c9370398478005d01344f5a42cb02d 100644 (file)
@@ -22,26 +22,21 @@ static inline int page_is_file_cache(struct page *page)
 }
 
 static inline void
-__add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l,
-                      struct list_head *head)
+add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list lru)
 {
-       list_add(&page->lru, head);
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, hpage_nr_pages(page));
-       mem_cgroup_add_lru_list(page, l);
-}
+       struct lruvec *lruvec;
 
-static inline void
-add_page_to_lru_list(struct zone *zone, struct page *page, enum lru_list l)
-{
-       __add_page_to_lru_list(zone, page, l, &zone->lru[l].list);
+       lruvec = mem_cgroup_lru_add_list(zone, page, lru);
+       list_add(&page->lru, &lruvec->lists[lru]);
+       __mod_zone_page_state(zone, NR_LRU_BASE + lru, hpage_nr_pages(page));
 }
 
 static inline void
-del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list l)
+del_page_from_lru_list(struct zone *zone, struct page *page, enum lru_list lru)
 {
+       mem_cgroup_lru_del_list(page, lru);
        list_del(&page->lru);
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, -hpage_nr_pages(page));
-       mem_cgroup_del_lru_list(page, l);
+       __mod_zone_page_state(zone, NR_LRU_BASE + lru, -hpage_nr_pages(page));
 }
 
 /**
@@ -59,24 +54,28 @@ static inline enum lru_list page_lru_base_type(struct page *page)
        return LRU_INACTIVE_ANON;
 }
 
-static inline void
-del_page_from_lru(struct zone *zone, struct page *page)
+/**
+ * page_off_lru - which LRU list was page on? clearing its lru flags.
+ * @page: the page to test
+ *
+ * Returns the LRU list a page was on, as an index into the array of LRU
+ * lists; and clears its Unevictable or Active flags, ready for freeing.
+ */
+static inline enum lru_list page_off_lru(struct page *page)
 {
-       enum lru_list l;
+       enum lru_list lru;
 
-       list_del(&page->lru);
        if (PageUnevictable(page)) {
                __ClearPageUnevictable(page);
-               l = LRU_UNEVICTABLE;
+               lru = LRU_UNEVICTABLE;
        } else {
-               l = page_lru_base_type(page);
+               lru = page_lru_base_type(page);
                if (PageActive(page)) {
                        __ClearPageActive(page);
-                       l += LRU_ACTIVE;
+                       lru += LRU_ACTIVE;
                }
        }
-       __mod_zone_page_state(zone, NR_LRU_BASE + l, -hpage_nr_pages(page));
-       mem_cgroup_del_lru_list(page, l);
+       return lru;
 }
 
 /**
@@ -97,7 +96,6 @@ static inline enum lru_list page_lru(struct page *page)
                if (PageActive(page))
                        lru += LRU_ACTIVE;
        }
-
        return lru;
 }
 
index 5b42f1b34eb74b59964f9a717d436cad44481c05..3cc3062b37679d2bcb58d04c51c5b42073f61725 100644 (file)
@@ -151,12 +151,11 @@ struct page {
 #endif
 }
 /*
- * If another subsystem starts using the double word pairing for atomic
- * operations on struct page then it must change the #if to ensure
- * proper alignment of the page struct.
+ * The struct page can be forced to be double word aligned so that atomic ops
+ * on double words work. The SLUB allocator can make use of such a feature.
  */
-#if defined(CONFIG_SLUB) && defined(CONFIG_CMPXCHG_LOCAL)
-       __attribute__((__aligned__(2*sizeof(unsigned long))))
+#ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
+       __aligned(2 * sizeof(unsigned long))
 #endif
 ;
 
index c8ef9bc54d500d0df052d4bd433e4b24d1855bb1..9f22ba572de0a9a332ec4c2156560b0eac8726cc 100644 (file)
@@ -71,6 +71,8 @@ struct mmc_ext_csd {
        bool                    hpi_en;                 /* HPI enablebit */
        bool                    hpi;                    /* HPI support bit */
        unsigned int            hpi_cmd;                /* cmd used as HPI */
+       unsigned int            boot_ro_lock;           /* ro lock support */
+       bool                    boot_ro_lockable;
        u8                      raw_partition_support;  /* 160 */
        u8                      raw_erased_mem_count;   /* 181 */
        u8                      raw_ext_csd_structure;  /* 194 */
@@ -110,6 +112,7 @@ struct sd_ssr {
 struct sd_switch_caps {
        unsigned int            hs_max_dtr;
        unsigned int            uhs_max_dtr;
+#define HIGH_SPEED_MAX_DTR     50000000
 #define UHS_SDR104_MAX_DTR     208000000
 #define UHS_SDR50_MAX_DTR      100000000
 #define UHS_DDR50_MAX_DTR      50000000
@@ -117,11 +120,13 @@ struct sd_switch_caps {
 #define UHS_SDR12_MAX_DTR      25000000
        unsigned int            sd3_bus_mode;
 #define UHS_SDR12_BUS_SPEED    0
+#define HIGH_SPEED_BUS_SPEED   1
 #define UHS_SDR25_BUS_SPEED    1
 #define UHS_SDR50_BUS_SPEED    2
 #define UHS_SDR104_BUS_SPEED   3
 #define UHS_DDR50_BUS_SPEED    4
 
+#define SD_MODE_HIGH_SPEED     (1 << HIGH_SPEED_BUS_SPEED)
 #define SD_MODE_UHS_SDR12      (1 << UHS_SDR12_BUS_SPEED)
 #define SD_MODE_UHS_SDR25      (1 << UHS_SDR25_BUS_SPEED)
 #define SD_MODE_UHS_SDR50      (1 << UHS_SDR50_BUS_SPEED)
@@ -184,6 +189,10 @@ struct mmc_part {
        unsigned int    part_cfg;       /* partition type */
        char    name[MAX_MMC_PART_NAME_LEN];
        bool    force_ro;       /* to make boot parts RO by default */
+       unsigned int    area_type;
+#define MMC_BLK_DATA_AREA_MAIN (1<<0)
+#define MMC_BLK_DATA_AREA_BOOT (1<<1)
+#define MMC_BLK_DATA_AREA_GP   (1<<2)
 };
 
 /*
@@ -206,6 +215,8 @@ struct mmc_card {
 #define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
 #define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
+#define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
+#define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -261,12 +272,14 @@ struct mmc_card {
  * This function fill contents in mmc_part.
  */
 static inline void mmc_part_add(struct mmc_card *card, unsigned int size,
-                       unsigned int part_cfg, char *name, int idx, bool ro)
+                       unsigned int part_cfg, char *name, int idx, bool ro,
+                       int area_type)
 {
        card->part[card->nr_parts].size = size;
        card->part[card->nr_parts].part_cfg = part_cfg;
        sprintf(card->part[card->nr_parts].name, name, idx);
        card->part[card->nr_parts].force_ro = ro;
+       card->part[card->nr_parts].area_type = area_type;
        card->nr_parts++;
 }
 
@@ -362,18 +375,24 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_hs200(c)      ((c)->state & MMC_STATE_HIGHSPEED_200)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
-#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_uhs(c)                ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_sd_card_uhs(c)     ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_hs200(c)  ((c)->state |= MMC_STATE_HIGHSPEED_200)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 
 /*
  * Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/cd-gpio.h b/include/linux/mmc/cd-gpio.h
new file mode 100644 (file)
index 0000000..a8e4697
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Generic GPIO card-detect helper header
+ *
+ * Copyright (C) 2011, 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 MMC_CD_GPIO_H
+#define MMC_CD_GPIO_H
+
+struct mmc_host;
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
+                       unsigned int irq, unsigned long flags);
+void mmc_cd_gpio_free(struct mmc_host *host);
+
+#endif
index 174a844a5dda67fae26d87514432a0080bf3d7b3..87a976cc5654d164361014849a8733c6733c18e9 100644 (file)
@@ -180,6 +180,8 @@ extern int mmc_try_claim_host(struct mmc_host *host);
 
 extern int mmc_flush_cache(struct mmc_card *);
 
+extern int mmc_detect_card_removed(struct mmc_host *host);
+
 /**
  *     mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
index 6dc9b80568a0d7766d6b8e447ca19b9dbd1d802c..e8779c6d175923172a9f2d00e7213b9305fd1e4b 100644 (file)
@@ -214,6 +214,7 @@ struct dw_mci_board {
        unsigned int bus_hz; /* Bus speed */
 
        unsigned int caps;      /* Capabilities */
+       unsigned int caps2;     /* More capabilities */
        /*
         * Override fifo depth. If 0, autodetect it from the FIFOTH register,
         * but note that this may not be reliable after a bootloader has used
index a3ac9c48e5de60dc71fe71f3eb5d067e315ac4fb..dd13e0539092585c0f8aca31eaea4a620d74f43b 100644 (file)
@@ -56,10 +56,13 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR50   3
 #define MMC_TIMING_UHS_SDR104  4
 #define MMC_TIMING_UHS_DDR50   5
+#define MMC_TIMING_MMC_HS200   6
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
+#define MMC_1_2V_SDR_MODE      3
+#define MMC_1_8V_SDR_MODE      4
 
        unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
 
@@ -148,7 +151,9 @@ struct mmc_host_ops {
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
 
        int     (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
-       int     (*execute_tuning)(struct mmc_host *host);
+
+       /* The tuning command opcode value is different for SD and eMMC cards */
+       int     (*execute_tuning)(struct mmc_host *host, u32 opcode);
        void    (*enable_preset_value)(struct mmc_host *host, bool enable);
        int     (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);
@@ -167,6 +172,11 @@ struct mmc_async_req {
        int (*err_check) (struct mmc_card *, struct mmc_async_req *);
 };
 
+struct mmc_hotplug {
+       unsigned int irq;
+       void *handler_priv;
+};
+
 struct mmc_host {
        struct device           *parent;
        struct device           class_dev;
@@ -242,6 +252,11 @@ struct mmc_host {
 #define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)      /* Notify poweroff supported */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
+#define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
+#define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
+#define MMC_CAP2_HS200_1_2V_SDR        (1 << 6)        /* can support */
+#define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
+                                MMC_CAP2_HS200_1_2V_SDR)
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
        unsigned int        power_notify_type;
@@ -253,10 +268,12 @@ struct mmc_host {
        int                     clk_requests;   /* internal reference counter */
        unsigned int            clk_delay;      /* number of MCI clk hold cycles */
        bool                    clk_gated;      /* clock gated */
-       struct work_struct      clk_gate_work; /* delayed clock gate */
+       struct delayed_work     clk_gate_work; /* delayed clock gate */
        unsigned int            clk_old;        /* old clock value cache */
        spinlock_t              clk_lock;       /* lock for clk fields */
        struct mutex            clk_gate_mutex; /* mutex for clock gating */
+       struct device_attribute clkgate_delay_attr;
+       unsigned long           clkgate_delay;
 #endif
 
        /* host specific block data */
@@ -297,6 +314,8 @@ struct mmc_host {
        int                     claim_cnt;      /* "claim" nesting count */
 
        struct delayed_work     detect;
+       int                     detect_change;  /* card detect flag */
+       struct mmc_hotplug      hotplug;
 
        const struct mmc_bus_ops *bus_ops;      /* current bus driver */
        unsigned int            bus_refs;       /* reference counter */
@@ -323,6 +342,8 @@ struct mmc_host {
        struct fault_attr       fail_mmc_request;
 #endif
 
+       unsigned int            actual_clock;   /* Actual HC clock rate */
+
        unsigned long           private[0] ____cacheline_aligned;
 };
 
index 0e7135697d1110923d6553f35f51171806be2251..fb9f6e116e1c7e0b79a2b25d55db8a48255e4bbf 100644 (file)
@@ -51,6 +51,7 @@
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
 #define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
+#define MMC_SEND_TUNING_BLOCK_HS200    21      /* adtc R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
@@ -280,6 +281,7 @@ struct _mmc_csd {
 #define EXT_CSD_RST_N_FUNCTION         162     /* R/W */
 #define EXT_CSD_SANITIZE_START         165     /* W */
 #define EXT_CSD_WR_REL_PARAM           166     /* RO */
+#define EXT_CSD_BOOT_WP                        173     /* R/W */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
 #define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
@@ -321,6 +323,11 @@ struct _mmc_csd {
 
 #define EXT_CSD_WR_REL_PARAM_EN                (1<<2)
 
+#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS   (0x40)
+#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS  (0x10)
+#define EXT_CSD_BOOT_WP_B_PERM_WP_EN   (0x04)
+#define EXT_CSD_BOOT_WP_B_PWR_WP_EN    (0x01)
+
 #define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
 #define EXT_CSD_PART_CONFIG_ACC_GP0    (0x4)
@@ -333,13 +340,76 @@ struct _mmc_csd {
 
 #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0x    /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK 0x3F    /* Mask out reserved bits */
 #define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
                                             /* DDR mode @1.8V or 3V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
                                             /* DDR mode @1.2V I/O */
 #define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
                                        | EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_1_8V     (1<<4)  /* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_SDR_1_2V     (1<<5)  /* Card can run at 200MHz */
+                                               /* SDR mode @1.2V I/O */
+
+#define EXT_CSD_CARD_TYPE_SDR_200      (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                        EXT_CSD_CARD_TYPE_SDR_1_2V)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL      (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define        EXT_CSD_CARD_TYPE_SDR_1_2V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define        EXT_CSD_CARD_TYPE_SDR_1_8V_ALL  (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                        EXT_CSD_CARD_TYPE_52 | \
+                                        EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V    (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V    (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52      (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V     (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_8V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V     (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_1_2V | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52       (EXT_CSD_CARD_TYPE_SDR_200 | \
+                                                EXT_CSD_CARD_TYPE_DDR_52 | \
+                                                EXT_CSD_CARD_TYPE_52 | \
+                                                EXT_CSD_CARD_TYPE_26)
 
 #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
diff --git a/include/linux/mmc/sdhci-pci-data.h b/include/linux/mmc/sdhci-pci-data.h
new file mode 100644 (file)
index 0000000..8959604
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LINUX_MMC_SDHCI_PCI_DATA_H
+#define LINUX_MMC_SDHCI_PCI_DATA_H
+
+struct pci_dev;
+
+struct sdhci_pci_data {
+       struct pci_dev  *pdev;
+       int             slotno;
+       int             rst_n_gpio; /* Set to -EINVAL if unused */
+       int             cd_gpio;    /* Set to -EINVAL if unused */
+       int             (*setup)(struct sdhci_pci_data *data);
+       void            (*cleanup)(struct sdhci_pci_data *data);
+};
+
+extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
+                               int slotno);
+
+#endif
index e4b69353678d0c69a97af270e02911e756f44863..c750f85177d95cb7b849249ef9a0c007b7687992 100644 (file)
@@ -90,8 +90,6 @@ struct sdhci_host {
 
        unsigned int quirks2;   /* More deviations from spec. */
 
-#define SDHCI_QUIRK2_OWN_CARD_DETECTION                        (1<<0)
-
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
 
@@ -121,6 +119,7 @@ struct sdhci_host {
 #define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 #define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
+#define SDHCI_HS200_NEEDS_TUNING (1<<10)       /* HS200 needs tuning */
 
        unsigned int version;   /* SDHCI spec. version */
 
index e0b1123497b9b5adba34126bc8f187e6c7d98a91..c9fe66c58f8fc718e68b2147733a0acab750d5aa 100644 (file)
@@ -38,6 +38,7 @@
  *      [8:0] Byte/block count
  */
 
+#define R4_18V_PRESENT (1<<24)
 #define R4_MEMORY_PRESENT (1 << 27)
 
 /*
@@ -85,6 +86,7 @@
 #define  SDIO_SD_REV_1_01      0       /* SD Physical Spec Version 1.01 */
 #define  SDIO_SD_REV_1_10      1       /* SD Physical Spec Version 1.10 */
 #define  SDIO_SD_REV_2_00      2       /* SD Physical Spec Version 2.00 */
+#define  SDIO_SD_REV_3_00      3       /* SD Physical Spev Version 3.00 */
 
 #define SDIO_CCCR_IOEx         0x02
 #define SDIO_CCCR_IORx         0x03
 #define SDIO_CCCR_SPEED                0x13
 
 #define  SDIO_SPEED_SHS                0x01    /* Supports High-Speed mode */
-#define  SDIO_SPEED_EHS                0x02    /* Enable High-Speed mode */
-
+#define  SDIO_SPEED_BSS_SHIFT  1
+#define  SDIO_SPEED_BSS_MASK   (7<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR12      (0<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR25      (1<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR50      (2<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_SDR104     (3<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_DDR50      (4<<SDIO_SPEED_BSS_SHIFT)
+#define  SDIO_SPEED_EHS                SDIO_SPEED_SDR25        /* Enable High-Speed */
+
+#define SDIO_CCCR_UHS          0x14
+#define  SDIO_UHS_SDR50                0x01
+#define  SDIO_UHS_SDR104       0x02
+#define  SDIO_UHS_DDR50                0x04
+
+#define SDIO_CCCR_DRIVE_STRENGTH 0x15
+#define  SDIO_SDTx_MASK                0x07
+#define  SDIO_DRIVE_SDTA       (1<<0)
+#define  SDIO_DRIVE_SDTC       (1<<1)
+#define  SDIO_DRIVE_SDTD       (1<<2)
+#define  SDIO_DRIVE_DTSx_MASK  0x03
+#define  SDIO_DRIVE_DTSx_SHIFT 4
+#define  SDIO_DTSx_SET_TYPE_B  (0 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_A  (1 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_C  (2 << SDIO_DRIVE_DTSx_SHIFT)
+#define  SDIO_DTSx_SET_TYPE_D  (3 << SDIO_DRIVE_DTSx_SHIFT)
 /*
  * Function Basic Registers (FBR)
  */
index 3ac040f1936963e729c3688af5702ec9f97bb977..650ba2fb3301af5975fa1b027ebdb008cf573e61 100644 (file)
@@ -140,25 +140,29 @@ enum lru_list {
        NR_LRU_LISTS
 };
 
-#define for_each_lru(l) for (l = 0; l < NR_LRU_LISTS; l++)
+#define for_each_lru(lru) for (lru = 0; lru < NR_LRU_LISTS; lru++)
 
-#define for_each_evictable_lru(l) for (l = 0; l <= LRU_ACTIVE_FILE; l++)
+#define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++)
 
-static inline int is_file_lru(enum lru_list l)
+static inline int is_file_lru(enum lru_list lru)
 {
-       return (l == LRU_INACTIVE_FILE || l == LRU_ACTIVE_FILE);
+       return (lru == LRU_INACTIVE_FILE || lru == LRU_ACTIVE_FILE);
 }
 
-static inline int is_active_lru(enum lru_list l)
+static inline int is_active_lru(enum lru_list lru)
 {
-       return (l == LRU_ACTIVE_ANON || l == LRU_ACTIVE_FILE);
+       return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE);
 }
 
-static inline int is_unevictable_lru(enum lru_list l)
+static inline int is_unevictable_lru(enum lru_list lru)
 {
-       return (l == LRU_UNEVICTABLE);
+       return (lru == LRU_UNEVICTABLE);
 }
 
+struct lruvec {
+       struct list_head lists[NR_LRU_LISTS];
+};
+
 /* Mask used at gathering information at once (see memcontrol.c) */
 #define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE))
 #define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON))
@@ -173,6 +177,8 @@ static inline int is_unevictable_lru(enum lru_list l)
 #define ISOLATE_CLEAN          ((__force isolate_mode_t)0x4)
 /* Isolate unmapped file */
 #define ISOLATE_UNMAPPED       ((__force isolate_mode_t)0x8)
+/* Isolate for asynchronous migration */
+#define ISOLATE_ASYNC_MIGRATE  ((__force isolate_mode_t)0x10)
 
 /* LRU Isolation modes. */
 typedef unsigned __bitwise__ isolate_mode_t;
@@ -317,6 +323,12 @@ struct zone {
         */
        unsigned long           lowmem_reserve[MAX_NR_ZONES];
 
+       /*
+        * This is a per-zone reserve of pages that should not be
+        * considered dirtyable memory.
+        */
+       unsigned long           dirty_balance_reserve;
+
 #ifdef CONFIG_NUMA
        int node;
        /*
@@ -358,10 +370,8 @@ struct zone {
        ZONE_PADDING(_pad1_)
 
        /* Fields commonly accessed by the page reclaim scanner */
-       spinlock_t              lru_lock;       
-       struct zone_lru {
-               struct list_head list;
-       } lru[NR_LRU_LISTS];
+       spinlock_t              lru_lock;
+       struct lruvec           lruvec;
 
        struct zone_reclaim_stat reclaim_stat;
 
index 83ac0713ed0aa9a2a0c79b95013c5bfd42137d9c..b29e7f6f8fa580d9c4c39b4fca596a98e249b2d4 100644 (file)
@@ -436,6 +436,17 @@ struct spi_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+/* mcp */
+
+#define MCP_NAME_SIZE  20
+#define MCP_MODULE_PREFIX "mcp:"
+
+struct mcp_device_id {
+       char name[MCP_NAME_SIZE];
+       kernel_ulong_t driver_data      /* Data private to the driver */
+                       __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
 /* dmi */
 enum dmi_field {
        DMI_NONE,
diff --git a/include/linux/mpi.h b/include/linux/mpi.h
new file mode 100644 (file)
index 0000000..06f8899
--- /dev/null
@@ -0,0 +1,146 @@
+/* mpi.h  -  Multi Precision Integers
+ *     Copyright (C) 1994, 1996, 1998, 1999,
+ *                    2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG.
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_H
+#define G10_MPI_H
+
+#include <linux/types.h>
+
+/* DSI defines */
+
+#define SHA1_DIGEST_LENGTH   20
+
+/*end of DSI defines */
+
+#define BYTES_PER_MPI_LIMB     (BITS_PER_LONG / 8)
+#define BITS_PER_MPI_LIMB      BITS_PER_LONG
+
+typedef unsigned long int mpi_limb_t;
+typedef signed long int mpi_limb_signed_t;
+
+struct gcry_mpi {
+       int alloced;            /* array size (# of allocated limbs) */
+       int nlimbs;             /* number of valid limbs */
+       int nbits;              /* the real number of valid bits (info only) */
+       int sign;               /* indicates a negative number */
+       unsigned flags;         /* bit 0: array must be allocated in secure memory space */
+       /* bit 1: not used */
+       /* bit 2: the limb is a pointer to some m_alloced data */
+       mpi_limb_t *d;          /* array with the limbs */
+};
+
+typedef struct gcry_mpi *MPI;
+
+#define MPI_NULL NULL
+
+#define mpi_get_nlimbs(a)     ((a)->nlimbs)
+#define mpi_is_neg(a)        ((a)->sign)
+
+/*-- mpiutil.c --*/
+MPI mpi_alloc(unsigned nlimbs);
+MPI mpi_alloc_secure(unsigned nlimbs);
+MPI mpi_alloc_like(MPI a);
+void mpi_free(MPI a);
+int mpi_resize(MPI a, unsigned nlimbs);
+int mpi_copy(MPI *copy, const MPI a);
+void mpi_clear(MPI a);
+int mpi_set(MPI w, MPI u);
+int mpi_set_ui(MPI w, ulong u);
+MPI mpi_alloc_set_ui(unsigned long u);
+void mpi_m_check(MPI a);
+void mpi_swap(MPI a, MPI b);
+
+/*-- mpicoder.c --*/
+MPI do_encode_md(const void *sha_buffer, unsigned nbits);
+MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
+int mpi_fromstr(MPI val, const char *str);
+u32 mpi_get_keyid(MPI a, u32 *keyid);
+void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
+void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign);
+int mpi_set_buffer(MPI a, const void *buffer, unsigned nbytes, int sign);
+
+#define log_mpidump g10_log_mpidump
+
+/*-- mpi-add.c --*/
+int mpi_add_ui(MPI w, MPI u, ulong v);
+int mpi_add(MPI w, MPI u, MPI v);
+int mpi_addm(MPI w, MPI u, MPI v, MPI m);
+int mpi_sub_ui(MPI w, MPI u, ulong v);
+int mpi_sub(MPI w, MPI u, MPI v);
+int mpi_subm(MPI w, MPI u, MPI v, MPI m);
+
+/*-- mpi-mul.c --*/
+int mpi_mul_ui(MPI w, MPI u, ulong v);
+int mpi_mul_2exp(MPI w, MPI u, ulong cnt);
+int mpi_mul(MPI w, MPI u, MPI v);
+int mpi_mulm(MPI w, MPI u, MPI v, MPI m);
+
+/*-- mpi-div.c --*/
+ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor);
+int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor);
+int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor);
+int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor);
+int mpi_tdiv_r(MPI rem, MPI num, MPI den);
+int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
+int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count);
+int mpi_divisible_ui(const MPI dividend, ulong divisor);
+
+/*-- mpi-gcd.c --*/
+int mpi_gcd(MPI g, const MPI a, const MPI b);
+
+/*-- mpi-pow.c --*/
+int mpi_pow(MPI w, MPI u, MPI v);
+int mpi_powm(MPI res, MPI base, MPI exp, MPI mod);
+
+/*-- mpi-mpow.c --*/
+int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI mod);
+
+/*-- mpi-cmp.c --*/
+int mpi_cmp_ui(MPI u, ulong v);
+int mpi_cmp(MPI u, MPI v);
+
+/*-- mpi-scan.c --*/
+int mpi_getbyte(MPI a, unsigned idx);
+void mpi_putbyte(MPI a, unsigned idx, int value);
+unsigned mpi_trailing_zeros(MPI a);
+
+/*-- mpi-bit.c --*/
+void mpi_normalize(MPI a);
+unsigned mpi_get_nbits(MPI a);
+int mpi_test_bit(MPI a, unsigned n);
+int mpi_set_bit(MPI a, unsigned n);
+int mpi_set_highbit(MPI a, unsigned n);
+void mpi_clear_highbit(MPI a, unsigned n);
+void mpi_clear_bit(MPI a, unsigned n);
+int mpi_rshift(MPI x, MPI a, unsigned n);
+
+/*-- mpi-inv.c --*/
+int mpi_invm(MPI x, MPI u, MPI v);
+
+#endif /*G10_MPI_H */
index b5479df8378d2fe3981ffab93bb5ff39980e9474..ba4d7656ecfde15c98188afee4a086b19746772f 100644 (file)
@@ -153,6 +153,7 @@ struct nfs_server {
        struct rb_root          openowner_id;
        struct rb_root          lockowner_id;
 #endif
+       struct list_head        state_owners_lru;
        struct list_head        layouts;
        struct list_head        delegations;
        void (*destroy)(struct nfs_server *);
index ae7d6a380dae2852b7e9a48fba3fb7265f0df6f0..308c188770185962547e196312aa87f304aa4502 100644 (file)
@@ -66,6 +66,8 @@ struct idmap_msg {
 /* Forward declaration to make this header independent of others */
 struct nfs_client;
 struct nfs_server;
+struct nfs_fattr;
+struct nfs4_string;
 
 #ifdef CONFIG_NFS_USE_NEW_IDMAPPER
 
@@ -97,6 +99,12 @@ void nfs_idmap_delete(struct nfs_client *);
 
 #endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
 
+void nfs_fattr_init_names(struct nfs_fattr *fattr,
+               struct nfs4_string *owner_name,
+               struct nfs4_string *group_name);
+void nfs_fattr_free_names(struct nfs_fattr *);
+void nfs_fattr_map_and_free_names(struct nfs_server *, struct nfs_fattr *);
+
 int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, __u32 *);
 int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, __u32 *);
 int nfs_map_uid_to_name(const struct nfs_server *, __u32, char *, size_t);
index 2a7c533be5dd8aa2f584fde1faad94c558130d75..a764cef06b733f34f89ed4a618bfb41e33428258 100644 (file)
 /* Forward declaration for NFS v3 */
 struct nfs4_secinfo_flavors;
 
+struct nfs4_string {
+       unsigned int len;
+       char *data;
+};
+
 struct nfs_fsid {
        uint64_t                major;
        uint64_t                minor;
@@ -61,6 +66,8 @@ struct nfs_fattr {
        struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
        unsigned long           time_start;
        unsigned long           gencount;
+       struct nfs4_string      *owner_name;
+       struct nfs4_string      *group_name;
 };
 
 #define NFS_ATTR_FATTR_TYPE            (1U << 0)
@@ -85,6 +92,8 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_V4_REFERRAL     (1U << 19)      /* NFSv4 referral */
 #define NFS_ATTR_FATTR_MOUNTPOINT      (1U << 20)      /* Treat as mountpoint */
 #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID               (1U << 21)
+#define NFS_ATTR_FATTR_OWNER_NAME      (1U << 22)
+#define NFS_ATTR_FATTR_GROUP_NAME      (1U << 23)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
                | NFS_ATTR_FATTR_MODE \
@@ -324,6 +333,7 @@ struct nfs_openargs {
        const struct qstr *     name;
        const struct nfs_server *server;         /* Needed for ID mapping */
        const u32 *             bitmask;
+       const u32 *             dir_bitmask;
        __u32                   claim;
        struct nfs4_sequence_args       seq_args;
 };
@@ -342,6 +352,8 @@ struct nfs_openres {
        __u32                   do_recall;
        __u64                   maxsize;
        __u32                   attrset[NFS4_BITMAP_SIZE];
+       struct nfs4_string      *owner;
+       struct nfs4_string      *group_owner;
        struct nfs4_sequence_res        seq_res;
 };
 
@@ -602,11 +614,16 @@ struct nfs_getaclargs {
        size_t                          acl_len;
        unsigned int                    acl_pgbase;
        struct page **                  acl_pages;
+       struct page *                   acl_scratch;
        struct nfs4_sequence_args       seq_args;
 };
 
+/* getxattr ACL interface flags */
+#define NFS4_ACL_LEN_REQUEST   0x0001  /* zero length getxattr buffer */
 struct nfs_getaclres {
        size_t                          acl_len;
+       size_t                          acl_data_offset;
+       int                             acl_flags;
        struct nfs4_sequence_res        seq_res;
 };
 
@@ -773,11 +790,6 @@ struct nfs3_getaclres {
        struct posix_acl *      acl_default;
 };
 
-struct nfs4_string {
-       unsigned int len;
-       char *data;
-};
-
 #ifdef CONFIG_NFS_V4
 
 typedef u64 clientid4;
index 6f9d04a8533606afa788c351909c5dba74e54438..552fba9c7d5a5a17386901ba00c6f403513e636f 100644 (file)
@@ -43,7 +43,7 @@ enum oom_constraint {
 extern void compare_swap_oom_score_adj(int old_val, int new_val);
 extern int test_set_oom_score_adj(int new_val);
 
-extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
+extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
                        const nodemask_t *nodemask, unsigned long totalpages);
 extern int try_set_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
 extern void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
index b0638fd91e92fdacc2f2675207ef723342072597..22691f614043df3d3cdf77c3b12dd97a551bf813 100644 (file)
@@ -13,6 +13,7 @@
 
 enum page_debug_flags {
        PAGE_DEBUG_FLAG_POISON,         /* Page is poisoned */
+       PAGE_DEBUG_FLAG_GUARD,
 };
 
 /*
@@ -21,7 +22,8 @@ enum page_debug_flags {
  */
 
 #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
-#if !defined(CONFIG_PAGE_POISONING) \
+#if !defined(CONFIG_PAGE_POISONING) && \
+    !defined(CONFIG_PAGE_GUARD) \
 /* && !defined(CONFIG_PAGE_DEBUG_SOMETHING_ELSE) && ... */
 #error WANT_PAGE_DEBUG_FLAGS is turned on with no debug features!
 #endif
index 961ecc7d30bc2ec69b87699c39e5db63a5aff0f7..a2d11771c84b1f4a8717670ddc6720f404a8820f 100644 (file)
@@ -10,8 +10,6 @@ enum {
        /* flags for mem_cgroup and file and I/O status */
        PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
        PCG_FILE_MAPPED, /* page is accounted as "mapped" */
-       /* No lock in page_cgroup */
-       PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
        __NR_PCG_FLAGS,
 };
 
@@ -31,7 +29,6 @@ enum {
 struct page_cgroup {
        unsigned long flags;
        struct mem_cgroup *mem_cgroup;
-       struct list_head lru;           /* per cgroup LRU list */
 };
 
 void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat);
@@ -76,12 +73,6 @@ TESTPCGFLAG(Used, USED)
 CLEARPCGFLAG(Used, USED)
 SETPCGFLAG(Used, USED)
 
-SETPCGFLAG(AcctLRU, ACCT_LRU)
-CLEARPCGFLAG(AcctLRU, ACCT_LRU)
-TESTPCGFLAG(AcctLRU, ACCT_LRU)
-TESTCLEARPCGFLAG(AcctLRU, ACCT_LRU)
-
-
 SETPCGFLAG(FileMapped, FILE_MAPPED)
 CLEARPCGFLAG(FileMapped, FILE_MAPPED)
 TESTPCGFLAG(FileMapped, FILE_MAPPED)
@@ -122,39 +113,6 @@ static inline void move_unlock_page_cgroup(struct page_cgroup *pc,
        local_irq_restore(*flags);
 }
 
-#ifdef CONFIG_SPARSEMEM
-#define PCG_ARRAYID_WIDTH      SECTIONS_SHIFT
-#else
-#define PCG_ARRAYID_WIDTH      NODES_SHIFT
-#endif
-
-#if (PCG_ARRAYID_WIDTH > BITS_PER_LONG - NR_PCG_FLAGS)
-#error Not enough space left in pc->flags to store page_cgroup array IDs
-#endif
-
-/* pc->flags: ARRAY-ID | FLAGS */
-
-#define PCG_ARRAYID_MASK       ((1UL << PCG_ARRAYID_WIDTH) - 1)
-
-#define PCG_ARRAYID_OFFSET     (BITS_PER_LONG - PCG_ARRAYID_WIDTH)
-/*
- * Zero the shift count for non-existent fields, to prevent compiler
- * warnings and ensure references are optimized away.
- */
-#define PCG_ARRAYID_SHIFT      (PCG_ARRAYID_OFFSET * (PCG_ARRAYID_WIDTH != 0))
-
-static inline void set_page_cgroup_array_id(struct page_cgroup *pc,
-                                           unsigned long id)
-{
-       pc->flags &= ~(PCG_ARRAYID_MASK << PCG_ARRAYID_SHIFT);
-       pc->flags |= (id & PCG_ARRAYID_MASK) << PCG_ARRAYID_SHIFT;
-}
-
-static inline unsigned long page_cgroup_array_id(struct page_cgroup *pc)
-{
-       return (pc->flags >> PCG_ARRAYID_SHIFT) & PCG_ARRAYID_MASK;
-}
-
 #else /* CONFIG_CGROUP_MEM_RES_CTLR */
 struct page_cgroup;
 
@@ -183,7 +141,7 @@ static inline void __init page_cgroup_init_flatmem(void)
 extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
                                        unsigned short old, unsigned short new);
 extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
-extern unsigned short lookup_swap_cgroup(swp_entry_t ent);
+extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
 extern int swap_cgroup_swapon(int type, unsigned long max_pages);
 extern void swap_cgroup_swapoff(int type);
 #else
@@ -195,7 +153,7 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 }
 
 static inline
-unsigned short lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
 {
        return 0;
 }
index bab82f4c571c611d91fb9f180dc2a69ed12c95e2..2aa12b8499c0446930ec46149d43e2c9bb8fe81d 100644 (file)
@@ -21,9 +21,7 @@ struct pagevec {
 };
 
 void __pagevec_release(struct pagevec *pvec);
-void __pagevec_free(struct pagevec *pvec);
-void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
-void pagevec_strip(struct pagevec *pvec);
+void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru);
 unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
                pgoff_t start, unsigned nr_pages);
 unsigned pagevec_lookup_tag(struct pagevec *pvec,
@@ -60,37 +58,30 @@ static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)
        return pagevec_space(pvec);
 }
 
-
 static inline void pagevec_release(struct pagevec *pvec)
 {
        if (pagevec_count(pvec))
                __pagevec_release(pvec);
 }
 
-static inline void pagevec_free(struct pagevec *pvec)
-{
-       if (pagevec_count(pvec))
-               __pagevec_free(pvec);
-}
-
 static inline void __pagevec_lru_add_anon(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_INACTIVE_ANON);
+       __pagevec_lru_add(pvec, LRU_INACTIVE_ANON);
 }
 
 static inline void __pagevec_lru_add_active_anon(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_ACTIVE_ANON);
+       __pagevec_lru_add(pvec, LRU_ACTIVE_ANON);
 }
 
 static inline void __pagevec_lru_add_file(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_INACTIVE_FILE);
+       __pagevec_lru_add(pvec, LRU_INACTIVE_FILE);
 }
 
 static inline void __pagevec_lru_add_active_file(struct pagevec *pvec)
 {
-       ____pagevec_lru_add(pvec, LRU_ACTIVE_FILE);
+       __pagevec_lru_add(pvec, LRU_ACTIVE_FILE);
 }
 
 static inline void pagevec_lru_add_file(struct pagevec *pvec)
index 84225c756bd131ce422e926fa0a43a6ddc3dd459..a16b1df3deff0c47212f09667704ef369a08cf1c 100644 (file)
@@ -111,7 +111,7 @@ enum {
        PCI_NUM_RESOURCES,
 
        /* preserve this for compatibility */
-       DEVICE_COUNT_RESOURCE
+       DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
 };
 
 typedef int __bitwise pci_power_t;
@@ -308,7 +308,7 @@ struct pci_dev {
        unsigned int    is_added:1;
        unsigned int    is_busmaster:1; /* device is busmaster */
        unsigned int    no_msi:1;       /* device may not use msi */
-       unsigned int    block_ucfg_access:1;    /* userspace config space access is blocked */
+       unsigned int    block_cfg_access:1;     /* config space access is blocked */
        unsigned int    broken_parity_status:1; /* Device generates false positive parity */
        unsigned int    irq_reroute_variant:2;  /* device needs IRQ rerouting variant */
        unsigned int    msi_enabled:1;
@@ -661,17 +661,13 @@ extern struct pci_bus *pci_find_bus(int domain, int busnr);
 void pci_bus_add_devices(const struct pci_bus *bus);
 struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
                                      struct pci_ops *ops, void *sysdata);
-static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops,
-                                          void *sysdata)
-{
-       struct pci_bus *root_bus;
-       root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
-       if (root_bus)
-               pci_bus_add_devices(root_bus);
-       return root_bus;
-}
-struct pci_bus *pci_create_bus(struct device *parent, int bus,
-                              struct pci_ops *ops, void *sysdata);
+struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+                                   struct pci_ops *ops, void *sysdata,
+                                   struct list_head *resources);
+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
+                                            struct pci_ops *ops, void *sysdata,
+                                            struct list_head *resources);
 struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
                                int busnr);
 void pcie_update_link_speed(struct pci_bus *bus, u16 link_status);
@@ -795,8 +791,11 @@ static inline int pci_is_managed(struct pci_dev *pdev)
 }
 
 void pci_disable_device(struct pci_dev *dev);
+
+extern unsigned int pcibios_max_latency;
 void pci_set_master(struct pci_dev *dev);
 void pci_clear_master(struct pci_dev *dev);
+
 int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
 int pci_set_cacheline_size(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
@@ -804,6 +803,9 @@ int __must_check pci_set_mwi(struct pci_dev *dev);
 int pci_try_set_mwi(struct pci_dev *dev);
 void pci_clear_mwi(struct pci_dev *dev);
 void pci_intx(struct pci_dev *dev, int enable);
+bool pci_intx_mask_supported(struct pci_dev *dev);
+bool pci_check_and_mask_intx(struct pci_dev *dev);
+bool pci_check_and_unmask_intx(struct pci_dev *dev);
 void pci_msi_off(struct pci_dev *dev);
 int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
 int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
@@ -911,6 +913,8 @@ int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
 void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
+void pci_add_resource(struct list_head *resources, struct resource *res);
+void pci_free_resource_list(struct list_head *resources);
 void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, unsigned int flags);
 struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n);
 void pci_bus_remove_resources(struct pci_bus *bus);
@@ -1085,8 +1089,9 @@ int  ht_create_irq(struct pci_dev *dev, int idx);
 void ht_destroy_irq(unsigned int irq);
 #endif /* CONFIG_HT_IRQ */
 
-extern void pci_block_user_cfg_access(struct pci_dev *dev);
-extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
+extern void pci_cfg_access_lock(struct pci_dev *dev);
+extern bool pci_cfg_access_trylock(struct pci_dev *dev);
+extern void pci_cfg_access_unlock(struct pci_dev *dev);
 
 /*
  * PCI domain support.  Sometimes called PCI segment (eg by ACPI),
@@ -1283,10 +1288,13 @@ static inline void pci_release_regions(struct pci_dev *dev)
 
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
-static inline void pci_block_user_cfg_access(struct pci_dev *dev)
+static inline void pci_block_cfg_access(struct pci_dev *dev)
 { }
 
-static inline void pci_unblock_user_cfg_access(struct pci_dev *dev)
+static inline int pci_block_cfg_access_in_atomic(struct pci_dev *dev)
+{ return 0; }
+
+static inline void pci_unblock_cfg_access(struct pci_dev *dev)
 { }
 
 static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
@@ -1424,10 +1432,10 @@ static inline void pci_fixup_device(enum pci_fixup_pass pass,
 void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
 void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
 void __iomem * const *pcim_iomap_table(struct pci_dev *pdev);
-int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
-int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask,
+int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name);
+int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
                                   const char *name);
-void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
+void pcim_iounmap_regions(struct pci_dev *pdev, int mask);
 
 extern int pci_pci_problems;
 #define PCIPCI_FAIL            1       /* No PCI PCI DMA */
@@ -1446,8 +1454,10 @@ extern u8 pci_cache_line_size;
 extern unsigned long pci_hotplug_io_size;
 extern unsigned long pci_hotplug_mem_size;
 
+/* Architecture specific versions may override these (weak) */
 int pcibios_add_platform_entries(struct pci_dev *dev);
 void pcibios_disable_device(struct pci_dev *dev);
+void pcibios_set_master(struct pci_dev *dev);
 int pcibios_set_pcie_reset_state(struct pci_dev *dev,
                                 enum pcie_reset_state state);
 
index 2aaee0ca9da847ec447abc59df56c916f18bc6ac..31d77af2ef42acfff8a1cb5b364f7fcfb6d054b6 100644 (file)
 #define PCI_DEVICE_ID_ELSA_QS3000      0x3000
 
 #define PCI_VENDOR_ID_STMICRO          0x104A
+#define PCI_DEVICE_ID_STMICRO_USB_HOST 0xCC00
+#define PCI_DEVICE_ID_STMICRO_USB_OHCI 0xCC01
+#define PCI_DEVICE_ID_STMICRO_USB_OTG  0xCC02
+#define PCI_DEVICE_ID_STMICRO_UART_HWFC 0xCC03
+#define PCI_DEVICE_ID_STMICRO_UART_NO_HWFC     0xCC04
+#define PCI_DEVICE_ID_STMICRO_SOC_DMA  0xCC05
+#define PCI_DEVICE_ID_STMICRO_SATA     0xCC06
+#define PCI_DEVICE_ID_STMICRO_I2C      0xCC07
+#define PCI_DEVICE_ID_STMICRO_SPI_HS   0xCC08
+#define PCI_DEVICE_ID_STMICRO_MAC      0xCC09
+#define PCI_DEVICE_ID_STMICRO_SDIO_EMMC 0xCC0A
+#define PCI_DEVICE_ID_STMICRO_SDIO     0xCC0B
+#define PCI_DEVICE_ID_STMICRO_GPIO     0xCC0C
+#define PCI_DEVICE_ID_STMICRO_VIP      0xCC0D
+#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_DMA 0xCC0E
+#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_SRCS 0xCC0F
+#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_MSPS 0xCC10
+#define PCI_DEVICE_ID_STMICRO_CAN      0xCC11
+#define PCI_DEVICE_ID_STMICRO_MLB      0xCC12
+#define PCI_DEVICE_ID_STMICRO_DBP      0xCC13
+#define PCI_DEVICE_ID_STMICRO_SATA_PHY 0xCC14
+#define PCI_DEVICE_ID_STMICRO_ESRAM    0xCC15
+#define PCI_DEVICE_ID_STMICRO_VIC      0xCC16
 
 #define PCI_VENDOR_ID_BUSLOGIC               0x104B
 #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
index 28fe380cb19d59f83f507cfc4e841b7dbf4c288a..e41a10f5ae83814c602002af8abdf59dba3d2b6c 100644 (file)
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
 #define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
 #define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
-#define  PCI_EXP_TYPE_RC_EC    0x10    /* Root Complex Event Collector */
+#define  PCI_EXP_TYPE_RC_EC    0x    /* Root Complex Event Collector */
 #define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
 #define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
 #define PCI_EXP_DEVCAP         4       /* Device capabilities */
index c9e4d814ff7795414b028ee7ebcd7ed46fcdddef..2bb62bf296ac2078d08005e6b3b728c6927bb440 100644 (file)
@@ -35,6 +35,8 @@ struct pda_power_pdata {
        unsigned int polling_interval; /* msecs, default is 2000 */
 
        unsigned long ac_max_uA; /* current to draw when on AC */
+
+       bool use_otg_notifier;
 };
 
 #endif /* __PDA_POWER_H__ */
index 79f337c47388ec759bd32190095a853afba978ce..c599f7eca1e7a4bb2f66ab1e644225c40cab8293 100644 (file)
@@ -129,7 +129,12 @@ struct mii_bus {
 };
 #define to_mii_bus(d) container_of(d, struct mii_bus, dev)
 
-struct mii_bus *mdiobus_alloc(void);
+struct mii_bus *mdiobus_alloc_size(size_t);
+static inline struct mii_bus *mdiobus_alloc(void)
+{
+       return mdiobus_alloc_size(0);
+}
+
 int mdiobus_register(struct mii_bus *bus);
 void mdiobus_unregister(struct mii_bus *bus);
 void mdiobus_free(struct mii_bus *bus);
index 38d10326246afbbec371b5cddc2beaff37f1dd48..e7cf6669ac3482e606c04e90470af6a37d4adcf4 100644 (file)
@@ -30,6 +30,8 @@ struct pid_namespace {
 #ifdef CONFIG_BSD_PROCESS_ACCT
        struct bsd_acct_struct *bacct;
 #endif
+       gid_t pid_gid;
+       int hide_pid;
 };
 
 extern struct pid_namespace init_pid_ns;
index 8f1b928f777c34c02d203e6f29674cf94b2d9b4e..0d5b79365d0350cc73f185ae85f11235d56ac7cf 100644 (file)
@@ -162,10 +162,30 @@ struct tc_sfq_qopt {
        unsigned        flows;          /* Maximal number of flows  */
 };
 
+struct tc_sfqred_stats {
+       __u32           prob_drop;      /* Early drops, below max threshold */
+       __u32           forced_drop;    /* Early drops, after max threshold */
+       __u32           prob_mark;      /* Marked packets, below max threshold */
+       __u32           forced_mark;    /* Marked packets, after max threshold */
+       __u32           prob_mark_head; /* Marked packets, below max threshold */
+       __u32           forced_mark_head;/* Marked packets, after max threshold */
+};
+
 struct tc_sfq_qopt_v1 {
        struct tc_sfq_qopt v0;
        unsigned int    depth;          /* max number of packets per flow */
        unsigned int    headdrop;
+/* SFQRED parameters */
+       __u32           limit;          /* HARD maximal flow queue length (bytes) */
+       __u32           qth_min;        /* Min average length threshold (bytes) */
+       __u32           qth_max;        /* Max average length threshold (bytes) */
+       unsigned char   Wlog;           /* log(W)               */
+       unsigned char   Plog;           /* log(P_max/(qth_max-qth_min)) */
+       unsigned char   Scell_log;      /* cell size for idle damping */
+       unsigned char   flags;
+       __u32           max_P;          /* probability, high resolution */
+/* SFQRED stats */
+       struct tc_sfqred_stats stats;
 };
 
 
diff --git a/include/linux/power/bq20z75.h b/include/linux/power/bq20z75.h
deleted file mode 100644 (file)
index 1398eb0..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Gas Gauge driver for TI's BQ20Z75
- *
- * Copyright (c) 2010, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef __LINUX_POWER_BQ20Z75_H_
-#define __LINUX_POWER_BQ20Z75_H_
-
-#include <linux/power_supply.h>
-#include <linux/types.h>
-
-/**
- * struct bq20z75_platform_data - platform data for bq20z75 devices
- * @battery_detect:            GPIO which is used to detect battery presence
- * @battery_detect_present:    gpio state when battery is present (0 / 1)
- * @i2c_retry_count:           # of times to retry on i2c IO failure
- * @poll_retry_count:          # of times to retry looking for new status after
- *                             external change notification
- */
-struct bq20z75_platform_data {
-       int battery_detect;
-       int battery_detect_present;
-       int i2c_retry_count;
-       int poll_retry_count;
-};
-
-#endif
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h
new file mode 100644 (file)
index 0000000..4f75e53
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * MyungJoo.Ham <myungjoo.ham@samsung.com>
+ *
+ * Charger Manager.
+ * This framework enables to control and multiple chargers and to
+ * monitor charging even in the context of suspend-to-RAM with
+ * an interface combining the chargers.
+ *
+ * This program is free software; you can 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 _CHARGER_MANAGER_H
+#define _CHARGER_MANAGER_H
+
+#include <linux/power_supply.h>
+
+enum data_source {
+       CM_FUEL_GAUGE,
+       CM_CHARGER_STAT,
+};
+
+enum polling_modes {
+       CM_POLL_DISABLE = 0,
+       CM_POLL_ALWAYS,
+       CM_POLL_EXTERNAL_POWER_ONLY,
+       CM_POLL_CHARGING_ONLY,
+};
+
+/**
+ * struct charger_global_desc
+ * @rtc_name: the name of RTC used to wake up the system from suspend.
+ * @rtc_only_wakeup:
+ *     If the system is woken up by waekup-sources other than the RTC or
+ *     callbacks, Charger Manager should recognize with
+ *     rtc_only_wakeup() returning false.
+ *     If the RTC given to CM is the only wakeup reason,
+ *     rtc_only_wakeup should return true.
+ */
+struct charger_global_desc {
+       char *rtc_name;
+
+       bool (*rtc_only_wakeup)(void);
+};
+
+/**
+ * struct charger_desc
+ * @psy_name: the name of power-supply-class for charger manager
+ * @polling_mode:
+ *     Determine which polling mode will be used
+ * @fullbatt_uV: voltage in microvolt
+ *     If it is not being charged and VBATT >= fullbatt_uV,
+ *     it is assumed to be full.
+ * @polling_interval_ms: interval in millisecond at which
+ *     charger manager will monitor battery health
+ * @battery_present:
+ *     Specify where information for existance of battery can be obtained
+ * @psy_charger_stat: the names of power-supply for chargers
+ * @num_charger_regulator: the number of entries in charger_regulators
+ * @charger_regulators: array of regulator_bulk_data for chargers
+ * @psy_fuel_gauge: the name of power-supply for fuel gauge
+ * @temperature_out_of_range:
+ *     Determine whether the status is overheat or cold or normal.
+ *     return_value > 0: overheat
+ *     return_value == 0: normal
+ *     return_value < 0: cold
+ * @measure_battery_temp:
+ *     true: measure battery temperature
+ *     false: measure ambient temperature
+ */
+struct charger_desc {
+       char *psy_name;
+
+       enum polling_modes polling_mode;
+       unsigned int polling_interval_ms;
+
+       unsigned int fullbatt_uV;
+
+       enum data_source battery_present;
+
+       char **psy_charger_stat;
+
+       int num_charger_regulators;
+       struct regulator_bulk_data *charger_regulators;
+
+       char *psy_fuel_gauge;
+
+       int (*temperature_out_of_range)(int *mC);
+       bool measure_battery_temp;
+};
+
+#define PSY_NAME_MAX   30
+
+/**
+ * struct charger_manager
+ * @entry: entry for list
+ * @dev: device pointer
+ * @desc: instance of charger_desc
+ * @fuel_gauge: power_supply for fuel gauge
+ * @charger_stat: array of power_supply for chargers
+ * @charger_enabled: the state of charger
+ * @emergency_stop:
+ *     When setting true, stop charging
+ * @last_temp_mC: the measured temperature in milli-Celsius
+ * @psy_name_buf: the name of power-supply-class for charger manager
+ * @charger_psy: power_supply for charger manager
+ * @status_save_ext_pwr_inserted:
+ *     saved status of external power before entering suspend-to-RAM
+ * @status_save_batt:
+ *     saved status of battery before entering suspend-to-RAM
+ */
+struct charger_manager {
+       struct list_head entry;
+       struct device *dev;
+       struct charger_desc *desc;
+
+       struct power_supply *fuel_gauge;
+       struct power_supply **charger_stat;
+
+       bool charger_enabled;
+
+       int emergency_stop;
+       int last_temp_mC;
+
+       char psy_name_buf[PSY_NAME_MAX + 1];
+       struct power_supply charger_psy;
+
+       bool status_save_ext_pwr_inserted;
+       bool status_save_batt;
+};
+
+#ifdef CONFIG_CHARGER_MANAGER
+extern int setup_charger_manager(struct charger_global_desc *gd);
+extern bool cm_suspend_again(void);
+#else
+static void __maybe_unused setup_charger_manager(struct charger_global_desc *gd)
+{ }
+
+static bool __maybe_unused cm_suspend_again(void)
+{
+       return false;
+}
+#endif
+
+#endif /* _CHARGER_MANAGER_H */
diff --git a/include/linux/power/sbs-battery.h b/include/linux/power/sbs-battery.h
new file mode 100644 (file)
index 0000000..2b0a9d9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Gas Gauge driver for SBS Compliant Gas Gauges
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __LINUX_POWER_SBS_BATTERY_H_
+#define __LINUX_POWER_SBS_BATTERY_H_
+
+#include <linux/power_supply.h>
+#include <linux/types.h>
+
+/**
+ * struct sbs_platform_data - platform data for sbs devices
+ * @battery_detect:            GPIO which is used to detect battery presence
+ * @battery_detect_present:    gpio state when battery is present (0 / 1)
+ * @i2c_retry_count:           # of times to retry on i2c IO failure
+ * @poll_retry_count:          # of times to retry looking for new status after
+ *                             external change notification
+ */
+struct sbs_platform_data {
+       int battery_detect;
+       int battery_detect_present;
+       int i2c_retry_count;
+       int poll_retry_count;
+};
+
+#endif
index 204c18dfdc9e839a378cfd4200342784c22be5b7..fa9b962aec124ad0e126d7400d8a92325525d9ff 100644 (file)
@@ -74,6 +74,12 @@ enum {
        POWER_SUPPLY_CAPACITY_LEVEL_FULL,
 };
 
+enum {
+       POWER_SUPPLY_SCOPE_UNKNOWN = 0,
+       POWER_SUPPLY_SCOPE_SYSTEM,
+       POWER_SUPPLY_SCOPE_DEVICE,
+};
+
 enum power_supply_property {
        /* Properties of type `int' */
        POWER_SUPPLY_PROP_STATUS = 0,
@@ -116,6 +122,7 @@ enum power_supply_property {
        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
        POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
        POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
+       POWER_SUPPLY_PROP_SCOPE,
        /* Properties of type `const char *' */
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
@@ -123,7 +130,8 @@ enum power_supply_property {
 };
 
 enum power_supply_type {
-       POWER_SUPPLY_TYPE_BATTERY = 0,
+       POWER_SUPPLY_TYPE_UNKNOWN = 0,
+       POWER_SUPPLY_TYPE_BATTERY,
        POWER_SUPPLY_TYPE_UPS,
        POWER_SUPPLY_TYPE_MAINS,
        POWER_SUPPLY_TYPE_USB,          /* Standard Downstream Port */
@@ -211,6 +219,7 @@ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
 extern int power_supply_register(struct device *parent,
                                 struct power_supply *psy);
 extern void power_supply_unregister(struct power_supply *psy);
+extern int power_supply_powers(struct power_supply *psy, struct device *dev);
 
 /* For APM emulation, think legacy userspace. */
 extern struct class *power_supply_class;
index a3baeb2c216156831606a11c5bd8636d80b8b76c..7ddc7f1b480fd41318d94c0a39c8e2ff80f9c5f8 100644 (file)
 
 #define PR_MCE_KILL_GET 34
 
+/*
+ * Tune up process memory map specifics.
+ */
+#define PR_SET_MM              35
+# define PR_SET_MM_START_CODE          1
+# define PR_SET_MM_END_CODE            2
+# define PR_SET_MM_START_DATA          3
+# define PR_SET_MM_END_DATA            4
+# define PR_SET_MM_START_STACK         5
+# define PR_SET_MM_START_BRK           6
+# define PR_SET_MM_BRK                 7
+
 #endif /* _LINUX_PRCTL_H */
index 6d9e575519cc1c4293372fbeb6f6761551298f38..85c5073062390b3b1129f1d5af9ec0c8ed1c4f5e 100644 (file)
@@ -253,7 +253,7 @@ extern const struct proc_ns_operations utsns_operations;
 extern const struct proc_ns_operations ipcns_operations;
 
 union proc_op {
-       int (*proc_get_link)(struct inode *, struct path *);
+       int (*proc_get_link)(struct dentry *, struct path *);
        int (*proc_read)(struct task_struct *task, char *page);
        int (*proc_show)(struct seq_file *m,
                struct pid_namespace *ns, struct pid *pid,
index 9d4539c52e53e5f3635345260049999ba90d735e..07e360b1b282b61b92c08fad6ebba553bc0bcb4d 100644 (file)
@@ -49,9 +49,6 @@
 #define RADIX_TREE_EXCEPTIONAL_ENTRY   2
 #define RADIX_TREE_EXCEPTIONAL_SHIFT   2
 
-#define radix_tree_indirect_to_ptr(ptr) \
-       radix_tree_indirect_to_ptr((void __force *)(ptr))
-
 static inline int radix_tree_is_indirect_ptr(void *ptr)
 {
        return (int)((unsigned long)ptr & RADIX_TREE_INDIRECT_PTR);
index 2148b122779b5a2fd8421c5e15cfc9ca91ea85ff..1cdd62a2788a99436f666ec9d9e194f3c341e769 100644 (file)
@@ -120,6 +120,7 @@ void anon_vma_init(void);   /* create anon_vma_cachep */
 int  anon_vma_prepare(struct vm_area_struct *);
 void unlink_anon_vmas(struct vm_area_struct *);
 int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *);
+void anon_vma_moveto_tail(struct vm_area_struct *);
 int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *);
 void __anon_vma_link(struct vm_area_struct *);
 
@@ -157,7 +158,7 @@ static inline void page_dup_rmap(struct page *page)
  * Called from mm/vmscan.c to handle paging out
  */
 int page_referenced(struct page *, int is_locked,
-                       struct mem_cgroup *cnt, unsigned long *vm_flags);
+                       struct mem_cgroup *memcg, unsigned long *vm_flags);
 int page_referenced_one(struct page *, struct vm_area_struct *,
        unsigned long address, unsigned int *mapcount, unsigned long *vm_flags);
 
@@ -235,7 +236,7 @@ int rmap_walk(struct page *page, int (*rmap_one)(struct page *,
 #define anon_vma_link(vma)     do {} while (0)
 
 static inline int page_referenced(struct page *page, int is_locked,
-                                 struct mem_cgroup *cnt,
+                                 struct mem_cgroup *memcg,
                                  unsigned long *vm_flags)
 {
        *vm_flags = 0;
index fbe58b7e63eb3fd6a6b917f19d63048e6ee818de..99dadbffdd4ff576f08473640608d0e28f57de83 100644 (file)
@@ -25,6 +25,10 @@ struct s3c_adc_bat_pdata {
        const unsigned int current_channel;
        const unsigned int backup_volt_channel;
 
+       const unsigned int volt_samples;
+       const unsigned int current_samples;
+       const unsigned int backup_volt_samples;
+
        const unsigned int volt_mult;
        const unsigned int current_mult;
        const unsigned int backup_volt_mult;
index f044f66018f2fa319347c7eb1365631ece58730b..4032ec1cf836fe2055a422c8d2356a4ea620117a 100644 (file)
@@ -1544,6 +1544,7 @@ struct task_struct {
         */
        int nr_dirtied;
        int nr_dirtied_pause;
+       unsigned long dirty_paused_when; /* start of a write-and-pause period */
 
 #ifdef CONFIG_LATENCYTOP
        int latency_record_count;
@@ -2274,7 +2275,7 @@ extern void __cleanup_sighand(struct sighand_struct *);
 extern void exit_itimers(struct signal_struct *);
 extern void flush_itimer_signals(void);
 
-extern NORET_TYPE void do_group_exit(int);
+extern void do_group_exit(int);
 
 extern void daemonize(const char *, ...);
 extern int allow_signal(int);
index 98112cf93884e9d6ed84266841d96664907dccb6..0ccceb9b104640f91e9738c7b467e0da1a74c7b8 100644 (file)
@@ -590,6 +590,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @reqprot contains the protection requested by the application.
  *     @prot contains the protection that will be applied by the kernel.
  *     @flags contains the operational flags.
+ *     @addr contains virtual address that will be used for the operation.
+ *     @addr_only contains a boolean: 0 if file-backed VMA, otherwise 1.
  *     Return 0 if permission is granted.
  * @file_mprotect:
  *     Check permissions before changing memory access permissions.
@@ -2043,7 +2045,7 @@ static inline void security_inode_free(struct inode *inode)
 static inline int security_inode_init_security(struct inode *inode,
                                                struct inode *dir,
                                                const struct qstr *qstr,
-                                               initxattrs initxattrs,
+                                               const initxattrs initxattrs,
                                                void *fs_data)
 {
        return 0;
index 369273a5267908791efc203537e0f349edaef0cf..78779074f6e8ff9b4f0d95fe9575e008eb0d1c81 100644 (file)
@@ -49,6 +49,10 @@ enum {
 
 #define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
 
+/* SCSPTR, optional */
+#define SCSPTR_RTSIO   (1 << 7)
+#define SCSPTR_CTSIO   (1 << 5)
+
 /* Offsets into the sci_port->irqs array */
 enum {
        SCIx_ERI_IRQ,
@@ -60,6 +64,17 @@ enum {
        SCIx_MUX_IRQ = SCIx_NR_IRQS,    /* special case */
 };
 
+/* Offsets into the sci_port->gpios array */
+enum {
+       SCIx_SCK,
+       SCIx_RXD,
+       SCIx_TXD,
+       SCIx_CTS,
+       SCIx_RTS,
+
+       SCIx_NR_FNS,
+};
+
 enum {
        SCIx_PROBE_REGTYPE,
 
@@ -108,14 +123,21 @@ struct plat_sci_port_ops {
        void (*init_pins)(struct uart_port *, unsigned int cflag);
 };
 
+/*
+ * Port-specific capabilities
+ */
+#define SCIx_HAVE_RTSCTS       (1 << 0)
+
 /*
  * Platform device specific platform_data struct
  */
 struct plat_sci_port {
        unsigned long   mapbase;                /* resource base */
        unsigned int    irqs[SCIx_NR_IRQS];     /* ERI, RXI, TXI, BRI */
+       unsigned int    gpios[SCIx_NR_FNS];     /* SCK, RXD, TXD, CTS, RTS */
        unsigned int    type;                   /* SCI / SCIF / IRDA */
        upf_t           flags;                  /* UPF_* flags */
+       unsigned long   capabilities;           /* Port features/capabilities */
 
        unsigned int    scbrr_algo_id;          /* SCBRR calculation algo */
        unsigned int    scscr;                  /* SCSCR initialization */
index a20831cf336a5ef5f6cc427b6b131766a34ca761..54341d811685a2088897491c2255ba605b71ab43 100644 (file)
@@ -49,6 +49,7 @@ struct clk {
 
        void __iomem            *enable_reg;
        unsigned int            enable_bit;
+       void __iomem            *mapped_reg;
 
        unsigned long           arch_flags;
        void                    *priv;
@@ -131,10 +132,9 @@ int sh_clk_div4_enable_register(struct clk *clks, int nr,
 int sh_clk_div4_reparent_register(struct clk *clks, int nr,
                         struct clk_div4_table *table);
 
-#define SH_CLK_DIV6_EXT(_parent, _reg, _flags, _parents,       \
+#define SH_CLK_DIV6_EXT(_reg, _flags, _parents,                        \
                        _num_parents, _src_shift, _src_width)   \
 {                                                              \
-       .parent = _parent,                                      \
        .enable_reg = (void __iomem *)_reg,                     \
        .flags = _flags,                                        \
        .parent_table = _parents,                               \
@@ -144,7 +144,11 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
 }
 
 #define SH_CLK_DIV6(_parent, _reg, _flags)                     \
-       SH_CLK_DIV6_EXT(_parent, _reg, _flags, NULL, 0, 0, 0)
+{                                                              \
+       .parent         = _parent,                              \
+       .enable_reg     = (void __iomem *)_reg,                 \
+       .flags          = _flags,                               \
+}
 
 int sh_clk_div6_register(struct clk *clks, int nr);
 int sh_clk_div6_reparent_register(struct clk *clks, int nr);
index 8446789216e568008fb71e9c85189758bf0197a4..5c15aed9c4b2430adebf1b5ca0b9325bcbd22acd 100644 (file)
@@ -45,16 +45,24 @@ struct pinmux_cfg_reg {
        unsigned long reg, reg_width, field_width;
        unsigned long *cnt;
        pinmux_enum_t *enum_ids;
+       unsigned long *var_field_width;
 };
 
 #define PINMUX_CFG_REG(name, r, r_width, f_width) \
        .reg = r, .reg_width = r_width, .field_width = f_width,         \
        .cnt = (unsigned long [r_width / f_width]) {}, \
-       .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \
+       .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)])
+
+#define PINMUX_CFG_REG_VAR(name, r, r_width, var_fw0, var_fwn...) \
+       .reg = r, .reg_width = r_width, \
+       .cnt = (unsigned long [r_width]) {}, \
+       .var_field_width = (unsigned long [r_width]) { var_fw0, var_fwn, 0 }, \
+       .enum_ids = (pinmux_enum_t [])
 
 struct pinmux_data_reg {
        unsigned long reg, reg_width, reg_shadow;
        pinmux_enum_t *enum_ids;
+       void __iomem *mapped_reg;
 };
 
 #define PINMUX_DATA_REG(name, r, r_width) \
@@ -75,6 +83,12 @@ struct pinmux_range {
        pinmux_enum_t force;
 };
 
+struct pfc_window {
+       phys_addr_t phys;
+       void __iomem *virt;
+       unsigned long size;
+};
+
 struct pinmux_info {
        char *name;
        pinmux_enum_t reserved_id;
@@ -98,6 +112,12 @@ struct pinmux_info {
        struct pinmux_irq *gpio_irq;
        unsigned int gpio_irq_size;
 
+       struct resource *resource;
+       unsigned int num_resources;
+       struct pfc_window *window;
+
+       unsigned long unlock_reg;
+
        struct gpio_chip chip;
 };
 
diff --git a/include/linux/sigma.h b/include/linux/sigma.h
deleted file mode 100644 (file)
index d0de882..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Load firmware files from Analog Devices SigmaStudio
- *
- * Copyright 2009-2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#ifndef __SIGMA_FIRMWARE_H__
-#define __SIGMA_FIRMWARE_H__
-
-#include <linux/firmware.h>
-#include <linux/types.h>
-
-struct i2c_client;
-
-#define SIGMA_MAGIC "ADISIGM"
-
-struct sigma_firmware {
-       const struct firmware *fw;
-       size_t pos;
-};
-
-struct sigma_firmware_header {
-       unsigned char magic[7];
-       u8 version;
-       __le32 crc;
-};
-
-enum {
-       SIGMA_ACTION_WRITEXBYTES = 0,
-       SIGMA_ACTION_WRITESINGLE,
-       SIGMA_ACTION_WRITESAFELOAD,
-       SIGMA_ACTION_DELAY,
-       SIGMA_ACTION_PLLWAIT,
-       SIGMA_ACTION_NOOP,
-       SIGMA_ACTION_END,
-};
-
-struct sigma_action {
-       u8 instr;
-       u8 len_hi;
-       __le16 len;
-       __be16 addr;
-       unsigned char payload[];
-};
-
-static inline u32 sigma_action_len(struct sigma_action *sa)
-{
-       return (sa->len_hi << 16) | le16_to_cpu(sa->len);
-}
-
-extern int process_sigma_firmware(struct i2c_client *client, const char *name);
-
-#endif
index a822300a253b0d2be69b477be3b078448ec25017..7987ce74874b366b413ef6191b67caf02b42aba4 100644 (file)
@@ -254,6 +254,7 @@ extern void set_current_blocked(const sigset_t *);
 extern int show_unhandled_signals;
 
 extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
+extern void block_sigmask(struct k_sigaction *ka, int signr);
 extern void exit_signals(struct task_struct *tsk);
 
 extern struct kmem_cache *sighand_cachep;
index febc4dbec2cad59adc05d3f97e39c8098b78aea4..7874a8a566386a02165ebc0bff474d8bf160f0c0 100644 (file)
@@ -26,6 +26,7 @@ struct auth_cred {
        uid_t   uid;
        gid_t   gid;
        struct group_info *group_info;
+       const char *principal;
        unsigned char machine_cred : 1;
 };
 
@@ -127,7 +128,7 @@ void                        rpc_destroy_generic_auth(void);
 void                   rpc_destroy_authunix(void);
 
 struct rpc_cred *      rpc_lookup_cred(void);
-struct rpc_cred *      rpc_lookup_machine_cred(void);
+struct rpc_cred *      rpc_lookup_machine_cred(const char *service_name);
 int                    rpcauth_register(const struct rpc_authops *);
 int                    rpcauth_unregister(const struct rpc_authops *);
 struct rpc_auth *      rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
index 8eee9dbbfe7aaddbdb5aaebfbaf5ad82669f846d..f1cfd4c85cd047c4b2fadd367eeb819aabc57d29 100644 (file)
@@ -82,8 +82,8 @@ struct gss_cred {
        enum rpc_gss_svc        gc_service;
        struct gss_cl_ctx __rcu *gc_ctx;
        struct gss_upcall_msg   *gc_upcall;
+       const char              *gc_principal;
        unsigned long           gc_upcall_timestamp;
-       unsigned char           gc_machine_cred : 1;
 };
 
 #endif /* __KERNEL__ */
index a20970ef9e4ebbf5b95aa224d11d30cef7ca7411..af70af3335461ee587d23a8567a9abdb9cc23eb9 100644 (file)
@@ -191,6 +191,8 @@ extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
                             struct xdr_array2_desc *desc);
 extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
                             struct xdr_array2_desc *desc);
+extern void _copy_from_pages(char *p, struct page **pages, size_t pgbase,
+                            size_t len);
 
 /*
  * Provide some simple tools for XDR buffer overflow-checking etc.
index 1e22e126d2acc7a880f449c5241c3a56e901e519..06061a7f8e69131e2401985e243298cbf9795a50 100644 (file)
@@ -207,6 +207,7 @@ struct swap_list_t {
 /* linux/mm/page_alloc.c */
 extern unsigned long totalram_pages;
 extern unsigned long totalreserve_pages;
+extern unsigned long dirty_balance_reserve;
 extern unsigned int nr_free_buffer_pages(void);
 extern unsigned int nr_free_pagecache_pages(void);
 
index 4c069d8bd74038568acc37992c4eb111188f261b..d0018d27c281ffa3a7135c1aa1a8deffc1b900ca 100644 (file)
@@ -25,70 +25,18 @@ struct virtqueue {
        void *priv;
 };
 
-/**
- * operations for virtqueue
- * virtqueue_add_buf: expose buffer to other end
- *     vq: the struct virtqueue we're talking about.
- *     sg: the description of the buffer(s).
- *     out_num: the number of sg readable by other side
- *     in_num: the number of sg which are writable (after readable ones)
- *     data: the token identifying the buffer.
- *     gfp: how to do memory allocations (if necessary).
- *      Returns remaining capacity of queue (sg segments) or a negative error.
- * virtqueue_kick: update after add_buf
- *     vq: the struct virtqueue
- *     After one or more add_buf calls, invoke this to kick the other side.
- * virtqueue_get_buf: get the next used buffer
- *     vq: the struct virtqueue we're talking about.
- *     len: the length written into the buffer
- *     Returns NULL or the "data" token handed to add_buf.
- * virtqueue_disable_cb: disable callbacks
- *     vq: the struct virtqueue we're talking about.
- *     Note that this is not necessarily synchronous, hence unreliable and only
- *     useful as an optimization.
- * virtqueue_enable_cb: restart callbacks after disable_cb.
- *     vq: the struct virtqueue we're talking about.
- *     This re-enables callbacks; it returns "false" if there are pending
- *     buffers in the queue, to detect a possible race between the driver
- *     checking for more work, and enabling callbacks.
- * virtqueue_enable_cb_delayed: restart callbacks after disable_cb.
- *     vq: the struct virtqueue we're talking about.
- *     This re-enables callbacks but hints to the other side to delay
- *     interrupts until most of the available buffers have been processed;
- *     it returns "false" if there are many pending buffers in the queue,
- *     to detect a possible race between the driver checking for more work,
- *     and enabling callbacks.
- * virtqueue_detach_unused_buf: detach first unused buffer
- *     vq: the struct virtqueue we're talking about.
- *     Returns NULL or the "data" token handed to add_buf
- * virtqueue_get_vring_size: return the size of the virtqueue's vring
- *     vq: the struct virtqueue containing the vring of interest.
- *     Returns the size of the vring.
- *
- * Locking rules are straightforward: the driver is responsible for
- * locking.  No two operations may be invoked simultaneously, with the exception
- * of virtqueue_disable_cb.
- *
- * All operations can be called in any context.
- */
+int virtqueue_add_buf(struct virtqueue *vq,
+                     struct scatterlist sg[],
+                     unsigned int out_num,
+                     unsigned int in_num,
+                     void *data,
+                     gfp_t gfp);
 
-int virtqueue_add_buf_gfp(struct virtqueue *vq,
-                         struct scatterlist sg[],
-                         unsigned int out_num,
-                         unsigned int in_num,
-                         void *data,
-                         gfp_t gfp);
+void virtqueue_kick(struct virtqueue *vq);
 
-static inline int virtqueue_add_buf(struct virtqueue *vq,
-                                   struct scatterlist sg[],
-                                   unsigned int out_num,
-                                   unsigned int in_num,
-                                   void *data)
-{
-       return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
-}
+bool virtqueue_kick_prepare(struct virtqueue *vq);
 
-void virtqueue_kick(struct virtqueue *vq);
+void virtqueue_notify(struct virtqueue *vq);
 
 void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
 
@@ -146,6 +94,11 @@ struct virtio_driver {
        int (*probe)(struct virtio_device *dev);
        void (*remove)(struct virtio_device *dev);
        void (*config_changed)(struct virtio_device *dev);
+#ifdef CONFIG_PM
+       int (*freeze)(struct virtio_device *dev);
+       int (*thaw)(struct virtio_device *dev);
+       int (*restore)(struct virtio_device *dev);
+#endif
 };
 
 int register_virtio_driver(struct virtio_driver *drv);
index 36be0f6e18a9cf9608c4288cb3343f618e329c87..e338730c2660f9e6efb593858bc672c486c8f996 100644 (file)
@@ -168,6 +168,7 @@ struct virtqueue;
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
                                      void (*callback)(struct virtqueue *vq),
index 0d556deb497b9988f14ac9322beb8cd815a85211..eb8b9f15f2e03b24ec6ca89b188ee9b955478268 100644 (file)
@@ -297,32 +297,50 @@ extern struct workqueue_struct *system_unbound_wq;
 extern struct workqueue_struct *system_freezable_wq;
 
 extern struct workqueue_struct *
-__alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
-                     struct lock_class_key *key, const char *lock_name);
+__alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
+       struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6);
 
+/**
+ * alloc_workqueue - allocate a workqueue
+ * @fmt: printf format for the name of the workqueue
+ * @flags: WQ_* flags
+ * @max_active: max in-flight work items, 0 for default
+ * @args: args for @fmt
+ *
+ * Allocate a workqueue with the specified parameters.  For detailed
+ * information on WQ_* flags, please refer to Documentation/workqueue.txt.
+ *
+ * The __lock_name macro dance is to guarantee that single lock_class_key
+ * doesn't end up with different namesm, which isn't allowed by lockdep.
+ *
+ * RETURNS:
+ * Pointer to the allocated workqueue on success, %NULL on failure.
+ */
 #ifdef CONFIG_LOCKDEP
-#define alloc_workqueue(name, flags, max_active)               \
+#define alloc_workqueue(fmt, flags, max_active, args...)       \
 ({                                                             \
        static struct lock_class_key __key;                     \
        const char *__lock_name;                                \
                                                                \
-       if (__builtin_constant_p(name))                         \
-               __lock_name = (name);                           \
+       if (__builtin_constant_p(fmt))                          \
+               __lock_name = (fmt);                            \
        else                                                    \
-               __lock_name = #name;                            \
+               __lock_name = #fmt;                             \
                                                                \
-       __alloc_workqueue_key((name), (flags), (max_active),    \
-                             &__key, __lock_name);             \
+       __alloc_workqueue_key((fmt), (flags), (max_active),     \
+                             &__key, __lock_name, ##args);     \
 })
 #else
-#define alloc_workqueue(name, flags, max_active)               \
-       __alloc_workqueue_key((name), (flags), (max_active), NULL, NULL)
+#define alloc_workqueue(fmt, flags, max_active, args...)       \
+       __alloc_workqueue_key((fmt), (flags), (max_active),     \
+                             NULL, NULL, ##args)
 #endif
 
 /**
  * alloc_ordered_workqueue - allocate an ordered workqueue
- * @name: name of the workqueue
+ * @fmt: printf format for the name of the workqueue
  * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful)
+ * @args: args for @fmt
  *
  * Allocate an ordered workqueue.  An ordered workqueue executes at
  * most one work item at any given time in the queued order.  They are
@@ -331,11 +349,8 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
  * RETURNS:
  * Pointer to the allocated workqueue on success, %NULL on failure.
  */
-static inline struct workqueue_struct *
-alloc_ordered_workqueue(const char *name, unsigned int flags)
-{
-       return alloc_workqueue(name, WQ_UNBOUND | flags, 1);
-}
+#define alloc_ordered_workqueue(fmt, flags, args...)           \
+       alloc_workqueue(fmt, WQ_UNBOUND | (flags), 1, ##args)
 
 #define create_workqueue(name)                                 \
        alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
index a378c295851f8cf9fe4d804080b30f72cf5101cd..995b8bf630aca90e6c29f0f0d919e95c51586c10 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 
+DECLARE_PER_CPU(int, dirty_throttle_leaks);
+
 /*
  * The 1/4 region under the global dirty thresh is for smooth dirty throttling:
  *
 #define DIRTY_SCOPE            8
 #define DIRTY_FULL_SCOPE       (DIRTY_SCOPE / 2)
 
-/*
- * 4MB minimal write chunk size
- */
-#define MIN_WRITEBACK_PAGES    (4096UL >> (PAGE_CACHE_SHIFT - 10))
-
 struct backing_dev_info;
 
 /*
@@ -124,6 +121,7 @@ void laptop_mode_timer_fn(unsigned long data);
 static inline void laptop_sync_completion(void) { }
 #endif
 void throttle_vm_writeout(gfp_t gfp_mask);
+bool zone_dirty_ok(struct zone *zone);
 
 extern unsigned long global_dirty_limit;
 
@@ -138,8 +136,6 @@ extern int vm_highmem_is_dirtyable;
 extern int block_dump;
 extern int laptop_mode;
 
-extern unsigned long determine_dirtyable_memory(void);
-
 extern int dirty_background_ratio_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
@@ -195,6 +191,8 @@ void writeback_set_ratelimit(void);
 void tag_pages_for_writeback(struct address_space *mapping,
                             pgoff_t start, pgoff_t end);
 
+void account_page_redirty(struct page *page);
+
 /* pdflush.c */
 extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
                                   read-only. */
index 2d70b95b3b555276a0c0f576d2334c6837b2d2fa..7184853ca36015c52d8c42573346e4edce41f1c0 100644 (file)
@@ -63,30 +63,16 @@ enum p9_debug_flags {
 
 #ifdef CONFIG_NET_9P_DEBUG
 extern unsigned int p9_debug_level;
-
-#define P9_DPRINTK(level, format, arg...) \
-do {  \
-       if ((p9_debug_level & level) == level) {\
-               if (level == P9_DEBUG_9P) \
-                       printk(KERN_NOTICE "(%8.8d) " \
-                       format , task_pid_nr(current) , ## arg); \
-               else \
-                       printk(KERN_NOTICE "-- %s (%d): " \
-                       format , __func__, task_pid_nr(current) , ## arg); \
-       } \
-} while (0)
-
+__printf(3, 4)
+void _p9_debug(enum p9_debug_flags level, const char *func,
+              const char *fmt, ...);
+#define p9_debug(level, fmt, ...)                      \
+       _p9_debug(level, __func__, fmt, ##__VA_ARGS__)
 #else
-#define P9_DPRINTK(level, format, arg...)  do { } while (0)
+#define p9_debug(level, fmt, ...)                      \
+       no_printk(fmt, ##__VA_ARGS__)
 #endif
 
-
-#define P9_EPRINTK(level, format, arg...) \
-do { \
-       printk(level "9p: %s (%d): " \
-               format , __func__, task_pid_nr(current), ## arg); \
-} while (0)
-
 /**
  * enum p9_msg_t - 9P message types
  * @P9_TLERROR: not used
index 5e2e984584968f0e6beea90c8657eb1639a1cba2..ea9231f4935feba9ebd791e4d12287cc24284fd6 100644 (file)
@@ -127,7 +127,7 @@ struct hci_dev {
        __u8            major_class;
        __u8            minor_class;
        __u8            features[8];
-       __u8            extfeatures[8];
+       __u8            host_features[8];
        __u8            commands[64];
        __u8            ssp_mode;
        __u8            hci_ver;
@@ -676,7 +676,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
 
 /* ----- Extended LMP capabilities ----- */
-#define lmp_host_le_capable(dev)   ((dev)->extfeatures[0] & LMP_HOST_LE)
+#define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
 
 /* ----- HCI protocols ----- */
 static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
index baab385a47363e85765ebf4b1b829684ef6024db..28068ec614b24da11b9cb3e9a390abb7aea5f47a 100644 (file)
@@ -199,7 +199,8 @@ static inline void red_set_parms(struct red_parms *p,
        p->Scell_log    = Scell_log;
        p->Scell_max    = (255 << Scell_log);
 
-       memcpy(p->Stab, stab, sizeof(p->Stab));
+       if (stab)
+               memcpy(p->Stab, stab, sizeof(p->Stab));
 }
 
 static inline int red_is_idling(const struct red_vars *v)
index 802947f60915c25ae1f301a580af50a24e9edafb..6df30ed1581c5b750f13335a3fd1b1743e05159e 100644 (file)
@@ -6,3 +6,5 @@ header-y += hdsp.h
 header-y += hdspm.h
 header-y += sb16_csp.h
 header-y += sfnt_info.h
+header-y += compress_params.h
+header-y += compress_offload.h
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
new file mode 100644 (file)
index 0000000..48f2a1f
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ *  compress_driver.h - compress offload driver definations
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *             Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef __COMPRESS_DRIVER_H
+#define __COMPRESS_DRIVER_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <sound/compress_offload.h>
+#include <sound/asound.h>
+#include <sound/pcm.h>
+
+struct snd_compr_ops;
+
+/**
+ * struct snd_compr_runtime: runtime stream description
+ * @state: stream state
+ * @ops: pointer to DSP callbacks
+ * @buffer: pointer to kernel buffer, valid only when not in mmap mode or
+ *     DSP doesn't implement copy
+ * @buffer_size: size of the above buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ * @hw_pointer: offset of last location in buffer where DSP copied data
+ * @app_pointer: offset of last location in buffer where app wrote data
+ * @total_bytes_available: cumulative number of bytes made available in
+ *     the ring buffer
+ * @total_bytes_transferred: cumulative bytes transferred by offload DSP
+ * @sleep: poll sleep
+ */
+struct snd_compr_runtime {
+       snd_pcm_state_t state;
+       struct snd_compr_ops *ops;
+       void *buffer;
+       u64 buffer_size;
+       u32 fragment_size;
+       u32 fragments;
+       u64 hw_pointer;
+       u64 app_pointer;
+       u64 total_bytes_available;
+       u64 total_bytes_transferred;
+       wait_queue_head_t sleep;
+};
+
+/**
+ * struct snd_compr_stream: compressed stream
+ * @name: device name
+ * @ops: pointer to DSP callbacks
+ * @runtime: pointer to runtime structure
+ * @device: device pointer
+ * @direction: stream direction, playback/recording
+ * @private_data: pointer to DSP private data
+ */
+struct snd_compr_stream {
+       const char *name;
+       struct snd_compr_ops *ops;
+       struct snd_compr_runtime *runtime;
+       struct snd_compr *device;
+       enum snd_compr_direction direction;
+       void *private_data;
+};
+
+/**
+ * struct snd_compr_ops: compressed path DSP operations
+ * @open: Open the compressed stream
+ * This callback is mandatory and shall keep dsp ready to receive the stream
+ * parameter
+ * @free: Close the compressed stream, mandatory
+ * @set_params: Sets the compressed stream parameters, mandatory
+ * This can be called in during stream creation only to set codec params
+ * and the stream properties
+ * @get_params: retrieve the codec parameters, mandatory
+ * @trigger: Trigger operations like start, pause, resume, drain, stop.
+ * This callback is mandatory
+ * @pointer: Retrieve current h/w pointer information. Mandatory
+ * @copy: Copy the compressed data to/from userspace, Optional
+ * Can't be implemented if DSP supports mmap
+ * @mmap: DSP mmap method to mmap DSP memory
+ * @ack: Ack for DSP when data is written to audio buffer, Optional
+ * Not valid if copy is implemented
+ * @get_caps: Retrieve DSP capabilities, mandatory
+ * @get_codec_caps: Retrieve capabilities for a specific codec, mandatory
+ */
+struct snd_compr_ops {
+       int (*open)(struct snd_compr_stream *stream);
+       int (*free)(struct snd_compr_stream *stream);
+       int (*set_params)(struct snd_compr_stream *stream,
+                       struct snd_compr_params *params);
+       int (*get_params)(struct snd_compr_stream *stream,
+                       struct snd_codec *params);
+       int (*trigger)(struct snd_compr_stream *stream, int cmd);
+       int (*pointer)(struct snd_compr_stream *stream,
+                       struct snd_compr_tstamp *tstamp);
+       int (*copy)(struct snd_compr_stream *stream, const char __user *buf,
+                      size_t count);
+       int (*mmap)(struct snd_compr_stream *stream,
+                       struct vm_area_struct *vma);
+       int (*ack)(struct snd_compr_stream *stream, size_t bytes);
+       int (*get_caps) (struct snd_compr_stream *stream,
+                       struct snd_compr_caps *caps);
+       int (*get_codec_caps) (struct snd_compr_stream *stream,
+                       struct snd_compr_codec_caps *codec);
+};
+
+/**
+ * struct snd_compr: Compressed device
+ * @name: DSP device name
+ * @dev: Device pointer
+ * @ops: pointer to DSP callbacks
+ * @private_data: pointer to DSP pvt data
+ * @card: sound card pointer
+ * @direction: Playback or capture direction
+ * @lock: device lock
+ * @device: device id
+ */
+struct snd_compr {
+       const char *name;
+       struct device *dev;
+       struct snd_compr_ops *ops;
+       void *private_data;
+       struct snd_card *card;
+       unsigned int direction;
+       struct mutex lock;
+       int device;
+};
+
+/* compress device register APIs */
+int snd_compress_register(struct snd_compr *device);
+int snd_compress_deregister(struct snd_compr *device);
+int snd_compress_new(struct snd_card *card, int device,
+                       int type, struct snd_compr *compr);
+
+/* dsp driver callback apis
+ * For playback: driver should call snd_compress_fragment_elapsed() to let the
+ * framework know that a fragment has been consumed from the ring buffer
+ *
+ * For recording: we want to know when a frame is available or when
+ * at least one frame is available so snd_compress_frame_elapsed()
+ * callback should be called when a encodeded frame is available
+ */
+static inline void snd_compr_fragment_elapsed(struct snd_compr_stream *stream)
+{
+       wake_up(&stream->runtime->sleep);
+}
+
+#endif
diff --git a/include/sound/compress_offload.h b/include/sound/compress_offload.h
new file mode 100644 (file)
index 0000000..05341a4
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  compress_offload.h - compress offload header definations
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *             Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#ifndef __COMPRESS_OFFLOAD_H
+#define __COMPRESS_OFFLOAD_H
+
+#include <linux/types.h>
+#include <sound/asound.h>
+#include <sound/compress_params.h>
+
+
+#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+/**
+ * struct snd_compressed_buffer: compressed buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ */
+struct snd_compressed_buffer {
+       __u32 fragment_size;
+       __u32 fragments;
+};
+
+/**
+ * struct snd_compr_params: compressed stream params
+ * @buffer: buffer description
+ * @codec: codec parameters
+ * @no_wake_mode: dont wake on fragment elapsed
+ */
+struct snd_compr_params {
+       struct snd_compressed_buffer buffer;
+       struct snd_codec codec;
+       __u8 no_wake_mode;
+};
+
+/**
+ * struct snd_compr_tstamp: timestamp descriptor
+ * @byte_offset: Byte offset in ring buffer to DSP
+ * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP
+ * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by
+ *     large steps and should only be used to monitor encoding/decoding
+ *     progress. It shall not be used for timing estimates.
+ * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio
+ * output/input. This field should be used for A/V sync or time estimates.
+ * @sampling_rate: sampling rate of audio
+ */
+struct snd_compr_tstamp {
+       __u32 byte_offset;
+       __u32 copied_total;
+       snd_pcm_uframes_t pcm_frames;
+       snd_pcm_uframes_t pcm_io_frames;
+       __u32 sampling_rate;
+};
+
+/**
+ * struct snd_compr_avail: avail descriptor
+ * @avail: Number of bytes available in ring buffer for writing/reading
+ * @tstamp: timestamp infomation
+ */
+struct snd_compr_avail {
+       __u64 avail;
+       struct snd_compr_tstamp tstamp;
+};
+
+enum snd_compr_direction {
+       SND_COMPRESS_PLAYBACK = 0,
+       SND_COMPRESS_CAPTURE
+};
+
+/**
+ * struct snd_compr_caps: caps descriptor
+ * @codecs: pointer to array of codecs
+ * @direction: direction supported. Of type snd_compr_direction
+ * @min_fragment_size: minimum fragment supported by DSP
+ * @max_fragment_size: maximum fragment supported by DSP
+ * @min_fragments: min fragments supported by DSP
+ * @max_fragments: max fragments supported by DSP
+ * @num_codecs: number of codecs supported
+ * @reserved: reserved field
+ */
+struct snd_compr_caps {
+       __u32 num_codecs;
+       __u32 direction;
+       __u32 min_fragment_size;
+       __u32 max_fragment_size;
+       __u32 min_fragments;
+       __u32 max_fragments;
+       __u32 codecs[MAX_NUM_CODECS];
+       __u32 reserved[11];
+};
+
+/**
+ * struct snd_compr_codec_caps: query capability of codec
+ * @codec: codec for which capability is queried
+ * @num_descriptors: number of codec descriptors
+ * @descriptor: array of codec capability descriptor
+ */
+struct snd_compr_codec_caps {
+       __u32 codec;
+       __u32 num_descriptors;
+       struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
+};
+
+/**
+ * compress path ioctl definitions
+ * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
+ * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
+ * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters
+ * Note: only codec params can be changed runtime and stream params cant be
+ * SNDRV_COMPRESS_GET_PARAMS: Query codec params
+ * SNDRV_COMPRESS_TSTAMP: get the current timestamp value
+ * SNDRV_COMPRESS_AVAIL: get the current buffer avail value.
+ * This also queries the tstamp properties
+ * SNDRV_COMPRESS_PAUSE: Pause the running stream
+ * SNDRV_COMPRESS_RESUME: resume a paused stream
+ * SNDRV_COMPRESS_START: Start a stream
+ * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content
+ * and the buffers currently with DSP
+ * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that
+ * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version
+ */
+#define SNDRV_COMPRESS_IOCTL_VERSION   _IOR('C', 0x00, int)
+#define SNDRV_COMPRESS_GET_CAPS                _IOWR('C', 0x10, struct snd_compr_caps)
+#define SNDRV_COMPRESS_GET_CODEC_CAPS  _IOWR('C', 0x11,\
+                                               struct snd_compr_codec_caps)
+#define SNDRV_COMPRESS_SET_PARAMS      _IOW('C', 0x12, struct snd_compr_params)
+#define SNDRV_COMPRESS_GET_PARAMS      _IOR('C', 0x13, struct snd_codec)
+#define SNDRV_COMPRESS_TSTAMP          _IOR('C', 0x20, struct snd_compr_tstamp)
+#define SNDRV_COMPRESS_AVAIL           _IOR('C', 0x21, struct snd_compr_avail)
+#define SNDRV_COMPRESS_PAUSE           _IO('C', 0x30)
+#define SNDRV_COMPRESS_RESUME          _IO('C', 0x31)
+#define SNDRV_COMPRESS_START           _IO('C', 0x32)
+#define SNDRV_COMPRESS_STOP            _IO('C', 0x33)
+#define SNDRV_COMPRESS_DRAIN           _IO('C', 0x34)
+/*
+ * TODO
+ * 1. add mmap support
+ *
+ */
+#define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
+#endif
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
new file mode 100644 (file)
index 0000000..d97d69f
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ *  compress_params.h - codec types and parameters for compressed data
+ *  streaming interface
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *  Authors:   Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *              Vinod Koul <vinod.koul@linux.intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The definitions in this file are derived from the OpenMAX AL version 1.1
+ * and OpenMAX IL v 1.1.2 header files which contain the copyright notice below.
+ *
+ * Copyright (c) 2007-2010 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and/or associated documentation files (the
+ * "Materials "), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ */
+#ifndef __SND_COMPRESS_PARAMS_H
+#define __SND_COMPRESS_PARAMS_H
+
+/* AUDIO CODECS SUPPORTED */
+#define MAX_NUM_CODECS 32
+#define MAX_NUM_CODEC_DESCRIPTORS 32
+#define MAX_NUM_BITRATES 32
+
+/* Codecs are listed linearly to allow for extensibility */
+#define SND_AUDIOCODEC_PCM                   ((__u32) 0x00000001)
+#define SND_AUDIOCODEC_MP3                   ((__u32) 0x00000002)
+#define SND_AUDIOCODEC_AMR                   ((__u32) 0x00000003)
+#define SND_AUDIOCODEC_AMRWB                 ((__u32) 0x00000004)
+#define SND_AUDIOCODEC_AMRWBPLUS             ((__u32) 0x00000005)
+#define SND_AUDIOCODEC_AAC                   ((__u32) 0x00000006)
+#define SND_AUDIOCODEC_WMA                   ((__u32) 0x00000007)
+#define SND_AUDIOCODEC_REAL                  ((__u32) 0x00000008)
+#define SND_AUDIOCODEC_VORBIS                ((__u32) 0x00000009)
+#define SND_AUDIOCODEC_FLAC                  ((__u32) 0x0000000A)
+#define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
+#define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
+#define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
+
+/*
+ * Profile and modes are listed with bit masks. This allows for a
+ * more compact representation of fields that will not evolve
+ * (in contrast to the list of codecs)
+ */
+
+#define SND_AUDIOPROFILE_PCM                 ((__u32) 0x00000001)
+
+/* MP3 modes are only useful for encoders */
+#define SND_AUDIOCHANMODE_MP3_MONO           ((__u32) 0x00000001)
+#define SND_AUDIOCHANMODE_MP3_STEREO         ((__u32) 0x00000002)
+#define SND_AUDIOCHANMODE_MP3_JOINTSTEREO    ((__u32) 0x00000004)
+#define SND_AUDIOCHANMODE_MP3_DUAL           ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_AMR                 ((__u32) 0x00000001)
+
+/* AMR modes are only useful for encoders */
+#define SND_AUDIOMODE_AMR_DTX_OFF            ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMR_VAD1               ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMR_VAD2               ((__u32) 0x00000004)
+
+#define SND_AUDIOSTREAMFORMAT_UNDEFINED             ((__u32) 0x00000000)
+#define SND_AUDIOSTREAMFORMAT_CONFORMANCE    ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_IF1            ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_IF2            ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_FSF            ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_RTPPAYLOAD     ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_ITU            ((__u32) 0x00000020)
+
+#define SND_AUDIOPROFILE_AMRWB               ((__u32) 0x00000001)
+
+/* AMRWB modes are only useful for encoders */
+#define SND_AUDIOMODE_AMRWB_DTX_OFF          ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMRWB_VAD1             ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMRWB_VAD2             ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_AMRWBPLUS           ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_AAC                 ((__u32) 0x00000001)
+
+/* AAC modes are required for encoders and decoders */
+#define SND_AUDIOMODE_AAC_MAIN               ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AAC_LC                 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AAC_SSR                ((__u32) 0x00000004)
+#define SND_AUDIOMODE_AAC_LTP                ((__u32) 0x00000008)
+#define SND_AUDIOMODE_AAC_HE                 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_AAC_SCALABLE           ((__u32) 0x00000020)
+#define SND_AUDIOMODE_AAC_ERLC               ((__u32) 0x00000040)
+#define SND_AUDIOMODE_AAC_LD                 ((__u32) 0x00000080)
+#define SND_AUDIOMODE_AAC_HE_PS              ((__u32) 0x00000100)
+#define SND_AUDIOMODE_AAC_HE_MPS             ((__u32) 0x00000200)
+
+/* AAC formats are required for encoders and decoders */
+#define SND_AUDIOSTREAMFORMAT_MP2ADTS        ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_MP4ADTS        ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_MP4LOAS        ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_MP4LATM        ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_ADIF           ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_MP4FF          ((__u32) 0x00000020)
+#define SND_AUDIOSTREAMFORMAT_RAW            ((__u32) 0x00000040)
+
+#define SND_AUDIOPROFILE_WMA7                ((__u32) 0x00000001)
+#define SND_AUDIOPROFILE_WMA8                ((__u32) 0x00000002)
+#define SND_AUDIOPROFILE_WMA9                ((__u32) 0x00000004)
+#define SND_AUDIOPROFILE_WMA10               ((__u32) 0x00000008)
+
+#define SND_AUDIOMODE_WMA_LEVEL1             ((__u32) 0x00000001)
+#define SND_AUDIOMODE_WMA_LEVEL2             ((__u32) 0x00000002)
+#define SND_AUDIOMODE_WMA_LEVEL3             ((__u32) 0x00000004)
+#define SND_AUDIOMODE_WMA_LEVEL4             ((__u32) 0x00000008)
+#define SND_AUDIOMODE_WMAPRO_LEVELM0         ((__u32) 0x00000010)
+#define SND_AUDIOMODE_WMAPRO_LEVELM1         ((__u32) 0x00000020)
+#define SND_AUDIOMODE_WMAPRO_LEVELM2         ((__u32) 0x00000040)
+#define SND_AUDIOMODE_WMAPRO_LEVELM3         ((__u32) 0x00000080)
+
+#define SND_AUDIOSTREAMFORMAT_WMA_ASF        ((__u32) 0x00000001)
+/*
+ * Some implementations strip the ASF header and only send ASF packets
+ * to the DSP
+ */
+#define SND_AUDIOSTREAMFORMAT_WMA_NOASF_HDR  ((__u32) 0x00000002)
+
+#define SND_AUDIOPROFILE_REALAUDIO           ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_REALAUDIO_G2           ((__u32) 0x00000001)
+#define SND_AUDIOMODE_REALAUDIO_8            ((__u32) 0x00000002)
+#define SND_AUDIOMODE_REALAUDIO_10           ((__u32) 0x00000004)
+#define SND_AUDIOMODE_REALAUDIO_SURROUND     ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_VORBIS              ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_VORBIS                 ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_FLAC                ((__u32) 0x00000001)
+
+/*
+ * Define quality levels for FLAC encoders, from LEVEL0 (fast)
+ * to LEVEL8 (best)
+ */
+#define SND_AUDIOMODE_FLAC_LEVEL0            ((__u32) 0x00000001)
+#define SND_AUDIOMODE_FLAC_LEVEL1            ((__u32) 0x00000002)
+#define SND_AUDIOMODE_FLAC_LEVEL2            ((__u32) 0x00000004)
+#define SND_AUDIOMODE_FLAC_LEVEL3            ((__u32) 0x00000008)
+#define SND_AUDIOMODE_FLAC_LEVEL4            ((__u32) 0x00000010)
+#define SND_AUDIOMODE_FLAC_LEVEL5            ((__u32) 0x00000020)
+#define SND_AUDIOMODE_FLAC_LEVEL6            ((__u32) 0x00000040)
+#define SND_AUDIOMODE_FLAC_LEVEL7            ((__u32) 0x00000080)
+#define SND_AUDIOMODE_FLAC_LEVEL8            ((__u32) 0x00000100)
+
+#define SND_AUDIOSTREAMFORMAT_FLAC           ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_FLAC_OGG       ((__u32) 0x00000002)
+
+/* IEC61937 payloads without CUVP and preambles */
+#define SND_AUDIOPROFILE_IEC61937            ((__u32) 0x00000001)
+/* IEC61937 with S/PDIF preambles+CUVP bits in 32-bit containers */
+#define SND_AUDIOPROFILE_IEC61937_SPDIF      ((__u32) 0x00000002)
+
+/*
+ * IEC modes are mandatory for decoders. Format autodetection
+ * will only happen on the DSP side with mode 0. The PCM mode should
+ * not be used, the PCM codec should be used instead.
+ */
+#define SND_AUDIOMODE_IEC_REF_STREAM_HEADER  ((__u32) 0x00000000)
+#define SND_AUDIOMODE_IEC_LPCM              ((__u32) 0x00000001)
+#define SND_AUDIOMODE_IEC_AC3               ((__u32) 0x00000002)
+#define SND_AUDIOMODE_IEC_MPEG1                     ((__u32) 0x00000004)
+#define SND_AUDIOMODE_IEC_MP3               ((__u32) 0x00000008)
+#define SND_AUDIOMODE_IEC_MPEG2                     ((__u32) 0x00000010)
+#define SND_AUDIOMODE_IEC_AACLC                     ((__u32) 0x00000020)
+#define SND_AUDIOMODE_IEC_DTS               ((__u32) 0x00000040)
+#define SND_AUDIOMODE_IEC_ATRAC                     ((__u32) 0x00000080)
+#define SND_AUDIOMODE_IEC_SACD              ((__u32) 0x00000100)
+#define SND_AUDIOMODE_IEC_EAC3              ((__u32) 0x00000200)
+#define SND_AUDIOMODE_IEC_DTS_HD            ((__u32) 0x00000400)
+#define SND_AUDIOMODE_IEC_MLP               ((__u32) 0x00000800)
+#define SND_AUDIOMODE_IEC_DST               ((__u32) 0x00001000)
+#define SND_AUDIOMODE_IEC_WMAPRO            ((__u32) 0x00002000)
+#define SND_AUDIOMODE_IEC_REF_CXT            ((__u32) 0x00004000)
+#define SND_AUDIOMODE_IEC_HE_AAC            ((__u32) 0x00008000)
+#define SND_AUDIOMODE_IEC_HE_AAC2           ((__u32) 0x00010000)
+#define SND_AUDIOMODE_IEC_MPEG_SURROUND             ((__u32) 0x00020000)
+
+#define SND_AUDIOPROFILE_G723_1              ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G723_1_ANNEX_A         ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G723_1_ANNEX_B         ((__u32) 0x00000002)
+#define SND_AUDIOMODE_G723_1_ANNEX_C         ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_G729                ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G729_ANNEX_A           ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G729_ANNEX_B           ((__u32) 0x00000002)
+
+/* <FIXME: multichannel encoders aren't supported for now. Would need
+   an additional definition of channel arrangement> */
+
+/* VBR/CBR definitions */
+#define SND_RATECONTROLMODE_CONSTANTBITRATE  ((__u32) 0x00000001)
+#define SND_RATECONTROLMODE_VARIABLEBITRATE  ((__u32) 0x00000002)
+
+/* Encoder options */
+
+struct snd_enc_wma {
+       __u32 super_block_align; /* WMA Type-specific data */
+};
+
+
+/**
+ * struct snd_enc_vorbis
+ * @quality: Sets encoding quality to n, between -1 (low) and 10 (high).
+ * In the default mode of operation, the quality level is 3.
+ * Normal quality range is 0 - 10.
+ * @managed: Boolean. Set  bitrate  management  mode. This turns off the
+ * normal VBR encoding, but allows hard or soft bitrate constraints to be
+ * enforced by the encoder. This mode can be slower, and may also be
+ * lower quality. It is primarily useful for streaming.
+ * @max_bit_rate: Enabled only if managed is TRUE
+ * @min_bit_rate: Enabled only if managed is TRUE
+ * @downmix: Boolean. Downmix input from stereo to mono (has no effect on
+ * non-stereo streams). Useful for lower-bitrate encoding.
+ *
+ * These options were extracted from the OpenMAX IL spec and Gstreamer vorbisenc
+ * properties
+ *
+ * For best quality users should specify VBR mode and set quality levels.
+ */
+
+struct snd_enc_vorbis {
+       __s32 quality;
+       __u32 managed;
+       __u32 max_bit_rate;
+       __u32 min_bit_rate;
+       __u32 downmix;
+};
+
+
+/**
+ * struct snd_enc_real
+ * @quant_bits: number of coupling quantization bits in the stream
+ * @start_region: coupling start region in the stream
+ * @num_regions: number of regions value
+ *
+ * These options were extracted from the OpenMAX IL spec
+ */
+
+struct snd_enc_real {
+       __u32 quant_bits;
+       __u32 start_region;
+       __u32 num_regions;
+};
+
+/**
+ * struct snd_enc_flac
+ * @num: serial number, valid only for OGG formats
+ *     needs to be set by application
+ * @gain: Add replay gain tags
+ *
+ * These options were extracted from the FLAC online documentation
+ * at http://flac.sourceforge.net/documentation_tools_flac.html
+ *
+ * To make the API simpler, it is assumed that the user will select quality
+ * profiles. Additional options that affect encoding quality and speed can
+ * be added at a later stage if needed.
+ *
+ * By default the Subset format is used by encoders.
+ *
+ * TAGS such as pictures, etc, cannot be handled by an offloaded encoder and are
+ * not supported in this API.
+ */
+
+struct snd_enc_flac {
+       __u32 num;
+       __u32 gain;
+};
+
+struct snd_enc_generic {
+       __u32 bw;       /* encoder bandwidth */
+       __s32 reserved[15];
+};
+
+union snd_codec_options {
+       struct snd_enc_wma wma;
+       struct snd_enc_vorbis vorbis;
+       struct snd_enc_real real;
+       struct snd_enc_flac flac;
+       struct snd_enc_generic generic;
+};
+
+/** struct snd_codec_desc - description of codec capabilities
+ * @max_ch: Maximum number of audio channels
+ * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this
+ * @bit_rate: Indexed array containing supported bit rates
+ * @num_bitrates: Number of valid values in bit_rate array
+ * @rate_control: value is specified by SND_RATECONTROLMODE defines.
+ * @profiles: Supported profiles. See SND_AUDIOPROFILE defines.
+ * @modes: Supported modes. See SND_AUDIOMODE defines
+ * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines
+ * @min_buffer: Minimum buffer size handled by codec implementation
+ * @reserved: reserved for future use
+ *
+ * This structure provides a scalar value for profiles, modes and stream
+ * format fields.
+ * If an implementation supports multiple combinations, they will be listed as
+ * codecs with different descriptors, for example there would be 2 descriptors
+ * for AAC-RAW and AAC-ADTS.
+ * This entails some redundancy but makes it easier to avoid invalid
+ * configurations.
+ *
+ */
+
+struct snd_codec_desc {
+       __u32 max_ch;
+       __u32 sample_rates;
+       __u32 bit_rate[MAX_NUM_BITRATES];
+       __u32 num_bitrates;
+       __u32 rate_control;
+       __u32 profiles;
+       __u32 modes;
+       __u32 formats;
+       __u32 min_buffer;
+       __u32 reserved[15];
+};
+
+/** struct snd_codec
+ * @id: Identifies the supported audio encoder/decoder.
+ *             See SND_AUDIOCODEC macros.
+ * @ch_in: Number of input audio channels
+ * @ch_out: Number of output channels. In case of contradiction between
+ *             this field and the channelMode field, the channelMode field
+ *             overrides.
+ * @sample_rate: Audio sample rate of input data
+ * @bit_rate: Bitrate of encoded data. May be ignored by decoders
+ * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines.
+ *               Encoders may rely on profiles for quality levels.
+ *              May be ignored by decoders.
+ * @profile: Mandatory for encoders, can be mandatory for specific
+ *             decoders as well. See SND_AUDIOPROFILE defines.
+ * @level: Supported level (Only used by WMA at the moment)
+ * @ch_mode: Channel mode for encoder. See SND_AUDIOCHANMODE defines
+ * @format: Format of encoded bistream. Mandatory when defined.
+ *             See SND_AUDIOSTREAMFORMAT defines.
+ * @align: Block alignment in bytes of an audio sample.
+ *             Only required for PCM or IEC formats.
+ * @options: encoder-specific settings
+ * @reserved: reserved for future use
+ */
+
+struct snd_codec {
+       __u32 id;
+       __u32 ch_in;
+       __u32 ch_out;
+       __u32 sample_rate;
+       __u32 bit_rate;
+       __u32 rate_control;
+       __u32 profile;
+       __u32 level;
+       __u32 ch_mode;
+       __u32 format;
+       __u32 align;
+       union snd_codec_options options;
+       __u32 reserved[3];
+};
+
+#endif
index 1a94a216ed99b72c1cca625d4bb637547fd61c85..b2796e83c7acf3d1b4dd5bfacd76966a4c3eff4e 100644 (file)
@@ -227,4 +227,12 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master,
        return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE);
 }
 
+/*
+ * Helper functions for jack-detection controls
+ */
+struct snd_kcontrol *
+snd_kctl_jack_new(const char *name, int idx, void *private_data);
+void snd_kctl_jack_report(struct snd_card *card,
+                         struct snd_kcontrol *kctl, bool status);
+
 #endif /* __SOUND_CONTROL_H */
index 3be5ab782b99c74d6f0a1326eaf28f6108dfa708..5ab255f196cc85c6b894adc2182f1271562a301e 100644 (file)
@@ -62,6 +62,7 @@ typedef int __bitwise snd_device_type_t;
 #define        SNDRV_DEV_BUS           ((__force snd_device_type_t) 0x1007)
 #define        SNDRV_DEV_CODEC         ((__force snd_device_type_t) 0x1008)
 #define        SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
+#define        SNDRV_DEV_COMPRESS      ((__force snd_device_type_t) 0x100A)
 #define        SNDRV_DEV_LOWLEVEL      ((__force snd_device_type_t) 0x2000)
 
 typedef int __bitwise snd_device_state_t;
index 8f764204a8567ddb7924ae78a7a083063ea191d2..5978f9a8c8b20bc9a99c50f43bfdde767def0439 100644 (file)
@@ -35,7 +35,7 @@
 #define SNDRV_MINOR_TIMER              33      /* SNDRV_MINOR_GLOBAL + 1 * 32 */
 
 #ifndef CONFIG_SND_DYNAMIC_MINORS
-                                               /* 2 - 3 (reserved) */
+#define SNDRV_MINOR_COMPRESS           2       /* 2 - 3 */
 #define SNDRV_MINOR_HWDEP              4       /* 4 - 7 */
 #define SNDRV_MINOR_RAWMIDI            8       /* 8 - 15 */
 #define SNDRV_MINOR_PCM_PLAYBACK       16      /* 16 - 23 */
@@ -49,6 +49,7 @@
 #define SNDRV_DEVICE_TYPE_PCM_CAPTURE  SNDRV_MINOR_PCM_CAPTURE
 #define SNDRV_DEVICE_TYPE_SEQUENCER    SNDRV_MINOR_SEQUENCER
 #define SNDRV_DEVICE_TYPE_TIMER                SNDRV_MINOR_TIMER
+#define SNDRV_DEVICE_TYPE_COMPRESS     SNDRV_MINOR_COMPRESS
 
 #else /* CONFIG_SND_DYNAMIC_MINORS */
 
@@ -60,6 +61,7 @@ enum {
        SNDRV_DEVICE_TYPE_RAWMIDI,
        SNDRV_DEVICE_TYPE_PCM_PLAYBACK,
        SNDRV_DEVICE_TYPE_PCM_CAPTURE,
+       SNDRV_DEVICE_TYPE_COMPRESS,
 };
 
 #endif /* CONFIG_SND_DYNAMIC_MINORS */
index 9a155f9d0a12a627f968821d25f890cb71efc403..9b1aacaa82fedd0fcb63365fae33237627c496c9 100644 (file)
@@ -78,4 +78,16 @@ struct sh_fsi_platform_info {
        int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
 };
 
+/*
+ * for fsi-ak4642
+ */
+struct fsi_ak4642_info {
+       const char *name;
+       const char *card;
+       const char *cpu_dai;
+       const char *codec;
+       const char *platform;
+       int id;
+};
+
 #endif /* __SOUND_FSI_H */
index 17a4c17f19f5ff672030d448bb84ea5b3d8a354a..d26a9b784772d797e88a529f199342f277e32390 100644 (file)
@@ -43,6 +43,9 @@
        .num_kcontrols = 0}
 
 /* platform domain */
+#define SND_SOC_DAPM_SIGGEN(wname) \
+{      .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \
+       .num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_INPUT(wname) \
 {      .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
        .num_kcontrols = 0, .reg = SND_SOC_NOPM }
@@ -380,6 +383,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
+void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
 
 /* Mostly internal - should not normally be used */
 void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
@@ -409,6 +413,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_supply,            /* power/clock supply */
        snd_soc_dapm_aif_in,            /* audio interface input */
        snd_soc_dapm_aif_out,           /* audio interface output */
+       snd_soc_dapm_siggen,            /* signal generator */
 };
 
 /*
index 11cfb5953e06eb82c22f52319aa2c4ea31d7f99a..0992dff559593d7015fcef0e5a58dd42134539d6 100644 (file)
@@ -231,6 +231,7 @@ enum snd_soc_bias_level {
        SND_SOC_BIAS_ON = 3,
 };
 
+struct device_node;
 struct snd_jack;
 struct snd_soc_card;
 struct snd_soc_pcm_stream;
@@ -266,8 +267,6 @@ enum snd_soc_control_type {
 
 enum snd_soc_compress_type {
        SND_SOC_FLAT_COMPRESSION = 1,
-       SND_SOC_LZO_COMPRESSION,
-       SND_SOC_RBTREE_COMPRESSION
 };
 
 enum snd_soc_pcm_subclass {
@@ -318,6 +317,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,
                                        unsigned int reg);
 int snd_soc_platform_write(struct snd_soc_platform *platform,
                                        unsigned int reg, unsigned int val);
+int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -593,8 +593,7 @@ struct snd_soc_codec_driver {
        /* driver ops */
        int (*probe)(struct snd_soc_codec *);
        int (*remove)(struct snd_soc_codec *);
-       int (*suspend)(struct snd_soc_codec *,
-                       pm_message_t state);
+       int (*suspend)(struct snd_soc_codec *);
        int (*resume)(struct snd_soc_codec *);
 
        /* Default control and setup, added after probe() is run */
@@ -706,8 +705,11 @@ struct snd_soc_dai_link {
        const char *name;                       /* Codec name */
        const char *stream_name;                /* Stream name */
        const char *codec_name;         /* for multi-codec */
+       const struct device_node *codec_of_node;
        const char *platform_name;      /* for multi-platform */
+       const struct device_node *platform_of_node;
        const char *cpu_dai_name;
+       const struct device_node *cpu_dai_of_node;
        const char *codec_dai_name;
 
        unsigned int dai_fmt;           /* format to set on init */
@@ -718,6 +720,9 @@ struct snd_soc_dai_link {
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 
+       /* pmdown_time is ignored at stop */
+       unsigned int ignore_pmdown_time:1;
+
        /* codec/machine specific init - e.g. add machine controls */
        int (*init)(struct snd_soc_pcm_runtime *rtd);
 
@@ -813,6 +818,7 @@ struct snd_soc_card {
        int num_dapm_widgets;
        const struct snd_soc_dapm_route *dapm_routes;
        int num_dapm_routes;
+       bool fully_routed;
 
        struct work_struct deferred_resume_work;
 
@@ -840,8 +846,8 @@ struct snd_soc_card {
 };
 
 /* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_pcm_runtime  {
-       struct device dev;
+struct snd_soc_pcm_runtime {
+       struct device *dev;
        struct snd_soc_card *card;
        struct snd_soc_dai_link *dai_link;
        struct mutex pcm_mutex;
@@ -927,12 +933,12 @@ static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platfo
 static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
                void *data)
 {
-       dev_set_drvdata(&rtd->dev, data);
+       dev_set_drvdata(rtd->dev, data);
 }
 
 static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
 {
-       return dev_get_drvdata(&rtd->dev);
+       return dev_get_drvdata(rtd->dev);
 }
 
 static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
@@ -960,6 +966,11 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
 int snd_soc_util_init(void);
 void snd_soc_util_exit(void);
 
+int snd_soc_of_parse_card_name(struct snd_soc_card *card,
+                              const char *propname);
+int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
+                                  const char *propname);
+
 #include <sound/soc-dai.h>
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/include/sound/sta32x.h b/include/sound/sta32x.h
new file mode 100644 (file)
index 0000000..8d93b03
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Platform data for ST STA32x ASoC codec driver.
+ *
+ * Copyright: 2011 Raumfeld GmbH
+ * Author: Johannes Stezenbach <js@sig21.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __LINUX_SND__STA32X_H
+#define __LINUX_SND__STA32X_H
+
+#define STA32X_OCFG_2CH                0
+#define STA32X_OCFG_2_1CH      1
+#define STA32X_OCFG_1CH                3
+
+#define STA32X_OM_CH1          0
+#define STA32X_OM_CH2          1
+#define STA32X_OM_CH3          2
+
+#define STA32X_THERMAL_ADJUSTMENT_ENABLE       1
+#define STA32X_THERMAL_RECOVERY_ENABLE         2
+
+struct sta32x_platform_data {
+       int output_conf;
+       int ch1_output_mapping;
+       int ch2_output_mapping;
+       int ch3_output_mapping;
+       int thermal_conf;
+       int needs_esd_watchdog;
+};
+
+#endif /* __LINUX_SND__STA32X_H */
index cf7ccb76a8de8ad7f7a409aad3a703addd574d06..b310c5a3a958dfd1e71f026e9c2e527c93071b61 100644 (file)
 #ifndef __LINUX_SND_WM8903_H
 #define __LINUX_SND_WM8903_H
 
-/* Used to enable configuration of a GPIO to all zeros */
-#define WM8903_GPIO_NO_CONFIG 0x8000
+/*
+ * Used to enable configuration of a GPIO to all zeros; a gpio_cfg value of
+ * zero in platform data means "don't touch this pin".
+ */
+#define WM8903_GPIO_CONFIG_ZERO 0x8000
 
 /*
  * R6 (0x06) - Mic Bias Control 0
index 748ff7cbe5557989e6fd40fcacb70e5b8760956f..319538bf17d219d1bb3c11525c94cecdf669b978 100644 (file)
@@ -573,9 +573,9 @@ TRACE_EVENT(ext4_mb_release_inode_pa,
 );
 
 TRACE_EVENT(ext4_mb_release_group_pa,
-       TP_PROTO(struct ext4_prealloc_space *pa),
+       TP_PROTO(struct super_block *sb, struct ext4_prealloc_space *pa),
 
-       TP_ARGS(pa),
+       TP_ARGS(sb, pa),
 
        TP_STRUCT__entry(
                __field(        dev_t,  dev                     )
@@ -585,7 +585,7 @@ TRACE_EVENT(ext4_mb_release_group_pa,
        ),
 
        TP_fast_assign(
-               __entry->dev            = pa->pa_inode->i_sb->s_dev;
+               __entry->dev            = sb->s_dev;
                __entry->pa_pstart      = pa->pa_pstart;
                __entry->pa_len         = pa->pa_len;
        ),
index a9c87ad8331c61de25b9d2a51489de398a03d306..5f889f16b0c891dbedafd65686c48688aa7110da 100644 (file)
@@ -147,7 +147,7 @@ DEFINE_EVENT(kmem_free, kmem_cache_free,
        TP_ARGS(call_site, ptr)
 );
 
-TRACE_EVENT(mm_page_free_direct,
+TRACE_EVENT(mm_page_free,
 
        TP_PROTO(struct page *page, unsigned int order),
 
@@ -169,7 +169,7 @@ TRACE_EVENT(mm_page_free_direct,
                        __entry->order)
 );
 
-TRACE_EVENT(mm_pagevec_free,
+TRACE_EVENT(mm_page_free_batched,
 
        TP_PROTO(struct page *page, int cold),
 
diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h
new file mode 100644 (file)
index 0000000..dd4ba3b
--- /dev/null
@@ -0,0 +1,33 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM oom
+
+#if !defined(_TRACE_OOM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_OOM_H
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(oom_score_adj_update,
+
+       TP_PROTO(struct task_struct *task),
+
+       TP_ARGS(task),
+
+       TP_STRUCT__entry(
+               __field(        pid_t,  pid)
+               __array(        char,   comm,   TASK_COMM_LEN )
+               __field(         int,   oom_score_adj)
+       ),
+
+       TP_fast_assign(
+               __entry->pid = task->pid;
+               memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+               __entry->oom_score_adj = task->signal->oom_score_adj;
+       ),
+
+       TP_printk("pid=%d comm=%s oom_score_adj=%d",
+               __entry->pid, __entry->comm, __entry->oom_score_adj)
+);
+
+#endif
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/task.h b/include/trace/events/task.h
new file mode 100644 (file)
index 0000000..b53add0
--- /dev/null
@@ -0,0 +1,61 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM task
+
+#if !defined(_TRACE_TASK_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TASK_H
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(task_newtask,
+
+       TP_PROTO(struct task_struct *task, unsigned long clone_flags),
+
+       TP_ARGS(task, clone_flags),
+
+       TP_STRUCT__entry(
+               __field(        pid_t,  pid)
+               __array(        char,   comm, TASK_COMM_LEN)
+               __field( unsigned long, clone_flags)
+               __field(        int,    oom_score_adj)
+       ),
+
+       TP_fast_assign(
+               __entry->pid = task->pid;
+               memcpy(__entry->comm, task->comm, TASK_COMM_LEN);
+               __entry->clone_flags = clone_flags;
+               __entry->oom_score_adj = task->signal->oom_score_adj;
+       ),
+
+       TP_printk("pid=%d comm=%s clone_flags=%lx oom_score_adj=%d",
+               __entry->pid, __entry->comm,
+               __entry->clone_flags, __entry->oom_score_adj)
+);
+
+TRACE_EVENT(task_rename,
+
+       TP_PROTO(struct task_struct *task, char *comm),
+
+       TP_ARGS(task, comm),
+
+       TP_STRUCT__entry(
+               __field(        pid_t,  pid)
+               __array(        char, oldcomm,  TASK_COMM_LEN)
+               __array(        char, newcomm,  TASK_COMM_LEN)
+               __field(        int, oom_score_adj)
+       ),
+
+       TP_fast_assign(
+               __entry->pid = task->pid;
+               memcpy(entry->oldcomm, task->comm, TASK_COMM_LEN);
+               memcpy(entry->newcomm, comm, TASK_COMM_LEN);
+               __entry->oom_score_adj = task->signal->oom_score_adj;
+       ),
+
+       TP_printk("pid=%d oldcomm=%s newcomm=%s oom_score_adj=%d",
+               __entry->pid, __entry->oldcomm,
+               __entry->newcomm, __entry->oom_score_adj)
+);
+
+#endif
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index edc4b3d25a2d4e38917c83554eccd23a32fc8815..f64560e204bc1f84cd6c8ba5e6ba7f1f6938c656 100644 (file)
@@ -266,9 +266,10 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode),
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file),
 
        TP_STRUCT__entry(
                __field(int, order)
@@ -279,6 +280,7 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __field(unsigned long, nr_lumpy_dirty)
                __field(unsigned long, nr_lumpy_failed)
                __field(isolate_mode_t, isolate_mode)
+               __field(int, file)
        ),
 
        TP_fast_assign(
@@ -290,9 +292,10 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->nr_lumpy_dirty = nr_lumpy_dirty;
                __entry->nr_lumpy_failed = nr_lumpy_failed;
                __entry->isolate_mode = isolate_mode;
+               __entry->file = file;
        ),
 
-       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu",
+       TP_printk("isolate_mode=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu contig_taken=%lu contig_dirty=%lu contig_failed=%lu file=%d",
                __entry->isolate_mode,
                __entry->order,
                __entry->nr_requested,
@@ -300,7 +303,8 @@ DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
                __entry->nr_taken,
                __entry->nr_lumpy_taken,
                __entry->nr_lumpy_dirty,
-               __entry->nr_lumpy_failed)
+               __entry->nr_lumpy_failed,
+               __entry->file)
 );
 
 DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
@@ -312,9 +316,10 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
 
 );
 
@@ -327,9 +332,10 @@ DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
                unsigned long nr_lumpy_taken,
                unsigned long nr_lumpy_dirty,
                unsigned long nr_lumpy_failed,
-               isolate_mode_t isolate_mode),
+               isolate_mode_t isolate_mode,
+               int file),
 
-       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode)
+       TP_ARGS(order, nr_requested, nr_scanned, nr_taken, nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed, isolate_mode, file)
 
 );
 
index 99d1d0decf88e41a7c0c038d463330e8351046b1..8588a891802339a2939dfc91e5630e3a826781d4 100644 (file)
@@ -300,12 +300,13 @@ TRACE_EVENT(balance_dirty_pages,
                 unsigned long dirty_ratelimit,
                 unsigned long task_ratelimit,
                 unsigned long dirtied,
+                unsigned long period,
                 long pause,
                 unsigned long start_time),
 
        TP_ARGS(bdi, thresh, bg_thresh, dirty, bdi_thresh, bdi_dirty,
                dirty_ratelimit, task_ratelimit,
-               dirtied, pause, start_time),
+               dirtied, period, pause, start_time),
 
        TP_STRUCT__entry(
                __array(         char,  bdi, 32)
@@ -320,6 +321,8 @@ TRACE_EVENT(balance_dirty_pages,
                __field(unsigned int,   dirtied_pause)
                __field(unsigned long,  paused)
                __field(         long,  pause)
+               __field(unsigned long,  period)
+               __field(         long,  think)
        ),
 
        TP_fast_assign(
@@ -336,6 +339,9 @@ TRACE_EVENT(balance_dirty_pages,
                __entry->task_ratelimit = KBps(task_ratelimit);
                __entry->dirtied        = dirtied;
                __entry->dirtied_pause  = current->nr_dirtied_pause;
+               __entry->think          = current->dirty_paused_when == 0 ? 0 :
+                        (long)(jiffies - current->dirty_paused_when) * 1000/HZ;
+               __entry->period         = period * 1000 / HZ;
                __entry->pause          = pause * 1000 / HZ;
                __entry->paused         = (jiffies - start_time) * 1000 / HZ;
        ),
@@ -346,7 +352,7 @@ TRACE_EVENT(balance_dirty_pages,
                  "bdi_setpoint=%lu bdi_dirty=%lu "
                  "dirty_ratelimit=%lu task_ratelimit=%lu "
                  "dirtied=%u dirtied_pause=%u "
-                 "paused=%lu pause=%ld",
+                 "paused=%lu pause=%ld period=%lu think=%ld",
                  __entry->bdi,
                  __entry->limit,
                  __entry->setpoint,
@@ -358,7 +364,9 @@ TRACE_EVENT(balance_dirty_pages,
                  __entry->dirtied,
                  __entry->dirtied_pause,
                  __entry->paused,      /* ms */
-                 __entry->pause        /* ms */
+                 __entry->pause,       /* ms */
+                 __entry->period,      /* ms */
+                 __entry->think        /* ms */
          )
 );
 
index a075765d5fbe4b85ca033708f454de38c3ea3798..6ac2236244c381f3bef900c600d1f9c1ba41c7f5 100644 (file)
@@ -713,7 +713,6 @@ config CGROUP_PERF
 
 menuconfig CGROUP_SCHED
        bool "Group CPU scheduler"
-       depends on EXPERIMENTAL
        default n
        help
          This feature lets CPU scheduler recognize task groups and control CPU
@@ -784,6 +783,17 @@ config DEBUG_BLK_CGROUP
 
 endif # CGROUPS
 
+config CHECKPOINT_RESTORE
+       bool "Checkpoint/restore support" if EXPERT
+       default n
+       help
+         Enables additional kernel features in a sake of checkpoint/restore.
+         In particular it adds auxiliary prctl codes to setup process text,
+         data and heap segment sizes, and a few additional /proc filesystem
+         entries.
+
+         If unsure, say N here.
+
 menuconfig NAMESPACES
        bool "Namespaces support" if EXPERT
        default !EXPERT
index 24df7976816c6ca99f3403f97444f8e49f69a0a7..5f117ca9e0694488765ed0d4c0ea70baae7e6a04 100644 (file)
@@ -246,6 +246,19 @@ recalibrate:
 
 static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 };
 
+/*
+ * Check if cpu calibration delay is already known. For example,
+ * some processors with multi-core sockets may have all cores
+ * with the same calibration delay.
+ *
+ * Architectures should override this function if a faster calibration
+ * method is available.
+ */
+unsigned long __attribute__((weak)) __cpuinit calibrate_delay_is_known(void)
+{
+       return 0;
+}
+
 void __cpuinit calibrate_delay(void)
 {
        unsigned long lpj;
@@ -265,6 +278,8 @@ void __cpuinit calibrate_delay(void)
                lpj = lpj_fine;
                pr_info("Calibrating delay loop (skipped), "
                        "value calculated using timer frequency.. ");
+       } else if ((lpj = calibrate_delay_is_known())) {
+               ;
        } else if ((lpj = calibrate_delay_direct()) != 0) {
                if (!printed)
                        pr_info("Calibrating delay using timer "
index b2eee02e0f83fd720f38cf83a2b5e58ea27997b1..2974c8b3b351b4a15b38acca4478e4032fece9fa 100644 (file)
@@ -400,15 +400,42 @@ out:
 }
  
 #ifdef CONFIG_ROOT_NFS
+
+#define NFSROOT_TIMEOUT_MIN    5
+#define NFSROOT_TIMEOUT_MAX    30
+#define NFSROOT_RETRY_MAX      5
+
 static int __init mount_nfs_root(void)
 {
        char *root_dev, *root_data;
+       unsigned int timeout;
+       int try, err;
 
-       if (nfs_root_data(&root_dev, &root_data) != 0)
-               return 0;
-       if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0)
+       err = nfs_root_data(&root_dev, &root_data);
+       if (err != 0)
                return 0;
-       return 1;
+
+       /*
+        * The server or network may not be ready, so try several
+        * times.  Stop after a few tries in case the client wants
+        * to fall back to other boot methods.
+        */
+       timeout = NFSROOT_TIMEOUT_MIN;
+       for (try = 1; ; try++) {
+               err = do_mount_root(root_dev, "nfs",
+                                       root_mountflags, root_data);
+               if (err == 0)
+                       return 1;
+               if (try > NFSROOT_RETRY_MAX)
+                       break;
+
+               /* Wait, in case the server refused us immediately */
+               ssleep(timeout);
+               timeout <<= 1;
+               if (timeout > NFSROOT_TIMEOUT_MAX)
+                       timeout = NFSROOT_TIMEOUT_MAX;
+       }
+       return 0;
 }
 #endif
 
index 2c76efb513c2c2e8f3c94a3c87665a3c6c9cc166..415548e808d2873fda39a123a202186b9968dd7f 100644 (file)
@@ -282,10 +282,6 @@ static int __init unknown_bootoption(char *param, char *val)
        return 0;
 }
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
-int __read_mostly debug_pagealloc_enabled = 0;
-#endif
-
 static int __init init_setup(char *str)
 {
        unsigned int i;
@@ -596,7 +592,6 @@ asmlinkage void __init start_kernel(void)
        }
 #endif
        page_cgroup_init();
-       enable_debug_pagealloc();
        debug_objects_mem_init();
        kmemleak_init();
        setup_per_cpu_pageset();
index 9a142a290749f2af819c47ac487f2192c6502675..9b7c8ab7d75cad27e92272c0a0c81927c9fbaa03 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/nsproxy.h>
 #include <linux/pid.h>
 #include <linux/ipc_namespace.h>
+#include <linux/user_namespace.h>
 #include <linux/slab.h>
 
 #include <net/sock.h>
@@ -542,9 +543,13 @@ static void __do_notify(struct mqueue_inode_info *info)
                        sig_i.si_errno = 0;
                        sig_i.si_code = SI_MESGQ;
                        sig_i.si_value = info->notify.sigev_value;
+                       /* map current pid/uid into info->owner's namespaces */
+                       rcu_read_lock();
                        sig_i.si_pid = task_tgid_nr_ns(current,
                                                ns_of_pid(info->notify_owner));
-                       sig_i.si_uid = current_uid();
+                       sig_i.si_uid = user_ns_map_uid(info->user->user_ns,
+                                               current_cred(), current_uid());
+                       rcu_read_unlock();
 
                        kill_pid_info(info->notify.sigev_signo,
                                      &sig_i, info->notify_owner);
index d9eab2e4b430a08a33a13e93f31a6d37a5d15794..c44738267be770118b64203eb3cbd411d9656686 100644 (file)
@@ -51,6 +51,7 @@
 #include <trace/events/sched.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/oom.h>
+#include <linux/writeback.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -886,7 +887,7 @@ static void check_stack_usage(void)
 static inline void check_stack_usage(void) {}
 #endif
 
-NORET_TYPE void do_exit(long code)
+void do_exit(long code)
 {
        struct task_struct *tsk = current;
        int group_dead;
@@ -1035,6 +1036,8 @@ NORET_TYPE void do_exit(long code)
        validate_creds_for_do_exit(tsk);
 
        preempt_disable();
+       if (tsk->nr_dirtied)
+               __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
        exit_rcu();
        /* causes final put_task_struct in finish_task_switch(). */
        tsk->state = TASK_DEAD;
@@ -1048,7 +1051,7 @@ NORET_TYPE void do_exit(long code)
 
 EXPORT_SYMBOL_GPL(do_exit);
 
-NORET_TYPE void complete_and_exit(struct completion *comp, long code)
+void complete_and_exit(struct completion *comp, long code)
 {
        if (comp)
                complete(comp);
@@ -1067,7 +1070,7 @@ SYSCALL_DEFINE1(exit, int, error_code)
  * Take down every thread in the group.  This is called by fatal signals
  * as well as by sys_exit_group (below).
  */
-NORET_TYPE void
+void
 do_group_exit(int exit_code)
 {
        struct signal_struct *sig = current->signal;
index b00711ce7c13222715f08b83a047afdcb1a5d02a..443f5125f11e39435929072e3abbd19d7a408ea9 100644 (file)
@@ -76,6 +76,9 @@
 
 #include <trace/events/sched.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/task.h>
+
 /*
  * Protected counters by write_lock_irq(&tasklist_lock)
  */
@@ -1291,6 +1294,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
        p->nr_dirtied = 0;
        p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10);
+       p->dirty_paused_when = 0;
 
        /*
         * Ok, make it visible to the rest of the system.
@@ -1370,6 +1374,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        if (clone_flags & CLONE_THREAD)
                threadgroup_change_end(current);
        perf_event_fork(p);
+
+       trace_task_newtask(p, clone_flags);
+
        return p;
 
 bad_fork_free_pid:
index 090ee10d960485c6b9ed1923ef66c467c6fa19ea..7b0886786701b845cfbd8823252392e40b11a1c8 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/console.h>
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
-#include <linux/kmsg_dump.h>
 #include <linux/syscore_ops.h>
 
 #include <asm/page.h>
@@ -1094,8 +1093,6 @@ void crash_kexec(struct pt_regs *regs)
                if (kexec_crash_image) {
                        struct pt_regs fixed_regs;
 
-                       kmsg_dump(KMSG_DUMP_KEXEC);
-
                        crash_setup_regs(&fixed_regs, regs);
                        crash_save_vmcoreinfo();
                        machine_crash_shutdown(&fixed_regs);
@@ -1132,6 +1129,8 @@ int crash_shrink_memory(unsigned long new_size)
 {
        int ret = 0;
        unsigned long start, end;
+       unsigned long old_size;
+       struct resource *ram_res;
 
        mutex_lock(&kexec_mutex);
 
@@ -1141,11 +1140,15 @@ int crash_shrink_memory(unsigned long new_size)
        }
        start = crashk_res.start;
        end = crashk_res.end;
+       old_size = (end == 0) ? 0 : end - start + 1;
+       if (new_size >= old_size) {
+               ret = (new_size == old_size) ? 0 : -EINVAL;
+               goto unlock;
+       }
 
-       if (new_size >= end - start + 1) {
-               ret = -EINVAL;
-               if (new_size == end - start + 1)
-                       ret = 0;
+       ram_res = kzalloc(sizeof(*ram_res), GFP_KERNEL);
+       if (!ram_res) {
+               ret = -ENOMEM;
                goto unlock;
        }
 
@@ -1157,7 +1160,15 @@ int crash_shrink_memory(unsigned long new_size)
 
        if ((start == end) && (crashk_res.parent != NULL))
                release_resource(&crashk_res);
+
+       ram_res->start = end;
+       ram_res->end = crashk_res.end;
+       ram_res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+       ram_res->name = "System RAM";
+
        crashk_res.end = end - 1;
+
+       insert_resource(&iomem_resource, ram_res);
        crash_unmap_reserved_pages();
 
 unlock:
index e5d84644823b4094a4e6c629985daddd753bdd19..95dd7212e610b5a3da4ce97997a88f5c67d89b2d 100644 (file)
@@ -2198,7 +2198,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
               const char __user *user_buf, size_t count, loff_t *ppos)
 {
        char buf[32];
-       int buf_size;
+       size_t buf_size;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
index 3458469eb7c3489badf84de6916defa9cd6472a0..80aed44e345abc648f7ac3d0e7560a05e453c7fd 100644 (file)
@@ -49,6 +49,15 @@ static long no_blink(int state)
 long (*panic_blink)(int state);
 EXPORT_SYMBOL(panic_blink);
 
+/*
+ * Stop ourself in panic -- architecture code may override this
+ */
+void __weak panic_smp_self_stop(void)
+{
+       while (1)
+               cpu_relax();
+}
+
 /**
  *     panic - halt the system
  *     @fmt: The text string to print
@@ -57,8 +66,9 @@ EXPORT_SYMBOL(panic_blink);
  *
  *     This function never returns.
  */
-NORET_TYPE void panic(const char * fmt, ...)
+void panic(const char *fmt, ...)
 {
+       static DEFINE_SPINLOCK(panic_lock);
        static char buf[1024];
        va_list args;
        long i, i_next = 0;
@@ -68,8 +78,14 @@ NORET_TYPE void panic(const char * fmt, ...)
         * It's possible to come here directly from a panic-assertion and
         * not have preempt disabled. Some functions called from here want
         * preempt to be disabled. No point enabling it later though...
+        *
+        * Only one CPU is allowed to execute the panic code from here. For
+        * multiple parallel invocations of panic, all other CPUs either
+        * stop themself or will wait until they are stopped by the 1st CPU
+        * with smp_send_stop().
         */
-       preempt_disable();
+       if (!spin_trylock(&panic_lock))
+               panic_smp_self_stop();
 
        console_verbose();
        bust_spinlocks(1);
@@ -78,7 +94,11 @@ NORET_TYPE void panic(const char * fmt, ...)
        va_end(args);
        printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
 #ifdef CONFIG_DEBUG_BUGVERBOSE
-       dump_stack();
+       /*
+        * Avoid nested stack-dumping if a panic occurs during oops processing
+        */
+       if (!oops_in_progress)
+               dump_stack();
 #endif
 
        /*
index fa5f72227e5f432127c4f3b1383e3c93abcd0eaa..ce8e00deaccb38452188436438dc942313bd6c44 100644 (file)
@@ -137,7 +137,9 @@ static int pid_before(int base, int a, int b)
 }
 
 /*
- * We might be racing with someone else trying to set pid_ns->last_pid.
+ * We might be racing with someone else trying to set pid_ns->last_pid
+ * at the pid allocation time (there's also a sysctl for this, but racing
+ * with this one is OK, see comment in kernel/pid_namespace.c about it).
  * We want the winner to have the "later" value, because if the
  * "earlier" value prevails, then a pid may get reused immediately.
  *
index e9c9adc84ca6e50f5f457e081bb45c36b35bf4d1..a8968396046d3b2f9310c0ca6bd6bb0757c34cca 100644 (file)
@@ -191,9 +191,40 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        return;
 }
 
+static int pid_ns_ctl_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table tmp = *table;
+
+       if (write && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       /*
+        * Writing directly to ns' last_pid field is OK, since this field
+        * is volatile in a living namespace anyway and a code writing to
+        * it should synchronize its usage with external means.
+        */
+
+       tmp.data = &current->nsproxy->pid_ns->last_pid;
+       return proc_dointvec(&tmp, write, buffer, lenp, ppos);
+}
+
+static struct ctl_table pid_ns_ctl_table[] = {
+       {
+               .procname = "ns_last_pid",
+               .maxlen = sizeof(int),
+               .mode = 0666, /* permissions are checked in the handler */
+               .proc_handler = pid_ns_ctl_handler,
+       },
+       { }
+};
+
+static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } };
+
 static __init int pid_namespaces_init(void)
 {
        pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC);
+       register_sysctl_paths(kern_path, pid_ns_ctl_table);
        return 0;
 }
 
index cbe2c14413927c665f25d778fb03fde84af73421..1cf88900ec4fdc162b6ad1250d2c4d13d3895458 100644 (file)
@@ -858,6 +858,9 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
            PageReserved(page))
                return NULL;
 
+       if (page_is_guard(page))
+               return NULL;
+
        return page;
 }
 
@@ -920,6 +923,9 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
            && (!kernel_page_present(page) || pfn_is_nosave(pfn)))
                return NULL;
 
+       if (page_is_guard(page))
+               return NULL;
+
        return page;
 }
 
index cecbb64be05fe166c60014af84de74056ed53fc8..fd7b25e9007933b29d02a71fae7e528deb0248f9 100644 (file)
@@ -7134,10 +7134,6 @@ void set_curr_task(int cpu, struct task_struct *p)
 
 #endif
 
-#ifdef CONFIG_RT_GROUP_SCHED
-#else /* !CONFIG_RT_GROUP_SCHED */
-#endif /* CONFIG_RT_GROUP_SCHED */
-
 #ifdef CONFIG_CGROUP_SCHED
 /* task_group_lock serializes the addition/removal of task groups */
 static DEFINE_SPINLOCK(task_group_lock);
@@ -7246,9 +7242,6 @@ void sched_move_task(struct task_struct *tsk)
 }
 #endif /* CONFIG_CGROUP_SCHED */
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-#endif
-
 #if defined(CONFIG_RT_GROUP_SCHED) || defined(CONFIG_CFS_BANDWIDTH)
 static unsigned long to_ratio(u64 period, u64 runtime)
 {
index 8e42de9105f800d1a7ca7231626b6d683b1cce4a..84adb2d66cbd3dc15e653532462203f8c73bba18 100644 (file)
@@ -3130,8 +3130,10 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
 }
 
 #define LBF_ALL_PINNED 0x01
-#define LBF_NEED_BREAK 0x02
-#define LBF_ABORT      0x04
+#define LBF_NEED_BREAK 0x02    /* clears into HAD_BREAK */
+#define LBF_HAD_BREAK  0x04
+#define LBF_HAD_BREAKS 0x0C    /* count HAD_BREAKs overflows into ABORT */
+#define LBF_ABORT      0x10
 
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
@@ -4508,7 +4510,9 @@ redo:
                        goto out_balanced;
 
                if (lb_flags & LBF_NEED_BREAK) {
-                       lb_flags &= ~LBF_NEED_BREAK;
+                       lb_flags += LBF_HAD_BREAK - LBF_NEED_BREAK;
+                       if (lb_flags & LBF_ABORT)
+                               goto out_balanced;
                        goto redo;
                }
 
index bb0efa5705ed3295bee197ae4dcbae8cfb5673f1..c73c4284160e1edd642a5fe2bd1d0067dca77539 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 #include <linux/nsproxy.h>
+#include <linux/user_namespace.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
 
@@ -1019,6 +1020,34 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
        return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
 }
 
+/*
+ * map the uid in struct cred into user namespace *ns
+ */
+static inline uid_t map_cred_ns(const struct cred *cred,
+                               struct user_namespace *ns)
+{
+       return user_ns_map_uid(ns, cred, cred->uid);
+}
+
+#ifdef CONFIG_USER_NS
+static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
+{
+       if (current_user_ns() == task_cred_xxx(t, user_ns))
+               return;
+
+       if (SI_FROMKERNEL(info))
+               return;
+
+       info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns),
+                                       current_cred(), info->si_uid);
+}
+#else
+static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
+{
+       return;
+}
+#endif
+
 static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
                        int group, int from_ancestor_ns)
 {
@@ -1088,6 +1117,9 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
                                q->info.si_pid = 0;
                        break;
                }
+
+               userns_fixup_signal_uid(&q->info, t);
+
        } else if (!is_si_special(info)) {
                if (sig >= SIGRTMIN && info->si_code != SI_USER) {
                        /*
@@ -1626,7 +1658,8 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
         */
        rcu_read_lock();
        info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
-       info.si_uid = __task_cred(tsk)->uid;
+       info.si_uid = map_cred_ns(__task_cred(tsk),
+                       task_cred_xxx(tsk->parent, user_ns));
        rcu_read_unlock();
 
        info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
@@ -1709,7 +1742,8 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
         */
        rcu_read_lock();
        info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
-       info.si_uid = __task_cred(tsk)->uid;
+       info.si_uid = map_cred_ns(__task_cred(tsk),
+                       task_cred_xxx(parent, user_ns));
        rcu_read_unlock();
 
        info.si_utime = cputime_to_clock_t(tsk->utime);
@@ -2125,8 +2159,11 @@ static int ptrace_signal(int signr, siginfo_t *info,
                info->si_signo = signr;
                info->si_errno = 0;
                info->si_code = SI_USER;
+               rcu_read_lock();
                info->si_pid = task_pid_vnr(current->parent);
-               info->si_uid = task_uid(current->parent);
+               info->si_uid = map_cred_ns(__task_cred(current->parent),
+                               current_user_ns());
+               rcu_read_unlock();
        }
 
        /* If the (new) signal is now blocked, requeue it.  */
@@ -2318,6 +2355,27 @@ relock:
        return signr;
 }
 
+/**
+ * block_sigmask - add @ka's signal mask to current->blocked
+ * @ka: action for @signr
+ * @signr: signal that has been successfully delivered
+ *
+ * This function should be called when a signal has succesfully been
+ * delivered. It adds the mask of signals for @ka to current->blocked
+ * so that they are blocked during the execution of the signal
+ * handler. In addition, @signr will be blocked unless %SA_NODEFER is
+ * set in @ka->sa.sa_flags.
+ */
+void block_sigmask(struct k_sigaction *ka, int signr)
+{
+       sigset_t blocked;
+
+       sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&blocked, signr);
+       set_current_blocked(&blocked);
+}
+
 /*
  * It could be that complete_signal() picked us to notify about the
  * group-wide signal. Other threads should be notified now to take
index ddf8155bf3f8c09a3745a3cea82ec4e9aef49208..40701538fbd168db2de95315ac5c512a79686f52 100644 (file)
@@ -1692,6 +1692,124 @@ SYSCALL_DEFINE1(umask, int, mask)
        return mask;
 }
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static int prctl_set_mm(int opt, unsigned long addr,
+                       unsigned long arg4, unsigned long arg5)
+{
+       unsigned long rlim = rlimit(RLIMIT_DATA);
+       unsigned long vm_req_flags;
+       unsigned long vm_bad_flags;
+       struct vm_area_struct *vma;
+       int error = 0;
+       struct mm_struct *mm = current->mm;
+
+       if (arg4 | arg5)
+               return -EINVAL;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (addr >= TASK_SIZE)
+               return -EINVAL;
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, addr);
+
+       if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) {
+               /* It must be existing VMA */
+               if (!vma || vma->vm_start > addr)
+                       goto out;
+       }
+
+       error = -EINVAL;
+       switch (opt) {
+       case PR_SET_MM_START_CODE:
+       case PR_SET_MM_END_CODE:
+               vm_req_flags = VM_READ | VM_EXEC;
+               vm_bad_flags = VM_WRITE | VM_MAYSHARE;
+
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
+                   (vma->vm_flags & vm_bad_flags))
+                       goto out;
+
+               if (opt == PR_SET_MM_START_CODE)
+                       mm->start_code = addr;
+               else
+                       mm->end_code = addr;
+               break;
+
+       case PR_SET_MM_START_DATA:
+       case PR_SET_MM_END_DATA:
+               vm_req_flags = VM_READ | VM_WRITE;
+               vm_bad_flags = VM_EXEC | VM_MAYSHARE;
+
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
+                   (vma->vm_flags & vm_bad_flags))
+                       goto out;
+
+               if (opt == PR_SET_MM_START_DATA)
+                       mm->start_data = addr;
+               else
+                       mm->end_data = addr;
+               break;
+
+       case PR_SET_MM_START_STACK:
+
+#ifdef CONFIG_STACK_GROWSUP
+               vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP;
+#else
+               vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN;
+#endif
+               if ((vma->vm_flags & vm_req_flags) != vm_req_flags)
+                       goto out;
+
+               mm->start_stack = addr;
+               break;
+
+       case PR_SET_MM_START_BRK:
+               if (addr <= mm->end_data)
+                       goto out;
+
+               if (rlim < RLIM_INFINITY &&
+                   (mm->brk - addr) +
+                   (mm->end_data - mm->start_data) > rlim)
+                       goto out;
+
+               mm->start_brk = addr;
+               break;
+
+       case PR_SET_MM_BRK:
+               if (addr <= mm->end_data)
+                       goto out;
+
+               if (rlim < RLIM_INFINITY &&
+                   (addr - mm->start_brk) +
+                   (mm->end_data - mm->start_data) > rlim)
+                       goto out;
+
+               mm->brk = addr;
+               break;
+
+       default:
+               error = -EINVAL;
+               goto out;
+       }
+
+       error = 0;
+
+out:
+       up_read(&mm->mmap_sem);
+
+       return error;
+}
+#else /* CONFIG_CHECKPOINT_RESTORE */
+static int prctl_set_mm(int opt, unsigned long addr,
+                       unsigned long arg4, unsigned long arg5)
+{
+       return -EINVAL;
+}
+#endif
+
 SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                unsigned long, arg4, unsigned long, arg5)
 {
@@ -1841,6 +1959,9 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        else
                                error = PR_MCE_KILL_DEFAULT;
                        break;
+               case PR_SET_MM:
+                       error = prctl_set_mm(arg2, arg3, arg4, arg5);
+                       break;
                default:
                        error = -EINVAL;
                        break;
index ae27196438541384fbfdc1a5c405681169ac8921..f487f257e05e4f1dc8836ded96ca36556b048706 100644 (file)
@@ -803,6 +803,15 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+       {
+               .procname       = "panic_on_stackoverflow",
+               .data           = &sysctl_panic_on_stackoverflow,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+#endif
        {
                .procname       = "bootloader_type",
                .data           = &bootloader_type,
index 42fa9ad0a810482494b5782f4ba9a23f4aa32b86..bec7b5b53e03db1d443a2f221255fd22344f4de4 100644 (file)
@@ -242,10 +242,10 @@ struct workqueue_struct {
 
        int                     nr_drainers;    /* W: drain in progress */
        int                     saved_max_active; /* W: saved cwq max_active */
-       const char              *name;          /* I: workqueue name */
 #ifdef CONFIG_LOCKDEP
        struct lockdep_map      lockdep_map;
 #endif
+       char                    name[];         /* I: workqueue name */
 };
 
 struct workqueue_struct *system_wq __read_mostly;
@@ -2954,14 +2954,29 @@ static int wq_clamp_max_active(int max_active, unsigned int flags,
        return clamp_val(max_active, 1, lim);
 }
 
-struct workqueue_struct *__alloc_workqueue_key(const char *name,
+struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
                                               unsigned int flags,
                                               int max_active,
                                               struct lock_class_key *key,
-                                              const char *lock_name)
+                                              const char *lock_name, ...)
 {
+       va_list args, args1;
        struct workqueue_struct *wq;
        unsigned int cpu;
+       size_t namelen;
+
+       /* determine namelen, allocate wq and format name */
+       va_start(args, lock_name);
+       va_copy(args1, args);
+       namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+
+       wq = kzalloc(sizeof(*wq) + namelen, GFP_KERNEL);
+       if (!wq)
+               goto err;
+
+       vsnprintf(wq->name, namelen, fmt, args1);
+       va_end(args);
+       va_end(args1);
 
        /*
         * Workqueues which may be used during memory reclaim should
@@ -2978,12 +2993,9 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
                flags |= WQ_HIGHPRI;
 
        max_active = max_active ?: WQ_DFL_ACTIVE;
-       max_active = wq_clamp_max_active(max_active, flags, name);
-
-       wq = kzalloc(sizeof(*wq), GFP_KERNEL);
-       if (!wq)
-               goto err;
+       max_active = wq_clamp_max_active(max_active, flags, wq->name);
 
+       /* init wq */
        wq->flags = flags;
        wq->saved_max_active = max_active;
        mutex_init(&wq->flush_mutex);
@@ -2991,7 +3003,6 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
        INIT_LIST_HEAD(&wq->flusher_queue);
        INIT_LIST_HEAD(&wq->flusher_overflow);
 
-       wq->name = name;
        lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
        INIT_LIST_HEAD(&wq->list);
 
@@ -3020,7 +3031,8 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
                if (!rescuer)
                        goto err;
 
-               rescuer->task = kthread_create(rescuer_thread, wq, "%s", name);
+               rescuer->task = kthread_create(rescuer_thread, wq, "%s",
+                                              wq->name);
                if (IS_ERR(rescuer->task))
                        goto err;
 
index f34be6417d712b2cf524de7e0897d1496520f8a6..201e1b33d721bf2ff83e6cd5ca817ea243861c39 100644 (file)
@@ -19,6 +19,13 @@ config RATIONAL
 config GENERIC_FIND_FIRST_BIT
        bool
 
+config GENERIC_PCI_IOMAP
+       bool
+
+config GENERIC_IOMAP
+       bool
+       select GENERIC_PCI_IOMAP
+
 config CRC_CCITT
        tristate "CRC-CCITT functions"
        help
@@ -278,4 +285,29 @@ config CORDIC
          This option provides an implementation of the CORDIC algorithm;
          calculations are in fixed point. Module will be called cordic.
 
+config MPILIB
+       tristate "Multiprecision maths library"
+       help
+         Multiprecision maths library from GnuPG.
+         It is used to implement RSA digital signature verification,
+         which is used by IMA/EVM digital signature extension.
+
+config MPILIB_EXTRA
+       bool "Multiprecision maths library - additional sources"
+       depends on MPILIB
+       help
+         Multiprecision maths library from GnuPG.
+         It is used to implement RSA digital signature verification,
+         which is used by IMA/EVM digital signature extension.
+         This code in unnecessary for RSA digital signature verification,
+         and can be compiled if needed.
+
+config DIGSIG
+       tristate "In-kernel signature checker"
+       depends on KEYS
+       select MPILIB
+       help
+         Digital signature verification. Currently only RSA is supported.
+         Implementation is done using GnuPG MPI library
+
 endmenu
index c0ffaaff653474ad553ceec7ff26dfa6634b0792..dace162c7e1c2f063498ded701e5576f3c16b75a 100644 (file)
@@ -33,6 +33,7 @@ endif
 
 lib-$(CONFIG_HOTPLUG) += kobject_uevent.o
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
+obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
 obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
@@ -117,6 +118,9 @@ obj-$(CONFIG_CORDIC) += cordic.o
 
 obj-$(CONFIG_DQL) += dynamic_queue_limits.o
 
+obj-$(CONFIG_MPILIB) += mpi/
+obj-$(CONFIG_DIGSIG) += digsig.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
index 2a34392bcecc3680dfb10fbbc7ae126792aa6713..e5ec1e9c1aa52cc08c710a4dcc4c1815cad9c67b 100644 (file)
@@ -357,6 +357,7 @@ miss:
        }
        return NULL;
 }
+EXPORT_SYMBOL_GPL(btree_get_prev);
 
 static int getpos(struct btree_geo *geo, unsigned long *node,
                unsigned long *key)
index a6e633a48cea887fbba14b7c1cbab84bd485c67b..4b35d2b4437cc76b3b75b45ae2d21ac6076f7809 100644 (file)
@@ -51,20 +51,21 @@ static inline u32
 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 {
 # ifdef __LITTLE_ENDIAN
-#  define DO_CRC(x) crc = tab[0][(crc ^ (x)) & 255] ^ (crc >> 8)
-#  define DO_CRC4 crc = tab[3][(crc) & 255] ^ \
-               tab[2][(crc >> 8) & 255] ^ \
-               tab[1][(crc >> 16) & 255] ^ \
-               tab[0][(crc >> 24) & 255]
+#  define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8)
+#  define DO_CRC4 crc = t3[(crc) & 255] ^ \
+               t2[(crc >> 8) & 255] ^ \
+               t1[(crc >> 16) & 255] ^ \
+               t0[(crc >> 24) & 255]
 # else
-#  define DO_CRC(x) crc = tab[0][((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
-#  define DO_CRC4 crc = tab[0][(crc) & 255] ^ \
-               tab[1][(crc >> 8) & 255] ^ \
-               tab[2][(crc >> 16) & 255] ^ \
-               tab[3][(crc >> 24) & 255]
+#  define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)
+#  define DO_CRC4 crc = t0[(crc) & 255] ^ \
+               t1[(crc >> 8) & 255] ^  \
+               t2[(crc >> 16) & 255] ^ \
+               t3[(crc >> 24) & 255]
 # endif
        const u32 *b;
        size_t    rem_len;
+       const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3];
 
        /* Align it */
        if (unlikely((long)buf & 3 && len)) {
index 5a7a2adf4c4c2aa8d64d881e0ff1739acbe8782c..4531294fa62f2cb5de592178ddca2c0afc223558 100644 (file)
@@ -279,7 +279,7 @@ STATIC inline int INIT unlzo(u8 *input, int in_len,
        ret = 0;
 exit_2:
        if (!input)
-               free(in_buf);
+               free(in_buf_save);
 exit_1:
        if (!output)
                free(out_buf);
index 4fbc09e6e9e6f9a83dbdc14ba99bfb1328bef577..9676617b44863fb1b19148abf2964beff1739c13 100644 (file)
@@ -304,7 +304,7 @@ EXPORT_SYMBOL(pcim_iounmap);
  *
  * Request and iomap regions specified by @mask.
  */
-int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
+int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
 {
        void __iomem * const *iomap;
        int i, rc;
@@ -357,7 +357,7 @@ EXPORT_SYMBOL(pcim_iomap_regions);
  *
  * Request all PCI BARs and iomap regions specified by @mask.
  */
-int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask,
+int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
                                   const char *name)
 {
        int request_mask = ((1 << 6) - 1) & ~mask;
@@ -381,7 +381,7 @@ EXPORT_SYMBOL(pcim_iomap_regions_request_all);
  *
  * Unmap and release regions specified by @mask.
  */
-void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
 {
        void __iomem * const *iomap;
        int i;
diff --git a/lib/digsig.c b/lib/digsig.c
new file mode 100644 (file)
index 0000000..fd2402f
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2011 Intel Corporation
+ *
+ * Author:
+ * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ *                 <dmitry.kasatkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * File: sign.c
+ *     implements signature (RSA) verification
+ *     pkcs decoding is based on LibTomCrypt code
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <keys/user-type.h>
+#include <linux/mpi.h>
+#include <linux/digsig.h>
+
+static struct crypto_shash *shash;
+
+static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
+                       unsigned long  msglen,
+                       unsigned long  modulus_bitlen,
+                       unsigned char *out,
+                       unsigned long *outlen,
+                       int *is_valid)
+{
+       unsigned long modulus_len, ps_len, i;
+       int result;
+
+       /* default to invalid packet */
+       *is_valid = 0;
+
+       modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+       /* test message size */
+       if ((msglen > modulus_len) || (modulus_len < 11))
+               return -EINVAL;
+
+       /* separate encoded message */
+       if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) {
+               result = -EINVAL;
+               goto bail;
+       }
+
+       for (i = 2; i < modulus_len - 1; i++)
+               if (msg[i] != 0xFF)
+                       break;
+
+       /* separator check */
+       if (msg[i] != 0) {
+               /* There was no octet with hexadecimal value 0x00
+               to separate ps from m. */
+               result = -EINVAL;
+               goto bail;
+       }
+
+       ps_len = i - 2;
+
+       if (*outlen < (msglen - (2 + ps_len + 1))) {
+               *outlen = msglen - (2 + ps_len + 1);
+               result = -EOVERFLOW;
+               goto bail;
+       }
+
+       *outlen = (msglen - (2 + ps_len + 1));
+       memcpy(out, &msg[2 + ps_len + 1], *outlen);
+
+       /* valid packet */
+       *is_valid = 1;
+       result    = 0;
+bail:
+       return result;
+}
+
+/*
+ * RSA Signature verification with public key
+ */
+static int digsig_verify_rsa(struct key *key,
+                   const char *sig, int siglen,
+                      const char *h, int hlen)
+{
+       int err = -EINVAL;
+       unsigned long len;
+       unsigned long mlen, mblen;
+       unsigned nret, l;
+       int valid, head, i;
+       unsigned char *out1 = NULL, *out2 = NULL;
+       MPI in = NULL, res = NULL, pkey[2];
+       uint8_t *p, *datap, *endp;
+       struct user_key_payload *ukp;
+       struct pubkey_hdr *pkh;
+
+       down_read(&key->sem);
+       ukp = key->payload.data;
+       pkh = (struct pubkey_hdr *)ukp->data;
+
+       if (pkh->version != 1)
+               goto err1;
+
+       if (pkh->algo != PUBKEY_ALGO_RSA)
+               goto err1;
+
+       if (pkh->nmpi != 2)
+               goto err1;
+
+       datap = pkh->mpi;
+       endp = datap + ukp->datalen;
+
+       for (i = 0; i < pkh->nmpi; i++) {
+               unsigned int remaining = endp - datap;
+               pkey[i] = mpi_read_from_buffer(datap, &remaining);
+               datap += remaining;
+       }
+
+       mblen = mpi_get_nbits(pkey[0]);
+       mlen = (mblen + 7)/8;
+
+       err = -ENOMEM;
+
+       out1 = kzalloc(mlen, GFP_KERNEL);
+       if (!out1)
+               goto err;
+
+       out2 = kzalloc(mlen, GFP_KERNEL);
+       if (!out2)
+               goto err;
+
+       nret = siglen;
+       in = mpi_read_from_buffer(sig, &nret);
+       if (!in)
+               goto err;
+
+       res = mpi_alloc(mpi_get_nlimbs(in) * 2);
+       if (!res)
+               goto err;
+
+       err = mpi_powm(res, in, pkey[1], pkey[0]);
+       if (err)
+               goto err;
+
+       if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       p = mpi_get_buffer(res, &l, NULL);
+       if (!p) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       len = mlen;
+       head = len - l;
+       memset(out1, 0, head);
+       memcpy(out1 + head, p, l);
+
+       err = -EINVAL;
+       pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len, &valid);
+
+       if (valid && len == hlen)
+               err = memcmp(out2, h, hlen);
+
+err:
+       mpi_free(in);
+       mpi_free(res);
+       kfree(out1);
+       kfree(out2);
+       mpi_free(pkey[0]);
+       mpi_free(pkey[1]);
+err1:
+       up_read(&key->sem);
+
+       return err;
+}
+
+/**
+ * digsig_verify() - digital signature verification with public key
+ * @keyring:   keyring to search key in
+ * @sig:       digital signature
+ * @sigen:     length of the signature
+ * @data:      data
+ * @datalen:   length of the data
+ * @return:    0 on success, -EINVAL otherwise
+ *
+ * Verifies data integrity against digital signature.
+ * Currently only RSA is supported.
+ * Normally hash of the content is used as a data for this function.
+ *
+ */
+int digsig_verify(struct key *keyring, const char *sig, int siglen,
+                                               const char *data, int datalen)
+{
+       int err = -ENOMEM;
+       struct signature_hdr *sh = (struct signature_hdr *)sig;
+       struct shash_desc *desc = NULL;
+       unsigned char hash[SHA1_DIGEST_SIZE];
+       struct key *key;
+       char name[20];
+
+       if (siglen < sizeof(*sh) + 2)
+               return -EINVAL;
+
+       if (sh->algo != PUBKEY_ALGO_RSA)
+               return -ENOTSUPP;
+
+       sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid));
+
+       if (keyring) {
+               /* search in specific keyring */
+               key_ref_t kref;
+               kref = keyring_search(make_key_ref(keyring, 1UL),
+                                               &key_type_user, name);
+               if (IS_ERR(kref))
+                       key = ERR_PTR(PTR_ERR(kref));
+               else
+                       key = key_ref_to_ptr(kref);
+       } else {
+               key = request_key(&key_type_user, name, NULL);
+       }
+       if (IS_ERR(key)) {
+               pr_err("key not found, id: %s\n", name);
+               return PTR_ERR(key);
+       }
+
+       desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
+                      GFP_KERNEL);
+       if (!desc)
+               goto err;
+
+       desc->tfm = shash;
+       desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       crypto_shash_init(desc);
+       crypto_shash_update(desc, data, datalen);
+       crypto_shash_update(desc, sig, sizeof(*sh));
+       crypto_shash_final(desc, hash);
+
+       kfree(desc);
+
+       /* pass signature mpis address */
+       err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh),
+                            hash, sizeof(hash));
+
+err:
+       key_put(key);
+
+       return err ? -EINVAL : 0;
+}
+EXPORT_SYMBOL_GPL(digsig_verify);
+
+static int __init digsig_init(void)
+{
+       shash = crypto_alloc_shash("sha1", 0, 0);
+       if (IS_ERR(shash)) {
+               pr_err("shash allocation failed\n");
+               return  PTR_ERR(shash);
+       }
+
+       return 0;
+
+}
+
+static void __exit digsig_cleanup(void)
+{
+       crypto_free_shash(shash);
+}
+
+module_init(digsig_init);
+module_exit(digsig_cleanup);
+
+MODULE_LICENSE("GPL");
index 5dbcb4b2d864b244d97d289fb7c0f7bc18651ea0..ada922a808e6d328983fa5406284eacf3eb93cf4 100644 (file)
@@ -242,45 +242,11 @@ EXPORT_SYMBOL(ioport_unmap);
 #endif /* CONFIG_HAS_IOPORT */
 
 #ifdef CONFIG_PCI
-/**
- * pci_iomap - create a virtual mapping cookie for a PCI BAR
- * @dev: PCI device that owns the BAR
- * @bar: BAR number
- * @maxlen: length of the memory to map
- *
- * Using this function you will get a __iomem address to your device BAR.
- * You can access it using ioread*() and iowrite*(). These functions hide
- * the details if this is a MMIO or PIO address space and will just do what
- * you expect from them in the correct way.
- *
- * @maxlen specifies the maximum length to map. If you want to get access to
- * the complete BAR without checking for its length first, pass %0 here.
- * */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       /* What? */
-       return NULL;
-}
-
+/* Hide the details if this is a MMIO or PIO address space and just do what
+ * you expect in the correct way. */
 void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 {
        IO_COND(addr, /* nothing */, iounmap(addr));
 }
-EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
 #endif /* CONFIG_PCI */
diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile
new file mode 100644 (file)
index 0000000..567d52e
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# MPI multiprecision maths library (from gpg)
+#
+
+obj-$(CONFIG_MPILIB) = mpi.o
+
+mpi-y = \
+       generic_mpih-lshift.o           \
+       generic_mpih-mul1.o             \
+       generic_mpih-mul2.o             \
+       generic_mpih-mul3.o             \
+       generic_mpih-rshift.o           \
+       generic_mpih-sub1.o             \
+       generic_mpih-add1.o             \
+       mpicoder.o                      \
+       mpi-bit.o                       \
+       mpih-cmp.o                      \
+       mpih-div.o                      \
+       mpih-mul.o                      \
+       mpi-pow.o                       \
+       mpiutil.o
+
+mpi-$(CONFIG_MPILIB_EXTRA) += \
+       mpi-add.o                       \
+       mpi-div.o                       \
+       mpi-cmp.o                       \
+       mpi-gcd.o                       \
+       mpi-inline.o                    \
+       mpi-inv.o                       \
+       mpi-mpow.o                      \
+       mpi-mul.o                       \
+       mpi-scan.o
diff --git a/lib/mpi/generic_mpi-asm-defs.h b/lib/mpi/generic_mpi-asm-defs.h
new file mode 100644 (file)
index 0000000..047d1f5
--- /dev/null
@@ -0,0 +1,4 @@
+/* This file defines some basic constants for the MPI machinery.  We
+ * need to define the types on a per-CPU basis, so it is done with
+ * this file here.  */
+#define BYTES_PER_MPI_LIMB  (SIZEOF_UNSIGNED_LONG)
diff --git a/lib/mpi/generic_mpih-add1.c b/lib/mpi/generic_mpih-add1.c
new file mode 100644 (file)
index 0000000..c94c7dd
--- /dev/null
@@ -0,0 +1,61 @@
+/* mpihelp-add_1.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998,
+ *               2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+mpi_limb_t
+mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+             mpi_ptr_t s2_ptr, mpi_size_t size)
+{
+       mpi_limb_t x, y, cy;
+       mpi_size_t j;
+
+       /* The loop counter and index J goes from -SIZE to -1.  This way
+          the loop becomes faster.  */
+       j = -size;
+
+       /* Offset the base pointers to compensate for the negative indices. */
+       s1_ptr -= j;
+       s2_ptr -= j;
+       res_ptr -= j;
+
+       cy = 0;
+       do {
+               y = s2_ptr[j];
+               x = s1_ptr[j];
+               y += cy;        /* add previous carry to one addend */
+               cy = y < cy;    /* get out carry from that addition */
+               y += x;         /* add other addend */
+               cy += y < x;    /* get out carry from that add, combine */
+               res_ptr[j] = y;
+       } while (++j);
+
+       return cy;
+}
diff --git a/lib/mpi/generic_mpih-lshift.c b/lib/mpi/generic_mpih-lshift.c
new file mode 100644 (file)
index 0000000..8631892
--- /dev/null
@@ -0,0 +1,63 @@
+/* mpihelp-lshift.c  - MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+
+/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
+ * and store the USIZE least significant digits of the result at WP.
+ * Return the bits shifted out from the most significant digit.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be >= UP.
+ */
+
+mpi_limb_t
+mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned int cnt)
+{
+       mpi_limb_t high_limb, low_limb;
+       unsigned sh_1, sh_2;
+       mpi_size_t i;
+       mpi_limb_t retval;
+
+       sh_1 = cnt;
+       wp += 1;
+       sh_2 = BITS_PER_MPI_LIMB - sh_1;
+       i = usize - 1;
+       low_limb = up[i];
+       retval = low_limb >> sh_2;
+       high_limb = low_limb;
+       while (--i >= 0) {
+               low_limb = up[i];
+               wp[i] = (high_limb << sh_1) | (low_limb >> sh_2);
+               high_limb = low_limb;
+       }
+       wp[i] = high_limb << sh_1;
+
+       return retval;
+}
diff --git a/lib/mpi/generic_mpih-mul1.c b/lib/mpi/generic_mpih-mul1.c
new file mode 100644 (file)
index 0000000..1668dfd
--- /dev/null
@@ -0,0 +1,57 @@
+/* mpihelp-mul_1.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+mpi_limb_t
+mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+             mpi_limb_t s2_limb)
+{
+       mpi_limb_t cy_limb;
+       mpi_size_t j;
+       mpi_limb_t prod_high, prod_low;
+
+       /* The loop counter and index J goes from -S1_SIZE to -1.  This way
+        * the loop becomes faster.  */
+       j = -s1_size;
+
+       /* Offset the base pointers to compensate for the negative indices.  */
+       s1_ptr -= j;
+       res_ptr -= j;
+
+       cy_limb = 0;
+       do {
+               umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
+               prod_low += cy_limb;
+               cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
+               res_ptr[j] = prod_low;
+       } while (++j);
+
+       return cy_limb;
+}
diff --git a/lib/mpi/generic_mpih-mul2.c b/lib/mpi/generic_mpih-mul2.c
new file mode 100644 (file)
index 0000000..8a7b29e
--- /dev/null
@@ -0,0 +1,60 @@
+/* mpihelp-mul_2.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+mpi_limb_t
+mpihelp_addmul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+       mpi_limb_t cy_limb;
+       mpi_size_t j;
+       mpi_limb_t prod_high, prod_low;
+       mpi_limb_t x;
+
+       /* The loop counter and index J goes from -SIZE to -1.  This way
+        * the loop becomes faster.  */
+       j = -s1_size;
+       res_ptr -= j;
+       s1_ptr -= j;
+
+       cy_limb = 0;
+       do {
+               umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
+
+               prod_low += cy_limb;
+               cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
+
+               x = res_ptr[j];
+               prod_low = x + prod_low;
+               cy_limb += prod_low < x ? 1 : 0;
+               res_ptr[j] = prod_low;
+       } while (++j);
+       return cy_limb;
+}
diff --git a/lib/mpi/generic_mpih-mul3.c b/lib/mpi/generic_mpih-mul3.c
new file mode 100644 (file)
index 0000000..f96df32
--- /dev/null
@@ -0,0 +1,61 @@
+/* mpihelp-mul_3.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+mpi_limb_t
+mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+       mpi_limb_t cy_limb;
+       mpi_size_t j;
+       mpi_limb_t prod_high, prod_low;
+       mpi_limb_t x;
+
+       /* The loop counter and index J goes from -SIZE to -1.  This way
+        * the loop becomes faster.  */
+       j = -s1_size;
+       res_ptr -= j;
+       s1_ptr -= j;
+
+       cy_limb = 0;
+       do {
+               umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
+
+               prod_low += cy_limb;
+               cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
+
+               x = res_ptr[j];
+               prod_low = x - prod_low;
+               cy_limb += prod_low > x ? 1 : 0;
+               res_ptr[j] = prod_low;
+       } while (++j);
+
+       return cy_limb;
+}
diff --git a/lib/mpi/generic_mpih-rshift.c b/lib/mpi/generic_mpih-rshift.c
new file mode 100644 (file)
index 0000000..ffa3288
--- /dev/null
@@ -0,0 +1,63 @@
+/* mpih-rshift.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 1999,
+ *               2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUPG
+ *
+ * GNUPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+
+/* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right
+ * and store the USIZE least significant limbs of the result at WP.
+ * The bits shifted out to the right are returned.
+ *
+ * Argument constraints:
+ * 1. 0 < CNT < BITS_PER_MP_LIMB
+ * 2. If the result is to be written over the input, WP must be <= UP.
+ */
+
+mpi_limb_t
+mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt)
+{
+       mpi_limb_t high_limb, low_limb;
+       unsigned sh_1, sh_2;
+       mpi_size_t i;
+       mpi_limb_t retval;
+
+       sh_1 = cnt;
+       wp -= 1;
+       sh_2 = BITS_PER_MPI_LIMB - sh_1;
+       high_limb = up[0];
+       retval = high_limb << sh_2;
+       low_limb = high_limb;
+       for (i = 1; i < usize; i++) {
+               high_limb = up[i];
+               wp[i] = (low_limb >> sh_1) | (high_limb << sh_2);
+               low_limb = high_limb;
+       }
+       wp[i] = low_limb >> sh_1;
+
+       return retval;
+}
diff --git a/lib/mpi/generic_mpih-sub1.c b/lib/mpi/generic_mpih-sub1.c
new file mode 100644 (file)
index 0000000..5d98ab7
--- /dev/null
@@ -0,0 +1,60 @@
+/* mpihelp-add_2.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+mpi_limb_t
+mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+             mpi_ptr_t s2_ptr, mpi_size_t size)
+{
+       mpi_limb_t x, y, cy;
+       mpi_size_t j;
+
+       /* The loop counter and index J goes from -SIZE to -1.  This way
+          the loop becomes faster.  */
+       j = -size;
+
+       /* Offset the base pointers to compensate for the negative indices.  */
+       s1_ptr -= j;
+       s2_ptr -= j;
+       res_ptr -= j;
+
+       cy = 0;
+       do {
+               y = s2_ptr[j];
+               x = s1_ptr[j];
+               y += cy;        /* add previous carry to subtrahend */
+               cy = y < cy;    /* get out carry from that addition */
+               y = x - y;      /* main subtract */
+               cy += y > x;    /* get out carry from the subtract, combine */
+               res_ptr[j] = y;
+       } while (++j);
+
+       return cy;
+}
diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
new file mode 100644 (file)
index 0000000..b87487b
--- /dev/null
@@ -0,0 +1,1478 @@
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+ * Note: I added some stuff for use with gnupg
+ *
+ * Copyright (C) 1991, 1992, 1993, 1994, 1996, 1998,
+ *     2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this file; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA. */
+
+/* You have to define the following before including this file:
+ *
+ * UWtype -- An unsigned type, default type for operations (typically a "word")
+ * UHWtype -- An unsigned type, at least half the size of UWtype.
+ * UDWtype -- An unsigned type, at least twice as large a UWtype
+ * W_TYPE_SIZE -- size in bits of UWtype
+ *
+ * SItype, USItype -- Signed and unsigned 32 bit types.
+ * DItype, UDItype -- Signed and unsigned 64 bit types.
+ *
+ * On a 32 bit machine UWtype should typically be USItype;
+ * on a 64 bit machine, UWtype should typically be UDItype.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+/* This is used to make sure no undesirable sharing between different libraries
+       that use this file takes place.  */
+#ifndef __MPN
+#define __MPN(x) __##x
+#endif
+
+/* Define auxiliary asm macros.
+ *
+ * 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
+ * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
+ * word product in HIGH_PROD and LOW_PROD.
+ *
+ * 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
+ * UDWtype product.  This is just a variant of umul_ppmm.
+
+ * 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ * denominator) divides a UDWtype, composed by the UWtype integers
+ * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+ * in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less
+ * than DENOMINATOR for correct operation.  If, in addition, the most
+ * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+ * UDIV_NEEDS_NORMALIZATION is defined to 1.
+ * 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+ * denominator).  Like udiv_qrnnd but the numbers are signed.  The quotient
+ * is rounded towards 0.
+ *
+ * 5) count_leading_zeros(count, x) counts the number of zero-bits from the
+ * msb to the first non-zero bit in the UWtype X.  This is the number of
+ * steps X needs to be shifted left to set the msb.  Undefined for X == 0,
+ * unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
+ *
+ * 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
+ * from the least significant end.
+ *
+ * 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+ * high_addend_2, low_addend_2) adds two UWtype integers, composed by
+ * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+ * respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
+ * (i.e. carry out) is not stored anywhere, and is lost.
+ *
+ * 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+ * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+ * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+ * LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
+ * and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
+ * and is lost.
+ *
+ * If any of these macros are left undefined for a particular CPU,
+ * C macros are used.  */
+
+/* The CPUs come in alphabetical order below.
+ *
+ * Please add support for more CPUs here, or improve the current support
+ * for the CPUs below! */
+
+#if defined(__GNUC__) && !defined(NO_ASM)
+
+/* We sometimes need to clobber "cc" with gcc2, but that would not be
+       understood by gcc1.     Use cpp to avoid major code duplication.  */
+#if __GNUC__ < 2
+#define __CLOBBER_CC
+#define __AND_CLOBBER_CC
+#else /* __GNUC__ >= 2 */
+#define __CLOBBER_CC : "cc"
+#define __AND_CLOBBER_CC , "cc"
+#endif /* __GNUC__ < 2 */
+
+/***************************************
+       **************  A29K  *****************
+       ***************************************/
+#if (defined(__a29k__) || defined(_AM29K)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("add %1,%4,%5\n" \
+               "addc %0,%2,%3" \
+       : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+       : "%r" ((USItype)(ah)), \
+               "rI" ((USItype)(bh)), \
+               "%r" ((USItype)(al)), \
+               "rI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("sub %1,%4,%5\n" \
+               "subc %0,%2,%3" \
+       : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+       : "r" ((USItype)(ah)), \
+               "rI" ((USItype)(bh)), \
+               "r" ((USItype)(al)), \
+               "rI" ((USItype)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+do { \
+               USItype __m0 = (m0), __m1 = (m1); \
+               __asm__ ("multiplu %0,%1,%2" \
+               : "=r" ((USItype)(xl)) \
+               : "r" (__m0), \
+                       "r" (__m1)); \
+               __asm__ ("multmu %0,%1,%2" \
+               : "=r" ((USItype)(xh)) \
+               : "r" (__m0), \
+                       "r" (__m1)); \
+} while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       __asm__ ("dividu %0,%3,%4" \
+       : "=r" ((USItype)(q)), \
+               "=q" ((USItype)(r)) \
+       : "1" ((USItype)(n1)), \
+               "r" ((USItype)(n0)), \
+               "r" ((USItype)(d)))
+
+#define count_leading_zeros(count, x) \
+       __asm__ ("clz %0,%1" \
+       : "=r" ((USItype)(count)) \
+       : "r" ((USItype)(x)))
+#define COUNT_LEADING_ZEROS_0 32
+#endif /* __a29k__ */
+
+#if defined(__alpha) && W_TYPE_SIZE == 64
+#define umul_ppmm(ph, pl, m0, m1) \
+do { \
+               UDItype __m0 = (m0), __m1 = (m1); \
+               __asm__ ("umulh %r1,%2,%0" \
+               : "=r" ((UDItype) ph) \
+               : "%rJ" (__m0), \
+                       "rI" (__m1)); \
+               (pl) = __m0 * __m1; \
+       } while (0)
+#define UMUL_TIME 46
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+do { UDItype __r; \
+       (q) = __udiv_qrnnd(&__r, (n1), (n0), (d)); \
+       (r) = __r; \
+} while (0)
+extern UDItype __udiv_qrnnd();
+#define UDIV_TIME 220
+#endif /* LONGLONG_STANDALONE */
+#endif /* __alpha */
+
+/***************************************
+       **************  ARM  ******************
+       ***************************************/
+#if defined(__arm__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("adds %1, %4, %5\n" \
+               "adc  %0, %2, %3" \
+       : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+       : "%r" ((USItype)(ah)), \
+               "rI" ((USItype)(bh)), \
+               "%r" ((USItype)(al)), \
+               "rI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subs %1, %4, %5\n" \
+               "sbc  %0, %2, %3" \
+       : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+       : "r" ((USItype)(ah)), \
+               "rI" ((USItype)(bh)), \
+               "r" ((USItype)(al)), \
+               "rI" ((USItype)(bl)))
+#if defined __ARM_ARCH_2__ || defined __ARM_ARCH_3__
+#define umul_ppmm(xh, xl, a, b) \
+       __asm__ ("%@ Inlined umul_ppmm\n" \
+               "mov    %|r0, %2, lsr #16               @ AAAA\n" \
+               "mov    %|r2, %3, lsr #16               @ BBBB\n" \
+               "bic    %|r1, %2, %|r0, lsl #16         @ aaaa\n" \
+               "bic    %0, %3, %|r2, lsl #16           @ bbbb\n" \
+               "mul    %1, %|r1, %|r2                  @ aaaa * BBBB\n" \
+               "mul    %|r2, %|r0, %|r2                @ AAAA * BBBB\n" \
+               "mul    %|r1, %0, %|r1                  @ aaaa * bbbb\n" \
+               "mul    %0, %|r0, %0                    @ AAAA * bbbb\n" \
+               "adds   %|r0, %1, %0                    @ central sum\n" \
+               "addcs  %|r2, %|r2, #65536\n" \
+               "adds   %1, %|r1, %|r0, lsl #16\n" \
+               "adc    %0, %|r2, %|r0, lsr #16" \
+       : "=&r" ((USItype)(xh)), \
+               "=r" ((USItype)(xl)) \
+       : "r" ((USItype)(a)), \
+               "r" ((USItype)(b)) \
+       : "r0", "r1", "r2")
+#else
+#define umul_ppmm(xh, xl, a, b) \
+       __asm__ ("%@ Inlined umul_ppmm\n" \
+               "umull %r1, %r0, %r2, %r3" \
+       : "=&r" ((USItype)(xh)), \
+                       "=r" ((USItype)(xl)) \
+       : "r" ((USItype)(a)), \
+                       "r" ((USItype)(b)) \
+       : "r0", "r1")
+#endif
+#define UMUL_TIME 20
+#define UDIV_TIME 100
+#endif /* __arm__ */
+
+/***************************************
+       **************  CLIPPER  **************
+       ***************************************/
+#if defined(__clipper__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+       ({union {UDItype __ll; \
+               struct {USItype __l, __h; } __i; \
+       } __xx; \
+       __asm__ ("mulwux %2,%0" \
+       : "=r" (__xx.__ll) \
+       : "%0" ((USItype)(u)), \
+               "r" ((USItype)(v))); \
+       (w1) = __xx.__i.__h; (w0) = __xx.__i.__l; })
+#define smul_ppmm(w1, w0, u, v) \
+       ({union {DItype __ll; \
+               struct {SItype __l, __h; } __i; \
+       } __xx; \
+       __asm__ ("mulwx %2,%0" \
+       : "=r" (__xx.__ll) \
+       : "%0" ((SItype)(u)), \
+               "r" ((SItype)(v))); \
+       (w1) = __xx.__i.__h; (w0) = __xx.__i.__l; })
+#define __umulsidi3(u, v) \
+       ({UDItype __w; \
+       __asm__ ("mulwux %2,%0" \
+       : "=r" (__w) \
+       : "%0" ((USItype)(u)), \
+               "r" ((USItype)(v))); \
+       __w; })
+#endif /* __clipper__ */
+
+/***************************************
+       **************  GMICRO  ***************
+       ***************************************/
+#if defined(__gmicro__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("add.w %5,%1\n" \
+               "addx %3,%0" \
+       : "=g" ((USItype)(sh)), \
+               "=&g" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+               "g" ((USItype)(bh)), \
+               "%1" ((USItype)(al)), \
+               "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("sub.w %5,%1\n" \
+               "subx %3,%0" \
+       : "=g" ((USItype)(sh)), \
+               "=&g" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+               "g" ((USItype)(bh)), \
+               "1" ((USItype)(al)), \
+               "g" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+       __asm__ ("mulx %3,%0,%1" \
+       : "=g" ((USItype)(ph)), \
+               "=r" ((USItype)(pl)) \
+       : "%0" ((USItype)(m0)), \
+               "g" ((USItype)(m1)))
+#define udiv_qrnnd(q, r, nh, nl, d) \
+       __asm__ ("divx %4,%0,%1" \
+       : "=g" ((USItype)(q)), \
+               "=r" ((USItype)(r)) \
+       : "1" ((USItype)(nh)), \
+               "0" ((USItype)(nl)), \
+               "g" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+       __asm__ ("bsch/1 %1,%0" \
+       : "=g" (count) \
+       : "g" ((USItype)(x)), \
+            "0" ((USItype)0))
+#endif
+
+/***************************************
+       **************  HPPA  *****************
+       ***************************************/
+#if defined(__hppa) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("add %4,%5,%1\n" \
+                  "addc %2,%3,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "%rM" ((USItype)(ah)), \
+            "rM" ((USItype)(bh)), \
+            "%rM" ((USItype)(al)), \
+            "rM" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("sub %4,%5,%1\n" \
+          "subb %2,%3,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "rM" ((USItype)(ah)), \
+            "rM" ((USItype)(bh)), \
+            "rM" ((USItype)(al)), \
+            "rM" ((USItype)(bl)))
+#if defined(_PA_RISC1_1)
+#define umul_ppmm(wh, wl, u, v) \
+do { \
+       union {UDItype __ll; \
+       struct {USItype __h, __l; } __i; \
+       } __xx; \
+       __asm__ ("xmpyu %1,%2,%0" \
+       : "=*f" (__xx.__ll) \
+       : "*f" ((USItype)(u)), \
+              "*f" ((USItype)(v))); \
+       (wh) = __xx.__i.__h; \
+       (wl) = __xx.__i.__l; \
+} while (0)
+#define UMUL_TIME 8
+#define UDIV_TIME 60
+#else
+#define UMUL_TIME 40
+#define UDIV_TIME 80
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+do { USItype __r; \
+       (q) = __udiv_qrnnd(&__r, (n1), (n0), (d)); \
+       (r) = __r; \
+} while (0)
+extern USItype __udiv_qrnnd();
+#endif /* LONGLONG_STANDALONE */
+#define count_leading_zeros(count, x) \
+do { \
+       USItype __tmp; \
+       __asm__ ( \
+       "ldi             1,%0\n" \
+       "extru,=        %1,15,16,%%r0  ; Bits 31..16 zero?\n" \
+       "extru,tr       %1,15,16,%1    ; No.  Shift down, skip add.\n" \
+       "ldo            16(%0),%0      ; Yes.   Perform add.\n" \
+       "extru,=        %1,23,8,%%r0   ; Bits 15..8 zero?\n" \
+       "extru,tr       %1,23,8,%1     ; No.  Shift down, skip add.\n" \
+       "ldo            8(%0),%0       ; Yes.   Perform add.\n" \
+       "extru,=        %1,27,4,%%r0   ; Bits 7..4 zero?\n" \
+       "extru,tr       %1,27,4,%1     ; No.  Shift down, skip add.\n" \
+       "ldo            4(%0),%0       ; Yes.   Perform add.\n" \
+       "extru,=        %1,29,2,%%r0   ; Bits 3..2 zero?\n" \
+       "extru,tr       %1,29,2,%1     ; No.  Shift down, skip add.\n" \
+       "ldo            2(%0),%0       ; Yes.   Perform add.\n" \
+       "extru          %1,30,1,%1     ; Extract bit 1.\n" \
+       "sub            %0,%1,%0       ; Subtract it.              " \
+       : "=r" (count), "=r" (__tmp) : "1" (x)); \
+} while (0)
+#endif /* hppa */
+
+/***************************************
+       **************  I370  *****************
+       ***************************************/
+#if (defined(__i370__) || defined(__mvs__)) && W_TYPE_SIZE == 32
+#define umul_ppmm(xh, xl, m0, m1) \
+do { \
+       union {UDItype __ll; \
+          struct {USItype __h, __l; } __i; \
+       } __xx; \
+       USItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ("mr %0,%3" \
+       : "=r" (__xx.__i.__h), \
+              "=r" (__xx.__i.__l) \
+       : "%1" (__m0), \
+              "r" (__m1)); \
+       (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+       (xh) += ((((SItype) __m0 >> 31) & __m1) \
+            + (((SItype) __m1 >> 31) & __m0)); \
+} while (0)
+#define smul_ppmm(xh, xl, m0, m1) \
+do { \
+       union {DItype __ll; \
+          struct {USItype __h, __l; } __i; \
+       } __xx; \
+       __asm__ ("mr %0,%3" \
+       : "=r" (__xx.__i.__h), \
+              "=r" (__xx.__i.__l) \
+       : "%1" (m0), \
+              "r" (m1)); \
+       (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+} while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+do { \
+       union {DItype __ll; \
+          struct {USItype __h, __l; } __i; \
+       } __xx; \
+       __xx.__i.__h = n1; __xx.__i.__l = n0; \
+       __asm__ ("dr %0,%2" \
+       : "=r" (__xx.__ll) \
+       : "0" (__xx.__ll), "r" (d)); \
+       (q) = __xx.__i.__l; (r) = __xx.__i.__h; \
+} while (0)
+#endif
+
+/***************************************
+       **************  I386  *****************
+       ***************************************/
+#undef __i386__
+#if (defined(__i386__) || defined(__i486__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("addl %5,%1\n" \
+          "adcl %3,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+            "g" ((USItype)(bh)), \
+            "%1" ((USItype)(al)), \
+            "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subl %5,%1\n" \
+          "sbbl %3,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+            "g" ((USItype)(bh)), \
+            "1" ((USItype)(al)), \
+            "g" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("mull %3" \
+       : "=a" ((USItype)(w0)), \
+            "=d" ((USItype)(w1)) \
+       : "%0" ((USItype)(u)), \
+            "rm" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       __asm__ ("divl %4" \
+       : "=a" ((USItype)(q)), \
+            "=d" ((USItype)(r)) \
+       : "0" ((USItype)(n0)), \
+            "1" ((USItype)(n1)), \
+            "rm" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+do { \
+       USItype __cbtmp; \
+       __asm__ ("bsrl %1,%0" \
+       : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
+       (count) = __cbtmp ^ 31; \
+} while (0)
+#define count_trailing_zeros(count, x) \
+       __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x)))
+#ifndef UMUL_TIME
+#define UMUL_TIME 40
+#endif
+#ifndef UDIV_TIME
+#define UDIV_TIME 40
+#endif
+#endif /* 80x86 */
+
+/***************************************
+       **************  I860  *****************
+       ***************************************/
+#if defined(__i860__) && W_TYPE_SIZE == 32
+#define rshift_rhlc(r, h, l, c) \
+       __asm__ ("shr %3,r0,r0\n" \
+       "shrd %1,%2,%0" \
+          "=r" (r) : "r" (h), "r" (l), "rn" (c))
+#endif /* i860 */
+
+/***************************************
+       **************  I960  *****************
+       ***************************************/
+#if defined(__i960__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("cmpo 1,0\n" \
+       "addc %5,%4,%1\n" \
+       "addc %3,%2,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "%dI" ((USItype)(ah)), \
+            "dI" ((USItype)(bh)), \
+            "%dI" ((USItype)(al)), \
+            "dI" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("cmpo 0,0\n" \
+       "subc %5,%4,%1\n" \
+       "subc %3,%2,%0" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "dI" ((USItype)(ah)), \
+            "dI" ((USItype)(bh)), \
+            "dI" ((USItype)(al)), \
+            "dI" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+       ({union {UDItype __ll; \
+          struct {USItype __l, __h; } __i; \
+       } __xx; \
+       __asm__ ("emul        %2,%1,%0" \
+       : "=d" (__xx.__ll) \
+       : "%dI" ((USItype)(u)), \
+            "dI" ((USItype)(v))); \
+       (w1) = __xx.__i.__h; (w0) = __xx.__i.__l; })
+#define __umulsidi3(u, v) \
+       ({UDItype __w; \
+       __asm__ ("emul      %2,%1,%0" \
+       : "=d" (__w) \
+       : "%dI" ((USItype)(u)), \
+              "dI" ((USItype)(v))); \
+       __w; })
+#define udiv_qrnnd(q, r, nh, nl, d) \
+do { \
+       union {UDItype __ll; \
+          struct {USItype __l, __h; } __i; \
+       } __nn; \
+       __nn.__i.__h = (nh); __nn.__i.__l = (nl); \
+       __asm__ ("ediv %d,%n,%0" \
+       : "=d" (__rq.__ll) \
+       : "dI" (__nn.__ll), \
+            "dI" ((USItype)(d))); \
+       (r) = __rq.__i.__l; (q) = __rq.__i.__h; \
+} while (0)
+#define count_leading_zeros(count, x) \
+do { \
+       USItype __cbtmp; \
+       __asm__ ("scanbit %1,%0" \
+       : "=r" (__cbtmp) \
+       : "r" ((USItype)(x))); \
+       (count) = __cbtmp ^ 31; \
+} while (0)
+#define COUNT_LEADING_ZEROS_0 (-32)    /* sic */
+#if defined(__i960mx)          /* what is the proper symbol to test??? */
+#define rshift_rhlc(r, h, l, c) \
+do { \
+       union {UDItype __ll; \
+          struct {USItype __l, __h; } __i; \
+       } __nn; \
+       __nn.__i.__h = (h); __nn.__i.__l = (l); \
+       __asm__ ("shre %2,%1,%0" \
+       : "=d" (r) : "dI" (__nn.__ll), "dI" (c)); \
+}
+#endif /* i960mx */
+#endif /* i960 */
+
+/***************************************
+       **************  68000   ****************
+       ***************************************/
+#if (defined(__mc68000__) || defined(__mc68020__) || defined(__NeXT__) || defined(mc68020)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("add%.l %5,%1\n" \
+          "addx%.l %3,%0" \
+       : "=d" ((USItype)(sh)), \
+            "=&d" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+            "d" ((USItype)(bh)), \
+            "%1" ((USItype)(al)), \
+            "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("sub%.l %5,%1\n" \
+          "subx%.l %3,%0" \
+       : "=d" ((USItype)(sh)), \
+            "=&d" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+            "d" ((USItype)(bh)), \
+            "1" ((USItype)(al)), \
+            "g" ((USItype)(bl)))
+#if (defined(__mc68020__) || defined(__NeXT__) || defined(mc68020))
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("mulu%.l %3,%1:%0" \
+       : "=d" ((USItype)(w0)), \
+            "=d" ((USItype)(w1)) \
+       : "%0" ((USItype)(u)), \
+            "dmi" ((USItype)(v)))
+#define UMUL_TIME 45
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       __asm__ ("divu%.l %4,%1:%0" \
+       : "=d" ((USItype)(q)), \
+            "=d" ((USItype)(r)) \
+       : "0" ((USItype)(n0)), \
+            "1" ((USItype)(n1)), \
+            "dmi" ((USItype)(d)))
+#define UDIV_TIME 90
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+       __asm__ ("divs%.l %4,%1:%0" \
+       : "=d" ((USItype)(q)), \
+            "=d" ((USItype)(r)) \
+       : "0" ((USItype)(n0)), \
+            "1" ((USItype)(n1)), \
+            "dmi" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+       __asm__ ("bfffo %1{%b2:%b2},%0" \
+       : "=d" ((USItype)(count)) \
+       : "od" ((USItype)(x)), "n" (0))
+#define COUNT_LEADING_ZEROS_0 32
+#else /* not mc68020 */
+#define umul_ppmm(xh, xl, a, b) \
+do { USItype __umul_tmp1, __umul_tmp2; \
+       __asm__ ("| Inlined umul_ppmm\n" \
+       "move%.l %5,%3\n" \
+       "move%.l %2,%0\n" \
+       "move%.w %3,%1\n" \
+       "swap   %3\n" \
+       "swap   %0\n" \
+       "mulu   %2,%1\n" \
+       "mulu   %3,%0\n" \
+       "mulu   %2,%3\n" \
+       "swap   %2\n" \
+       "mulu   %5,%2\n" \
+       "add%.l %3,%2\n" \
+       "jcc    1f\n" \
+       "add%.l %#0x10000,%0\n" \
+       "1:     move%.l %2,%3\n" \
+       "clr%.w %2\n" \
+       "swap   %2\n" \
+       "swap   %3\n" \
+       "clr%.w %3\n" \
+       "add%.l %3,%1\n" \
+       "addx%.l %2,%0\n" \
+       "| End inlined umul_ppmm" \
+       : "=&d" ((USItype)(xh)), "=&d" ((USItype)(xl)), \
+               "=d" (__umul_tmp1), "=&d" (__umul_tmp2) \
+       : "%2" ((USItype)(a)), "d" ((USItype)(b))); \
+} while (0)
+#define UMUL_TIME 100
+#define UDIV_TIME 400
+#endif /* not mc68020 */
+#endif /* mc68000 */
+
+/***************************************
+       **************  88000   ****************
+       ***************************************/
+#if defined(__m88000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("addu.co %1,%r4,%r5\n" \
+          "addu.ci %0,%r2,%r3" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "%rJ" ((USItype)(ah)), \
+            "rJ" ((USItype)(bh)), \
+            "%rJ" ((USItype)(al)), \
+            "rJ" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subu.co %1,%r4,%r5\n" \
+          "subu.ci %0,%r2,%r3" \
+       : "=r" ((USItype)(sh)), \
+            "=&r" ((USItype)(sl)) \
+       : "rJ" ((USItype)(ah)), \
+            "rJ" ((USItype)(bh)), \
+            "rJ" ((USItype)(al)), \
+            "rJ" ((USItype)(bl)))
+#define count_leading_zeros(count, x) \
+do { \
+       USItype __cbtmp; \
+       __asm__ ("ff1 %0,%1" \
+       : "=r" (__cbtmp) \
+       : "r" ((USItype)(x))); \
+       (count) = __cbtmp ^ 31; \
+} while (0)
+#define COUNT_LEADING_ZEROS_0 63       /* sic */
+#if defined(__m88110__)
+#define umul_ppmm(wh, wl, u, v) \
+do { \
+       union {UDItype __ll; \
+          struct {USItype __h, __l; } __i; \
+       } __x; \
+       __asm__ ("mulu.d %0,%1,%2" : "=r" (__x.__ll) : "r" (u), "r" (v)); \
+       (wh) = __x.__i.__h; \
+       (wl) = __x.__i.__l; \
+} while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       ({union {UDItype __ll; \
+          struct {USItype __h, __l; } __i; \
+       } __x, __q; \
+       __x.__i.__h = (n1); __x.__i.__l = (n0); \
+       __asm__ ("divu.d %0,%1,%2" \
+       : "=r" (__q.__ll) : "r" (__x.__ll), "r" (d)); \
+       (r) = (n0) - __q.__l * (d); (q) = __q.__l; })
+#define UMUL_TIME 5
+#define UDIV_TIME 25
+#else
+#define UMUL_TIME 17
+#define UDIV_TIME 150
+#endif /* __m88110__ */
+#endif /* __m88000__ */
+
+/***************************************
+       **************  MIPS  *****************
+       ***************************************/
+#if defined(__mips__) && W_TYPE_SIZE == 32
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("multu %2,%3" \
+       : "=l" ((USItype)(w0)), \
+            "=h" ((USItype)(w1)) \
+       : "d" ((USItype)(u)), \
+            "d" ((USItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("multu %2,%3\n" \
+          "mflo %0\n" \
+          "mfhi %1" \
+       : "=d" ((USItype)(w0)), \
+            "=d" ((USItype)(w1)) \
+       : "d" ((USItype)(u)), \
+            "d" ((USItype)(v)))
+#endif
+#define UMUL_TIME 10
+#define UDIV_TIME 100
+#endif /* __mips__ */
+
+/***************************************
+       **************  MIPS/64  **************
+       ***************************************/
+#if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("dmultu %2,%3" \
+       : "=l" ((UDItype)(w0)), \
+            "=h" ((UDItype)(w1)) \
+       : "d" ((UDItype)(u)), \
+            "d" ((UDItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("dmultu %2,%3\n" \
+          "mflo %0\n" \
+          "mfhi %1" \
+       : "=d" ((UDItype)(w0)), \
+            "=d" ((UDItype)(w1)) \
+       : "d" ((UDItype)(u)), \
+            "d" ((UDItype)(v)))
+#endif
+#define UMUL_TIME 20
+#define UDIV_TIME 140
+#endif /* __mips__ */
+
+/***************************************
+       **************  32000   ****************
+       ***************************************/
+#if defined(__ns32000__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+       ({union {UDItype __ll; \
+          struct {USItype __l, __h; } __i; \
+       } __xx; \
+       __asm__ ("meid %2,%0" \
+       : "=g" (__xx.__ll) \
+       : "%0" ((USItype)(u)), \
+            "g" ((USItype)(v))); \
+       (w1) = __xx.__i.__h; (w0) = __xx.__i.__l; })
+#define __umulsidi3(u, v) \
+       ({UDItype __w; \
+       __asm__ ("meid %2,%0" \
+       : "=g" (__w) \
+       : "%0" ((USItype)(u)), \
+              "g" ((USItype)(v))); \
+       __w; })
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       ({union {UDItype __ll; \
+          struct {USItype __l, __h; } __i; \
+       } __xx; \
+       __xx.__i.__h = (n1); __xx.__i.__l = (n0); \
+       __asm__ ("deid %2,%0" \
+       : "=g" (__xx.__ll) \
+       : "0" (__xx.__ll), \
+            "g" ((USItype)(d))); \
+       (r) = __xx.__i.__l; (q) = __xx.__i.__h; })
+#define count_trailing_zeros(count, x) \
+do { \
+       __asm__("ffsd      %2,%0" \
+       : "=r"((USItype) (count)) \
+       : "0"((USItype) 0), "r"((USItype) (x))); \
+       } while (0)
+#endif /* __ns32000__ */
+
+/***************************************
+       **************  PPC  ******************
+       ***************************************/
+#if (defined(_ARCH_PPC) || defined(_IBMR2)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+do { \
+       if (__builtin_constant_p(bh) && (bh) == 0) \
+               __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "%r" ((USItype)(ah)), \
+               "%r" ((USItype)(al)), \
+               "rI" ((USItype)(bl))); \
+       else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
+               __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "%r" ((USItype)(ah)), \
+               "%r" ((USItype)(al)), \
+               "rI" ((USItype)(bl))); \
+       else \
+               __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "%r" ((USItype)(ah)), \
+               "r" ((USItype)(bh)), \
+               "%r" ((USItype)(al)), \
+               "rI" ((USItype)(bl))); \
+} while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+do { \
+       if (__builtin_constant_p(ah) && (ah) == 0) \
+               __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "r" ((USItype)(bh)), \
+               "rI" ((USItype)(al)), \
+               "r" ((USItype)(bl))); \
+       else if (__builtin_constant_p(ah) && (ah) == ~(USItype) 0) \
+               __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "r" ((USItype)(bh)), \
+               "rI" ((USItype)(al)), \
+               "r" ((USItype)(bl))); \
+       else if (__builtin_constant_p(bh) && (bh) == 0) \
+               __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "r" ((USItype)(ah)), \
+               "rI" ((USItype)(al)), \
+               "r" ((USItype)(bl))); \
+       else if (__builtin_constant_p(bh) && (bh) == ~(USItype) 0) \
+               __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "r" ((USItype)(ah)), \
+               "rI" ((USItype)(al)), \
+               "r" ((USItype)(bl))); \
+       else \
+               __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
+               : "=r" ((USItype)(sh)), \
+               "=&r" ((USItype)(sl)) \
+               : "r" ((USItype)(ah)), \
+               "r" ((USItype)(bh)), \
+               "rI" ((USItype)(al)), \
+               "r" ((USItype)(bl))); \
+} while (0)
+#define count_leading_zeros(count, x) \
+       __asm__ ("{cntlz|cntlzw} %0,%1" \
+       : "=r" ((USItype)(count)) \
+       : "r" ((USItype)(x)))
+#define COUNT_LEADING_ZEROS_0 32
+#if defined(_ARCH_PPC)
+#define umul_ppmm(ph, pl, m0, m1) \
+do { \
+       USItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ("mulhwu %0,%1,%2" \
+       : "=r" ((USItype) ph) \
+       : "%r" (__m0), \
+       "r" (__m1)); \
+       (pl) = __m0 * __m1; \
+} while (0)
+#define UMUL_TIME 15
+#define smul_ppmm(ph, pl, m0, m1) \
+do { \
+       SItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ("mulhw %0,%1,%2" \
+       : "=r" ((SItype) ph) \
+       : "%r" (__m0), \
+       "r" (__m1)); \
+       (pl) = __m0 * __m1; \
+} while (0)
+#define SMUL_TIME 14
+#define UDIV_TIME 120
+#else
+#define umul_ppmm(xh, xl, m0, m1) \
+do { \
+       USItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ("mul %0,%2,%3" \
+       : "=r" ((USItype)(xh)), \
+       "=q" ((USItype)(xl)) \
+       : "r" (__m0), \
+       "r" (__m1)); \
+       (xh) += ((((SItype) __m0 >> 31) & __m1) \
+       + (((SItype) __m1 >> 31) & __m0)); \
+} while (0)
+#define UMUL_TIME 8
+#define smul_ppmm(xh, xl, m0, m1) \
+       __asm__ ("mul %0,%2,%3" \
+       : "=r" ((SItype)(xh)), \
+       "=q" ((SItype)(xl)) \
+       : "r" (m0), \
+       "r" (m1))
+#define SMUL_TIME 4
+#define sdiv_qrnnd(q, r, nh, nl, d) \
+       __asm__ ("div %0,%2,%4" \
+       : "=r" ((SItype)(q)), "=q" ((SItype)(r)) \
+       : "r" ((SItype)(nh)), "1" ((SItype)(nl)), "r" ((SItype)(d)))
+#define UDIV_TIME 100
+#endif
+#endif /* Power architecture variants.  */
+
+/***************************************
+       **************  PYR  ******************
+       ***************************************/
+#if defined(__pyr__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("addw        %5,%1\n" \
+       "addwc  %3,%0" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+       "g" ((USItype)(bh)), \
+       "%1" ((USItype)(al)), \
+       "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subw        %5,%1\n" \
+       "subwb  %3,%0" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+       "g" ((USItype)(bh)), \
+       "1" ((USItype)(al)), \
+       "g" ((USItype)(bl)))
+       /* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP.  */
+#define umul_ppmm(w1, w0, u, v) \
+       ({union {UDItype __ll; \
+       struct {USItype __h, __l; } __i; \
+       } __xx; \
+       __asm__ ("movw %1,%R0\n" \
+       "uemul %2,%0" \
+       : "=&r" (__xx.__ll) \
+       : "g" ((USItype) (u)), \
+       "g" ((USItype)(v))); \
+       (w1) = __xx.__i.__h; (w0) = __xx.__i.__l; })
+#endif /* __pyr__ */
+
+/***************************************
+       **************  RT/ROMP  **************
+       ***************************************/
+#if defined(__ibm032__) /* RT/ROMP */  && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("a %1,%5\n" \
+       "ae %0,%3" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+       "r" ((USItype)(bh)), \
+       "%1" ((USItype)(al)), \
+       "r" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("s %1,%5\n" \
+       "se %0,%3" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+       "r" ((USItype)(bh)), \
+       "1" ((USItype)(al)), \
+       "r" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+do { \
+       USItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ( \
+       "s       r2,r2\n" \
+       "mts    r10,%2\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "m      r2,%3\n" \
+       "cas    %0,r2,r0\n" \
+       "mfs    r10,%1" \
+       : "=r" ((USItype)(ph)), \
+       "=r" ((USItype)(pl)) \
+       : "%r" (__m0), \
+       "r" (__m1) \
+       : "r2"); \
+       (ph) += ((((SItype) __m0 >> 31) & __m1) \
+       + (((SItype) __m1 >> 31) & __m0)); \
+} while (0)
+#define UMUL_TIME 20
+#define UDIV_TIME 200
+#define count_leading_zeros(count, x) \
+do { \
+       if ((x) >= 0x10000) \
+               __asm__ ("clz     %0,%1" \
+               : "=r" ((USItype)(count)) \
+               : "r" ((USItype)(x) >> 16)); \
+       else { \
+               __asm__ ("clz   %0,%1" \
+               : "=r" ((USItype)(count)) \
+               : "r" ((USItype)(x))); \
+               (count) += 16; \
+       } \
+} while (0)
+#endif /* RT/ROMP */
+
+/***************************************
+       **************  SH2  ******************
+       ***************************************/
+#if (defined(__sh2__) || defined(__sh3__) || defined(__SH4__)) \
+       && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ( \
+       "dmulu.l %2,%3\n" \
+       "sts    macl,%1\n" \
+       "sts    mach,%0" \
+       : "=r" ((USItype)(w1)), \
+       "=r" ((USItype)(w0)) \
+       : "r" ((USItype)(u)), \
+       "r" ((USItype)(v)) \
+       : "macl", "mach")
+#define UMUL_TIME 5
+#endif
+
+/***************************************
+       **************  SPARC   ****************
+       ***************************************/
+#if defined(__sparc__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("addcc %r4,%5,%1\n" \
+       "addx %r2,%3,%0" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "%rJ" ((USItype)(ah)), \
+       "rI" ((USItype)(bh)), \
+       "%rJ" ((USItype)(al)), \
+       "rI" ((USItype)(bl)) \
+       __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subcc %r4,%5,%1\n" \
+       "subx %r2,%3,%0" \
+       : "=r" ((USItype)(sh)), \
+       "=&r" ((USItype)(sl)) \
+       : "rJ" ((USItype)(ah)), \
+       "rI" ((USItype)(bh)), \
+       "rJ" ((USItype)(al)), \
+       "rI" ((USItype)(bl)) \
+       __CLOBBER_CC)
+#if defined(__sparc_v8__)
+/* Don't match immediate range because, 1) it is not often useful,
+       2) the 'I' flag thinks of the range as a 13 bit signed interval,
+       while we want to match a 13 bit interval, sign extended to 32 bits,
+       but INTERPRETED AS UNSIGNED.  */
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+       : "=r" ((USItype)(w1)), \
+       "=r" ((USItype)(w0)) \
+       : "r" ((USItype)(u)), \
+       "r" ((USItype)(v)))
+#define UMUL_TIME 5
+#ifndef SUPERSPARC             /* SuperSPARC's udiv only handles 53 bit dividends */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+do { \
+       USItype __q; \
+       __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0" \
+       : "=r" ((USItype)(__q)) \
+       : "r" ((USItype)(n1)), \
+       "r" ((USItype)(n0)), \
+       "r" ((USItype)(d))); \
+       (r) = (n0) - __q * (d); \
+       (q) = __q; \
+} while (0)
+#define UDIV_TIME 25
+#endif /* SUPERSPARC */
+#else /* ! __sparc_v8__ */
+#if defined(__sparclite__)
+/* This has hardware multiply but not divide.  It also has two additional
+       instructions scan (ffs from high bit) and divscc.  */
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("umul %2,%3,%1;rd %%y,%0" \
+       : "=r" ((USItype)(w1)), \
+       "=r" ((USItype)(w0)) \
+       : "r" ((USItype)(u)), \
+       "r" ((USItype)(v)))
+#define UMUL_TIME 5
+#define udiv_qrnnd(q, r, n1, n0, d) \
+       __asm__ ("! Inlined udiv_qrnnd\n" \
+       "wr     %%g0,%2,%%y     ! Not a delayed write for sparclite\n" \
+       "tst    %%g0\n" \
+       "divscc %3,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%%g1\n" \
+       "divscc %%g1,%4,%0\n" \
+       "rd     %%y,%1\n" \
+       "bl,a 1f\n" \
+       "add    %1,%4,%1\n" \
+       "1:     ! End of inline udiv_qrnnd" \
+       : "=r" ((USItype)(q)), \
+       "=r" ((USItype)(r)) \
+       : "r" ((USItype)(n1)), \
+       "r" ((USItype)(n0)), \
+       "rI" ((USItype)(d)) \
+       : "%g1" __AND_CLOBBER_CC)
+#define UDIV_TIME 37
+#define count_leading_zeros(count, x) \
+       __asm__ ("scan %1,0,%0" \
+       : "=r" ((USItype)(x)) \
+       : "r" ((USItype)(count)))
+/* Early sparclites return 63 for an argument of 0, but they warn that future
+       implementations might change this.  Therefore, leave COUNT_LEADING_ZEROS_0
+       undefined.  */
+#endif /* __sparclite__ */
+#endif /* __sparc_v8__ */
+       /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd.  */
+#ifndef umul_ppmm
+#define umul_ppmm(w1, w0, u, v) \
+       __asm__ ("! Inlined umul_ppmm\n" \
+       "wr     %%g0,%2,%%y     ! SPARC has 0-3 delay insn after a wr\n" \
+       "sra    %3,31,%%g2      ! Don't move this insn\n" \
+       "and    %2,%%g2,%%g2    ! Don't move this insn\n" \
+       "andcc  %%g0,0,%%g1     ! Don't move this insn\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,%3,%%g1\n" \
+       "mulscc %%g1,0,%%g1\n" \
+       "add    %%g1,%%g2,%0\n" \
+       "rd     %%y,%1" \
+       : "=r" ((USItype)(w1)), \
+       "=r" ((USItype)(w0)) \
+       : "%rI" ((USItype)(u)), \
+       "r" ((USItype)(v)) \
+       : "%g1", "%g2" __AND_CLOBBER_CC)
+#define UMUL_TIME 39           /* 39 instructions */
+#endif
+#ifndef udiv_qrnnd
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+do { USItype __r; \
+       (q) = __udiv_qrnnd(&__r, (n1), (n0), (d)); \
+       (r) = __r; \
+} while (0)
+       extern USItype __udiv_qrnnd();
+#define UDIV_TIME 140
+#endif /* LONGLONG_STANDALONE */
+#endif /* udiv_qrnnd */
+#endif /* __sparc__ */
+
+/***************************************
+       **************  VAX  ******************
+       ***************************************/
+#if defined(__vax__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("addl2 %5,%1\n" \
+       "adwc %3,%0" \
+       : "=g" ((USItype)(sh)), \
+       "=&g" ((USItype)(sl)) \
+       : "%0" ((USItype)(ah)), \
+       "g" ((USItype)(bh)), \
+       "%1" ((USItype)(al)), \
+       "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("subl2 %5,%1\n" \
+       "sbwc %3,%0" \
+       : "=g" ((USItype)(sh)), \
+       "=&g" ((USItype)(sl)) \
+       : "0" ((USItype)(ah)), \
+       "g" ((USItype)(bh)), \
+       "1" ((USItype)(al)), \
+       "g" ((USItype)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+do { \
+       union {UDItype __ll; \
+       struct {USItype __l, __h; } __i; \
+       } __xx; \
+       USItype __m0 = (m0), __m1 = (m1); \
+       __asm__ ("emul %1,%2,$0,%0" \
+       : "=g" (__xx.__ll) \
+       : "g" (__m0), \
+       "g" (__m1)); \
+       (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+       (xh) += ((((SItype) __m0 >> 31) & __m1) \
+       + (((SItype) __m1 >> 31) & __m0)); \
+} while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+do { \
+       union {DItype __ll; \
+       struct {SItype __l, __h; } __i; \
+       } __xx; \
+       __xx.__i.__h = n1; __xx.__i.__l = n0; \
+       __asm__ ("ediv %3,%2,%0,%1" \
+       : "=g" (q), "=g" (r) \
+       : "g" (__xx.__ll), "g" (d)); \
+} while (0)
+#endif /* __vax__ */
+
+/***************************************
+       **************  Z8000   ****************
+       ***************************************/
+#if defined(__z8000__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+       __asm__ ("add %H1,%H5\n\tadc  %H0,%H3" \
+       : "=r" ((unsigned int)(sh)), \
+       "=&r" ((unsigned int)(sl)) \
+       : "%0" ((unsigned int)(ah)), \
+       "r" ((unsigned int)(bh)), \
+       "%1" ((unsigned int)(al)), \
+       "rQR" ((unsigned int)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+       __asm__ ("sub %H1,%H5\n\tsbc  %H0,%H3" \
+       : "=r" ((unsigned int)(sh)), \
+       "=&r" ((unsigned int)(sl)) \
+       : "0" ((unsigned int)(ah)), \
+       "r" ((unsigned int)(bh)), \
+       "1" ((unsigned int)(al)), \
+       "rQR" ((unsigned int)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+do { \
+       union {long int __ll; \
+       struct {unsigned int __h, __l; } __i; \
+       } __xx; \
+       unsigned int __m0 = (m0), __m1 = (m1); \
+       __asm__ ("mult      %S0,%H3" \
+       : "=r" (__xx.__i.__h), \
+       "=r" (__xx.__i.__l) \
+       : "%1" (__m0), \
+       "rQR" (__m1)); \
+       (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \
+       (xh) += ((((signed int) __m0 >> 15) & __m1) \
+       + (((signed int) __m1 >> 15) & __m0)); \
+} while (0)
+#endif /* __z8000__ */
+
+#endif /* __GNUC__ */
+
+/***************************************
+       ***********  Generic Versions   ********
+       ***************************************/
+#if !defined(umul_ppmm) && defined(__umulsidi3)
+#define umul_ppmm(ph, pl, m0, m1) \
+{ \
+       UDWtype __ll = __umulsidi3(m0, m1); \
+       ph = (UWtype) (__ll >> W_TYPE_SIZE); \
+       pl = (UWtype) __ll; \
+}
+#endif
+
+#if !defined(__umulsidi3)
+#define __umulsidi3(u, v) \
+       ({UWtype __hi, __lo; \
+       umul_ppmm(__hi, __lo, u, v); \
+       ((UDWtype) __hi << W_TYPE_SIZE) | __lo; })
+#endif
+
+       /* If this machine has no inline assembler, use C macros.  */
+
+#if !defined(add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+do { \
+       UWtype __x; \
+       __x = (al) + (bl); \
+       (sh) = (ah) + (bh) + (__x < (al)); \
+       (sl) = __x; \
+} while (0)
+#endif
+
+#if !defined(sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+do { \
+       UWtype __x; \
+       __x = (al) - (bl); \
+       (sh) = (ah) - (bh) - (__x > (al)); \
+       (sl) = __x; \
+} while (0)
+#endif
+
+#if !defined(umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+do { \
+       UWtype __x0, __x1, __x2, __x3; \
+       UHWtype __ul, __vl, __uh, __vh; \
+       UWtype __u = (u), __v = (v); \
+       \
+       __ul = __ll_lowpart(__u); \
+       __uh = __ll_highpart(__u); \
+       __vl = __ll_lowpart(__v); \
+       __vh = __ll_highpart(__v); \
+       \
+       __x0 = (UWtype) __ul * __vl; \
+       __x1 = (UWtype) __ul * __vh; \
+       __x2 = (UWtype) __uh * __vl; \
+       __x3 = (UWtype) __uh * __vh; \
+       \
+       __x1 += __ll_highpart(__x0);/* this can't give carry */ \
+       __x1 += __x2;           /* but this indeed can */ \
+       if (__x1 < __x2)                /* did we get it? */ \
+       __x3 += __ll_B;         /* yes, add it in the proper pos. */ \
+       \
+       (w1) = __x3 + __ll_highpart(__x1); \
+       (w0) = (__ll_lowpart(__x1) << W_TYPE_SIZE/2) + __ll_lowpart(__x0); \
+} while (0)
+#endif
+
+#if !defined(umul_ppmm)
+#define smul_ppmm(w1, w0, u, v) \
+do { \
+       UWtype __w1; \
+       UWtype __m0 = (u), __m1 = (v); \
+       umul_ppmm(__w1, w0, __m0, __m1); \
+       (w1) = __w1 - (-(__m0 >> (W_TYPE_SIZE - 1)) & __m1) \
+       - (-(__m1 >> (W_TYPE_SIZE - 1)) & __m0); \
+} while (0)
+#endif
+
+       /* Define this unconditionally, so it can be used for debugging.  */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+do { \
+       UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \
+       __d1 = __ll_highpart(d); \
+       __d0 = __ll_lowpart(d); \
+       \
+       __r1 = (n1) % __d1; \
+       __q1 = (n1) / __d1; \
+       __m = (UWtype) __q1 * __d0; \
+       __r1 = __r1 * __ll_B | __ll_highpart(n0); \
+       if (__r1 < __m) { \
+               __q1--, __r1 += (d); \
+               if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */ \
+               if (__r1 < __m) \
+                       __q1--, __r1 += (d); \
+       } \
+       __r1 -= __m; \
+       \
+       __r0 = __r1 % __d1; \
+       __q0 = __r1 / __d1; \
+       __m = (UWtype) __q0 * __d0; \
+       __r0 = __r0 * __ll_B | __ll_lowpart(n0); \
+       if (__r0 < __m) { \
+               __q0--, __r0 += (d); \
+               if (__r0 >= (d)) \
+                       if (__r0 < __m) \
+                               __q0--, __r0 += (d); \
+       } \
+       __r0 -= __m; \
+       \
+       (q) = (UWtype) __q1 * __ll_B | __q0; \
+       (r) = __r0; \
+} while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+       __udiv_w_sdiv (defined in libgcc or elsewhere).  */
+#if !defined(udiv_qrnnd) && defined(sdiv_qrnnd)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+do { \
+       UWtype __r; \
+       (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d); \
+       (r) = __r; \
+} while (0)
+#endif
+
+       /* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c.  */
+#if !defined(udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#undef count_leading_zeros
+#if !defined(count_leading_zeros)
+       extern
+#ifdef __STDC__
+                       const
+#endif
+                       unsigned char __clz_tab[];
+#define count_leading_zeros(count, x) \
+do { \
+       UWtype __xr = (x); \
+       UWtype __a; \
+       \
+       if (W_TYPE_SIZE <= 32) { \
+               __a = __xr < ((UWtype) 1 << 2*__BITS4) \
+               ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \
+               : (__xr < ((UWtype) 1 << 3*__BITS4) ?  2*__BITS4 : 3*__BITS4); \
+       } \
+       else { \
+               for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \
+                       if (((__xr >> __a) & 0xff) != 0) \
+                               break; \
+       } \
+       \
+       (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
+} while (0)
+       /* This version gives a well-defined value for zero. */
+#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE
+#endif
+
+#if !defined(count_trailing_zeros)
+/* Define count_trailing_zeros using count_leading_zeros.  The latter might be
+       defined in asm, but if it is not, the C version above is good enough.  */
+#define count_trailing_zeros(count, x) \
+do { \
+       UWtype __ctz_x = (x); \
+       UWtype __ctz_c; \
+       count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \
+       (count) = W_TYPE_SIZE - 1 - __ctz_c; \
+} while (0)
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
diff --git a/lib/mpi/mpi-add.c b/lib/mpi/mpi-add.c
new file mode 100644 (file)
index 0000000..f56b9ba
--- /dev/null
@@ -0,0 +1,234 @@
+/* mpi-add.c  -  MPI functions
+ *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+
+/****************
+ * Add the unsigned integer V to the mpi-integer U and store the
+ * result in W. U and V may be the same.
+ */
+int mpi_add_ui(MPI w, const MPI u, unsigned long v)
+{
+       mpi_ptr_t wp, up;
+       mpi_size_t usize, wsize;
+       int usign, wsign;
+
+       usize = u->nlimbs;
+       usign = u->sign;
+       wsign = 0;
+
+       /* If not space for W (and possible carry), increase space.  */
+       wsize = usize + 1;
+       if (w->alloced < wsize)
+               if (mpi_resize(w, wsize) < 0)
+                       return -ENOMEM;
+
+       /* These must be after realloc (U may be the same as W).  */
+       up = u->d;
+       wp = w->d;
+
+       if (!usize) {           /* simple */
+               wp[0] = v;
+               wsize = v ? 1 : 0;
+       } else if (!usign) {    /* mpi is not negative */
+               mpi_limb_t cy;
+               cy = mpihelp_add_1(wp, up, usize, v);
+               wp[usize] = cy;
+               wsize = usize + cy;
+       } else {                /* The signs are different.  Need exact comparison to determine
+                                * which operand to subtract from which.  */
+               if (usize == 1 && up[0] < v) {
+                       wp[0] = v - up[0];
+                       wsize = 1;
+               } else {
+                       mpihelp_sub_1(wp, up, usize, v);
+                       /* Size can decrease with at most one limb. */
+                       wsize = usize - (wp[usize - 1] == 0);
+                       wsign = 1;
+               }
+       }
+
+       w->nlimbs = wsize;
+       w->sign = wsign;
+       return 0;
+}
+
+int mpi_add(MPI w, MPI u, MPI v)
+{
+       mpi_ptr_t wp, up, vp;
+       mpi_size_t usize, vsize, wsize;
+       int usign, vsign, wsign;
+
+       if (u->nlimbs < v->nlimbs) {    /* Swap U and V. */
+               usize = v->nlimbs;
+               usign = v->sign;
+               vsize = u->nlimbs;
+               vsign = u->sign;
+               wsize = usize + 1;
+               if (RESIZE_IF_NEEDED(w, wsize) < 0)
+                       return -ENOMEM;
+               /* These must be after realloc (u or v may be the same as w).  */
+               up = v->d;
+               vp = u->d;
+       } else {
+               usize = u->nlimbs;
+               usign = u->sign;
+               vsize = v->nlimbs;
+               vsign = v->sign;
+               wsize = usize + 1;
+               if (RESIZE_IF_NEEDED(w, wsize) < 0)
+                       return -ENOMEM;
+               /* These must be after realloc (u or v may be the same as w).  */
+               up = u->d;
+               vp = v->d;
+       }
+       wp = w->d;
+       wsign = 0;
+
+       if (!vsize) {           /* simple */
+               MPN_COPY(wp, up, usize);
+               wsize = usize;
+               wsign = usign;
+       } else if (usign != vsign) {    /* different sign */
+               /* This test is right since USIZE >= VSIZE */
+               if (usize != vsize) {
+                       mpihelp_sub(wp, up, usize, vp, vsize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       wsign = usign;
+               } else if (mpihelp_cmp(up, vp, usize) < 0) {
+                       mpihelp_sub_n(wp, vp, up, usize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       if (!usign)
+                               wsign = 1;
+               } else {
+                       mpihelp_sub_n(wp, up, vp, usize);
+                       wsize = usize;
+                       MPN_NORMALIZE(wp, wsize);
+                       if (usign)
+                               wsign = 1;
+               }
+       } else {                /* U and V have same sign. Add them. */
+               mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
+               wp[usize] = cy;
+               wsize = usize + cy;
+               if (usign)
+                       wsign = 1;
+       }
+
+       w->nlimbs = wsize;
+       w->sign = wsign;
+       return 0;
+}
+
+/****************
+ * Subtract the unsigned integer V from the mpi-integer U and store the
+ * result in W.
+ */
+int mpi_sub_ui(MPI w, MPI u, unsigned long v)
+{
+       mpi_ptr_t wp, up;
+       mpi_size_t usize, wsize;
+       int usign, wsign;
+
+       usize = u->nlimbs;
+       usign = u->sign;
+       wsign = 0;
+
+       /* If not space for W (and possible carry), increase space.  */
+       wsize = usize + 1;
+       if (w->alloced < wsize)
+               if (mpi_resize(w, wsize) < 0)
+                       return -ENOMEM;
+
+       /* These must be after realloc (U may be the same as W).  */
+       up = u->d;
+       wp = w->d;
+
+       if (!usize) {           /* simple */
+               wp[0] = v;
+               wsize = v ? 1 : 0;
+               wsign = 1;
+       } else if (usign) {     /* mpi and v are negative */
+               mpi_limb_t cy;
+               cy = mpihelp_add_1(wp, up, usize, v);
+               wp[usize] = cy;
+               wsize = usize + cy;
+       } else {                /* The signs are different.  Need exact comparison to determine
+                                * which operand to subtract from which.  */
+               if (usize == 1 && up[0] < v) {
+                       wp[0] = v - up[0];
+                       wsize = 1;
+                       wsign = 1;
+               } else {
+                       mpihelp_sub_1(wp, up, usize, v);
+                       /* Size can decrease with at most one limb. */
+                       wsize = usize - (wp[usize - 1] == 0);
+               }
+       }
+
+       w->nlimbs = wsize;
+       w->sign = wsign;
+       return 0;
+}
+
+int mpi_sub(MPI w, MPI u, MPI v)
+{
+       int rc;
+
+       if (w == v) {
+               MPI vv;
+               if (mpi_copy(&vv, v) < 0)
+                       return -ENOMEM;
+               vv->sign = !vv->sign;
+               rc = mpi_add(w, u, vv);
+               mpi_free(vv);
+       } else {
+               /* fixme: this is not thread-save (we temp. modify v) */
+               v->sign = !v->sign;
+               rc = mpi_add(w, u, v);
+               v->sign = !v->sign;
+       }
+       return rc;
+}
+
+int mpi_addm(MPI w, MPI u, MPI v, MPI m)
+{
+       if (mpi_add(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
+               return -ENOMEM;
+       return 0;
+}
+
+int mpi_subm(MPI w, MPI u, MPI v, MPI m)
+{
+       if (mpi_sub(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
+               return -ENOMEM;
+       return 0;
+}
diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c
new file mode 100644 (file)
index 0000000..854c9c6
--- /dev/null
@@ -0,0 +1,236 @@
+/* mpi-bit.c  -  MPI bit level fucntions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+#include "longlong.h"
+
+const unsigned char __clz_tab[] = {
+       0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+           5, 5, 5, 5, 5, 5, 5, 5,
+       6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+           6, 6, 6, 6, 6, 6, 6, 6,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+           7, 7, 7, 7, 7, 7, 7, 7,
+       7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+           7, 7, 7, 7, 7, 7, 7, 7,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+           8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+           8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+           8, 8, 8, 8, 8, 8, 8, 8,
+       8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+           8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+#define A_LIMB_1 ((mpi_limb_t) 1)
+
+/****************
+ * Sometimes we have MSL (most significant limbs) which are 0;
+ * this is for some reasons not good, so this function removes them.
+ */
+void mpi_normalize(MPI a)
+{
+       for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--)
+               ;
+}
+
+/****************
+ * Return the number of bits in A.
+ */
+unsigned mpi_get_nbits(MPI a)
+{
+       unsigned n;
+
+       mpi_normalize(a);
+
+       if (a->nlimbs) {
+               mpi_limb_t alimb = a->d[a->nlimbs - 1];
+               if (alimb)
+                       count_leading_zeros(n, alimb);
+               else
+                       n = BITS_PER_MPI_LIMB;
+               n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
+       } else
+               n = 0;
+       return n;
+}
+EXPORT_SYMBOL_GPL(mpi_get_nbits);
+
+/****************
+ * Test whether bit N is set.
+ */
+int mpi_test_bit(MPI a, unsigned n)
+{
+       unsigned limbno, bitno;
+       mpi_limb_t limb;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return 0;       /* too far left: this is a 0 */
+       limb = a->d[limbno];
+       return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
+}
+
+/****************
+ * Set bit N of A.
+ */
+int mpi_set_bit(MPI a, unsigned n)
+{
+       unsigned limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs) {      /* resize */
+               if (a->alloced >= limbno)
+                       if (mpi_resize(a, limbno + 1) < 0)
+                               return -ENOMEM;
+               a->nlimbs = limbno + 1;
+       }
+       a->d[limbno] |= (A_LIMB_1 << bitno);
+       return 0;
+}
+
+/****************
+ * Set bit N of A. and clear all bits above
+ */
+int mpi_set_highbit(MPI a, unsigned n)
+{
+       unsigned limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs) {      /* resize */
+               if (a->alloced >= limbno)
+                       if (mpi_resize(a, limbno + 1) < 0)
+                               return -ENOMEM;
+               a->nlimbs = limbno + 1;
+       }
+       a->d[limbno] |= (A_LIMB_1 << bitno);
+       for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
+               a->d[limbno] &= ~(A_LIMB_1 << bitno);
+       a->nlimbs = limbno + 1;
+       return 0;
+}
+
+/****************
+ * clear bit N of A and all bits above
+ */
+void mpi_clear_highbit(MPI a, unsigned n)
+{
+       unsigned limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return;         /* not allocated, so need to clear bits :-) */
+
+       for (; bitno < BITS_PER_MPI_LIMB; bitno++)
+               a->d[limbno] &= ~(A_LIMB_1 << bitno);
+       a->nlimbs = limbno + 1;
+}
+
+/****************
+ * Clear bit N of A.
+ */
+void mpi_clear_bit(MPI a, unsigned n)
+{
+       unsigned limbno, bitno;
+
+       limbno = n / BITS_PER_MPI_LIMB;
+       bitno = n % BITS_PER_MPI_LIMB;
+
+       if (limbno >= a->nlimbs)
+               return;         /* don't need to clear this bit, it's to far to left */
+       a->d[limbno] &= ~(A_LIMB_1 << bitno);
+}
+
+/****************
+ * Shift A by N bits to the right
+ * FIXME: should use alloc_limb if X and A are same.
+ */
+int mpi_rshift(MPI x, MPI a, unsigned n)
+{
+       mpi_ptr_t xp;
+       mpi_size_t xsize;
+
+       xsize = a->nlimbs;
+       x->sign = a->sign;
+       if (RESIZE_IF_NEEDED(x, (size_t) xsize) < 0)
+               return -ENOMEM;
+       xp = x->d;
+
+       if (xsize) {
+               mpihelp_rshift(xp, a->d, xsize, n);
+               MPN_NORMALIZE(xp, xsize);
+       }
+       x->nlimbs = xsize;
+       return 0;
+}
+
+/****************
+ * Shift A by COUNT limbs to the left
+ * This is used only within the MPI library
+ */
+int mpi_lshift_limbs(MPI a, unsigned int count)
+{
+       mpi_ptr_t ap = a->d;
+       int n = a->nlimbs;
+       int i;
+
+       if (!count || !n)
+               return 0;
+
+       if (RESIZE_IF_NEEDED(a, n + count) < 0)
+               return -ENOMEM;
+
+       for (i = n - 1; i >= 0; i--)
+               ap[i + count] = ap[i];
+       for (i = 0; i < count; i++)
+               ap[i] = 0;
+       a->nlimbs += count;
+       return 0;
+}
+
+/****************
+ * Shift A by COUNT limbs to the right
+ * This is used only within the MPI library
+ */
+void mpi_rshift_limbs(MPI a, unsigned int count)
+{
+       mpi_ptr_t ap = a->d;
+       mpi_size_t n = a->nlimbs;
+       unsigned int i;
+
+       if (count >= n) {
+               a->nlimbs = 0;
+               return;
+       }
+
+       for (i = 0; i < n - count; i++)
+               ap[i] = ap[i + count];
+       ap[i] = 0;
+       a->nlimbs -= count;
+}
diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c
new file mode 100644 (file)
index 0000000..914bc42
--- /dev/null
@@ -0,0 +1,68 @@
+/* mpi-cmp.c  -  MPI functions
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+
+int mpi_cmp_ui(MPI u, unsigned long v)
+{
+       mpi_limb_t limb = v;
+
+       mpi_normalize(u);
+       if (!u->nlimbs && !limb)
+               return 0;
+       if (u->sign)
+               return -1;
+       if (u->nlimbs > 1)
+               return 1;
+
+       if (u->d[0] == limb)
+               return 0;
+       else if (u->d[0] > limb)
+               return 1;
+       else
+               return -1;
+}
+
+int mpi_cmp(MPI u, MPI v)
+{
+       mpi_size_t usize, vsize;
+       int cmp;
+
+       mpi_normalize(u);
+       mpi_normalize(v);
+       usize = u->nlimbs;
+       vsize = v->nlimbs;
+       if (!u->sign && v->sign)
+               return 1;
+       if (u->sign && !v->sign)
+               return -1;
+       if (usize != vsize && !u->sign && !v->sign)
+               return usize - vsize;
+       if (usize != vsize && u->sign && v->sign)
+               return vsize + usize;
+       if (!usize)
+               return 0;
+       cmp = mpihelp_cmp(u->d, v->d, usize);
+       if (!cmp)
+               return 0;
+       if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
+               return 1;
+       return -1;
+}
diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c
new file mode 100644 (file)
index 0000000..c3087d1
--- /dev/null
@@ -0,0 +1,333 @@
+/* mpi-div.c  -  MPI functions
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include <linux/string.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
+{
+       int rc = -ENOMEM;
+       int divisor_sign = divisor->sign;
+       MPI temp_divisor = NULL;
+
+       /* We need the original value of the divisor after the remainder has been
+        * preliminary calculated.      We have to copy it to temporary space if it's
+        * the same variable as REM.  */
+       if (rem == divisor) {
+               if (mpi_copy(&temp_divisor, divisor) < 0)
+                       goto nomem;
+               divisor = temp_divisor;
+       }
+
+       if (mpi_tdiv_qr(NULL, rem, dividend, divisor) < 0)
+               goto nomem;
+       if (((divisor_sign ? 1 : 0) ^ (dividend->sign ? 1 : 0)) && rem->nlimbs)
+               if (mpi_add(rem, rem, divisor) < 0)
+                       goto nomem;
+
+       rc = 0;
+
+nomem:
+       if (temp_divisor)
+               mpi_free(temp_divisor);
+       return rc;
+}
+
+/****************
+ * Division rounding the quotient towards -infinity.
+ * The remainder gets the same sign as the denominator.
+ * rem is optional
+ */
+
+ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor)
+{
+       mpi_limb_t rlimb;
+
+       rlimb = mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
+       if (rlimb && dividend->sign)
+               rlimb = divisor - rlimb;
+
+       if (rem) {
+               rem->d[0] = rlimb;
+               rem->nlimbs = rlimb ? 1 : 0;
+       }
+       return rlimb;
+}
+
+int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor)
+{
+       MPI tmp = mpi_alloc(mpi_get_nlimbs(quot));
+       if (!tmp)
+               return -ENOMEM;
+       mpi_fdiv_qr(quot, tmp, dividend, divisor);
+       mpi_free(tmp);
+       return 0;
+}
+
+int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor)
+{
+       int divisor_sign = divisor->sign;
+       MPI temp_divisor = NULL;
+
+       if (quot == divisor || rem == divisor) {
+               if (mpi_copy(&temp_divisor, divisor) < 0)
+                       return -ENOMEM;
+               divisor = temp_divisor;
+       }
+
+       if (mpi_tdiv_qr(quot, rem, dividend, divisor) < 0)
+               goto nomem;
+
+       if ((divisor_sign ^ dividend->sign) && rem->nlimbs) {
+               if (mpi_sub_ui(quot, quot, 1) < 0)
+                       goto nomem;
+               if (mpi_add(rem, rem, divisor) < 0)
+                       goto nomem;
+       }
+
+       if (temp_divisor)
+               mpi_free(temp_divisor);
+
+       return 0;
+
+nomem:
+       mpi_free(temp_divisor);
+       return -ENOMEM;
+}
+
+/* If den == quot, den needs temporary storage.
+ * If den == rem, den needs temporary storage.
+ * If num == quot, num needs temporary storage.
+ * If den has temporary storage, it can be normalized while being copied,
+ *   i.e no extra storage should be allocated.
+ */
+
+int mpi_tdiv_r(MPI rem, MPI num, MPI den)
+{
+       return mpi_tdiv_qr(NULL, rem, num, den);
+}
+
+int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
+{
+       int rc = -ENOMEM;
+       mpi_ptr_t np, dp;
+       mpi_ptr_t qp, rp;
+       mpi_size_t nsize = num->nlimbs;
+       mpi_size_t dsize = den->nlimbs;
+       mpi_size_t qsize, rsize;
+       mpi_size_t sign_remainder = num->sign;
+       mpi_size_t sign_quotient = num->sign ^ den->sign;
+       unsigned normalization_steps;
+       mpi_limb_t q_limb;
+       mpi_ptr_t marker[5];
+       int markidx = 0;
+
+       memset(marker, 0, sizeof(marker));
+
+       /* Ensure space is enough for quotient and remainder.
+        * We need space for an extra limb in the remainder, because it's
+        * up-shifted (normalized) below.  */
+       rsize = nsize + 1;
+       if (mpi_resize(rem, rsize) < 0)
+               goto nomem;
+
+       qsize = rsize - dsize;  /* qsize cannot be bigger than this.  */
+       if (qsize <= 0) {
+               if (num != rem) {
+                       rem->nlimbs = num->nlimbs;
+                       rem->sign = num->sign;
+                       MPN_COPY(rem->d, num->d, nsize);
+               }
+               if (quot) {
+                       /* This needs to follow the assignment to rem, in case the
+                        * numerator and quotient are the same.  */
+                       quot->nlimbs = 0;
+                       quot->sign = 0;
+               }
+               return 0;
+       }
+
+       if (quot)
+               if (mpi_resize(quot, qsize) < 0)
+                       goto nomem;
+
+       /* Read pointers here, when reallocation is finished.  */
+       np = num->d;
+       dp = den->d;
+       rp = rem->d;
+
+       /* Optimize division by a single-limb divisor.  */
+       if (dsize == 1) {
+               mpi_limb_t rlimb;
+               if (quot) {
+                       qp = quot->d;
+                       rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
+                       qsize -= qp[qsize - 1] == 0;
+                       quot->nlimbs = qsize;
+                       quot->sign = sign_quotient;
+               } else
+                       rlimb = mpihelp_mod_1(np, nsize, dp[0]);
+               rp[0] = rlimb;
+               rsize = rlimb != 0 ? 1 : 0;
+               rem->nlimbs = rsize;
+               rem->sign = sign_remainder;
+               return 0;
+       }
+
+       if (quot) {
+               qp = quot->d;
+               /* Make sure QP and NP point to different objects.  Otherwise the
+                * numerator would be gradually overwritten by the quotient limbs.  */
+               if (qp == np) { /* Copy NP object to temporary space.  */
+                       np = marker[markidx++] = mpi_alloc_limb_space(nsize);
+                       MPN_COPY(np, qp, nsize);
+               }
+       } else                  /* Put quotient at top of remainder. */
+               qp = rp + dsize;
+
+       count_leading_zeros(normalization_steps, dp[dsize - 1]);
+
+       /* Normalize the denominator, i.e. make its most significant bit set by
+        * shifting it NORMALIZATION_STEPS bits to the left.  Also shift the
+        * numerator the same number of steps (to keep the quotient the same!).
+        */
+       if (normalization_steps) {
+               mpi_ptr_t tp;
+               mpi_limb_t nlimb;
+
+               /* Shift up the denominator setting the most significant bit of
+                * the most significant word.  Use temporary storage not to clobber
+                * the original contents of the denominator.  */
+               tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+               if (!tp)
+                       goto nomem;
+               mpihelp_lshift(tp, dp, dsize, normalization_steps);
+               dp = tp;
+
+               /* Shift up the numerator, possibly introducing a new most
+                * significant word.  Move the shifted numerator in the remainder
+                * meanwhile.  */
+               nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
+               if (nlimb) {
+                       rp[nsize] = nlimb;
+                       rsize = nsize + 1;
+               } else
+                       rsize = nsize;
+       } else {
+               /* The denominator is already normalized, as required.  Copy it to
+                * temporary space if it overlaps with the quotient or remainder.  */
+               if (dp == rp || (quot && (dp == qp))) {
+                       mpi_ptr_t tp;
+
+                       tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
+                       if (!tp)
+                               goto nomem;
+                       MPN_COPY(tp, dp, dsize);
+                       dp = tp;
+               }
+
+               /* Move the numerator to the remainder.  */
+               if (rp != np)
+                       MPN_COPY(rp, np, nsize);
+
+               rsize = nsize;
+       }
+
+       q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
+
+       if (quot) {
+               qsize = rsize - dsize;
+               if (q_limb) {
+                       qp[qsize] = q_limb;
+                       qsize += 1;
+               }
+
+               quot->nlimbs = qsize;
+               quot->sign = sign_quotient;
+       }
+
+       rsize = dsize;
+       MPN_NORMALIZE(rp, rsize);
+
+       if (normalization_steps && rsize) {
+               mpihelp_rshift(rp, rp, rsize, normalization_steps);
+               rsize -= rp[rsize - 1] == 0 ? 1 : 0;
+       }
+
+       rem->nlimbs = rsize;
+       rem->sign = sign_remainder;
+
+       rc = 0;
+nomem:
+       while (markidx)
+               mpi_free_limb_space(marker[--markidx]);
+       return rc;
+}
+
+int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count)
+{
+       mpi_size_t usize, wsize;
+       mpi_size_t limb_cnt;
+
+       usize = u->nlimbs;
+       limb_cnt = count / BITS_PER_MPI_LIMB;
+       wsize = usize - limb_cnt;
+       if (limb_cnt >= usize)
+               w->nlimbs = 0;
+       else {
+               mpi_ptr_t wp;
+               mpi_ptr_t up;
+
+               if (RESIZE_IF_NEEDED(w, wsize) < 0)
+                       return -ENOMEM;
+               wp = w->d;
+               up = u->d;
+
+               count %= BITS_PER_MPI_LIMB;
+               if (count) {
+                       mpihelp_rshift(wp, up + limb_cnt, wsize, count);
+                       wsize -= !wp[wsize - 1];
+               } else {
+                       MPN_COPY_INCR(wp, up + limb_cnt, wsize);
+               }
+
+               w->nlimbs = wsize;
+       }
+       return 0;
+}
+
+/****************
+ * Check whether dividend is divisible by divisor
+ * (note: divisor must fit into a limb)
+ */
+int mpi_divisible_ui(MPI dividend, ulong divisor)
+{
+       return !mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
+}
diff --git a/lib/mpi/mpi-gcd.c b/lib/mpi/mpi-gcd.c
new file mode 100644 (file)
index 0000000..13c48ae
--- /dev/null
@@ -0,0 +1,59 @@
+/* mpi-gcd.c  -  MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+
+/****************
+ * Find the greatest common divisor G of A and B.
+ * Return: true if this 1, false in all other cases
+ */
+int mpi_gcd(MPI g, const MPI xa, const MPI xb)
+{
+       MPI a = NULL, b = NULL;
+
+       if (mpi_copy(&a, xa) < 0)
+               goto nomem;
+
+       if (mpi_copy(&b, xb) < 0)
+               goto nomem;
+
+       /* TAOCP Vol II, 4.5.2, Algorithm A */
+       a->sign = 0;
+       b->sign = 0;
+       while (mpi_cmp_ui(b, 0)) {
+               if (mpi_fdiv_r(g, a, b) < 0)    /* g used as temorary variable */
+                       goto nomem;
+               if (mpi_set(a, b) < 0)
+                       goto nomem;
+               if (mpi_set(b, g) < 0)
+                       goto nomem;
+       }
+       if (mpi_set(g, a) < 0)
+               goto nomem;
+
+       mpi_free(a);
+       mpi_free(b);
+       return !mpi_cmp_ui(g, 1);
+
+nomem:
+       mpi_free(a);
+       mpi_free(b);
+       return -ENOMEM;
+}
diff --git a/lib/mpi/mpi-inline.c b/lib/mpi/mpi-inline.c
new file mode 100644 (file)
index 0000000..654f68a
--- /dev/null
@@ -0,0 +1,31 @@
+/* mpi-inline.c
+ * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ */
+
+/* put the inline functions as real functions into the lib */
+#define G10_MPI_INLINE_DECL
+
+#include "mpi-internal.h"
+
+/* always include the header becuase it is only
+ * included by mpi-internal if __GCC__ is defined but we
+ * need it here in all cases and the above definition of
+ * of the macro allows us to do so
+ */
+#include "mpi-inline.h"
diff --git a/lib/mpi/mpi-inline.h b/lib/mpi/mpi-inline.h
new file mode 100644 (file)
index 0000000..e2b3985
--- /dev/null
@@ -0,0 +1,122 @@
+/* mpi-inline.h  -  Internal to the Multi Precision Integers
+ *     Copyright (C) 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_INLINE_H
+#define G10_MPI_INLINE_H
+
+#ifndef G10_MPI_INLINE_DECL
+#define G10_MPI_INLINE_DECL  extern inline
+#endif
+
+G10_MPI_INLINE_DECL mpi_limb_t
+mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+             mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+       mpi_limb_t x;
+
+       x = *s1_ptr++;
+       s2_limb += x;
+       *res_ptr++ = s2_limb;
+       if (s2_limb < x) {      /* sum is less than the left operand: handle carry */
+               while (--s1_size) {
+                       x = *s1_ptr++ + 1;      /* add carry */
+                       *res_ptr++ = x; /* and store */
+                       if (x)  /* not 0 (no overflow): we can stop */
+                               goto leave;
+               }
+               return 1;       /* return carry (size of s1 to small) */
+       }
+
+leave:
+       if (res_ptr != s1_ptr) {        /* not the same variable */
+               mpi_size_t i;   /* copy the rest */
+               for (i = 0; i < s1_size - 1; i++)
+                       res_ptr[i] = s1_ptr[i];
+       }
+       return 0;               /* no carry */
+}
+
+G10_MPI_INLINE_DECL mpi_limb_t
+mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+           mpi_ptr_t s2_ptr, mpi_size_t s2_size)
+{
+       mpi_limb_t cy = 0;
+
+       if (s2_size)
+               cy = mpihelp_add_n(res_ptr, s1_ptr, s2_ptr, s2_size);
+
+       if (s1_size - s2_size)
+               cy = mpihelp_add_1(res_ptr + s2_size, s1_ptr + s2_size,
+                                  s1_size - s2_size, cy);
+       return cy;
+}
+
+G10_MPI_INLINE_DECL mpi_limb_t
+mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+             mpi_size_t s1_size, mpi_limb_t s2_limb)
+{
+       mpi_limb_t x;
+
+       x = *s1_ptr++;
+       s2_limb = x - s2_limb;
+       *res_ptr++ = s2_limb;
+       if (s2_limb > x) {
+               while (--s1_size) {
+                       x = *s1_ptr++;
+                       *res_ptr++ = x - 1;
+                       if (x)
+                               goto leave;
+               }
+               return 1;
+       }
+
+leave:
+       if (res_ptr != s1_ptr) {
+               mpi_size_t i;
+               for (i = 0; i < s1_size - 1; i++)
+                       res_ptr[i] = s1_ptr[i];
+       }
+       return 0;
+}
+
+G10_MPI_INLINE_DECL mpi_limb_t
+mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+           mpi_ptr_t s2_ptr, mpi_size_t s2_size)
+{
+       mpi_limb_t cy = 0;
+
+       if (s2_size)
+               cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size);
+
+       if (s1_size - s2_size)
+               cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size,
+                                  s1_size - s2_size, cy);
+       return cy;
+}
+
+#endif /*G10_MPI_INLINE_H */
diff --git a/lib/mpi/mpi-internal.h b/lib/mpi/mpi-internal.h
new file mode 100644 (file)
index 0000000..77adcf6
--- /dev/null
@@ -0,0 +1,261 @@
+/* mpi-internal.h  -  Internal to the Multi Precision Integers
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#ifndef G10_MPI_INTERNAL_H
+#define G10_MPI_INTERNAL_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mpi.h>
+#include <linux/errno.h>
+
+#define log_debug printk
+#define log_bug printk
+
+#define assert(x) \
+       do { \
+               if (!x) \
+                       log_bug("failed assertion\n"); \
+       } while (0);
+
+/* If KARATSUBA_THRESHOLD is not already defined, define it to a
+ * value which is good on most machines.  */
+
+/* tested 4, 16, 32 and 64, where 16 gave the best performance when
+ * checking a 768 and a 1024 bit ElGamal signature.
+ * (wk 22.12.97) */
+#ifndef KARATSUBA_THRESHOLD
+#define KARATSUBA_THRESHOLD 16
+#endif
+
+/* The code can't handle KARATSUBA_THRESHOLD smaller than 2.  */
+#if KARATSUBA_THRESHOLD < 2
+#undef KARATSUBA_THRESHOLD
+#define KARATSUBA_THRESHOLD 2
+#endif
+
+typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */
+typedef int mpi_size_t;                /* (must be a signed type) */
+
+#define ABS(x) (x >= 0 ? x : -x)
+#define MIN(l, o) ((l) < (o) ? (l) : (o))
+#define MAX(h, i) ((h) > (i) ? (h) : (i))
+
+static inline int RESIZE_IF_NEEDED(MPI a, unsigned b)
+{
+       if (a->alloced < b)
+               return mpi_resize(a, b);
+       return 0;
+}
+
+/* Copy N limbs from S to D.  */
+#define MPN_COPY(d, s, n) \
+       do {                                    \
+               mpi_size_t _i;                  \
+               for (_i = 0; _i < (n); _i++)    \
+                       (d)[_i] = (s)[_i];      \
+       } while (0)
+
+#define MPN_COPY_INCR(d, s, n) \
+       do {                                    \
+               mpi_size_t _i;                  \
+               for (_i = 0; _i < (n); _i++)    \
+                       (d)[_i] = (d)[_i];      \
+       } while (0)
+
+#define MPN_COPY_DECR(d, s, n) \
+       do {                                    \
+               mpi_size_t _i;                  \
+               for (_i = (n)-1; _i >= 0; _i--) \
+                       (d)[_i] = (s)[_i];      \
+       } while (0)
+
+/* Zero N limbs at D */
+#define MPN_ZERO(d, n) \
+       do {                                    \
+               int  _i;                        \
+               for (_i = 0; _i < (n); _i++)    \
+                       (d)[_i] = 0;            \
+       } while (0)
+
+#define MPN_NORMALIZE(d, n)  \
+       do {                                    \
+               while ((n) > 0) {               \
+                       if ((d)[(n)-1])         \
+                               break;          \
+                       (n)--;                  \
+               }                               \
+       } while (0)
+
+#define MPN_NORMALIZE_NOT_ZERO(d, n) \
+       do {                            \
+               for (;;) {              \
+                       if ((d)[(n)-1]) \
+                               break;  \
+                       (n)--;          \
+               }                       \
+       } while (0)
+
+#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \
+       do {                                                    \
+               if ((size) < KARATSUBA_THRESHOLD)               \
+                       mul_n_basecase(prodp, up, vp, size);    \
+               else                                            \
+                       mul_n(prodp, up, vp, size, tspace);     \
+       } while (0);
+
+/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest
+ * limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB).
+ * If this would yield overflow, DI should be the largest possible number
+ * (i.e., only ones).  For correct operation, the most significant bit of D
+ * has to be set.  Put the quotient in Q and the remainder in R.
+ */
+#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di) \
+       do {                                                            \
+               mpi_limb_t _q, _ql, _r;                                 \
+               mpi_limb_t _xh, _xl;                                    \
+               umul_ppmm(_q, _ql, (nh), (di));                         \
+               _q += (nh);     /* DI is 2**BITS_PER_MPI_LIMB too small */ \
+               umul_ppmm(_xh, _xl, _q, (d));                           \
+               sub_ddmmss(_xh, _r, (nh), (nl), _xh, _xl);              \
+               if (_xh) {                                              \
+                       sub_ddmmss(_xh, _r, _xh, _r, 0, (d));           \
+                       _q++;                                           \
+                       if (_xh) {                                      \
+                               sub_ddmmss(_xh, _r, _xh, _r, 0, (d));   \
+                               _q++;                                   \
+                       }                                               \
+               }                                                       \
+               if (_r >= (d)) {                                        \
+                       _r -= (d);                                      \
+                       _q++;                                           \
+               }                                                       \
+               (r) = _r;                                               \
+               (q) = _q;                                               \
+       } while (0)
+
+/*-- mpiutil.c --*/
+mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs);
+void mpi_free_limb_space(mpi_ptr_t a);
+void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs);
+
+/*-- mpi-bit.c --*/
+void mpi_rshift_limbs(MPI a, unsigned int count);
+int mpi_lshift_limbs(MPI a, unsigned int count);
+
+/*-- mpihelp-add.c --*/
+mpi_limb_t mpihelp_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                        mpi_size_t s1_size, mpi_limb_t s2_limb);
+mpi_limb_t mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                        mpi_ptr_t s2_ptr, mpi_size_t size);
+mpi_limb_t mpihelp_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+                      mpi_ptr_t s2_ptr, mpi_size_t s2_size);
+
+/*-- mpihelp-sub.c --*/
+mpi_limb_t mpihelp_sub_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                        mpi_size_t s1_size, mpi_limb_t s2_limb);
+mpi_limb_t mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                        mpi_ptr_t s2_ptr, mpi_size_t size);
+mpi_limb_t mpihelp_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
+                      mpi_ptr_t s2_ptr, mpi_size_t s2_size);
+
+/*-- mpihelp-cmp.c --*/
+int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size);
+
+/*-- mpihelp-mul.c --*/
+
+struct karatsuba_ctx {
+       struct karatsuba_ctx *next;
+       mpi_ptr_t tspace;
+       mpi_size_t tspace_size;
+       mpi_ptr_t tp;
+       mpi_size_t tp_size;
+};
+
+void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx);
+
+mpi_limb_t mpihelp_addmul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                           mpi_size_t s1_size, mpi_limb_t s2_limb);
+mpi_limb_t mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                           mpi_size_t s1_size, mpi_limb_t s2_limb);
+int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size);
+int mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
+               mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result);
+void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size);
+void mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size,
+               mpi_ptr_t tspace);
+
+int mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
+                              mpi_ptr_t up, mpi_size_t usize,
+                              mpi_ptr_t vp, mpi_size_t vsize,
+                              struct karatsuba_ctx *ctx);
+
+/*-- mpihelp-mul_1.c (or xxx/cpu/ *.S) --*/
+mpi_limb_t mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
+                        mpi_size_t s1_size, mpi_limb_t s2_limb);
+
+/*-- mpihelp-div.c --*/
+mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                        mpi_limb_t divisor_limb);
+mpi_limb_t mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs,
+                         mpi_ptr_t np, mpi_size_t nsize,
+                         mpi_ptr_t dp, mpi_size_t dsize);
+mpi_limb_t mpihelp_divmod_1(mpi_ptr_t quot_ptr,
+                           mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                           mpi_limb_t divisor_limb);
+
+/*-- mpihelp-shift.c --*/
+mpi_limb_t mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+                         unsigned cnt);
+mpi_limb_t mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
+                         unsigned cnt);
+
+/* Define stuff for longlong.h.  */
+#define W_TYPE_SIZE BITS_PER_MPI_LIMB
+typedef mpi_limb_t UWtype;
+typedef unsigned int UHWtype;
+#if defined(__GNUC__)
+typedef unsigned int UQItype __attribute__ ((mode(QI)));
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef unsigned int UDItype __attribute__ ((mode(DI)));
+#else
+typedef unsigned char UQItype;
+typedef long SItype;
+typedef unsigned long USItype;
+#endif
+
+#ifdef __GNUC__
+#include "mpi-inline.h"
+#endif
+
+#endif /*G10_MPI_INTERNAL_H */
diff --git a/lib/mpi/mpi-inv.c b/lib/mpi/mpi-inv.c
new file mode 100644 (file)
index 0000000..0951f98
--- /dev/null
@@ -0,0 +1,187 @@
+/* mpi-inv.c  -  MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+
+/****************
+ * Calculate the multiplicative inverse X of A mod N
+ * That is: Find the solution x for
+ *             1 = (a*x) mod n
+ */
+int mpi_invm(MPI x, const MPI a, const MPI n)
+{
+       /* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X)
+        * modified according to Michael Penk's solution for Exercice 35
+        * with further enhancement */
+       MPI u = NULL, v = NULL;
+       MPI u1 = NULL, u2 = NULL, u3 = NULL;
+       MPI v1 = NULL, v2 = NULL, v3 = NULL;
+       MPI t1 = NULL, t2 = NULL, t3 = NULL;
+       unsigned k;
+       int sign;
+       int odd = 0;
+       int rc = -ENOMEM;
+
+       if (mpi_copy(&u, a) < 0)
+               goto cleanup;
+       if (mpi_copy(&v, n) < 0)
+               goto cleanup;
+
+       for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) {
+               if (mpi_rshift(u, u, 1) < 0)
+                       goto cleanup;
+               if (mpi_rshift(v, v, 1) < 0)
+                       goto cleanup;
+       }
+       odd = mpi_test_bit(v, 0);
+
+       u1 = mpi_alloc_set_ui(1);
+       if (!u1)
+               goto cleanup;
+       if (!odd) {
+               u2 = mpi_alloc_set_ui(0);
+               if (!u2)
+                       goto cleanup;
+       }
+       if (mpi_copy(&u3, u) < 0)
+               goto cleanup;
+       if (mpi_copy(&v1, v) < 0)
+               goto cleanup;
+       if (!odd) {
+               v2 = mpi_alloc(mpi_get_nlimbs(u));
+               if (!v2)
+                       goto cleanup;
+               if (mpi_sub(v2, u1, u) < 0)
+                       goto cleanup;   /* U is used as const 1 */
+       }
+       if (mpi_copy(&v3, v) < 0)
+               goto cleanup;
+       if (mpi_test_bit(u, 0)) {       /* u is odd */
+               t1 = mpi_alloc_set_ui(0);
+               if (!t1)
+                       goto cleanup;
+               if (!odd) {
+                       t2 = mpi_alloc_set_ui(1);
+                       if (!t2)
+                               goto cleanup;
+                       t2->sign = 1;
+               }
+               if (mpi_copy(&t3, v) < 0)
+                       goto cleanup;
+               t3->sign = !t3->sign;
+               goto Y4;
+       } else {
+               t1 = mpi_alloc_set_ui(1);
+               if (!t1)
+                       goto cleanup;
+               if (!odd) {
+                       t2 = mpi_alloc_set_ui(0);
+                       if (!t2)
+                               goto cleanup;
+               }
+               if (mpi_copy(&t3, u) < 0)
+                       goto cleanup;
+       }
+       do {
+               do {
+                       if (!odd) {
+                               if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) {       /* one is odd */
+                                       if (mpi_add(t1, t1, v) < 0)
+                                               goto cleanup;
+                                       if (mpi_sub(t2, t2, u) < 0)
+                                               goto cleanup;
+                               }
+                               if (mpi_rshift(t1, t1, 1) < 0)
+                                       goto cleanup;
+                               if (mpi_rshift(t2, t2, 1) < 0)
+                                       goto cleanup;
+                               if (mpi_rshift(t3, t3, 1) < 0)
+                                       goto cleanup;
+                       } else {
+                               if (mpi_test_bit(t1, 0))
+                                       if (mpi_add(t1, t1, v) < 0)
+                                               goto cleanup;
+                               if (mpi_rshift(t1, t1, 1) < 0)
+                                       goto cleanup;
+                               if (mpi_rshift(t3, t3, 1) < 0)
+                                       goto cleanup;
+                       }
+Y4:
+                       ;
+               } while (!mpi_test_bit(t3, 0)); /* while t3 is even */
+
+               if (!t3->sign) {
+                       if (mpi_set(u1, t1) < 0)
+                               goto cleanup;
+                       if (!odd)
+                               if (mpi_set(u2, t2) < 0)
+                                       goto cleanup;
+                       if (mpi_set(u3, t3) < 0)
+                               goto cleanup;
+               } else {
+                       if (mpi_sub(v1, v, t1) < 0)
+                               goto cleanup;
+                       sign = u->sign;
+                       u->sign = !u->sign;
+                       if (!odd)
+                               if (mpi_sub(v2, u, t2) < 0)
+                                       goto cleanup;
+                       u->sign = sign;
+                       sign = t3->sign;
+                       t3->sign = !t3->sign;
+                       if (mpi_set(v3, t3) < 0)
+                               goto cleanup;
+                       t3->sign = sign;
+               }
+               if (mpi_sub(t1, u1, v1) < 0)
+                       goto cleanup;
+               if (!odd)
+                       if (mpi_sub(t2, u2, v2) < 0)
+                               goto cleanup;
+               if (mpi_sub(t3, u3, v3) < 0)
+                       goto cleanup;
+               if (t1->sign) {
+                       if (mpi_add(t1, t1, v) < 0)
+                               goto cleanup;
+                       if (!odd)
+                               if (mpi_sub(t2, t2, u) < 0)
+                                       goto cleanup;
+               }
+       } while (mpi_cmp_ui(t3, 0));    /* while t3 != 0 */
+       /* mpi_lshift( u3, k ); */
+       rc = mpi_set(x, u1);
+
+cleanup:
+       mpi_free(u1);
+       mpi_free(v1);
+       mpi_free(t1);
+       if (!odd) {
+               mpi_free(u2);
+               mpi_free(v2);
+               mpi_free(t2);
+       }
+       mpi_free(u3);
+       mpi_free(v3);
+       mpi_free(t3);
+
+       mpi_free(u);
+       mpi_free(v);
+       return rc;
+}
diff --git a/lib/mpi/mpi-mpow.c b/lib/mpi/mpi-mpow.c
new file mode 100644 (file)
index 0000000..7328d0d
--- /dev/null
@@ -0,0 +1,134 @@
+/* mpi-mpow.c  -  MPI functions
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+#include "longlong.h"
+
+static int build_index(const MPI *exparray, int k, int i, int t)
+{
+       int j, bitno;
+       int index = 0;
+
+       bitno = t - i;
+       for (j = k - 1; j >= 0; j--) {
+               index <<= 1;
+               if (mpi_test_bit(exparray[j], bitno))
+                       index |= 1;
+       }
+       return index;
+}
+
+/****************
+ * RES = (BASE[0] ^ EXP[0]) *  (BASE[1] ^ EXP[1]) * ... * mod M
+ */
+int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI m)
+{
+       int rc = -ENOMEM;
+       int k;                  /* number of elements */
+       int t;                  /* bit size of largest exponent */
+       int i, j, idx;
+       MPI *G = NULL;          /* table with precomputed values of size 2^k */
+       MPI tmp = NULL;
+
+       for (k = 0; basearray[k]; k++)
+               ;
+       if (!k) {
+               pr_emerg("mpi_mulpowm: assert(k) failed\n");
+               BUG();
+       }
+       for (t = 0, i = 0; (tmp = exparray[i]); i++) {
+               j = mpi_get_nbits(tmp);
+               if (j > t)
+                       t = j;
+       }
+       if (i != k) {
+               pr_emerg("mpi_mulpowm: assert(i==k) failed\n");
+               BUG();
+       }
+       if (!t) {
+               pr_emerg("mpi_mulpowm: assert(t) failed\n");
+               BUG();
+       }
+       if (k >= 10) {
+               pr_emerg("mpi_mulpowm: assert(k<10) failed\n");
+               BUG();
+       }
+
+       G = kzalloc((1 << k) * sizeof *G, GFP_KERNEL);
+       if (!G)
+               goto err_out;
+
+       /* and calculate */
+       tmp = mpi_alloc(mpi_get_nlimbs(m) + 1);
+       if (!tmp)
+               goto nomem;
+       if (mpi_set_ui(res, 1) < 0)
+               goto nomem;
+       for (i = 1; i <= t; i++) {
+               if (mpi_mulm(tmp, res, res, m) < 0)
+                       goto nomem;
+               idx = build_index(exparray, k, i, t);
+               if (!(idx >= 0 && idx < (1 << k))) {
+                       pr_emerg("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n");
+                       BUG();
+               }
+               if (!G[idx]) {
+                       if (!idx) {
+                               G[0] = mpi_alloc_set_ui(1);
+                               if (!G[0])
+                                       goto nomem;
+                       } else {
+                               for (j = 0; j < k; j++) {
+                                       if ((idx & (1 << j))) {
+                                               if (!G[idx]) {
+                                                       if (mpi_copy
+                                                           (&G[idx],
+                                                            basearray[j]) < 0)
+                                                               goto nomem;
+                                               } else {
+                                                       if (mpi_mulm
+                                                           (G[idx], G[idx],
+                                                            basearray[j],
+                                                            m) < 0)
+                                                               goto nomem;
+                                               }
+                                       }
+                               }
+                               if (!G[idx]) {
+                                       G[idx] = mpi_alloc(0);
+                                       if (!G[idx])
+                                               goto nomem;
+                               }
+                       }
+               }
+               if (mpi_mulm(res, tmp, G[idx], m) < 0)
+                       goto nomem;
+       }
+
+       rc = 0;
+nomem:
+       /* cleanup */
+       mpi_free(tmp);
+       for (i = 0; i < (1 << k); i++)
+               mpi_free(G[i]);
+       kfree(G);
+err_out:
+       return rc;
+}
diff --git a/lib/mpi/mpi-mul.c b/lib/mpi/mpi-mul.c
new file mode 100644 (file)
index 0000000..1f3219e
--- /dev/null
@@ -0,0 +1,194 @@
+/* mpi-mul.c  -  MPI functions
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+
+int mpi_mul_ui(MPI prod, MPI mult, unsigned long small_mult)
+{
+       mpi_size_t size, prod_size;
+       mpi_ptr_t prod_ptr;
+       mpi_limb_t cy;
+       int sign;
+
+       size = mult->nlimbs;
+       sign = mult->sign;
+
+       if (!size || !small_mult) {
+               prod->nlimbs = 0;
+               prod->sign = 0;
+               return 0;
+       }
+
+       prod_size = size + 1;
+       if (prod->alloced < prod_size)
+               if (mpi_resize(prod, prod_size) < 0)
+                       return -ENOMEM;
+       prod_ptr = prod->d;
+
+       cy = mpihelp_mul_1(prod_ptr, mult->d, size, (mpi_limb_t) small_mult);
+       if (cy)
+               prod_ptr[size++] = cy;
+       prod->nlimbs = size;
+       prod->sign = sign;
+       return 0;
+}
+
+int mpi_mul_2exp(MPI w, MPI u, unsigned long cnt)
+{
+       mpi_size_t usize, wsize, limb_cnt;
+       mpi_ptr_t wp;
+       mpi_limb_t wlimb;
+       int usign, wsign;
+
+       usize = u->nlimbs;
+       usign = u->sign;
+
+       if (!usize) {
+               w->nlimbs = 0;
+               w->sign = 0;
+               return 0;
+       }
+
+       limb_cnt = cnt / BITS_PER_MPI_LIMB;
+       wsize = usize + limb_cnt + 1;
+       if (w->alloced < wsize)
+               if (mpi_resize(w, wsize) < 0)
+                       return -ENOMEM;
+       wp = w->d;
+       wsize = usize + limb_cnt;
+       wsign = usign;
+
+       cnt %= BITS_PER_MPI_LIMB;
+       if (cnt) {
+               wlimb = mpihelp_lshift(wp + limb_cnt, u->d, usize, cnt);
+               if (wlimb) {
+                       wp[wsize] = wlimb;
+                       wsize++;
+               }
+       } else {
+               MPN_COPY_DECR(wp + limb_cnt, u->d, usize);
+       }
+
+       /* Zero all whole limbs at low end.  Do it here and not before calling
+        * mpn_lshift, not to lose for U == W.  */
+       MPN_ZERO(wp, limb_cnt);
+
+       w->nlimbs = wsize;
+       w->sign = wsign;
+       return 0;
+}
+
+int mpi_mul(MPI w, MPI u, MPI v)
+{
+       int rc = -ENOMEM;
+       mpi_size_t usize, vsize, wsize;
+       mpi_ptr_t up, vp, wp;
+       mpi_limb_t cy;
+       int usign, vsign, sign_product;
+       int assign_wp = 0;
+       mpi_ptr_t tmp_limb = NULL;
+
+       if (u->nlimbs < v->nlimbs) {    /* Swap U and V. */
+               usize = v->nlimbs;
+               usign = v->sign;
+               up = v->d;
+               vsize = u->nlimbs;
+               vsign = u->sign;
+               vp = u->d;
+       } else {
+               usize = u->nlimbs;
+               usign = u->sign;
+               up = u->d;
+               vsize = v->nlimbs;
+               vsign = v->sign;
+               vp = v->d;
+       }
+       sign_product = usign ^ vsign;
+       wp = w->d;
+
+       /* Ensure W has space enough to store the result.  */
+       wsize = usize + vsize;
+       if (w->alloced < (size_t) wsize) {
+               if (wp == up || wp == vp) {
+                       wp = mpi_alloc_limb_space(wsize);
+                       if (!wp)
+                               goto nomem;
+                       assign_wp = 1;
+               } else {
+                       if (mpi_resize(w, wsize) < 0)
+                               goto nomem;
+                       wp = w->d;
+               }
+       } else {                /* Make U and V not overlap with W.      */
+               if (wp == up) {
+                       /* W and U are identical.  Allocate temporary space for U.      */
+                       up = tmp_limb = mpi_alloc_limb_space(usize);
+                       if (!up)
+                               goto nomem;
+                       /* Is V identical too?  Keep it identical with U.  */
+                       if (wp == vp)
+                               vp = up;
+                       /* Copy to the temporary space.  */
+                       MPN_COPY(up, wp, usize);
+               } else if (wp == vp) {
+                       /* W and V are identical.  Allocate temporary space for V.      */
+                       vp = tmp_limb = mpi_alloc_limb_space(vsize);
+                       if (!vp)
+                               goto nomem;
+                       /* Copy to the temporary space.  */
+                       MPN_COPY(vp, wp, vsize);
+               }
+       }
+
+       if (!vsize)
+               wsize = 0;
+       else {
+               if (mpihelp_mul(wp, up, usize, vp, vsize, &cy) < 0)
+                       goto nomem;
+               wsize -= cy ? 0 : 1;
+       }
+
+       if (assign_wp)
+               mpi_assign_limb_space(w, wp, wsize);
+
+       w->nlimbs = wsize;
+       w->sign = sign_product;
+       rc = 0;
+nomem:
+       if (tmp_limb)
+               mpi_free_limb_space(tmp_limb);
+       return rc;
+}
+
+int mpi_mulm(MPI w, MPI u, MPI v, MPI m)
+{
+       if (mpi_mul(w, u, v) < 0)
+               return -ENOMEM;
+       return mpi_fdiv_r(w, w, m);
+}
diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c
new file mode 100644 (file)
index 0000000..b04a3cf
--- /dev/null
@@ -0,0 +1,323 @@
+/* mpi-pow.c  -  MPI functions
+ *     Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include <linux/string.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+/****************
+ * RES = BASE ^ EXP mod MOD
+ */
+int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
+{
+       mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL;
+       mpi_ptr_t xp_marker = NULL;
+       mpi_ptr_t tspace = NULL;
+       mpi_ptr_t rp, ep, mp, bp;
+       mpi_size_t esize, msize, bsize, rsize;
+       int esign, msign, bsign, rsign;
+       mpi_size_t size;
+       int mod_shift_cnt;
+       int negative_result;
+       int assign_rp = 0;
+       mpi_size_t tsize = 0;   /* to avoid compiler warning */
+       /* fixme: we should check that the warning is void */
+       int rc = -ENOMEM;
+
+       esize = exp->nlimbs;
+       msize = mod->nlimbs;
+       size = 2 * msize;
+       esign = exp->sign;
+       msign = mod->sign;
+
+       rp = res->d;
+       ep = exp->d;
+
+       if (!msize)
+               msize = 1 / msize;      /* provoke a signal */
+
+       if (!esize) {
+               /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
+                * depending on if MOD equals 1.  */
+               rp[0] = 1;
+               res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
+               res->sign = 0;
+               goto leave;
+       }
+
+       /* Normalize MOD (i.e. make its most significant bit set) as required by
+        * mpn_divrem.  This will make the intermediate values in the calculation
+        * slightly larger, but the correct result is obtained after a final
+        * reduction using the original MOD value.  */
+       mp = mp_marker = mpi_alloc_limb_space(msize);
+       if (!mp)
+               goto enomem;
+       count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]);
+       if (mod_shift_cnt)
+               mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt);
+       else
+               MPN_COPY(mp, mod->d, msize);
+
+       bsize = base->nlimbs;
+       bsign = base->sign;
+       if (bsize > msize) {    /* The base is larger than the module. Reduce it. */
+               /* Allocate (BSIZE + 1) with space for remainder and quotient.
+                * (The quotient is (bsize - msize + 1) limbs.)  */
+               bp = bp_marker = mpi_alloc_limb_space(bsize + 1);
+               if (!bp)
+                       goto enomem;
+               MPN_COPY(bp, base->d, bsize);
+               /* We don't care about the quotient, store it above the remainder,
+                * at BP + MSIZE.  */
+               mpihelp_divrem(bp + msize, 0, bp, bsize, mp, msize);
+               bsize = msize;
+               /* Canonicalize the base, since we are going to multiply with it
+                * quite a few times.  */
+               MPN_NORMALIZE(bp, bsize);
+       } else
+               bp = base->d;
+
+       if (!bsize) {
+               res->nlimbs = 0;
+               res->sign = 0;
+               goto leave;
+       }
+
+       if (res->alloced < size) {
+               /* We have to allocate more space for RES.  If any of the input
+                * parameters are identical to RES, defer deallocation of the old
+                * space.  */
+               if (rp == ep || rp == mp || rp == bp) {
+                       rp = mpi_alloc_limb_space(size);
+                       if (!rp)
+                               goto enomem;
+                       assign_rp = 1;
+               } else {
+                       if (mpi_resize(res, size) < 0)
+                               goto enomem;
+                       rp = res->d;
+               }
+       } else {                /* Make BASE, EXP and MOD not overlap with RES.  */
+               if (rp == bp) {
+                       /* RES and BASE are identical.  Allocate temp. space for BASE.  */
+                       BUG_ON(bp_marker);
+                       bp = bp_marker = mpi_alloc_limb_space(bsize);
+                       if (!bp)
+                               goto enomem;
+                       MPN_COPY(bp, rp, bsize);
+               }
+               if (rp == ep) {
+                       /* RES and EXP are identical.  Allocate temp. space for EXP.  */
+                       ep = ep_marker = mpi_alloc_limb_space(esize);
+                       if (!ep)
+                               goto enomem;
+                       MPN_COPY(ep, rp, esize);
+               }
+               if (rp == mp) {
+                       /* RES and MOD are identical.  Allocate temporary space for MOD. */
+                       BUG_ON(mp_marker);
+                       mp = mp_marker = mpi_alloc_limb_space(msize);
+                       if (!mp)
+                               goto enomem;
+                       MPN_COPY(mp, rp, msize);
+               }
+       }
+
+       MPN_COPY(rp, bp, bsize);
+       rsize = bsize;
+       rsign = bsign;
+
+       {
+               mpi_size_t i;
+               mpi_ptr_t xp;
+               int c;
+               mpi_limb_t e;
+               mpi_limb_t carry_limb;
+               struct karatsuba_ctx karactx;
+
+               xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1));
+               if (!xp)
+                       goto enomem;
+
+               memset(&karactx, 0, sizeof karactx);
+               negative_result = (ep[0] & 1) && base->sign;
+
+               i = esize - 1;
+               e = ep[i];
+               count_leading_zeros(c, e);
+               e = (e << c) << 1;      /* shift the exp bits to the left, lose msb */
+               c = BITS_PER_MPI_LIMB - 1 - c;
+
+               /* Main loop.
+                *
+                * Make the result be pointed to alternately by XP and RP.  This
+                * helps us avoid block copying, which would otherwise be necessary
+                * with the overlap restrictions of mpihelp_divmod. With 50% probability
+                * the result after this loop will be in the area originally pointed
+                * by RP (==RES->d), and with 50% probability in the area originally
+                * pointed to by XP.
+                */
+
+               for (;;) {
+                       while (c) {
+                               mpi_ptr_t tp;
+                               mpi_size_t xsize;
+
+                               /*if (mpihelp_mul_n(xp, rp, rp, rsize) < 0) goto enomem */
+                               if (rsize < KARATSUBA_THRESHOLD)
+                                       mpih_sqr_n_basecase(xp, rp, rsize);
+                               else {
+                                       if (!tspace) {
+                                               tsize = 2 * rsize;
+                                               tspace =
+                                                   mpi_alloc_limb_space(tsize);
+                                               if (!tspace)
+                                                       goto enomem;
+                                       } else if (tsize < (2 * rsize)) {
+                                               mpi_free_limb_space(tspace);
+                                               tsize = 2 * rsize;
+                                               tspace =
+                                                   mpi_alloc_limb_space(tsize);
+                                               if (!tspace)
+                                                       goto enomem;
+                                       }
+                                       mpih_sqr_n(xp, rp, rsize, tspace);
+                               }
+
+                               xsize = 2 * rsize;
+                               if (xsize > msize) {
+                                       mpihelp_divrem(xp + msize, 0, xp, xsize,
+                                                      mp, msize);
+                                       xsize = msize;
+                               }
+
+                               tp = rp;
+                               rp = xp;
+                               xp = tp;
+                               rsize = xsize;
+
+                               if ((mpi_limb_signed_t) e < 0) {
+                                       /*mpihelp_mul( xp, rp, rsize, bp, bsize ); */
+                                       if (bsize < KARATSUBA_THRESHOLD) {
+                                               mpi_limb_t tmp;
+                                               if (mpihelp_mul
+                                                   (xp, rp, rsize, bp, bsize,
+                                                    &tmp) < 0)
+                                                       goto enomem;
+                                       } else {
+                                               if (mpihelp_mul_karatsuba_case
+                                                   (xp, rp, rsize, bp, bsize,
+                                                    &karactx) < 0)
+                                                       goto enomem;
+                                       }
+
+                                       xsize = rsize + bsize;
+                                       if (xsize > msize) {
+                                               mpihelp_divrem(xp + msize, 0,
+                                                              xp, xsize, mp,
+                                                              msize);
+                                               xsize = msize;
+                                       }
+
+                                       tp = rp;
+                                       rp = xp;
+                                       xp = tp;
+                                       rsize = xsize;
+                               }
+                               e <<= 1;
+                               c--;
+                       }
+
+                       i--;
+                       if (i < 0)
+                               break;
+                       e = ep[i];
+                       c = BITS_PER_MPI_LIMB;
+               }
+
+               /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
+                * steps.  Adjust the result by reducing it with the original MOD.
+                *
+                * Also make sure the result is put in RES->d (where it already
+                * might be, see above).
+                */
+               if (mod_shift_cnt) {
+                       carry_limb =
+                           mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt);
+                       rp = res->d;
+                       if (carry_limb) {
+                               rp[rsize] = carry_limb;
+                               rsize++;
+                       }
+               } else {
+                       MPN_COPY(res->d, rp, rsize);
+                       rp = res->d;
+               }
+
+               if (rsize >= msize) {
+                       mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize);
+                       rsize = msize;
+               }
+
+               /* Remove any leading zero words from the result.  */
+               if (mod_shift_cnt)
+                       mpihelp_rshift(rp, rp, rsize, mod_shift_cnt);
+               MPN_NORMALIZE(rp, rsize);
+
+               mpihelp_release_karatsuba_ctx(&karactx);
+       }
+
+       if (negative_result && rsize) {
+               if (mod_shift_cnt)
+                       mpihelp_rshift(mp, mp, msize, mod_shift_cnt);
+               mpihelp_sub(rp, mp, msize, rp, rsize);
+               rsize = msize;
+               rsign = msign;
+               MPN_NORMALIZE(rp, rsize);
+       }
+       res->nlimbs = rsize;
+       res->sign = rsign;
+
+leave:
+       rc = 0;
+enomem:
+       if (assign_rp)
+               mpi_assign_limb_space(res, rp, size);
+       if (mp_marker)
+               mpi_free_limb_space(mp_marker);
+       if (bp_marker)
+               mpi_free_limb_space(bp_marker);
+       if (ep_marker)
+               mpi_free_limb_space(ep_marker);
+       if (xp_marker)
+               mpi_free_limb_space(xp_marker);
+       if (tspace)
+               mpi_free_limb_space(tspace);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(mpi_powm);
diff --git a/lib/mpi/mpi-scan.c b/lib/mpi/mpi-scan.c
new file mode 100644 (file)
index 0000000..b2da5ad
--- /dev/null
@@ -0,0 +1,136 @@
+/* mpi-scan.c  -  MPI functions
+ * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+#include "longlong.h"
+
+/****************
+ * Scan through an mpi and return byte for byte. a -1 is returned to indicate
+ * the end of the mpi. Scanning is done from the lsb to the msb, returned
+ * values are in the range of 0 .. 255.
+ *
+ * FIXME: This code is VERY ugly!
+ */
+int mpi_getbyte(const MPI a, unsigned idx)
+{
+       int i, j;
+       unsigned n;
+       mpi_ptr_t ap;
+       mpi_limb_t limb;
+
+       ap = a->d;
+       for (n = 0, i = 0; i < a->nlimbs; i++) {
+               limb = ap[i];
+               for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
+                       if (n == idx)
+                               return (limb >> j * 8) & 0xff;
+       }
+       return -1;
+}
+
+/****************
+ * Put a value at position IDX into A. idx counts from lsb to msb
+ */
+void mpi_putbyte(MPI a, unsigned idx, int xc)
+{
+       int i, j;
+       unsigned n;
+       mpi_ptr_t ap;
+       mpi_limb_t limb, c;
+
+       c = xc & 0xff;
+       ap = a->d;
+       for (n = 0, i = 0; i < a->alloced; i++) {
+               limb = ap[i];
+               for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
+                       if (n == idx) {
+#if BYTES_PER_MPI_LIMB == 4
+                               if (j == 0)
+                                       limb = (limb & 0xffffff00) | c;
+                               else if (j == 1)
+                                       limb = (limb & 0xffff00ff) | (c << 8);
+                               else if (j == 2)
+                                       limb = (limb & 0xff00ffff) | (c << 16);
+                               else
+                                       limb = (limb & 0x00ffffff) | (c << 24);
+#elif BYTES_PER_MPI_LIMB == 8
+                               if (j == 0)
+                                       limb = (limb & 0xffffffffffffff00) | c;
+                               else if (j == 1)
+                                       limb =
+                                           (limb & 0xffffffffffff00ff) | (c <<
+                                                                          8);
+                               else if (j == 2)
+                                       limb =
+                                           (limb & 0xffffffffff00ffff) | (c <<
+                                                                          16);
+                               else if (j == 3)
+                                       limb =
+                                           (limb & 0xffffffff00ffffff) | (c <<
+                                                                          24);
+                               else if (j == 4)
+                                       limb =
+                                           (limb & 0xffffff00ffffffff) | (c <<
+                                                                          32);
+                               else if (j == 5)
+                                       limb =
+                                           (limb & 0xffff00ffffffffff) | (c <<
+                                                                          40);
+                               else if (j == 6)
+                                       limb =
+                                           (limb & 0xff00ffffffffffff) | (c <<
+                                                                          48);
+                               else
+                                       limb =
+                                           (limb & 0x00ffffffffffffff) | (c <<
+                                                                          56);
+#else
+#error please enhance this function, its ugly - i know.
+#endif
+                               if (a->nlimbs <= i)
+                                       a->nlimbs = i + 1;
+                               ap[i] = limb;
+                               return;
+                       }
+       }
+       log_bug("index out of range\n");
+}
+
+/****************
+ * Count the number of zerobits at the low end of A
+ */
+unsigned mpi_trailing_zeros(const MPI a)
+{
+       unsigned n, count = 0;
+
+       for (n = 0; n < a->nlimbs; n++) {
+               if (a->d[n]) {
+                       unsigned nn;
+                       mpi_limb_t alimb = a->d[n];
+
+                       count_trailing_zeros(nn, alimb);
+                       count += nn;
+                       break;
+               }
+               count += BITS_PER_MPI_LIMB;
+       }
+       return count;
+
+}
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
new file mode 100644 (file)
index 0000000..fe84bb9
--- /dev/null
@@ -0,0 +1,365 @@
+/* mpicoder.c  -  Coder for the external representation of MPIs
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#define MAX_EXTERN_MPI_BITS 16384
+
+static uint8_t asn[15] =       /* Object ID is 1.3.14.3.2.26 */
+{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
+       0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
+};
+
+MPI do_encode_md(const void *sha_buffer, unsigned nbits)
+{
+       int nframe = (nbits + 7) / 8;
+       uint8_t *frame, *fr_pt;
+       int i = 0, n;
+       size_t asnlen = DIM(asn);
+       MPI a = MPI_NULL;
+
+       if (SHA1_DIGEST_LENGTH + asnlen + 4 > nframe)
+               pr_info("MPI: can't encode a %d bit MD into a %d bits frame\n",
+                      (int)(SHA1_DIGEST_LENGTH * 8), (int)nbits);
+
+       /* We encode the MD in this way:
+        *
+        *       0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
+        *
+        * PAD consists of FF bytes.
+        */
+       frame = kmalloc(nframe, GFP_KERNEL);
+       if (!frame)
+               return MPI_NULL;
+       n = 0;
+       frame[n++] = 0;
+       frame[n++] = 1;         /* block type */
+       i = nframe - SHA1_DIGEST_LENGTH - asnlen - 3;
+
+       if (i <= 1) {
+               pr_info("MPI: message digest encoding failed\n");
+               kfree(frame);
+               return a;
+       }
+
+       memset(frame + n, 0xff, i);
+       n += i;
+       frame[n++] = 0;
+       memcpy(frame + n, &asn, asnlen);
+       n += asnlen;
+       memcpy(frame + n, sha_buffer, SHA1_DIGEST_LENGTH);
+       n += SHA1_DIGEST_LENGTH;
+
+       i = nframe;
+       fr_pt = frame;
+
+       if (n != nframe) {
+               printk
+                   ("MPI: message digest encoding failed, frame length is wrong\n");
+               kfree(frame);
+               return a;
+       }
+
+       a = mpi_alloc((nframe + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
+       mpi_set_buffer(a, frame, nframe, 0);
+       kfree(frame);
+
+       return a;
+}
+
+MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
+{
+       const uint8_t *buffer = xbuffer;
+       int i, j;
+       unsigned nbits, nbytes, nlimbs, nread = 0;
+       mpi_limb_t a;
+       MPI val = MPI_NULL;
+
+       if (*ret_nread < 2)
+               goto leave;
+       nbits = buffer[0] << 8 | buffer[1];
+
+       if (nbits > MAX_EXTERN_MPI_BITS) {
+               pr_info("MPI: mpi too large (%u bits)\n", nbits);
+               goto leave;
+       }
+       buffer += 2;
+       nread = 2;
+
+       nbytes = (nbits + 7) / 8;
+       nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+       val = mpi_alloc(nlimbs);
+       if (!val)
+               return MPI_NULL;
+       i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+       i %= BYTES_PER_MPI_LIMB;
+       val->nbits = nbits;
+       j = val->nlimbs = nlimbs;
+       val->sign = 0;
+       for (; j > 0; j--) {
+               a = 0;
+               for (; i < BYTES_PER_MPI_LIMB; i++) {
+                       if (++nread > *ret_nread) {
+                               printk
+                                   ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n",
+                                    nread, *ret_nread);
+                               goto leave;
+                       }
+                       a <<= 8;
+                       a |= *buffer++;
+               }
+               i = 0;
+               val->d[j - 1] = a;
+       }
+
+leave:
+       *ret_nread = nread;
+       return val;
+}
+EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
+
+/****************
+ * Make an mpi from a character string.
+ */
+int mpi_fromstr(MPI val, const char *str)
+{
+       int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2;
+       unsigned nbits, nbytes, nlimbs;
+       mpi_limb_t a;
+
+       if (*str == '-') {
+               sign = 1;
+               str++;
+       }
+       if (*str == '0' && str[1] == 'x')
+               hexmode = 1;
+       else
+               return -EINVAL; /* other bases are not yet supported */
+       str += 2;
+
+       nbits = strlen(str) * 4;
+       if (nbits % 8)
+               prepend_zero = 1;
+       nbytes = (nbits + 7) / 8;
+       nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+       if (val->alloced < nlimbs)
+               if (!mpi_resize(val, nlimbs))
+                       return -ENOMEM;
+       i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
+       i %= BYTES_PER_MPI_LIMB;
+       j = val->nlimbs = nlimbs;
+       val->sign = sign;
+       for (; j > 0; j--) {
+               a = 0;
+               for (; i < BYTES_PER_MPI_LIMB; i++) {
+                       if (prepend_zero) {
+                               c1 = '0';
+                               prepend_zero = 0;
+                       } else
+                               c1 = *str++;
+                       assert(c1);
+                       c2 = *str++;
+                       assert(c2);
+                       if (c1 >= '0' && c1 <= '9')
+                               c = c1 - '0';
+                       else if (c1 >= 'a' && c1 <= 'f')
+                               c = c1 - 'a' + 10;
+                       else if (c1 >= 'A' && c1 <= 'F')
+                               c = c1 - 'A' + 10;
+                       else {
+                               mpi_clear(val);
+                               return 1;
+                       }
+                       c <<= 4;
+                       if (c2 >= '0' && c2 <= '9')
+                               c |= c2 - '0';
+                       else if (c2 >= 'a' && c2 <= 'f')
+                               c |= c2 - 'a' + 10;
+                       else if (c2 >= 'A' && c2 <= 'F')
+                               c |= c2 - 'A' + 10;
+                       else {
+                               mpi_clear(val);
+                               return 1;
+                       }
+                       a <<= 8;
+                       a |= c;
+               }
+               i = 0;
+
+               val->d[j - 1] = a;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_fromstr);
+
+/****************
+ * Special function to get the low 8 bytes from an mpi.
+ * This can be used as a keyid; KEYID is an 2 element array.
+ * Return the low 4 bytes.
+ */
+u32 mpi_get_keyid(const MPI a, u32 *keyid)
+{
+#if BYTES_PER_MPI_LIMB == 4
+       if (keyid) {
+               keyid[0] = a->nlimbs >= 2 ? a->d[1] : 0;
+               keyid[1] = a->nlimbs >= 1 ? a->d[0] : 0;
+       }
+       return a->nlimbs >= 1 ? a->d[0] : 0;
+#elif BYTES_PER_MPI_LIMB == 8
+       if (keyid) {
+               keyid[0] = a->nlimbs ? (u32) (a->d[0] >> 32) : 0;
+               keyid[1] = a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0;
+       }
+       return a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0;
+#else
+#error Make this function work with other LIMB sizes
+#endif
+}
+
+/****************
+ * Return an allocated buffer with the MPI (msb first).
+ * NBYTES receives the length of this buffer. Caller must free the
+ * return string (This function does return a 0 byte buffer with NBYTES
+ * set to zero if the value of A is zero. If sign is not NULL, it will
+ * be set to the sign of the A.
+ */
+void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
+{
+       uint8_t *p, *buffer;
+       mpi_limb_t alimb;
+       int i;
+       unsigned int n;
+
+       if (sign)
+               *sign = a->sign;
+       *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
+       if (!n)
+               n++;            /* avoid zero length allocation */
+       p = buffer = kmalloc(n, GFP_KERNEL);
+
+       for (i = a->nlimbs - 1; i >= 0; i--) {
+               alimb = a->d[i];
+#if BYTES_PER_MPI_LIMB == 4
+               *p++ = alimb >> 24;
+               *p++ = alimb >> 16;
+               *p++ = alimb >> 8;
+               *p++ = alimb;
+#elif BYTES_PER_MPI_LIMB == 8
+               *p++ = alimb >> 56;
+               *p++ = alimb >> 48;
+               *p++ = alimb >> 40;
+               *p++ = alimb >> 32;
+               *p++ = alimb >> 24;
+               *p++ = alimb >> 16;
+               *p++ = alimb >> 8;
+               *p++ = alimb;
+#else
+#error please implement for this limb size.
+#endif
+       }
+
+       /* this is sub-optimal but we need to do the shift operation
+        * because the caller has to free the returned buffer */
+       for (p = buffer; !*p && *nbytes; p++, --*nbytes)
+               ;
+       if (p != buffer)
+               memmove(buffer, p, *nbytes);
+
+       return buffer;
+}
+EXPORT_SYMBOL_GPL(mpi_get_buffer);
+
+/****************
+ * Use BUFFER to update MPI.
+ */
+int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
+{
+       const uint8_t *buffer = xbuffer, *p;
+       mpi_limb_t alimb;
+       int nlimbs;
+       int i;
+
+       nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
+       if (RESIZE_IF_NEEDED(a, nlimbs) < 0)
+               return -ENOMEM;
+       a->sign = sign;
+
+       for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) {
+#if BYTES_PER_MPI_LIMB == 4
+               alimb = (mpi_limb_t) *p--;
+               alimb |= (mpi_limb_t) *p-- << 8;
+               alimb |= (mpi_limb_t) *p-- << 16;
+               alimb |= (mpi_limb_t) *p-- << 24;
+#elif BYTES_PER_MPI_LIMB == 8
+               alimb = (mpi_limb_t) *p--;
+               alimb |= (mpi_limb_t) *p-- << 8;
+               alimb |= (mpi_limb_t) *p-- << 16;
+               alimb |= (mpi_limb_t) *p-- << 24;
+               alimb |= (mpi_limb_t) *p-- << 32;
+               alimb |= (mpi_limb_t) *p-- << 40;
+               alimb |= (mpi_limb_t) *p-- << 48;
+               alimb |= (mpi_limb_t) *p-- << 56;
+#else
+#error please implement for this limb size.
+#endif
+               a->d[i++] = alimb;
+       }
+       if (p >= buffer) {
+#if BYTES_PER_MPI_LIMB == 4
+               alimb = *p--;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 8;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 16;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 24;
+#elif BYTES_PER_MPI_LIMB == 8
+               alimb = (mpi_limb_t) *p--;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 8;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 16;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 24;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 32;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 40;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 48;
+               if (p >= buffer)
+                       alimb |= (mpi_limb_t) *p-- << 56;
+#else
+#error please implement for this limb size.
+#endif
+               a->d[i++] = alimb;
+       }
+       a->nlimbs = i;
+
+       if (i != nlimbs) {
+               pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i,
+                      nlimbs);
+               BUG();
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_set_buffer);
diff --git a/lib/mpi/mpih-cmp.c b/lib/mpi/mpih-cmp.c
new file mode 100644 (file)
index 0000000..b2fd396
--- /dev/null
@@ -0,0 +1,56 @@
+/* mpihelp-sub.c  -  MPI helper functions
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+
+/****************
+ * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE.
+ * There are no restrictions on the relative sizes of
+ * the two arguments.
+ * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2.
+ */
+int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size)
+{
+       mpi_size_t i;
+       mpi_limb_t op1_word, op2_word;
+
+       for (i = size - 1; i >= 0; i--) {
+               op1_word = op1_ptr[i];
+               op2_word = op2_ptr[i];
+               if (op1_word != op2_word)
+                       goto diff;
+       }
+       return 0;
+
+diff:
+       /* This can *not* be simplified to
+        *   op2_word - op2_word
+        * since that expression might give signed overflow.  */
+       return (op1_word > op2_word) ? 1 : -1;
+}
diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c
new file mode 100644 (file)
index 0000000..87ede16
--- /dev/null
@@ -0,0 +1,541 @@
+/* mpihelp-div.c  -  MPI helper functions
+ *     Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#ifndef UMUL_TIME
+#define UMUL_TIME 1
+#endif
+#ifndef UDIV_TIME
+#define UDIV_TIME UMUL_TIME
+#endif
+
+/* FIXME: We should be using invert_limb (or invert_normalized_limb)
+ * here (not udiv_qrnnd).
+ */
+
+mpi_limb_t
+mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+             mpi_limb_t divisor_limb)
+{
+       mpi_size_t i;
+       mpi_limb_t n1, n0, r;
+       int dummy;
+
+       /* Botch: Should this be handled at all?  Rely on callers?  */
+       if (!dividend_size)
+               return 0;
+
+       /* If multiplication is much faster than division, and the
+        * dividend is large, pre-invert the divisor, and use
+        * only multiplications in the inner loop.
+        *
+        * This test should be read:
+        *   Does it ever help to use udiv_qrnnd_preinv?
+        *     && Does what we save compensate for the inversion overhead?
+        */
+       if (UDIV_TIME > (2 * UMUL_TIME + 6)
+           && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
+               int normalization_steps;
+
+               count_leading_zeros(normalization_steps, divisor_limb);
+               if (normalization_steps) {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       divisor_limb <<= normalization_steps;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        *
+                        * Special case for DIVISOR_LIMB == 100...000.
+                        */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t) 0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                          -divisor_limb, 0, divisor_limb);
+
+                       n1 = dividend_ptr[dividend_size - 1];
+                       r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                       /* Possible optimization:
+                        * if (r == 0
+                        * && divisor_limb > ((n1 << normalization_steps)
+                        *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                        * ...one division less...
+                        */
+                       for (i = dividend_size - 2; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(dummy, r, r,
+                                                 ((n1 << normalization_steps)
+                                                  | (n0 >>
+                                                     (BITS_PER_MPI_LIMB -
+                                                      normalization_steps))),
+                                                 divisor_limb,
+                                                 divisor_limb_inverted);
+                               n1 = n0;
+                       }
+                       UDIV_QRNND_PREINV(dummy, r, r,
+                                         n1 << normalization_steps,
+                                         divisor_limb, divisor_limb_inverted);
+                       return r >> normalization_steps;
+               } else {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        *
+                        * Special case for DIVISOR_LIMB == 100...000.
+                        */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t) 0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                          -divisor_limb, 0, divisor_limb);
+
+                       i = dividend_size - 1;
+                       r = dividend_ptr[i];
+
+                       if (r >= divisor_limb)
+                               r = 0;
+                       else
+                               i--;
+
+                       for (; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(dummy, r, r,
+                                                 n0, divisor_limb,
+                                                 divisor_limb_inverted);
+                       }
+                       return r;
+               }
+       } else {
+               if (UDIV_NEEDS_NORMALIZATION) {
+                       int normalization_steps;
+
+                       count_leading_zeros(normalization_steps, divisor_limb);
+                       if (normalization_steps) {
+                               divisor_limb <<= normalization_steps;
+
+                               n1 = dividend_ptr[dividend_size - 1];
+                               r = n1 >> (BITS_PER_MPI_LIMB -
+                                          normalization_steps);
+
+                               /* Possible optimization:
+                                * if (r == 0
+                                * && divisor_limb > ((n1 << normalization_steps)
+                                *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                                * ...one division less...
+                                */
+                               for (i = dividend_size - 2; i >= 0; i--) {
+                                       n0 = dividend_ptr[i];
+                                       udiv_qrnnd(dummy, r, r,
+                                                  ((n1 << normalization_steps)
+                                                   | (n0 >>
+                                                      (BITS_PER_MPI_LIMB -
+                                                       normalization_steps))),
+                                                  divisor_limb);
+                                       n1 = n0;
+                               }
+                               udiv_qrnnd(dummy, r, r,
+                                          n1 << normalization_steps,
+                                          divisor_limb);
+                               return r >> normalization_steps;
+                       }
+               }
+               /* No normalization needed, either because udiv_qrnnd doesn't require
+                * it, or because DIVISOR_LIMB is already normalized.  */
+               i = dividend_size - 1;
+               r = dividend_ptr[i];
+
+               if (r >= divisor_limb)
+                       r = 0;
+               else
+                       i--;
+
+               for (; i >= 0; i--) {
+                       n0 = dividend_ptr[i];
+                       udiv_qrnnd(dummy, r, r, n0, divisor_limb);
+               }
+               return r;
+       }
+}
+
+/* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
+ * the NSIZE-DSIZE least significant quotient limbs at QP
+ * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is
+ * non-zero, generate that many fraction bits and append them after the
+ * other quotient limbs.
+ * Return the most significant limb of the quotient, this is always 0 or 1.
+ *
+ * Preconditions:
+ * 0. NSIZE >= DSIZE.
+ * 1. The most significant bit of the divisor must be set.
+ * 2. QP must either not overlap with the input operands at all, or
+ *    QP + DSIZE >= NP must hold true. (This means that it's
+ *    possible to put the quotient in the high part of NUM, right after the
+ *    remainder in NUM.
+ * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero.
+ */
+
+mpi_limb_t
+mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs,
+              mpi_ptr_t np, mpi_size_t nsize, mpi_ptr_t dp, mpi_size_t dsize)
+{
+       mpi_limb_t most_significant_q_limb = 0;
+
+       switch (dsize) {
+       case 0:
+               /* We are asked to divide by zero, so go ahead and do it!  (To make
+                  the compiler not remove this statement, return the value.)  */
+               return 1 / dsize;
+
+       case 1:
+               {
+                       mpi_size_t i;
+                       mpi_limb_t n1;
+                       mpi_limb_t d;
+
+                       d = dp[0];
+                       n1 = np[nsize - 1];
+
+                       if (n1 >= d) {
+                               n1 -= d;
+                               most_significant_q_limb = 1;
+                       }
+
+                       qp += qextra_limbs;
+                       for (i = nsize - 2; i >= 0; i--)
+                               udiv_qrnnd(qp[i], n1, n1, np[i], d);
+                       qp -= qextra_limbs;
+
+                       for (i = qextra_limbs - 1; i >= 0; i--)
+                               udiv_qrnnd(qp[i], n1, n1, 0, d);
+
+                       np[0] = n1;
+               }
+               break;
+
+       case 2:
+               {
+                       mpi_size_t i;
+                       mpi_limb_t n1, n0, n2;
+                       mpi_limb_t d1, d0;
+
+                       np += nsize - 2;
+                       d1 = dp[1];
+                       d0 = dp[0];
+                       n1 = np[1];
+                       n0 = np[0];
+
+                       if (n1 >= d1 && (n1 > d1 || n0 >= d0)) {
+                               sub_ddmmss(n1, n0, n1, n0, d1, d0);
+                               most_significant_q_limb = 1;
+                       }
+
+                       for (i = qextra_limbs + nsize - 2 - 1; i >= 0; i--) {
+                               mpi_limb_t q;
+                               mpi_limb_t r;
+
+                               if (i >= qextra_limbs)
+                                       np--;
+                               else
+                                       np[0] = 0;
+
+                               if (n1 == d1) {
+                                       /* Q should be either 111..111 or 111..110.  Need special
+                                        * treatment of this rare case as normal division would
+                                        * give overflow.  */
+                                       q = ~(mpi_limb_t) 0;
+
+                                       r = n0 + d1;
+                                       if (r < d1) {   /* Carry in the addition? */
+                                               add_ssaaaa(n1, n0, r - d0,
+                                                          np[0], 0, d0);
+                                               qp[i] = q;
+                                               continue;
+                                       }
+                                       n1 = d0 - (d0 != 0 ? 1 : 0);
+                                       n0 = -d0;
+                               } else {
+                                       udiv_qrnnd(q, r, n1, n0, d1);
+                                       umul_ppmm(n1, n0, d0, q);
+                               }
+
+                               n2 = np[0];
+q_test:
+                               if (n1 > r || (n1 == r && n0 > n2)) {
+                                       /* The estimated Q was too large.  */
+                                       q--;
+                                       sub_ddmmss(n1, n0, n1, n0, 0, d0);
+                                       r += d1;
+                                       if (r >= d1)    /* If not carry, test Q again.  */
+                                               goto q_test;
+                               }
+
+                               qp[i] = q;
+                               sub_ddmmss(n1, n0, r, n2, n1, n0);
+                       }
+                       np[1] = n1;
+                       np[0] = n0;
+               }
+               break;
+
+       default:
+               {
+                       mpi_size_t i;
+                       mpi_limb_t dX, d1, n0;
+
+                       np += nsize - dsize;
+                       dX = dp[dsize - 1];
+                       d1 = dp[dsize - 2];
+                       n0 = np[dsize - 1];
+
+                       if (n0 >= dX) {
+                               if (n0 > dX
+                                   || mpihelp_cmp(np, dp, dsize - 1) >= 0) {
+                                       mpihelp_sub_n(np, np, dp, dsize);
+                                       n0 = np[dsize - 1];
+                                       most_significant_q_limb = 1;
+                               }
+                       }
+
+                       for (i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) {
+                               mpi_limb_t q;
+                               mpi_limb_t n1, n2;
+                               mpi_limb_t cy_limb;
+
+                               if (i >= qextra_limbs) {
+                                       np--;
+                                       n2 = np[dsize];
+                               } else {
+                                       n2 = np[dsize - 1];
+                                       MPN_COPY_DECR(np + 1, np, dsize - 1);
+                                       np[0] = 0;
+                               }
+
+                               if (n0 == dX) {
+                                       /* This might over-estimate q, but it's probably not worth
+                                        * the extra code here to find out.  */
+                                       q = ~(mpi_limb_t) 0;
+                               } else {
+                                       mpi_limb_t r;
+
+                                       udiv_qrnnd(q, r, n0, np[dsize - 1], dX);
+                                       umul_ppmm(n1, n0, d1, q);
+
+                                       while (n1 > r
+                                              || (n1 == r
+                                                  && n0 > np[dsize - 2])) {
+                                               q--;
+                                               r += dX;
+                                               if (r < dX)     /* I.e. "carry in previous addition?" */
+                                                       break;
+                                               n1 -= n0 < d1;
+                                               n0 -= d1;
+                                       }
+                               }
+
+                               /* Possible optimization: We already have (q * n0) and (1 * n1)
+                                * after the calculation of q.  Taking advantage of that, we
+                                * could make this loop make two iterations less.  */
+                               cy_limb = mpihelp_submul_1(np, dp, dsize, q);
+
+                               if (n2 != cy_limb) {
+                                       mpihelp_add_n(np, np, dp, dsize);
+                                       q--;
+                               }
+
+                               qp[i] = q;
+                               n0 = np[dsize - 1];
+                       }
+               }
+       }
+
+       return most_significant_q_limb;
+}
+
+/****************
+ * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+ * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
+ * Return the single-limb remainder.
+ * There are no constraints on the value of the divisor.
+ *
+ * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
+ */
+
+mpi_limb_t
+mpihelp_divmod_1(mpi_ptr_t quot_ptr,
+                mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
+                mpi_limb_t divisor_limb)
+{
+       mpi_size_t i;
+       mpi_limb_t n1, n0, r;
+       int dummy;
+
+       if (!dividend_size)
+               return 0;
+
+       /* If multiplication is much faster than division, and the
+        * dividend is large, pre-invert the divisor, and use
+        * only multiplications in the inner loop.
+        *
+        * This test should be read:
+        * Does it ever help to use udiv_qrnnd_preinv?
+        * && Does what we save compensate for the inversion overhead?
+        */
+       if (UDIV_TIME > (2 * UMUL_TIME + 6)
+           && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) {
+               int normalization_steps;
+
+               count_leading_zeros(normalization_steps, divisor_limb);
+               if (normalization_steps) {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       divisor_limb <<= normalization_steps;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        */
+                       /* Special case for DIVISOR_LIMB == 100...000.  */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t) 0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                          -divisor_limb, 0, divisor_limb);
+
+                       n1 = dividend_ptr[dividend_size - 1];
+                       r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
+
+                       /* Possible optimization:
+                        * if (r == 0
+                        * && divisor_limb > ((n1 << normalization_steps)
+                        *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                        * ...one division less...
+                        */
+                       for (i = dividend_size - 2; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r,
+                                                 ((n1 << normalization_steps)
+                                                  | (n0 >>
+                                                     (BITS_PER_MPI_LIMB -
+                                                      normalization_steps))),
+                                                 divisor_limb,
+                                                 divisor_limb_inverted);
+                               n1 = n0;
+                       }
+                       UDIV_QRNND_PREINV(quot_ptr[0], r, r,
+                                         n1 << normalization_steps,
+                                         divisor_limb, divisor_limb_inverted);
+                       return r >> normalization_steps;
+               } else {
+                       mpi_limb_t divisor_limb_inverted;
+
+                       /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
+                        * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
+                        * most significant bit (with weight 2**N) implicit.
+                        */
+                       /* Special case for DIVISOR_LIMB == 100...000.  */
+                       if (!(divisor_limb << 1))
+                               divisor_limb_inverted = ~(mpi_limb_t) 0;
+                       else
+                               udiv_qrnnd(divisor_limb_inverted, dummy,
+                                          -divisor_limb, 0, divisor_limb);
+
+                       i = dividend_size - 1;
+                       r = dividend_ptr[i];
+
+                       if (r >= divisor_limb)
+                               r = 0;
+                       else
+                               quot_ptr[i--] = 0;
+
+                       for (; i >= 0; i--) {
+                               n0 = dividend_ptr[i];
+                               UDIV_QRNND_PREINV(quot_ptr[i], r, r,
+                                                 n0, divisor_limb,
+                                                 divisor_limb_inverted);
+                       }
+                       return r;
+               }
+       } else {
+               if (UDIV_NEEDS_NORMALIZATION) {
+                       int normalization_steps;
+
+                       count_leading_zeros(normalization_steps, divisor_limb);
+                       if (normalization_steps) {
+                               divisor_limb <<= normalization_steps;
+
+                               n1 = dividend_ptr[dividend_size - 1];
+                               r = n1 >> (BITS_PER_MPI_LIMB -
+                                          normalization_steps);
+
+                               /* Possible optimization:
+                                * if (r == 0
+                                * && divisor_limb > ((n1 << normalization_steps)
+                                *                 | (dividend_ptr[dividend_size - 2] >> ...)))
+                                * ...one division less...
+                                */
+                               for (i = dividend_size - 2; i >= 0; i--) {
+                                       n0 = dividend_ptr[i];
+                                       udiv_qrnnd(quot_ptr[i + 1], r, r,
+                                                  ((n1 << normalization_steps)
+                                                   | (n0 >>
+                                                      (BITS_PER_MPI_LIMB -
+                                                       normalization_steps))),
+                                                  divisor_limb);
+                                       n1 = n0;
+                               }
+                               udiv_qrnnd(quot_ptr[0], r, r,
+                                          n1 << normalization_steps,
+                                          divisor_limb);
+                               return r >> normalization_steps;
+                       }
+               }
+               /* No normalization needed, either because udiv_qrnnd doesn't require
+                * it, or because DIVISOR_LIMB is already normalized.  */
+               i = dividend_size - 1;
+               r = dividend_ptr[i];
+
+               if (r >= divisor_limb)
+                       r = 0;
+               else
+                       quot_ptr[i--] = 0;
+
+               for (; i >= 0; i--) {
+                       n0 = dividend_ptr[i];
+                       udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb);
+               }
+               return r;
+       }
+}
diff --git a/lib/mpi/mpih-mul.c b/lib/mpi/mpih-mul.c
new file mode 100644 (file)
index 0000000..c69c5ee
--- /dev/null
@@ -0,0 +1,527 @@
+/* mpihelp-mul.c  -  MPI helper functions
+ * Copyright (C) 1994, 1996, 1998, 1999,
+ *               2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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
+ *
+ * Note: This code is heavily based on the GNU MP Library.
+ *      Actually it's the same code with only minor changes in the
+ *      way the data is stored; this is to support the abstraction
+ *      of an optional secure memory allocation which may be used
+ *      to avoid revealing of sensitive data due to paging etc.
+ *      The GNU MP Library itself is published under the LGPL;
+ *      however I decided to publish this code under the plain GPL.
+ */
+
+#include <linux/string.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace)         \
+       do {                                                    \
+               if ((size) < KARATSUBA_THRESHOLD)               \
+                       mul_n_basecase(prodp, up, vp, size);    \
+               else                                            \
+                       mul_n(prodp, up, vp, size, tspace);     \
+       } while (0);
+
+#define MPN_SQR_N_RECURSE(prodp, up, size, tspace)             \
+       do {                                                    \
+               if ((size) < KARATSUBA_THRESHOLD)               \
+                       mpih_sqr_n_basecase(prodp, up, size);   \
+               else                                            \
+                       mpih_sqr_n(prodp, up, size, tspace);    \
+       } while (0);
+
+/* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP),
+ * both with SIZE limbs, and store the result at PRODP.  2 * SIZE limbs are
+ * always stored.  Return the most significant limb.
+ *
+ * Argument constraints:
+ * 1. PRODP != UP and PRODP != VP, i.e. the destination
+ *    must be distinct from the multiplier and the multiplicand.
+ *
+ *
+ * Handle simple cases with traditional multiplication.
+ *
+ * This is the most critical code of multiplication.  All multiplies rely
+ * on this, both small and huge.  Small ones arrive here immediately.  Huge
+ * ones arrive here as this is the base case for Karatsuba's recursive
+ * algorithm below.
+ */
+
+static mpi_limb_t
+mul_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
+{
+       mpi_size_t i;
+       mpi_limb_t cy;
+       mpi_limb_t v_limb;
+
+       /* Multiply by the first limb in V separately, as the result can be
+        * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
+       v_limb = vp[0];
+       if (v_limb <= 1) {
+               if (v_limb == 1)
+                       MPN_COPY(prodp, up, size);
+               else
+                       MPN_ZERO(prodp, size);
+               cy = 0;
+       } else
+               cy = mpihelp_mul_1(prodp, up, size, v_limb);
+
+       prodp[size] = cy;
+       prodp++;
+
+       /* For each iteration in the outer loop, multiply one limb from
+        * U with one limb from V, and add it to PROD.  */
+       for (i = 1; i < size; i++) {
+               v_limb = vp[i];
+               if (v_limb <= 1) {
+                       cy = 0;
+                       if (v_limb == 1)
+                               cy = mpihelp_add_n(prodp, prodp, up, size);
+               } else
+                       cy = mpihelp_addmul_1(prodp, up, size, v_limb);
+
+               prodp[size] = cy;
+               prodp++;
+       }
+
+       return cy;
+}
+
+static void
+mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
+               mpi_size_t size, mpi_ptr_t tspace)
+{
+       if (size & 1) {
+               /* The size is odd, and the code below doesn't handle that.
+                * Multiply the least significant (size - 1) limbs with a recursive
+                * call, and handle the most significant limb of S1 and S2
+                * separately.
+                * A slightly faster way to do this would be to make the Karatsuba
+                * code below behave as if the size were even, and let it check for
+                * odd size in the end.  I.e., in essence move this code to the end.
+                * Doing so would save us a recursive call, and potentially make the
+                * stack grow a lot less.
+                */
+               mpi_size_t esize = size - 1;    /* even size */
+               mpi_limb_t cy_limb;
+
+               MPN_MUL_N_RECURSE(prodp, up, vp, esize, tspace);
+               cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, vp[esize]);
+               prodp[esize + esize] = cy_limb;
+               cy_limb = mpihelp_addmul_1(prodp + esize, vp, size, up[esize]);
+               prodp[esize + size] = cy_limb;
+       } else {
+               /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
+                *
+                * Split U in two pieces, U1 and U0, such that
+                * U = U0 + U1*(B**n),
+                * and V in V1 and V0, such that
+                * V = V0 + V1*(B**n).
+                *
+                * UV is then computed recursively using the identity
+                *
+                *        2n   n          n                     n
+                * UV = (B  + B )U V  +  B (U -U )(V -V )  +  (B + 1)U V
+                *                1 1        1  0   0  1              0 0
+                *
+                * Where B = 2**BITS_PER_MP_LIMB.
+                */
+               mpi_size_t hsize = size >> 1;
+               mpi_limb_t cy;
+               int negflg;
+
+               /* Product H.      ________________  ________________
+                *                |_____U1 x V1____||____U0 x V0_____|
+                * Put result in upper part of PROD and pass low part of TSPACE
+                * as new TSPACE.
+                */
+               MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize,
+                                 tspace);
+
+               /* Product M.      ________________
+                *                |_(U1-U0)(V0-V1)_|
+                */
+               if (mpihelp_cmp(up + hsize, up, hsize) >= 0) {
+                       mpihelp_sub_n(prodp, up + hsize, up, hsize);
+                       negflg = 0;
+               } else {
+                       mpihelp_sub_n(prodp, up, up + hsize, hsize);
+                       negflg = 1;
+               }
+               if (mpihelp_cmp(vp + hsize, vp, hsize) >= 0) {
+                       mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize);
+                       negflg ^= 1;
+               } else {
+                       mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize);
+                       /* No change of NEGFLG.  */
+               }
+               /* Read temporary operands from low part of PROD.
+                * Put result in low part of TSPACE using upper part of TSPACE
+                * as new TSPACE.
+                */
+               MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize,
+                                 tspace + size);
+
+               /* Add/copy product H. */
+               MPN_COPY(prodp + hsize, prodp + size, hsize);
+               cy = mpihelp_add_n(prodp + size, prodp + size,
+                                  prodp + size + hsize, hsize);
+
+               /* Add product M (if NEGFLG M is a negative number) */
+               if (negflg)
+                       cy -=
+                           mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace,
+                                         size);
+               else
+                       cy +=
+                           mpihelp_add_n(prodp + hsize, prodp + hsize, tspace,
+                                         size);
+
+               /* Product L.      ________________  ________________
+                *                |________________||____U0 x V0_____|
+                * Read temporary operands from low part of PROD.
+                * Put result in low part of TSPACE using upper part of TSPACE
+                * as new TSPACE.
+                */
+               MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size);
+
+               /* Add/copy Product L (twice) */
+
+               cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
+               if (cy)
+                       mpihelp_add_1(prodp + hsize + size,
+                                     prodp + hsize + size, hsize, cy);
+
+               MPN_COPY(prodp, tspace, hsize);
+               cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize,
+                                  hsize);
+               if (cy)
+                       mpihelp_add_1(prodp + size, prodp + size, size, 1);
+       }
+}
+
+void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size)
+{
+       mpi_size_t i;
+       mpi_limb_t cy_limb;
+       mpi_limb_t v_limb;
+
+       /* Multiply by the first limb in V separately, as the result can be
+        * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
+       v_limb = up[0];
+       if (v_limb <= 1) {
+               if (v_limb == 1)
+                       MPN_COPY(prodp, up, size);
+               else
+                       MPN_ZERO(prodp, size);
+               cy_limb = 0;
+       } else
+               cy_limb = mpihelp_mul_1(prodp, up, size, v_limb);
+
+       prodp[size] = cy_limb;
+       prodp++;
+
+       /* For each iteration in the outer loop, multiply one limb from
+        * U with one limb from V, and add it to PROD.  */
+       for (i = 1; i < size; i++) {
+               v_limb = up[i];
+               if (v_limb <= 1) {
+                       cy_limb = 0;
+                       if (v_limb == 1)
+                               cy_limb = mpihelp_add_n(prodp, prodp, up, size);
+               } else
+                       cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb);
+
+               prodp[size] = cy_limb;
+               prodp++;
+       }
+}
+
+void
+mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
+{
+       if (size & 1) {
+               /* The size is odd, and the code below doesn't handle that.
+                * Multiply the least significant (size - 1) limbs with a recursive
+                * call, and handle the most significant limb of S1 and S2
+                * separately.
+                * A slightly faster way to do this would be to make the Karatsuba
+                * code below behave as if the size were even, and let it check for
+                * odd size in the end.  I.e., in essence move this code to the end.
+                * Doing so would save us a recursive call, and potentially make the
+                * stack grow a lot less.
+                */
+               mpi_size_t esize = size - 1;    /* even size */
+               mpi_limb_t cy_limb;
+
+               MPN_SQR_N_RECURSE(prodp, up, esize, tspace);
+               cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, up[esize]);
+               prodp[esize + esize] = cy_limb;
+               cy_limb = mpihelp_addmul_1(prodp + esize, up, size, up[esize]);
+
+               prodp[esize + size] = cy_limb;
+       } else {
+               mpi_size_t hsize = size >> 1;
+               mpi_limb_t cy;
+
+               /* Product H.      ________________  ________________
+                *                |_____U1 x U1____||____U0 x U0_____|
+                * Put result in upper part of PROD and pass low part of TSPACE
+                * as new TSPACE.
+                */
+               MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace);
+
+               /* Product M.      ________________
+                *                |_(U1-U0)(U0-U1)_|
+                */
+               if (mpihelp_cmp(up + hsize, up, hsize) >= 0)
+                       mpihelp_sub_n(prodp, up + hsize, up, hsize);
+               else
+                       mpihelp_sub_n(prodp, up, up + hsize, hsize);
+
+               /* Read temporary operands from low part of PROD.
+                * Put result in low part of TSPACE using upper part of TSPACE
+                * as new TSPACE.  */
+               MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size);
+
+               /* Add/copy product H  */
+               MPN_COPY(prodp + hsize, prodp + size, hsize);
+               cy = mpihelp_add_n(prodp + size, prodp + size,
+                                  prodp + size + hsize, hsize);
+
+               /* Add product M (if NEGFLG M is a negative number).  */
+               cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size);
+
+               /* Product L.      ________________  ________________
+                *                |________________||____U0 x U0_____|
+                * Read temporary operands from low part of PROD.
+                * Put result in low part of TSPACE using upper part of TSPACE
+                * as new TSPACE.  */
+               MPN_SQR_N_RECURSE(tspace, up, hsize, tspace + size);
+
+               /* Add/copy Product L (twice).  */
+               cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
+               if (cy)
+                       mpihelp_add_1(prodp + hsize + size,
+                                     prodp + hsize + size, hsize, cy);
+
+               MPN_COPY(prodp, tspace, hsize);
+               cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize,
+                                  hsize);
+               if (cy)
+                       mpihelp_add_1(prodp + size, prodp + size, size, 1);
+       }
+}
+
+/* This should be made into an inline function in gmp.h.  */
+int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
+{
+       if (up == vp) {
+               if (size < KARATSUBA_THRESHOLD)
+                       mpih_sqr_n_basecase(prodp, up, size);
+               else {
+                       mpi_ptr_t tspace;
+                       tspace = mpi_alloc_limb_space(2 * size);
+                       if (!tspace)
+                               return -ENOMEM;
+                       mpih_sqr_n(prodp, up, size, tspace);
+                       mpi_free_limb_space(tspace);
+               }
+       } else {
+               if (size < KARATSUBA_THRESHOLD)
+                       mul_n_basecase(prodp, up, vp, size);
+               else {
+                       mpi_ptr_t tspace;
+                       tspace = mpi_alloc_limb_space(2 * size);
+                       if (!tspace)
+                               return -ENOMEM;
+                       mul_n(prodp, up, vp, size, tspace);
+                       mpi_free_limb_space(tspace);
+               }
+       }
+
+       return 0;
+}
+
+int
+mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
+                          mpi_ptr_t up, mpi_size_t usize,
+                          mpi_ptr_t vp, mpi_size_t vsize,
+                          struct karatsuba_ctx *ctx)
+{
+       mpi_limb_t cy;
+
+       if (!ctx->tspace || ctx->tspace_size < vsize) {
+               if (ctx->tspace)
+                       mpi_free_limb_space(ctx->tspace);
+               ctx->tspace = mpi_alloc_limb_space(2 * vsize);
+               if (!ctx->tspace)
+                       return -ENOMEM;
+               ctx->tspace_size = vsize;
+       }
+
+       MPN_MUL_N_RECURSE(prodp, up, vp, vsize, ctx->tspace);
+
+       prodp += vsize;
+       up += vsize;
+       usize -= vsize;
+       if (usize >= vsize) {
+               if (!ctx->tp || ctx->tp_size < vsize) {
+                       if (ctx->tp)
+                               mpi_free_limb_space(ctx->tp);
+                       ctx->tp = mpi_alloc_limb_space(2 * vsize);
+                       if (!ctx->tp) {
+                               if (ctx->tspace)
+                                       mpi_free_limb_space(ctx->tspace);
+                               ctx->tspace = NULL;
+                               return -ENOMEM;
+                       }
+                       ctx->tp_size = vsize;
+               }
+
+               do {
+                       MPN_MUL_N_RECURSE(ctx->tp, up, vp, vsize, ctx->tspace);
+                       cy = mpihelp_add_n(prodp, prodp, ctx->tp, vsize);
+                       mpihelp_add_1(prodp + vsize, ctx->tp + vsize, vsize,
+                                     cy);
+                       prodp += vsize;
+                       up += vsize;
+                       usize -= vsize;
+               } while (usize >= vsize);
+       }
+
+       if (usize) {
+               if (usize < KARATSUBA_THRESHOLD) {
+                       mpi_limb_t tmp;
+                       if (mpihelp_mul(ctx->tspace, vp, vsize, up, usize, &tmp)
+                           < 0)
+                               return -ENOMEM;
+               } else {
+                       if (!ctx->next) {
+                               ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL);
+                               if (!ctx->next)
+                                       return -ENOMEM;
+                       }
+                       if (mpihelp_mul_karatsuba_case(ctx->tspace,
+                                                      vp, vsize,
+                                                      up, usize,
+                                                      ctx->next) < 0)
+                               return -ENOMEM;
+               }
+
+               cy = mpihelp_add_n(prodp, prodp, ctx->tspace, vsize);
+               mpihelp_add_1(prodp + vsize, ctx->tspace + vsize, usize, cy);
+       }
+
+       return 0;
+}
+
+void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx)
+{
+       struct karatsuba_ctx *ctx2;
+
+       if (ctx->tp)
+               mpi_free_limb_space(ctx->tp);
+       if (ctx->tspace)
+               mpi_free_limb_space(ctx->tspace);
+       for (ctx = ctx->next; ctx; ctx = ctx2) {
+               ctx2 = ctx->next;
+               if (ctx->tp)
+                       mpi_free_limb_space(ctx->tp);
+               if (ctx->tspace)
+                       mpi_free_limb_space(ctx->tspace);
+               kfree(ctx);
+       }
+}
+
+/* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
+ * and v (pointed to by VP, with VSIZE limbs), and store the result at
+ * PRODP.  USIZE + VSIZE limbs are always stored, but if the input
+ * operands are normalized.  Return the most significant limb of the
+ * result.
+ *
+ * NOTE: The space pointed to by PRODP is overwritten before finished
+ * with U and V, so overlap is an error.
+ *
+ * Argument constraints:
+ * 1. USIZE >= VSIZE.
+ * 2. PRODP != UP and PRODP != VP, i.e. the destination
+ *    must be distinct from the multiplier and the multiplicand.
+ */
+
+int
+mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
+           mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result)
+{
+       mpi_ptr_t prod_endp = prodp + usize + vsize - 1;
+       mpi_limb_t cy;
+       struct karatsuba_ctx ctx;
+
+       if (vsize < KARATSUBA_THRESHOLD) {
+               mpi_size_t i;
+               mpi_limb_t v_limb;
+
+               if (!vsize) {
+                       *_result = 0;
+                       return 0;
+               }
+
+               /* Multiply by the first limb in V separately, as the result can be
+                * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
+               v_limb = vp[0];
+               if (v_limb <= 1) {
+                       if (v_limb == 1)
+                               MPN_COPY(prodp, up, usize);
+                       else
+                               MPN_ZERO(prodp, usize);
+                       cy = 0;
+               } else
+                       cy = mpihelp_mul_1(prodp, up, usize, v_limb);
+
+               prodp[usize] = cy;
+               prodp++;
+
+               /* For each iteration in the outer loop, multiply one limb from
+                * U with one limb from V, and add it to PROD.  */
+               for (i = 1; i < vsize; i++) {
+                       v_limb = vp[i];
+                       if (v_limb <= 1) {
+                               cy = 0;
+                               if (v_limb == 1)
+                                       cy = mpihelp_add_n(prodp, prodp, up,
+                                                          usize);
+                       } else
+                               cy = mpihelp_addmul_1(prodp, up, usize, v_limb);
+
+                       prodp[usize] = cy;
+                       prodp++;
+               }
+
+               *_result = cy;
+               return 0;
+       }
+
+       memset(&ctx, 0, sizeof ctx);
+       if (mpihelp_mul_karatsuba_case(prodp, up, usize, vp, vsize, &ctx) < 0)
+               return -ENOMEM;
+       mpihelp_release_karatsuba_ctx(&ctx);
+       *_result = *prod_endp;
+       return 0;
+}
diff --git a/lib/mpi/mpiutil.c b/lib/mpi/mpiutil.c
new file mode 100644 (file)
index 0000000..eefc55d
--- /dev/null
@@ -0,0 +1,208 @@
+/* mpiutil.ac  -  Utility functions for MPI
+ * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 "mpi-internal.h"
+
+/****************
+ * Note:  It was a bad idea to use the number of limbs to allocate
+ *       because on a alpha the limbs are large but we normally need
+ *       integers of n bits - So we should chnage this to bits (or bytes).
+ *
+ *       But mpi_alloc is used in a lot of places :-)
+ */
+MPI mpi_alloc(unsigned nlimbs)
+{
+       MPI a;
+
+       a = kmalloc(sizeof *a, GFP_KERNEL);
+       if (!a)
+               return a;
+
+       if (nlimbs) {
+               a->d = mpi_alloc_limb_space(nlimbs);
+               if (!a->d) {
+                       kfree(a);
+                       return NULL;
+               }
+       } else {
+               a->d = NULL;
+       }
+
+       a->alloced = nlimbs;
+       a->nlimbs = 0;
+       a->sign = 0;
+       a->flags = 0;
+       a->nbits = 0;
+       return a;
+}
+EXPORT_SYMBOL_GPL(mpi_alloc);
+
+mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs)
+{
+       size_t len = nlimbs * sizeof(mpi_limb_t);
+
+       return kmalloc(len, GFP_KERNEL);
+}
+
+void mpi_free_limb_space(mpi_ptr_t a)
+{
+       if (!a)
+               return;
+
+       kfree(a);
+}
+
+void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs)
+{
+       mpi_free_limb_space(a->d);
+       a->d = ap;
+       a->alloced = nlimbs;
+}
+
+/****************
+ * Resize the array of A to NLIMBS. the additional space is cleared
+ * (set to 0) [done by m_realloc()]
+ */
+int mpi_resize(MPI a, unsigned nlimbs)
+{
+       void *p;
+
+       if (nlimbs <= a->alloced)
+               return 0;       /* no need to do it */
+
+       if (a->d) {
+               p = kmalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+               memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t));
+               kfree(a->d);
+               a->d = p;
+       } else {
+               a->d = kzalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL);
+               if (!a->d)
+                       return -ENOMEM;
+       }
+       a->alloced = nlimbs;
+       return 0;
+}
+
+void mpi_clear(MPI a)
+{
+       a->nlimbs = 0;
+       a->nbits = 0;
+       a->flags = 0;
+}
+
+void mpi_free(MPI a)
+{
+       if (!a)
+               return;
+
+       if (a->flags & 4)
+               kfree(a->d);
+       else
+               mpi_free_limb_space(a->d);
+
+       if (a->flags & ~7)
+               pr_info("invalid flag value in mpi\n");
+       kfree(a);
+}
+EXPORT_SYMBOL_GPL(mpi_free);
+
+/****************
+ * Note: This copy function should not interpret the MPI
+ *      but copy it transparently.
+ */
+int mpi_copy(MPI *copied, const MPI a)
+{
+       size_t i;
+       MPI b;
+
+       *copied = MPI_NULL;
+
+       if (a) {
+               b = mpi_alloc(a->nlimbs);
+               if (!b)
+                       return -ENOMEM;
+
+               b->nlimbs = a->nlimbs;
+               b->sign = a->sign;
+               b->flags = a->flags;
+               b->nbits = a->nbits;
+
+               for (i = 0; i < b->nlimbs; i++)
+                       b->d[i] = a->d[i];
+
+               *copied = b;
+       }
+
+       return 0;
+}
+
+int mpi_set(MPI w, const MPI u)
+{
+       mpi_ptr_t wp, up;
+       mpi_size_t usize = u->nlimbs;
+       int usign = u->sign;
+
+       if (RESIZE_IF_NEEDED(w, (size_t) usize) < 0)
+               return -ENOMEM;
+
+       wp = w->d;
+       up = u->d;
+       MPN_COPY(wp, up, usize);
+       w->nlimbs = usize;
+       w->nbits = u->nbits;
+       w->flags = u->flags;
+       w->sign = usign;
+       return 0;
+}
+
+int mpi_set_ui(MPI w, unsigned long u)
+{
+       if (RESIZE_IF_NEEDED(w, 1) < 0)
+               return -ENOMEM;
+       w->d[0] = u;
+       w->nlimbs = u ? 1 : 0;
+       w->sign = 0;
+       w->nbits = 0;
+       w->flags = 0;
+       return 0;
+}
+
+MPI mpi_alloc_set_ui(unsigned long u)
+{
+       MPI w = mpi_alloc(1);
+       if (!w)
+               return w;
+       w->d[0] = u;
+       w->nlimbs = u ? 1 : 0;
+       w->sign = 0;
+       return w;
+}
+
+void mpi_swap(MPI a, MPI b)
+{
+       struct gcry_mpi tmp;
+
+       tmp = *a;
+       *a = *b;
+       *b = tmp;
+}
diff --git a/lib/pci_iomap.c b/lib/pci_iomap.c
new file mode 100644 (file)
index 0000000..4b0fdc2
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Implement the default iomap interfaces
+ *
+ * (C) Copyright 2004 Linus Torvalds
+ */
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <linux/export.h>
+
+#ifdef CONFIG_PCI
+/**
+ * pci_iomap - create a virtual mapping cookie for a PCI BAR
+ * @dev: PCI device that owns the BAR
+ * @bar: BAR number
+ * @maxlen: length of the memory to map
+ *
+ * Using this function you will get a __iomem address to your device BAR.
+ * You can access it using ioread*() and iowrite*(). These functions hide
+ * the details if this is a MMIO or PIO address space and will just do what
+ * you expect from them in the correct way.
+ *
+ * @maxlen specifies the maximum length to map. If you want to get access to
+ * the complete BAR without checking for its length first, pass %0 here.
+ * */
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       resource_size_t start = pci_resource_start(dev, bar);
+       resource_size_t len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start)
+               return NULL;
+       if (maxlen && len > maxlen)
+               len = maxlen;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE)
+                       return ioremap(start, len);
+               return ioremap_nocache(start, len);
+       }
+       /* What? */
+       return NULL;
+}
+
+EXPORT_SYMBOL(pci_iomap);
+#endif /* CONFIG_PCI */
index d9df7454519cd546c71aa10adf14204bee86ef7f..dc63d08183945bd25e1c1f854f65cfd75b20b254 100644 (file)
 struct radix_tree_node {
        unsigned int    height;         /* Height from the bottom */
        unsigned int    count;
-       struct rcu_head rcu_head;
+       union {
+               struct radix_tree_node *parent; /* Used when ascending tree */
+               struct rcu_head rcu_head;       /* Used when freeing node */
+       };
        void __rcu      *slots[RADIX_TREE_MAP_SIZE];
        unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
 };
 
-struct radix_tree_path {
-       struct radix_tree_node *node;
-       int offset;
-};
-
 #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
 #define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
                                          RADIX_TREE_MAP_SHIFT))
@@ -256,6 +254,7 @@ static inline unsigned long radix_tree_maxindex(unsigned int height)
 static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
 {
        struct radix_tree_node *node;
+       struct radix_tree_node *slot;
        unsigned int height;
        int tag;
 
@@ -274,18 +273,23 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                if (!(node = radix_tree_node_alloc(root)))
                        return -ENOMEM;
 
-               /* Increase the height.  */
-               node->slots[0] = indirect_to_ptr(root->rnode);
-
                /* Propagate the aggregated tag info into the new root */
                for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
                        if (root_tag_get(root, tag))
                                tag_set(node, tag, 0);
                }
 
+               /* Increase the height.  */
                newheight = root->height+1;
                node->height = newheight;
                node->count = 1;
+               node->parent = NULL;
+               slot = root->rnode;
+               if (newheight > 1) {
+                       slot = indirect_to_ptr(slot);
+                       slot->parent = node;
+               }
+               node->slots[0] = slot;
                node = ptr_to_indirect(node);
                rcu_assign_pointer(root->rnode, node);
                root->height = newheight;
@@ -331,6 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                        if (!(slot = radix_tree_node_alloc(root)))
                                return -ENOMEM;
                        slot->height = height;
+                       slot->parent = node;
                        if (node) {
                                rcu_assign_pointer(node->slots[offset], slot);
                                node->count++;
@@ -504,47 +509,41 @@ EXPORT_SYMBOL(radix_tree_tag_set);
 void *radix_tree_tag_clear(struct radix_tree_root *root,
                        unsigned long index, unsigned int tag)
 {
-       /*
-        * The radix tree path needs to be one longer than the maximum path
-        * since the "list" is null terminated.
-        */
-       struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot = NULL;
        unsigned int height, shift;
+       int uninitialized_var(offset);
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
                goto out;
 
-       shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       pathp->node = NULL;
+       shift = height * RADIX_TREE_MAP_SHIFT;
        slot = indirect_to_ptr(root->rnode);
 
-       while (height > 0) {
-               int offset;
-
+       while (shift) {
                if (slot == NULL)
                        goto out;
 
+               shift -= RADIX_TREE_MAP_SHIFT;
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               pathp[1].offset = offset;
-               pathp[1].node = slot;
+               node = slot;
                slot = slot->slots[offset];
-               pathp++;
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
        }
 
        if (slot == NULL)
                goto out;
 
-       while (pathp->node) {
-               if (!tag_get(pathp->node, tag, pathp->offset))
+       while (node) {
+               if (!tag_get(node, tag, offset))
                        goto out;
-               tag_clear(pathp->node, tag, pathp->offset);
-               if (any_tag_set(pathp->node, tag))
+               tag_clear(node, tag, offset);
+               if (any_tag_set(node, tag))
                        goto out;
-               pathp--;
+
+               index >>= RADIX_TREE_MAP_SHIFT;
+               offset = index & RADIX_TREE_MAP_MASK;
+               node = node->parent;
        }
 
        /* clear the root's tag bit */
@@ -646,8 +645,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                unsigned int iftag, unsigned int settag)
 {
        unsigned int height = root->height;
-       struct radix_tree_path path[height];
-       struct radix_tree_path *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot;
        unsigned int shift;
        unsigned long tagged = 0;
@@ -671,14 +669,8 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        slot = indirect_to_ptr(root->rnode);
 
-       /*
-        * we fill the path from (root->height - 2) to 0, leaving the index at
-        * (root->height - 1) as a terminator. Zero the node in the terminator
-        * so that we can use this to end walk loops back up the path.
-        */
-       path[height - 1].node = NULL;
-
        for (;;) {
+               unsigned long upindex;
                int offset;
 
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
@@ -686,12 +678,10 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                        goto next;
                if (!tag_get(slot, iftag, offset))
                        goto next;
-               if (height > 1) {
+               if (shift) {
                        /* Go down one level */
-                       height--;
                        shift -= RADIX_TREE_MAP_SHIFT;
-                       path[height - 1].node = slot;
-                       path[height - 1].offset = offset;
+                       node = slot;
                        slot = slot->slots[offset];
                        continue;
                }
@@ -701,15 +691,27 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
                tag_set(slot, settag, offset);
 
                /* walk back up the path tagging interior nodes */
-               pathp = &path[0];
-               while (pathp->node) {
+               upindex = index;
+               while (node) {
+                       upindex >>= RADIX_TREE_MAP_SHIFT;
+                       offset = upindex & RADIX_TREE_MAP_MASK;
+
                        /* stop if we find a node with the tag already set */
-                       if (tag_get(pathp->node, settag, pathp->offset))
+                       if (tag_get(node, settag, offset))
                                break;
-                       tag_set(pathp->node, settag, pathp->offset);
-                       pathp++;
+                       tag_set(node, settag, offset);
+                       node = node->parent;
                }
 
+               /*
+                * Small optimization: now clear that node pointer.
+                * Since all of this slot's ancestors now have the tag set
+                * from setting it above, we have no further need to walk
+                * back up the tree setting tags, until we update slot to
+                * point to another radix_tree_node.
+                */
+               node = NULL;
+
 next:
                /* Go to next item at level determined by 'shift' */
                index = ((index >> shift) + 1) << shift;
@@ -724,8 +726,7 @@ next:
                         * last_index is guaranteed to be in the tree, what
                         * we do below cannot wander astray.
                         */
-                       slot = path[height - 1].node;
-                       height++;
+                       slot = slot->parent;
                        shift += RADIX_TREE_MAP_SHIFT;
                }
        }
@@ -1299,7 +1300,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
        /* try to shrink tree height */
        while (root->height > 0) {
                struct radix_tree_node *to_free = root->rnode;
-               void *newptr;
+               struct radix_tree_node *slot;
 
                BUG_ON(!radix_tree_is_indirect_ptr(to_free));
                to_free = indirect_to_ptr(to_free);
@@ -1320,10 +1321,12 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
                 * (to_free->slots[0]), it will be safe to dereference the new
                 * one (root->rnode) as far as dependent read barriers go.
                 */
-               newptr = to_free->slots[0];
-               if (root->height > 1)
-                       newptr = ptr_to_indirect(newptr);
-               root->rnode = newptr;
+               slot = to_free->slots[0];
+               if (root->height > 1) {
+                       slot->parent = NULL;
+                       slot = ptr_to_indirect(slot);
+               }
+               root->rnode = slot;
                root->height--;
 
                /*
@@ -1363,16 +1366,12 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
  */
 void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
 {
-       /*
-        * The radix tree path needs to be one longer than the maximum path
-        * since the "list" is null terminated.
-        */
-       struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
+       struct radix_tree_node *node = NULL;
        struct radix_tree_node *slot = NULL;
        struct radix_tree_node *to_free;
        unsigned int height, shift;
        int tag;
-       int offset;
+       int uninitialized_var(offset);
 
        height = root->height;
        if (index > radix_tree_maxindex(height))
@@ -1385,39 +1384,35 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                goto out;
        }
        slot = indirect_to_ptr(slot);
-
-       shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       pathp->node = NULL;
+       shift = height * RADIX_TREE_MAP_SHIFT;
 
        do {
                if (slot == NULL)
                        goto out;
 
-               pathp++;
+               shift -= RADIX_TREE_MAP_SHIFT;
                offset = (index >> shift) & RADIX_TREE_MAP_MASK;
-               pathp->offset = offset;
-               pathp->node = slot;
+               node = slot;
                slot = slot->slots[offset];
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
-       } while (height > 0);
+       } while (shift);
 
        if (slot == NULL)
                goto out;
 
        /*
-        * Clear all tags associated with the just-deleted item
+        * Clear all tags associated with the item to be deleted.
+        * This way of doing it would be inefficient, but seldom is any set.
         */
        for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
-               if (tag_get(pathp->node, tag, pathp->offset))
+               if (tag_get(node, tag, offset))
                        radix_tree_tag_clear(root, index, tag);
        }
 
        to_free = NULL;
        /* Now free the nodes we do not need anymore */
-       while (pathp->node) {
-               pathp->node->slots[pathp->offset] = NULL;
-               pathp->node->count--;
+       while (node) {
+               node->slots[offset] = NULL;
+               node->count--;
                /*
                 * Queue the node for deferred freeing after the
                 * last reference to it disappears (set NULL, above).
@@ -1425,17 +1420,20 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                if (to_free)
                        radix_tree_node_free(to_free);
 
-               if (pathp->node->count) {
-                       if (pathp->node == indirect_to_ptr(root->rnode))
+               if (node->count) {
+                       if (node == indirect_to_ptr(root->rnode))
                                radix_tree_shrink(root);
                        goto out;
                }
 
                /* Node with zero slots in use so free it */
-               to_free = pathp->node;
-               pathp--;
+               to_free = node;
 
+               index >>= RADIX_TREE_MAP_SHIFT;
+               offset = index & RADIX_TREE_MAP_MASK;
+               node = node->parent;
        }
+
        root_tag_clear_all(root);
        root->height = 0;
        root->rnode = NULL;
index 8b1a477162dc07242e7a461951bca291cff3dde7..4b2443254de260d2e05cdecb8d3eea903d91734f 100644 (file)
@@ -4,6 +4,7 @@ config DEBUG_PAGEALLOC
        depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC
        depends on !KMEMCHECK
        select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC
+       select PAGE_GUARD if ARCH_SUPPORTS_DEBUG_PAGEALLOC
        ---help---
          Unmap pages from the kernel linear mapping after free_pages().
          This results in a large slowdown, but helps to find certain types
@@ -22,3 +23,7 @@ config WANT_PAGE_DEBUG_FLAGS
 config PAGE_POISONING
        bool
        select WANT_PAGE_DEBUG_FLAGS
+
+config PAGE_GUARD
+       bool
+       select WANT_PAGE_DEBUG_FLAGS
index 1a77012ecdb3c56a92d53ef5b779c9648d54c6a3..668e94df8cf23ab1fa68ab54ff0cd8542a4c460c 100644 (file)
@@ -56,7 +56,7 @@ early_param("bootmem_debug", bootmem_debug_setup);
 
 static unsigned long __init bootmap_bytes(unsigned long pages)
 {
-       unsigned long bytes = (pages + 7) / 8;
+       unsigned long bytes = DIV_ROUND_UP(pages, 8);
 
        return ALIGN(bytes, sizeof(long));
 }
@@ -171,7 +171,6 @@ void __init free_bootmem_late(unsigned long addr, unsigned long size)
 
 static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
 {
-       int aligned;
        struct page *page;
        unsigned long start, end, pages, count = 0;
 
@@ -181,14 +180,8 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
        start = bdata->node_min_pfn;
        end = bdata->node_low_pfn;
 
-       /*
-        * If the start is aligned to the machines wordsize, we might
-        * be able to free pages in bulks of that order.
-        */
-       aligned = !(start & (BITS_PER_LONG - 1));
-
-       bdebug("nid=%td start=%lx end=%lx aligned=%d\n",
-               bdata - bootmem_node_data, start, end, aligned);
+       bdebug("nid=%td start=%lx end=%lx\n",
+               bdata - bootmem_node_data, start, end);
 
        while (start < end) {
                unsigned long *map, idx, vec;
@@ -196,12 +189,17 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
                map = bdata->node_bootmem_map;
                idx = start - bdata->node_min_pfn;
                vec = ~map[idx / BITS_PER_LONG];
-
-               if (aligned && vec == ~0UL && start + BITS_PER_LONG < end) {
+               /*
+                * If we have a properly aligned and fully unreserved
+                * BITS_PER_LONG block of pages in front of us, free
+                * it in one go.
+                */
+               if (IS_ALIGNED(start, BITS_PER_LONG) && vec == ~0UL) {
                        int order = ilog2(BITS_PER_LONG);
 
                        __free_pages_bootmem(pfn_to_page(start), order);
                        count += BITS_PER_LONG;
+                       start += BITS_PER_LONG;
                } else {
                        unsigned long off = 0;
 
@@ -214,8 +212,8 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
                                vec >>= 1;
                                off++;
                        }
+                       start = ALIGN(start + 1, BITS_PER_LONG);
                }
-               start += BITS_PER_LONG;
        }
 
        page = virt_to_page(bdata->node_bootmem_map);
index 1253d7ac332b5031515b5a2f3e9ba4bb4956a27f..71a58f67f4817720a4eca34678b2353fa96863e6 100644 (file)
@@ -350,7 +350,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
                }
 
                if (!cc->sync)
-                       mode |= ISOLATE_CLEAN;
+                       mode |= ISOLATE_ASYNC_MIGRATE;
 
                /* Try isolate the page */
                if (__isolate_lru_page(page, mode, 0) != 0)
@@ -365,8 +365,10 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
                nr_isolated++;
 
                /* Avoid isolating too much */
-               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX)
+               if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) {
+                       ++low_pfn;
                        break;
+               }
        }
 
        acct_isolated(zone, cc);
@@ -555,7 +557,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                nr_migrate = cc->nr_migratepages;
                err = migrate_pages(&cc->migratepages, compaction_alloc,
                                (unsigned long)cc, false,
-                               cc->sync);
+                               cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC);
                update_nr_listpages(cc);
                nr_remaining = cc->nr_migratepages;
 
@@ -669,6 +671,7 @@ static int compact_node(int nid)
                        .nr_freepages = 0,
                        .nr_migratepages = 0,
                        .order = -1,
+                       .sync = true,
                };
 
                zone = &pgdat->node_zones[zoneid];
index 7cea557407f40ef96351a91ade5fd3b9cbe915c0..789ff70c8a4ab7f84bb81410d3e3982a7cb3f987 100644 (file)
@@ -95,9 +95,6 @@ static void unpoison_pages(struct page *page, int n)
 
 void kernel_map_pages(struct page *page, int numpages, int enable)
 {
-       if (!debug_pagealloc_enabled)
-               return;
-
        if (enable)
                unpoison_pages(page, numpages);
        else
index 8d723c9e8b75b316041ea564f5e243b79a94e2b7..469491e0af79fed994d48fd4ada817f8e50c6d6a 100644 (file)
@@ -117,7 +117,8 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
                break;
        case POSIX_FADV_DONTNEED:
                if (!bdi_write_congested(mapping->backing_dev_info))
-                       filemap_flush(mapping);
+                       __filemap_fdatawrite_range(mapping, offset, endbyte,
+                                                  WB_SYNC_NONE);
 
                /* First and last FULL page! */
                start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
index a0701e6eec107ae5247f41885e62a73efb4b4bdc..97f49ed35bd24fba29677857433814103949dd14 100644 (file)
@@ -393,24 +393,11 @@ EXPORT_SYMBOL(filemap_write_and_wait_range);
 int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
 {
        int error;
-       struct mem_cgroup *memcg = NULL;
 
        VM_BUG_ON(!PageLocked(old));
        VM_BUG_ON(!PageLocked(new));
        VM_BUG_ON(new->mapping);
 
-       /*
-        * This is not page migration, but prepare_migration and
-        * end_migration does enough work for charge replacement.
-        *
-        * In the longer term we probably want a specialized function
-        * for moving the charge from old to new in a more efficient
-        * manner.
-        */
-       error = mem_cgroup_prepare_migration(old, new, &memcg, gfp_mask);
-       if (error)
-               return error;
-
        error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
        if (!error) {
                struct address_space *mapping = old->mapping;
@@ -432,13 +419,12 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
                if (PageSwapBacked(new))
                        __inc_zone_page_state(new, NR_SHMEM);
                spin_unlock_irq(&mapping->tree_lock);
+               /* mem_cgroup codes must not be called under tree_lock */
+               mem_cgroup_replace_page_cache(old, new);
                radix_tree_preload_end();
                if (freepage)
                        freepage(old);
                page_cache_release(old);
-               mem_cgroup_end_migration(memcg, old, new, true);
-       } else {
-               mem_cgroup_end_migration(memcg, old, new, false);
        }
 
        return error;
@@ -2351,8 +2337,11 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,
                                        pgoff_t index, unsigned flags)
 {
        int status;
+       gfp_t gfp_mask;
        struct page *page;
        gfp_t gfp_notmask = 0;
+
+       gfp_mask = mapping_gfp_mask(mapping) | __GFP_WRITE;
        if (flags & AOP_FLAG_NOFS)
                gfp_notmask = __GFP_FS;
 repeat:
@@ -2360,7 +2349,7 @@ repeat:
        if (page)
                goto found;
 
-       page = __page_cache_alloc(mapping_gfp_mask(mapping) & ~gfp_notmask);
+       page = __page_cache_alloc(gfp_mask & ~gfp_notmask);
        if (!page)
                return NULL;
        status = add_to_page_cache_lru(page, mapping, index,
index 36b3d988b4ef6ac8c263ee0732c1d08513afb04f..b3ffc21ce8010b9de9c92004e2a364326af8dc1b 100644 (file)
@@ -487,41 +487,68 @@ static struct attribute_group khugepaged_attr_group = {
        .attrs = khugepaged_attr,
        .name = "khugepaged",
 };
-#endif /* CONFIG_SYSFS */
 
-static int __init hugepage_init(void)
+static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 {
        int err;
-#ifdef CONFIG_SYSFS
-       static struct kobject *hugepage_kobj;
-#endif
-
-       err = -EINVAL;
-       if (!has_transparent_hugepage()) {
-               transparent_hugepage_flags = 0;
-               goto out;
-       }
 
-#ifdef CONFIG_SYSFS
-       err = -ENOMEM;
-       hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
-       if (unlikely(!hugepage_kobj)) {
+       *hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
+       if (unlikely(!*hugepage_kobj)) {
                printk(KERN_ERR "hugepage: failed kobject create\n");
-               goto out;
+               return -ENOMEM;
        }
 
-       err = sysfs_create_group(hugepage_kobj, &hugepage_attr_group);
+       err = sysfs_create_group(*hugepage_kobj, &hugepage_attr_group);
        if (err) {
                printk(KERN_ERR "hugepage: failed register hugeage group\n");
-               goto out;
+               goto delete_obj;
        }
 
-       err = sysfs_create_group(hugepage_kobj, &khugepaged_attr_group);
+       err = sysfs_create_group(*hugepage_kobj, &khugepaged_attr_group);
        if (err) {
                printk(KERN_ERR "hugepage: failed register hugeage group\n");
-               goto out;
+               goto remove_hp_group;
        }
-#endif
+
+       return 0;
+
+remove_hp_group:
+       sysfs_remove_group(*hugepage_kobj, &hugepage_attr_group);
+delete_obj:
+       kobject_put(*hugepage_kobj);
+       return err;
+}
+
+static void __init hugepage_exit_sysfs(struct kobject *hugepage_kobj)
+{
+       sysfs_remove_group(hugepage_kobj, &khugepaged_attr_group);
+       sysfs_remove_group(hugepage_kobj, &hugepage_attr_group);
+       kobject_put(hugepage_kobj);
+}
+#else
+static inline int hugepage_init_sysfs(struct kobject **hugepage_kobj)
+{
+       return 0;
+}
+
+static inline void hugepage_exit_sysfs(struct kobject *hugepage_kobj)
+{
+}
+#endif /* CONFIG_SYSFS */
+
+static int __init hugepage_init(void)
+{
+       int err;
+       struct kobject *hugepage_kobj;
+
+       if (!has_transparent_hugepage()) {
+               transparent_hugepage_flags = 0;
+               return -EINVAL;
+       }
+
+       err = hugepage_init_sysfs(&hugepage_kobj);
+       if (err)
+               return err;
 
        err = khugepaged_slab_init();
        if (err)
@@ -545,7 +572,9 @@ static int __init hugepage_init(void)
 
        set_recommended_min_free_kbytes();
 
+       return 0;
 out:
+       hugepage_exit_sysfs(hugepage_kobj);
        return err;
 }
 module_init(hugepage_init)
@@ -997,7 +1026,7 @@ out:
 }
 
 int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
-                pmd_t *pmd)
+                pmd_t *pmd, unsigned long addr)
 {
        int ret = 0;
 
@@ -1013,6 +1042,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
                        pgtable = get_pmd_huge_pte(tlb->mm);
                        page = pmd_page(*pmd);
                        pmd_clear(pmd);
+                       tlb_remove_pmd_tlb_entry(tlb, pmd, addr);
                        page_remove_rmap(page);
                        VM_BUG_ON(page_mapcount(page) < 0);
                        add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR);
@@ -1116,7 +1146,6 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                        entry = pmd_modify(entry, newprot);
                        set_pmd_at(mm, addr, pmd, entry);
                        spin_unlock(&vma->vm_mm->page_table_lock);
-                       flush_tlb_range(vma, addr, addr + HPAGE_PMD_SIZE);
                        ret = 1;
                }
        } else
@@ -1199,16 +1228,16 @@ static int __split_huge_page_splitting(struct page *page,
 static void __split_huge_page_refcount(struct page *page)
 {
        int i;
-       unsigned long head_index = page->index;
        struct zone *zone = page_zone(page);
-       int zonestat;
        int tail_count = 0;
 
        /* prevent PageLRU to go away from under us, and freeze lru stats */
        spin_lock_irq(&zone->lru_lock);
        compound_lock(page);
+       /* complete memcg works before add pages to LRU */
+       mem_cgroup_split_huge_fixup(page);
 
-       for (i = 1; i < HPAGE_PMD_NR; i++) {
+       for (i = HPAGE_PMD_NR - 1; i >= 1; i--) {
                struct page *page_tail = page + i;
 
                /* tail_page->_mapcount cannot change */
@@ -1271,14 +1300,13 @@ static void __split_huge_page_refcount(struct page *page)
                BUG_ON(page_tail->mapping);
                page_tail->mapping = page->mapping;
 
-               page_tail->index = ++head_index;
+               page_tail->index = page->index + i;
 
                BUG_ON(!PageAnon(page_tail));
                BUG_ON(!PageUptodate(page_tail));
                BUG_ON(!PageDirty(page_tail));
                BUG_ON(!PageSwapBacked(page_tail));
 
-               mem_cgroup_split_huge_fixup(page, page_tail);
 
                lru_add_page_tail(zone, page, page_tail);
        }
@@ -1288,15 +1316,6 @@ static void __split_huge_page_refcount(struct page *page)
        __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
        __mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR);
 
-       /*
-        * A hugepage counts for HPAGE_PMD_NR pages on the LRU statistics,
-        * so adjust those appropriately if this page is on the LRU.
-        */
-       if (PageLRU(page)) {
-               zonestat = NR_LRU_BASE + page_lru(page);
-               __mod_zone_page_state(zone, zonestat, -(HPAGE_PMD_NR-1));
-       }
-
        ClearPageCompound(page);
        compound_unlock(page);
        spin_unlock_irq(&zone->lru_lock);
index 7acd12503f734bfcaff2c4fed244e594952962ea..ea8c3a4cd2ae8acdf52a7a4e862e277f2390c265 100644 (file)
@@ -800,7 +800,7 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
 
        if (page && arch_prepare_hugepage(page)) {
                __free_pages(page, huge_page_order(h));
-               return NULL;
+               page = NULL;
        }
 
        spin_lock(&hugetlb_lock);
@@ -2315,8 +2315,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
         * from page cache lookup which is in HPAGE_SIZE units.
         */
        address = address & huge_page_mask(h);
-       pgoff = ((address - vma->vm_start) >> PAGE_SHIFT)
-               + (vma->vm_pgoff >> PAGE_SHIFT);
+       pgoff = vma_hugecache_offset(h, vma, address);
        mapping = (struct address_space *)page_private(page);
 
        /*
@@ -2349,6 +2348,9 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
 
 /*
  * Hugetlb_cow() should be called with page lock of the original hugepage held.
+ * Called with hugetlb_instantiation_mutex held and pte_page locked so we
+ * cannot race with other handlers or page migration.
+ * Keep the pte_same checks anyway to make transition from the mutex easier.
  */
 static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, pte_t *ptep, pte_t pte,
@@ -2408,7 +2410,14 @@ retry_avoidcopy:
                                BUG_ON(page_count(old_page) != 1);
                                BUG_ON(huge_pte_none(pte));
                                spin_lock(&mm->page_table_lock);
-                               goto retry_avoidcopy;
+                               ptep = huge_pte_offset(mm, address & huge_page_mask(h));
+                               if (likely(pte_same(huge_ptep_get(ptep), pte)))
+                                       goto retry_avoidcopy;
+                               /*
+                                * race occurs while re-acquiring page_table_lock, and
+                                * our job is done.
+                                */
+                               return 0;
                        }
                        WARN_ON_ONCE(1);
                }
@@ -2630,6 +2639,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        static DEFINE_MUTEX(hugetlb_instantiation_mutex);
        struct hstate *h = hstate_vma(vma);
 
+       address &= huge_page_mask(h);
+
        ptep = huge_pte_offset(mm, address);
        if (ptep) {
                entry = huge_ptep_get(ptep);
index 310544a379ae9c7b886b3b50815e5f3d5a991ba8..1925ffbfb27f00ac3d3d262ce0ea1c8aaa3a117f 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -28,6 +28,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/memcontrol.h>
 #include <linux/rbtree.h>
 #include <linux/memory.h>
 #include <linux/mmu_notifier.h>
@@ -1571,6 +1572,16 @@ struct page *ksm_does_need_to_copy(struct page *page,
 
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
        if (new_page) {
+               /*
+                * The memcg-specific accounting when moving
+                * pages around the LRU lists relies on the
+                * page's owner (memcg) to be valid.  Usually,
+                * pages are assigned to a new owner before
+                * being put on the LRU list, but since this
+                * is not the case here, the stale owner from
+                * a previous allocation cycle must be reset.
+                */
+               mem_cgroup_reset_owner(new_page);
                copy_user_highpage(new_page, page, address, vma);
 
                SetPageDirty(new_page);
index d87aa3510c5e0a0e62e6c97ec6f0a85420c40d9d..602207be985379f7e15e94ea546b8d70b0b2a7b9 100644 (file)
@@ -123,16 +123,22 @@ struct mem_cgroup_stat_cpu {
        unsigned long targets[MEM_CGROUP_NTARGETS];
 };
 
+struct mem_cgroup_reclaim_iter {
+       /* css_id of the last scanned hierarchy member */
+       int position;
+       /* scan generation, increased every round-trip */
+       unsigned int generation;
+};
+
 /*
  * per-zone information in memory controller.
  */
 struct mem_cgroup_per_zone {
-       /*
-        * spin_lock to protect the per cgroup LRU
-        */
-       struct list_head        lists[NR_LRU_LISTS];
+       struct lruvec           lruvec;
        unsigned long           count[NR_LRU_LISTS];
 
+       struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1];
+
        struct zone_reclaim_stat reclaim_stat;
        struct rb_node          tree_node;      /* RB tree node */
        unsigned long long      usage_in_excess;/* Set to the value by which */
@@ -233,11 +239,6 @@ struct mem_cgroup {
         * per zone LRU lists.
         */
        struct mem_cgroup_lru_info info;
-       /*
-        * While reclaiming in a hierarchy, we cache the last child we
-        * reclaimed from.
-        */
-       int last_scanned_child;
        int last_scanned_node;
 #if MAX_NUMNODES > 1
        nodemask_t      scan_nodes;
@@ -366,8 +367,6 @@ enum charge_type {
 #define MEM_CGROUP_RECLAIM_NOSWAP      (1 << MEM_CGROUP_RECLAIM_NOSWAP_BIT)
 #define MEM_CGROUP_RECLAIM_SHRINK_BIT  0x1
 #define MEM_CGROUP_RECLAIM_SHRINK      (1 << MEM_CGROUP_RECLAIM_SHRINK_BIT)
-#define MEM_CGROUP_RECLAIM_SOFT_BIT    0x2
-#define MEM_CGROUP_RECLAIM_SOFT                (1 << MEM_CGROUP_RECLAIM_SOFT_BIT)
 
 static void mem_cgroup_get(struct mem_cgroup *memcg);
 static void mem_cgroup_put(struct mem_cgroup *memcg);
@@ -566,7 +565,7 @@ static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg)
        struct mem_cgroup_per_zone *mz;
        struct mem_cgroup_tree_per_zone *mctz;
 
-       for_each_node_state(node, N_POSSIBLE) {
+       for_each_node(node) {
                for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                        mz = mem_cgroup_zoneinfo(memcg, node, zone);
                        mctz = soft_limit_tree_node_zone(node, zone);
@@ -656,16 +655,6 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
        this_cpu_add(memcg->stat->count[MEM_CGROUP_STAT_SWAPOUT], val);
 }
 
-void mem_cgroup_pgfault(struct mem_cgroup *memcg, int val)
-{
-       this_cpu_add(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT], val);
-}
-
-void mem_cgroup_pgmajfault(struct mem_cgroup *memcg, int val)
-{
-       this_cpu_add(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT], val);
-}
-
 static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
                                            enum mem_cgroup_events_index idx)
 {
@@ -749,37 +738,32 @@ static unsigned long mem_cgroup_nr_lru_pages(struct mem_cgroup *memcg,
        return total;
 }
 
-static bool __memcg_event_check(struct mem_cgroup *memcg, int target)
+static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
+                                      enum mem_cgroup_events_target target)
 {
        unsigned long val, next;
 
        val = __this_cpu_read(memcg->stat->events[MEM_CGROUP_EVENTS_COUNT]);
        next = __this_cpu_read(memcg->stat->targets[target]);
        /* from time_after() in jiffies.h */
-       return ((long)next - (long)val < 0);
-}
-
-static void __mem_cgroup_target_update(struct mem_cgroup *memcg, int target)
-{
-       unsigned long val, next;
-
-       val = __this_cpu_read(memcg->stat->events[MEM_CGROUP_EVENTS_COUNT]);
-
-       switch (target) {
-       case MEM_CGROUP_TARGET_THRESH:
-               next = val + THRESHOLDS_EVENTS_TARGET;
-               break;
-       case MEM_CGROUP_TARGET_SOFTLIMIT:
-               next = val + SOFTLIMIT_EVENTS_TARGET;
-               break;
-       case MEM_CGROUP_TARGET_NUMAINFO:
-               next = val + NUMAINFO_EVENTS_TARGET;
-               break;
-       default:
-               return;
+       if ((long)next - (long)val < 0) {
+               switch (target) {
+               case MEM_CGROUP_TARGET_THRESH:
+                       next = val + THRESHOLDS_EVENTS_TARGET;
+                       break;
+               case MEM_CGROUP_TARGET_SOFTLIMIT:
+                       next = val + SOFTLIMIT_EVENTS_TARGET;
+                       break;
+               case MEM_CGROUP_TARGET_NUMAINFO:
+                       next = val + NUMAINFO_EVENTS_TARGET;
+                       break;
+               default:
+                       break;
+               }
+               __this_cpu_write(memcg->stat->targets[target], next);
+               return true;
        }
-
-       __this_cpu_write(memcg->stat->targets[target], next);
+       return false;
 }
 
 /*
@@ -790,25 +774,27 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
 {
        preempt_disable();
        /* threshold event is triggered in finer grain than soft limit */
-       if (unlikely(__memcg_event_check(memcg, MEM_CGROUP_TARGET_THRESH))) {
+       if (unlikely(mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_THRESH))) {
+               bool do_softlimit, do_numainfo;
+
+               do_softlimit = mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_SOFTLIMIT);
+#if MAX_NUMNODES > 1
+               do_numainfo = mem_cgroup_event_ratelimit(memcg,
+                                               MEM_CGROUP_TARGET_NUMAINFO);
+#endif
+               preempt_enable();
+
                mem_cgroup_threshold(memcg);
-               __mem_cgroup_target_update(memcg, MEM_CGROUP_TARGET_THRESH);
-               if (unlikely(__memcg_event_check(memcg,
-                            MEM_CGROUP_TARGET_SOFTLIMIT))) {
+               if (unlikely(do_softlimit))
                        mem_cgroup_update_tree(memcg, page);
-                       __mem_cgroup_target_update(memcg,
-                                                  MEM_CGROUP_TARGET_SOFTLIMIT);
-               }
 #if MAX_NUMNODES > 1
-               if (unlikely(__memcg_event_check(memcg,
-                       MEM_CGROUP_TARGET_NUMAINFO))) {
+               if (unlikely(do_numainfo))
                        atomic_inc(&memcg->numainfo_events);
-                       __mem_cgroup_target_update(memcg,
-                               MEM_CGROUP_TARGET_NUMAINFO);
-               }
 #endif
-       }
-       preempt_enable();
+       } else
+               preempt_enable();
 }
 
 struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont)
@@ -853,83 +839,116 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
        return memcg;
 }
 
-/* The caller has to guarantee "mem" exists before calling this */
-static struct mem_cgroup *mem_cgroup_start_loop(struct mem_cgroup *memcg)
+/**
+ * mem_cgroup_iter - iterate over memory cgroup hierarchy
+ * @root: hierarchy root
+ * @prev: previously returned memcg, NULL on first invocation
+ * @reclaim: cookie for shared reclaim walks, NULL for full walks
+ *
+ * Returns references to children of the hierarchy below @root, or
+ * @root itself, or %NULL after a full round-trip.
+ *
+ * Caller must pass the return value in @prev on subsequent
+ * invocations for reference counting, or use mem_cgroup_iter_break()
+ * to cancel a hierarchy walk before the round-trip is complete.
+ *
+ * Reclaimers can specify a zone and a priority level in @reclaim to
+ * divide up the memcgs in the hierarchy among all concurrent
+ * reclaimers operating on the same zone and priority.
+ */
+struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
+                                  struct mem_cgroup *prev,
+                                  struct mem_cgroup_reclaim_cookie *reclaim)
 {
-       struct cgroup_subsys_state *css;
-       int found;
+       struct mem_cgroup *memcg = NULL;
+       int id = 0;
 
-       if (!memcg) /* ROOT cgroup has the smallest ID */
-               return root_mem_cgroup; /*css_put/get against root is ignored*/
-       if (!memcg->use_hierarchy) {
-               if (css_tryget(&memcg->css))
-                       return memcg;
+       if (mem_cgroup_disabled())
                return NULL;
-       }
-       rcu_read_lock();
-       /*
-        * searching a memory cgroup which has the smallest ID under given
-        * ROOT cgroup. (ID >= 1)
-        */
-       css = css_get_next(&mem_cgroup_subsys, 1, &memcg->css, &found);
-       if (css && css_tryget(css))
-               memcg = container_of(css, struct mem_cgroup, css);
-       else
-               memcg = NULL;
-       rcu_read_unlock();
-       return memcg;
-}
 
-static struct mem_cgroup *mem_cgroup_get_next(struct mem_cgroup *iter,
-                                       struct mem_cgroup *root,
-                                       bool cond)
-{
-       int nextid = css_id(&iter->css) + 1;
-       int found;
-       int hierarchy_used;
-       struct cgroup_subsys_state *css;
+       if (!root)
+               root = root_mem_cgroup;
 
-       hierarchy_used = iter->use_hierarchy;
+       if (prev && !reclaim)
+               id = css_id(&prev->css);
 
-       css_put(&iter->css);
-       /* If no ROOT, walk all, ignore hierarchy */
-       if (!cond || (root && !hierarchy_used))
-               return NULL;
+       if (prev && prev != root)
+               css_put(&prev->css);
 
-       if (!root)
-               root = root_mem_cgroup;
+       if (!root->use_hierarchy && root != root_mem_cgroup) {
+               if (prev)
+                       return NULL;
+               return root;
+       }
 
-       do {
-               iter = NULL;
-               rcu_read_lock();
+       while (!memcg) {
+               struct mem_cgroup_reclaim_iter *uninitialized_var(iter);
+               struct cgroup_subsys_state *css;
+
+               if (reclaim) {
+                       int nid = zone_to_nid(reclaim->zone);
+                       int zid = zone_idx(reclaim->zone);
+                       struct mem_cgroup_per_zone *mz;
 
-               css = css_get_next(&mem_cgroup_subsys, nextid,
-                               &root->css, &found);
-               if (css && css_tryget(css))
-                       iter = container_of(css, struct mem_cgroup, css);
+                       mz = mem_cgroup_zoneinfo(root, nid, zid);
+                       iter = &mz->reclaim_iter[reclaim->priority];
+                       if (prev && reclaim->generation != iter->generation)
+                               return NULL;
+                       id = iter->position;
+               }
+
+               rcu_read_lock();
+               css = css_get_next(&mem_cgroup_subsys, id + 1, &root->css, &id);
+               if (css) {
+                       if (css == &root->css || css_tryget(css))
+                               memcg = container_of(css,
+                                                    struct mem_cgroup, css);
+               } else
+                       id = 0;
                rcu_read_unlock();
-               /* If css is NULL, no more cgroups will be found */
-               nextid = found + 1;
-       } while (css && !iter);
 
-       return iter;
+               if (reclaim) {
+                       iter->position = id;
+                       if (!css)
+                               iter->generation++;
+                       else if (!prev && memcg)
+                               reclaim->generation = iter->generation;
+               }
+
+               if (prev && !css)
+                       return NULL;
+       }
+       return memcg;
 }
-/*
- * for_eacn_mem_cgroup_tree() for visiting all cgroup under tree. Please
- * be careful that "break" loop is not allowed. We have reference count.
- * Instead of that modify "cond" to be false and "continue" to exit the loop.
- */
-#define for_each_mem_cgroup_tree_cond(iter, root, cond)        \
-       for (iter = mem_cgroup_start_loop(root);\
-            iter != NULL;\
-            iter = mem_cgroup_get_next(iter, root, cond))
 
-#define for_each_mem_cgroup_tree(iter, root) \
-       for_each_mem_cgroup_tree_cond(iter, root, true)
+/**
+ * mem_cgroup_iter_break - abort a hierarchy walk prematurely
+ * @root: hierarchy root
+ * @prev: last visited hierarchy member as returned by mem_cgroup_iter()
+ */
+void mem_cgroup_iter_break(struct mem_cgroup *root,
+                          struct mem_cgroup *prev)
+{
+       if (!root)
+               root = root_mem_cgroup;
+       if (prev && prev != root)
+               css_put(&prev->css);
+}
 
-#define for_each_mem_cgroup_all(iter) \
-       for_each_mem_cgroup_tree_cond(iter, NULL, true)
+/*
+ * Iteration constructs for visiting all cgroups (under a tree).  If
+ * loops are exited prematurely (break), mem_cgroup_iter_break() must
+ * be used for reference counting.
+ */
+#define for_each_mem_cgroup_tree(iter, root)           \
+       for (iter = mem_cgroup_iter(root, NULL, NULL);  \
+            iter != NULL;                              \
+            iter = mem_cgroup_iter(root, iter, NULL))
 
+#define for_each_mem_cgroup(iter)                      \
+       for (iter = mem_cgroup_iter(NULL, NULL, NULL);  \
+            iter != NULL;                              \
+            iter = mem_cgroup_iter(NULL, iter, NULL))
 
 static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
 {
@@ -949,11 +968,11 @@ void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
                goto out;
 
        switch (idx) {
-       case PGMAJFAULT:
-               mem_cgroup_pgmajfault(memcg, 1);
-               break;
        case PGFAULT:
-               mem_cgroup_pgfault(memcg, 1);
+               this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT]);
+               break;
+       case PGMAJFAULT:
+               this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT]);
                break;
        default:
                BUG();
@@ -963,6 +982,27 @@ out:
 }
 EXPORT_SYMBOL(mem_cgroup_count_vm_event);
 
+/**
+ * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg
+ * @zone: zone of the wanted lruvec
+ * @mem: memcg of the wanted lruvec
+ *
+ * Returns the lru list vector holding pages for the given @zone and
+ * @mem.  This can be the global zone lruvec, if the memory controller
+ * is disabled.
+ */
+struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
+                                     struct mem_cgroup *memcg)
+{
+       struct mem_cgroup_per_zone *mz;
+
+       if (mem_cgroup_disabled())
+               return &zone->lruvec;
+
+       mz = mem_cgroup_zoneinfo(memcg, zone_to_nid(zone), zone_idx(zone));
+       return &mz->lruvec;
+}
+
 /*
  * Following LRU functions are allowed to be used without PCG_LOCK.
  * Operations are called by routine of global LRU independently from memcg.
@@ -977,180 +1017,91 @@ EXPORT_SYMBOL(mem_cgroup_count_vm_event);
  * When moving account, the page is not on LRU. It's isolated.
  */
 
-void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru)
-{
-       struct page_cgroup *pc;
-       struct mem_cgroup_per_zone *mz;
-
-       if (mem_cgroup_disabled())
-               return;
-       pc = lookup_page_cgroup(page);
-       /* can happen while we handle swapcache. */
-       if (!TestClearPageCgroupAcctLRU(pc))
-               return;
-       VM_BUG_ON(!pc->mem_cgroup);
-       /*
-        * We don't check PCG_USED bit. It's cleared when the "page" is finally
-        * removed from global LRU.
-        */
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       /* huge page split is done under lru_lock. so, we have no races. */
-       MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       VM_BUG_ON(list_empty(&pc->lru));
-       list_del_init(&pc->lru);
-}
-
-void mem_cgroup_del_lru(struct page *page)
-{
-       mem_cgroup_del_lru_list(page, page_lru(page));
-}
-
-/*
- * Writeback is about to end against a page which has been marked for immediate
- * reclaim.  If it still appears to be reclaimable, move it to the tail of the
- * inactive list.
+/**
+ * mem_cgroup_lru_add_list - account for adding an lru page and return lruvec
+ * @zone: zone of the page
+ * @page: the page
+ * @lru: current lru
+ *
+ * This function accounts for @page being added to @lru, and returns
+ * the lruvec for the given @zone and the memcg @page is charged to.
+ *
+ * The callsite is then responsible for physically linking the page to
+ * the returned lruvec->lists[@lru].
  */
-void mem_cgroup_rotate_reclaimable_page(struct page *page)
+struct lruvec *mem_cgroup_lru_add_list(struct zone *zone, struct page *page,
+                                      enum lru_list lru)
 {
        struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup *memcg;
        struct page_cgroup *pc;
-       enum lru_list lru = page_lru(page);
 
        if (mem_cgroup_disabled())
-               return;
+               return &zone->lruvec;
 
        pc = lookup_page_cgroup(page);
-       /* unused or root page is not rotated. */
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       list_move_tail(&pc->lru, &mz->lists[lru]);
+       memcg = pc->mem_cgroup;
+       mz = page_cgroup_zoneinfo(memcg, page);
+       /* compound_order() is stabilized through lru_lock */
+       MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
+       return &mz->lruvec;
 }
 
-void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
+/**
+ * mem_cgroup_lru_del_list - account for removing an lru page
+ * @page: the page
+ * @lru: target lru
+ *
+ * This function accounts for @page being removed from @lru.
+ *
+ * The callsite is then responsible for physically unlinking
+ * @page->lru.
+ */
+void mem_cgroup_lru_del_list(struct page *page, enum lru_list lru)
 {
        struct mem_cgroup_per_zone *mz;
+       struct mem_cgroup *memcg;
        struct page_cgroup *pc;
 
        if (mem_cgroup_disabled())
                return;
 
        pc = lookup_page_cgroup(page);
-       /* unused or root page is not rotated. */
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
-       list_move(&pc->lru, &mz->lists[lru]);
-}
-
-void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
-{
-       struct page_cgroup *pc;
-       struct mem_cgroup_per_zone *mz;
-
-       if (mem_cgroup_disabled())
-               return;
-       pc = lookup_page_cgroup(page);
-       VM_BUG_ON(PageCgroupAcctLRU(pc));
-       /*
-        * putback:                             charge:
-        * SetPageLRU                           SetPageCgroupUsed
-        * smp_mb                               smp_mb
-        * PageCgroupUsed && add to memcg LRU   PageLRU && add to memcg LRU
-        *
-        * Ensure that one of the two sides adds the page to the memcg
-        * LRU during a race.
-        */
-       smp_mb();
-       if (!PageCgroupUsed(pc))
-               return;
-       /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
-       smp_rmb();
-       mz = page_cgroup_zoneinfo(pc->mem_cgroup, page);
+       memcg = pc->mem_cgroup;
+       VM_BUG_ON(!memcg);
+       mz = page_cgroup_zoneinfo(memcg, page);
        /* huge page split is done under lru_lock. so, we have no races. */
-       MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
-       SetPageCgroupAcctLRU(pc);
-       if (mem_cgroup_is_root(pc->mem_cgroup))
-               return;
-       list_add(&pc->lru, &mz->lists[lru]);
-}
-
-/*
- * At handling SwapCache and other FUSE stuff, pc->mem_cgroup may be changed
- * while it's linked to lru because the page may be reused after it's fully
- * uncharged. To handle that, unlink page_cgroup from LRU when charge it again.
- * It's done under lock_page and expected that zone->lru_lock isnever held.
- */
-static void mem_cgroup_lru_del_before_commit(struct page *page)
-{
-       unsigned long flags;
-       struct zone *zone = page_zone(page);
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-
-       /*
-        * Doing this check without taking ->lru_lock seems wrong but this
-        * is safe. Because if page_cgroup's USED bit is unset, the page
-        * will not be added to any memcg's LRU. If page_cgroup's USED bit is
-        * set, the commit after this will fail, anyway.
-        * This all charge/uncharge is done under some mutual execustion.
-        * So, we don't need to taking care of changes in USED bit.
-        */
-       if (likely(!PageLRU(page)))
-               return;
-
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       /*
-        * Forget old LRU when this page_cgroup is *not* used. This Used bit
-        * is guarded by lock_page() because the page is SwapCache.
-        */
-       if (!PageCgroupUsed(pc))
-               mem_cgroup_del_lru_list(page, page_lru(page));
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
+       VM_BUG_ON(MEM_CGROUP_ZSTAT(mz, lru) < (1 << compound_order(page)));
+       MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
 }
 
-static void mem_cgroup_lru_add_after_commit(struct page *page)
+void mem_cgroup_lru_del(struct page *page)
 {
-       unsigned long flags;
-       struct zone *zone = page_zone(page);
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-       /*
-        * putback:                             charge:
-        * SetPageLRU                           SetPageCgroupUsed
-        * smp_mb                               smp_mb
-        * PageCgroupUsed && add to memcg LRU   PageLRU && add to memcg LRU
-        *
-        * Ensure that one of the two sides adds the page to the memcg
-        * LRU during a race.
-        */
-       smp_mb();
-       /* taking care of that the page is added to LRU while we commit it */
-       if (likely(!PageLRU(page)))
-               return;
-       spin_lock_irqsave(&zone->lru_lock, flags);
-       /* link when the page is linked to LRU but page_cgroup isn't */
-       if (PageLRU(page) && !PageCgroupAcctLRU(pc))
-               mem_cgroup_add_lru_list(page, page_lru(page));
-       spin_unlock_irqrestore(&zone->lru_lock, flags);
+       mem_cgroup_lru_del_list(page, page_lru(page));
 }
 
-
-void mem_cgroup_move_lists(struct page *page,
-                          enum lru_list from, enum lru_list to)
+/**
+ * mem_cgroup_lru_move_lists - account for moving a page between lrus
+ * @zone: zone of the page
+ * @page: the page
+ * @from: current lru
+ * @to: target lru
+ *
+ * This function accounts for @page being moved between the lrus @from
+ * and @to, and returns the lruvec for the given @zone and the memcg
+ * @page is charged to.
+ *
+ * The callsite is then responsible for physically relinking
+ * @page->lru to the returned lruvec->lists[@to].
+ */
+struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone,
+                                        struct page *page,
+                                        enum lru_list from,
+                                        enum lru_list to)
 {
-       if (mem_cgroup_disabled())
-               return;
-       mem_cgroup_del_lru_list(page, from);
-       mem_cgroup_add_lru_list(page, to);
+       /* XXX: Optimize this, especially for @from == @to */
+       mem_cgroup_lru_del_list(page, from);
+       return mem_cgroup_lru_add_list(zone, page, to);
 }
 
 /*
@@ -1175,10 +1126,21 @@ int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg)
        struct task_struct *p;
 
        p = find_lock_task_mm(task);
-       if (!p)
-               return 0;
-       curr = try_get_mem_cgroup_from_mm(p->mm);
-       task_unlock(p);
+       if (p) {
+               curr = try_get_mem_cgroup_from_mm(p->mm);
+               task_unlock(p);
+       } else {
+               /*
+                * All threads may have already detached their mm's, but the oom
+                * killer still needs to detect if they have already been oom
+                * killed to prevent needlessly killing additional tasks.
+                */
+               task_lock(task);
+               curr = mem_cgroup_from_task(task);
+               if (curr)
+                       css_get(&curr->css);
+               task_unlock(task);
+       }
        if (!curr)
                return 0;
        /*
@@ -1258,68 +1220,6 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
        return &mz->reclaim_stat;
 }
 
-unsigned long mem_cgroup_isolate_pages(unsigned long nr_to_scan,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z,
-                                       struct mem_cgroup *mem_cont,
-                                       int active, int file)
-{
-       unsigned long nr_taken = 0;
-       struct page *page;
-       unsigned long scan;
-       LIST_HEAD(pc_list);
-       struct list_head *src;
-       struct page_cgroup *pc, *tmp;
-       int nid = zone_to_nid(z);
-       int zid = zone_idx(z);
-       struct mem_cgroup_per_zone *mz;
-       int lru = LRU_FILE * file + active;
-       int ret;
-
-       BUG_ON(!mem_cont);
-       mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
-       src = &mz->lists[lru];
-
-       scan = 0;
-       list_for_each_entry_safe_reverse(pc, tmp, src, lru) {
-               if (scan >= nr_to_scan)
-                       break;
-
-               if (unlikely(!PageCgroupUsed(pc)))
-                       continue;
-
-               page = lookup_cgroup_page(pc);
-
-               if (unlikely(!PageLRU(page)))
-                       continue;
-
-               scan++;
-               ret = __isolate_lru_page(page, mode, file);
-               switch (ret) {
-               case 0:
-                       list_move(&page->lru, dst);
-                       mem_cgroup_del_lru(page);
-                       nr_taken += hpage_nr_pages(page);
-                       break;
-               case -EBUSY:
-                       /* we don't affect global LRU but rotate in our LRU */
-                       mem_cgroup_rotate_lru_list(page, page_lru(page));
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       *scanned = scan;
-
-       trace_mm_vmscan_memcg_isolate(0, nr_to_scan, scan, nr_taken,
-                                     0, 0, 0, mode);
-
-       return nr_taken;
-}
-
 #define mem_cgroup_from_res_counter(counter, member)   \
        container_of(counter, struct mem_cgroup, member)
 
@@ -1536,41 +1436,40 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
        return min(limit, memsw);
 }
 
-/*
- * Visit the first child (need not be the first child as per the ordering
- * of the cgroup list, since we track last_scanned_child) of @mem and use
- * that to reclaim free pages from.
- */
-static struct mem_cgroup *
-mem_cgroup_select_victim(struct mem_cgroup *root_memcg)
+static unsigned long mem_cgroup_reclaim(struct mem_cgroup *memcg,
+                                       gfp_t gfp_mask,
+                                       unsigned long flags)
 {
-       struct mem_cgroup *ret = NULL;
-       struct cgroup_subsys_state *css;
-       int nextid, found;
-
-       if (!root_memcg->use_hierarchy) {
-               css_get(&root_memcg->css);
-               ret = root_memcg;
-       }
+       unsigned long total = 0;
+       bool noswap = false;
+       int loop;
 
-       while (!ret) {
-               rcu_read_lock();
-               nextid = root_memcg->last_scanned_child + 1;
-               css = css_get_next(&mem_cgroup_subsys, nextid, &root_memcg->css,
-                                  &found);
-               if (css && css_tryget(css))
-                       ret = container_of(css, struct mem_cgroup, css);
+       if (flags & MEM_CGROUP_RECLAIM_NOSWAP)
+               noswap = true;
+       if (!(flags & MEM_CGROUP_RECLAIM_SHRINK) && memcg->memsw_is_minimum)
+               noswap = true;
 
-               rcu_read_unlock();
-               /* Updates scanning parameter */
-               if (!css) {
-                       /* this means start scan from ID:1 */
-                       root_memcg->last_scanned_child = 0;
-               } else
-                       root_memcg->last_scanned_child = found;
+       for (loop = 0; loop < MEM_CGROUP_MAX_RECLAIM_LOOPS; loop++) {
+               if (loop)
+                       drain_all_stock_async(memcg);
+               total += try_to_free_mem_cgroup_pages(memcg, gfp_mask, noswap);
+               /*
+                * Allow limit shrinkers, which are triggered directly
+                * by userspace, to catch signals and stop reclaim
+                * after minimal progress, regardless of the margin.
+                */
+               if (total && (flags & MEM_CGROUP_RECLAIM_SHRINK))
+                       break;
+               if (mem_cgroup_margin(memcg))
+                       break;
+               /*
+                * If nothing was reclaimed after two attempts, there
+                * may be no reclaimable pages in this hierarchy.
+                */
+               if (loop && !total)
+                       break;
        }
-
-       return ret;
+       return total;
 }
 
 /**
@@ -1710,61 +1609,35 @@ bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
 }
 #endif
 
-/*
- * Scan the hierarchy if needed to reclaim memory. We remember the last child
- * we reclaimed from, so that we don't end up penalizing one child extensively
- * based on its position in the children list.
- *
- * root_memcg is the original ancestor that we've been reclaim from.
- *
- * We give up and return to the caller when we visit root_memcg twice.
- * (other groups can be removed while we're walking....)
- *
- * If shrink==true, for avoiding to free too much, this returns immedieately.
- */
-static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
-                                               struct zone *zone,
-                                               gfp_t gfp_mask,
-                                               unsigned long reclaim_options,
-                                               unsigned long *total_scanned)
-{
-       struct mem_cgroup *victim;
-       int ret, total = 0;
+static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
+                                  struct zone *zone,
+                                  gfp_t gfp_mask,
+                                  unsigned long *total_scanned)
+{
+       struct mem_cgroup *victim = NULL;
+       int total = 0;
        int loop = 0;
-       bool noswap = reclaim_options & MEM_CGROUP_RECLAIM_NOSWAP;
-       bool shrink = reclaim_options & MEM_CGROUP_RECLAIM_SHRINK;
-       bool check_soft = reclaim_options & MEM_CGROUP_RECLAIM_SOFT;
        unsigned long excess;
        unsigned long nr_scanned;
+       struct mem_cgroup_reclaim_cookie reclaim = {
+               .zone = zone,
+               .priority = 0,
+       };
 
        excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT;
 
-       /* If memsw_is_minimum==1, swap-out is of-no-use. */
-       if (!check_soft && !shrink && root_memcg->memsw_is_minimum)
-               noswap = true;
-
        while (1) {
-               victim = mem_cgroup_select_victim(root_memcg);
-               if (victim == root_memcg) {
+               victim = mem_cgroup_iter(root_memcg, victim, &reclaim);
+               if (!victim) {
                        loop++;
-                       /*
-                        * We are not draining per cpu cached charges during
-                        * soft limit reclaim  because global reclaim doesn't
-                        * care about charges. It tries to free some memory and
-                        * charges will not give any.
-                        */
-                       if (!check_soft && loop >= 1)
-                               drain_all_stock_async(root_memcg);
                        if (loop >= 2) {
                                /*
                                 * If we have not been able to reclaim
                                 * anything, it might because there are
                                 * no reclaimable pages under this hierarchy
                                 */
-                               if (!check_soft || !total) {
-                                       css_put(&victim->css);
+                               if (!total)
                                        break;
-                               }
                                /*
                                 * We want to do more targeted reclaim.
                                 * excess >> 2 is not to excessive so as to
@@ -1772,40 +1645,20 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
                                 * coming back to reclaim from this cgroup
                                 */
                                if (total >= (excess >> 2) ||
-                                       (loop > MEM_CGROUP_MAX_RECLAIM_LOOPS)) {
-                                       css_put(&victim->css);
+                                       (loop > MEM_CGROUP_MAX_RECLAIM_LOOPS))
                                        break;
-                               }
                        }
-               }
-               if (!mem_cgroup_reclaimable(victim, noswap)) {
-                       /* this cgroup's local usage == 0 */
-                       css_put(&victim->css);
                        continue;
                }
-               /* we use swappiness of local cgroup */
-               if (check_soft) {
-                       ret = mem_cgroup_shrink_node_zone(victim, gfp_mask,
-                               noswap, zone, &nr_scanned);
-                       *total_scanned += nr_scanned;
-               } else
-                       ret = try_to_free_mem_cgroup_pages(victim, gfp_mask,
-                                               noswap);
-               css_put(&victim->css);
-               /*
-                * At shrinking usage, we can't check we should stop here or
-                * reclaim more. It's depends on callers. last_scanned_child
-                * will work enough for keeping fairness under tree.
-                */
-               if (shrink)
-                       return ret;
-               total += ret;
-               if (check_soft) {
-                       if (!res_counter_soft_limit_excess(&root_memcg->res))
-                               return total;
-               } else if (mem_cgroup_margin(root_memcg))
-                       return total;
+               if (!mem_cgroup_reclaimable(victim, false))
+                       continue;
+               total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
+                                                    zone, &nr_scanned);
+               *total_scanned += nr_scanned;
+               if (!res_counter_soft_limit_excess(&root_memcg->res))
+                       break;
        }
+       mem_cgroup_iter_break(root_memcg, victim);
        return total;
 }
 
@@ -1817,16 +1670,16 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_memcg,
 static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
 {
        struct mem_cgroup *iter, *failed = NULL;
-       bool cond = true;
 
-       for_each_mem_cgroup_tree_cond(iter, memcg, cond) {
+       for_each_mem_cgroup_tree(iter, memcg) {
                if (iter->oom_lock) {
                        /*
                         * this subtree of our hierarchy is already locked
                         * so we cannot give a lock.
                         */
                        failed = iter;
-                       cond = false;
+                       mem_cgroup_iter_break(memcg, iter);
+                       break;
                } else
                        iter->oom_lock = true;
        }
@@ -1838,11 +1691,10 @@ static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
         * OK, we failed to lock the whole subtree so we have to clean up
         * what we set up to the failing subtree
         */
-       cond = true;
-       for_each_mem_cgroup_tree_cond(iter, memcg, cond) {
+       for_each_mem_cgroup_tree(iter, memcg) {
                if (iter == failed) {
-                       cond = false;
-                       continue;
+                       mem_cgroup_iter_break(memcg, iter);
+                       break;
                }
                iter->oom_lock = false;
        }
@@ -2007,7 +1859,7 @@ void mem_cgroup_update_page_stat(struct page *page,
        bool need_unlock = false;
        unsigned long uninitialized_var(flags);
 
-       if (unlikely(!pc))
+       if (mem_cgroup_disabled())
                return;
 
        rcu_read_lock();
@@ -2238,7 +2090,7 @@ static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb,
        struct mem_cgroup *iter;
 
        if ((action == CPU_ONLINE)) {
-               for_each_mem_cgroup_all(iter)
+               for_each_mem_cgroup(iter)
                        synchronize_mem_cgroup_on_move(iter, cpu);
                return NOTIFY_OK;
        }
@@ -2246,7 +2098,7 @@ static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb,
        if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN)
                return NOTIFY_OK;
 
-       for_each_mem_cgroup_all(iter)
+       for_each_mem_cgroup(iter)
                mem_cgroup_drain_pcp_counter(iter, cpu);
 
        stock = &per_cpu(memcg_stock, cpu);
@@ -2300,8 +2152,7 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        if (!(gfp_mask & __GFP_WAIT))
                return CHARGE_WOULDBLOCK;
 
-       ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
-                                             gfp_mask, flags, NULL);
+       ret = mem_cgroup_reclaim(mem_over_limit, gfp_mask, flags);
        if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
                return CHARGE_RETRY;
        /*
@@ -2334,8 +2185,25 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
 }
 
 /*
- * Unlike exported interface, "oom" parameter is added. if oom==true,
- * oom-killer can be invoked.
+ * __mem_cgroup_try_charge() does
+ * 1. detect memcg to be charged against from passed *mm and *ptr,
+ * 2. update res_counter
+ * 3. call memory reclaim if necessary.
+ *
+ * In some special case, if the task is fatal, fatal_signal_pending() or
+ * has TIF_MEMDIE, this function returns -EINTR while writing root_mem_cgroup
+ * to *ptr. There are two reasons for this. 1: fatal threads should quit as soon
+ * as possible without any hazards. 2: all pages should have a valid
+ * pc->mem_cgroup. If mm is NULL and the caller doesn't pass a valid memcg
+ * pointer, that is treated as a charge to root_mem_cgroup.
+ *
+ * So __mem_cgroup_try_charge() will return
+ *  0       ...  on success, filling *ptr with a valid memcg pointer.
+ *  -ENOMEM ...  charge failure because of resource limits.
+ *  -EINTR  ...  if thread is fatal. *ptr is filled with root_mem_cgroup.
+ *
+ * Unlike the exported interface, an "oom" parameter is added. if oom==true,
+ * the oom-killer can be invoked.
  */
 static int __mem_cgroup_try_charge(struct mm_struct *mm,
                                   gfp_t gfp_mask,
@@ -2364,7 +2232,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
         * set, if so charge the init_mm (happens for pagecache usage).
         */
        if (!*ptr && !mm)
-               goto bypass;
+               *ptr = root_mem_cgroup;
 again:
        if (*ptr) { /* css should be a valid one */
                memcg = *ptr;
@@ -2390,7 +2258,9 @@ again:
                 * task-struct. So, mm->owner can be NULL.
                 */
                memcg = mem_cgroup_from_task(p);
-               if (!memcg || mem_cgroup_is_root(memcg)) {
+               if (!memcg)
+                       memcg = root_mem_cgroup;
+               if (mem_cgroup_is_root(memcg)) {
                        rcu_read_unlock();
                        goto done;
                }
@@ -2465,8 +2335,8 @@ nomem:
        *ptr = NULL;
        return -ENOMEM;
 bypass:
-       *ptr = NULL;
-       return 0;
+       *ptr = root_mem_cgroup;
+       return -EINTR;
 }
 
 /*
@@ -2522,7 +2392,7 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
                        memcg = NULL;
        } else if (PageSwapCache(page)) {
                ent.val = page_private(page);
-               id = lookup_swap_cgroup(ent);
+               id = lookup_swap_cgroup_id(ent);
                rcu_read_lock();
                memcg = mem_cgroup_lookup(id);
                if (memcg && !css_tryget(&memcg->css))
@@ -2574,6 +2444,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
 
        mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), nr_pages);
        unlock_page_cgroup(pc);
+       WARN_ON_ONCE(PageLRU(page));
        /*
         * "charge_statistics" updated event counter. Then, check it.
         * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
@@ -2585,44 +2456,29 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 #define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\
-                       (1 << PCG_ACCT_LRU) | (1 << PCG_MIGRATION))
+                       (1 << PCG_MIGRATION))
 /*
  * Because tail pages are not marked as "used", set it. We're under
- * zone->lru_lock, 'splitting on pmd' and compund_lock.
+ * zone->lru_lock, 'splitting on pmd' and compound_lock.
+ * charge/uncharge will be never happen and move_account() is done under
+ * compound_lock(), so we don't have to take care of races.
  */
-void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
+void mem_cgroup_split_huge_fixup(struct page *head)
 {
        struct page_cgroup *head_pc = lookup_page_cgroup(head);
-       struct page_cgroup *tail_pc = lookup_page_cgroup(tail);
-       unsigned long flags;
+       struct page_cgroup *pc;
+       int i;
 
        if (mem_cgroup_disabled())
                return;
-       /*
-        * We have no races with charge/uncharge but will have races with
-        * page state accounting.
-        */
-       move_lock_page_cgroup(head_pc, &flags);
-
-       tail_pc->mem_cgroup = head_pc->mem_cgroup;
-       smp_wmb(); /* see __commit_charge() */
-       if (PageCgroupAcctLRU(head_pc)) {
-               enum lru_list lru;
-               struct mem_cgroup_per_zone *mz;
-
-               /*
-                * LRU flags cannot be copied because we need to add tail
-                *.page to LRU by generic call and our hook will be called.
-                * We hold lru_lock, then, reduce counter directly.
-                */
-               lru = page_lru(head);
-               mz = page_cgroup_zoneinfo(head_pc->mem_cgroup, head);
-               MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+       for (i = 1; i < HPAGE_PMD_NR; i++) {
+               pc = head_pc + i;
+               pc->mem_cgroup = head_pc->mem_cgroup;
+               smp_wmb();/* see __commit_charge() */
+               pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
        }
-       tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
-       move_unlock_page_cgroup(head_pc, &flags);
 }
-#endif
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /**
  * mem_cgroup_move_account - move account of the page
@@ -2737,7 +2593,7 @@ static int mem_cgroup_move_parent(struct page *page,
 
        parent = mem_cgroup_from_cont(pcg);
        ret = __mem_cgroup_try_charge(NULL, gfp_mask, nr_pages, &parent, false);
-       if (ret || !parent)
+       if (ret)
                goto put_back;
 
        if (nr_pages > 1)
@@ -2783,12 +2639,9 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
        }
 
        pc = lookup_page_cgroup(page);
-       BUG_ON(!pc); /* XXX: remove this and move pc lookup into commit */
-
        ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom);
-       if (ret || !memcg)
+       if (ret == -ENOMEM)
                return ret;
-
        __mem_cgroup_commit_charge(memcg, page, nr_pages, pc, ctype);
        return 0;
 }
@@ -2798,19 +2651,11 @@ int mem_cgroup_newpage_charge(struct page *page,
 {
        if (mem_cgroup_disabled())
                return 0;
-       /*
-        * If already mapped, we don't have to account.
-        * If page cache, page->mapping has address_space.
-        * But page->mapping may have out-of-use anon_vma pointer,
-        * detecit it by PageAnon() check. newly-mapped-anon's page->mapping
-        * is NULL.
-        */
-       if (page_mapped(page) || (page->mapping && !PageAnon(page)))
-               return 0;
-       if (unlikely(!mm))
-               mm = &init_mm;
+       VM_BUG_ON(page_mapped(page));
+       VM_BUG_ON(page->mapping && !PageAnon(page));
+       VM_BUG_ON(!mm);
        return mem_cgroup_charge_common(page, mm, gfp_mask,
-                               MEM_CGROUP_CHARGE_TYPE_MAPPED);
+                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
 static void
@@ -2822,14 +2667,27 @@ __mem_cgroup_commit_charge_lrucare(struct page *page, struct mem_cgroup *memcg,
                                        enum charge_type ctype)
 {
        struct page_cgroup *pc = lookup_page_cgroup(page);
+       struct zone *zone = page_zone(page);
+       unsigned long flags;
+       bool removed = false;
+
        /*
         * In some case, SwapCache, FUSE(splice_buf->radixtree), the page
         * is already on LRU. It means the page may on some other page_cgroup's
         * LRU. Take care of it.
         */
-       mem_cgroup_lru_del_before_commit(page);
+       spin_lock_irqsave(&zone->lru_lock, flags);
+       if (PageLRU(page)) {
+               del_page_from_lru_list(zone, page, page_lru(page));
+               ClearPageLRU(page);
+               removed = true;
+       }
        __mem_cgroup_commit_charge(memcg, page, 1, pc, ctype);
-       mem_cgroup_lru_add_after_commit(page);
+       if (removed) {
+               add_page_to_lru_list(zone, page, page_lru(page));
+               SetPageLRU(page);
+       }
+       spin_unlock_irqrestore(&zone->lru_lock, flags);
        return;
 }
 
@@ -2837,6 +2695,7 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
        struct mem_cgroup *memcg = NULL;
+       enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
        int ret;
 
        if (mem_cgroup_disabled())
@@ -2846,31 +2705,16 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
 
        if (unlikely(!mm))
                mm = &init_mm;
+       if (!page_is_file_cache(page))
+               type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
 
-       if (page_is_file_cache(page)) {
-               ret = __mem_cgroup_try_charge(mm, gfp_mask, 1, &memcg, true);
-               if (ret || !memcg)
-                       return ret;
-
-               /*
-                * FUSE reuses pages without going through the final
-                * put that would remove them from the LRU list, make
-                * sure that they get relinked properly.
-                */
-               __mem_cgroup_commit_charge_lrucare(page, memcg,
-                                       MEM_CGROUP_CHARGE_TYPE_CACHE);
-               return ret;
-       }
-       /* shmem */
-       if (PageSwapCache(page)) {
+       if (!PageSwapCache(page))
+               ret = mem_cgroup_charge_common(page, mm, gfp_mask, type);
+       else { /* page is swapcache/shmem */
                ret = mem_cgroup_try_charge_swapin(mm, page, gfp_mask, &memcg);
                if (!ret)
-                       __mem_cgroup_commit_charge_swapin(page, memcg,
-                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
-       } else
-               ret = mem_cgroup_charge_common(page, mm, gfp_mask,
-                                       MEM_CGROUP_CHARGE_TYPE_SHMEM);
-
+                       __mem_cgroup_commit_charge_swapin(page, memcg, type);
+       }
        return ret;
 }
 
@@ -2882,12 +2726,12 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
  */
 int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
                                 struct page *page,
-                                gfp_t mask, struct mem_cgroup **ptr)
+                                gfp_t mask, struct mem_cgroup **memcgp)
 {
        struct mem_cgroup *memcg;
        int ret;
 
-       *ptr = NULL;
+       *memcgp = NULL;
 
        if (mem_cgroup_disabled())
                return 0;
@@ -2905,27 +2749,32 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
        memcg = try_get_mem_cgroup_from_page(page);
        if (!memcg)
                goto charge_cur_mm;
-       *ptr = memcg;
-       ret = __mem_cgroup_try_charge(NULL, mask, 1, ptr, true);
+       *memcgp = memcg;
+       ret = __mem_cgroup_try_charge(NULL, mask, 1, memcgp, true);
        css_put(&memcg->css);
+       if (ret == -EINTR)
+               ret = 0;
        return ret;
 charge_cur_mm:
        if (unlikely(!mm))
                mm = &init_mm;
-       return __mem_cgroup_try_charge(mm, mask, 1, ptr, true);
+       ret = __mem_cgroup_try_charge(mm, mask, 1, memcgp, true);
+       if (ret == -EINTR)
+               ret = 0;
+       return ret;
 }
 
 static void
-__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
+__mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *memcg,
                                        enum charge_type ctype)
 {
        if (mem_cgroup_disabled())
                return;
-       if (!ptr)
+       if (!memcg)
                return;
-       cgroup_exclude_rmdir(&ptr->css);
+       cgroup_exclude_rmdir(&memcg->css);
 
-       __mem_cgroup_commit_charge_lrucare(page, ptr, ctype);
+       __mem_cgroup_commit_charge_lrucare(page, memcg, ctype);
        /*
         * Now swap is on-memory. This means this page may be
         * counted both as mem and swap....double count.
@@ -2935,21 +2784,22 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
         */
        if (do_swap_account && PageSwapCache(page)) {
                swp_entry_t ent = {.val = page_private(page)};
+               struct mem_cgroup *swap_memcg;
                unsigned short id;
-               struct mem_cgroup *memcg;
 
                id = swap_cgroup_record(ent, 0);
                rcu_read_lock();
-               memcg = mem_cgroup_lookup(id);
-               if (memcg) {
+               swap_memcg = mem_cgroup_lookup(id);
+               if (swap_memcg) {
                        /*
                         * This recorded memcg can be obsolete one. So, avoid
                         * calling css_tryget
                         */
-                       if (!mem_cgroup_is_root(memcg))
-                               res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
-                       mem_cgroup_swap_statistics(memcg, false);
-                       mem_cgroup_put(memcg);
+                       if (!mem_cgroup_is_root(swap_memcg))
+                               res_counter_uncharge(&swap_memcg->memsw,
+                                                    PAGE_SIZE);
+                       mem_cgroup_swap_statistics(swap_memcg, false);
+                       mem_cgroup_put(swap_memcg);
                }
                rcu_read_unlock();
        }
@@ -2958,13 +2808,14 @@ __mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr,
         * So, rmdir()->pre_destroy() can be called while we do this charge.
         * In that case, we need to call pre_destroy() again. check it here.
         */
-       cgroup_release_and_wakeup_rmdir(&ptr->css);
+       cgroup_release_and_wakeup_rmdir(&memcg->css);
 }
 
-void mem_cgroup_commit_charge_swapin(struct page *page, struct mem_cgroup *ptr)
+void mem_cgroup_commit_charge_swapin(struct page *page,
+                                    struct mem_cgroup *memcg)
 {
-       __mem_cgroup_commit_charge_swapin(page, ptr,
-                                       MEM_CGROUP_CHARGE_TYPE_MAPPED);
+       __mem_cgroup_commit_charge_swapin(page, memcg,
+                                         MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
 void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg)
@@ -3054,7 +2905,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
         * Check if our page_cgroup is valid
         */
        pc = lookup_page_cgroup(page);
-       if (unlikely(!pc || !PageCgroupUsed(pc)))
+       if (unlikely(!PageCgroupUsed(pc)))
                return NULL;
 
        lock_page_cgroup(pc);
@@ -3117,8 +2968,7 @@ void mem_cgroup_uncharge_page(struct page *page)
        /* early check. */
        if (page_mapped(page))
                return;
-       if (page->mapping && !PageAnon(page))
-               return;
+       VM_BUG_ON(page->mapping && !PageAnon(page));
        __mem_cgroup_uncharge_common(page, MEM_CGROUP_CHARGE_TYPE_MAPPED);
 }
 
@@ -3176,6 +3026,23 @@ void mem_cgroup_uncharge_end(void)
        batch->memcg = NULL;
 }
 
+/*
+ * A function for resetting pc->mem_cgroup for newly allocated pages.
+ * This function should be called if the newpage will be added to LRU
+ * before start accounting.
+ */
+void mem_cgroup_reset_owner(struct page *newpage)
+{
+       struct page_cgroup *pc;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pc = lookup_page_cgroup(newpage);
+       VM_BUG_ON(PageCgroupUsed(pc));
+       pc->mem_cgroup = root_mem_cgroup;
+}
+
 #ifdef CONFIG_SWAP
 /*
  * called after __delete_from_swap_cache() and drop "page" account.
@@ -3293,14 +3160,14 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
  * page belongs to.
  */
 int mem_cgroup_prepare_migration(struct page *page,
-       struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask)
+       struct page *newpage, struct mem_cgroup **memcgp, gfp_t gfp_mask)
 {
        struct mem_cgroup *memcg = NULL;
        struct page_cgroup *pc;
        enum charge_type ctype;
        int ret = 0;
 
-       *ptr = NULL;
+       *memcgp = NULL;
 
        VM_BUG_ON(PageTransHuge(page));
        if (mem_cgroup_disabled())
@@ -3351,10 +3218,10 @@ int mem_cgroup_prepare_migration(struct page *page,
        if (!memcg)
                return 0;
 
-       *ptr = memcg;
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, ptr, false);
+       *memcgp = memcg;
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask, 1, memcgp, false);
        css_put(&memcg->css);/* drop extra refcnt */
-       if (ret || *ptr == NULL) {
+       if (ret) {
                if (PageAnon(page)) {
                        lock_page_cgroup(pc);
                        ClearPageCgroupMigration(pc);
@@ -3364,6 +3231,7 @@ int mem_cgroup_prepare_migration(struct page *page,
                         */
                        mem_cgroup_uncharge_page(page);
                }
+               /* we'll need to revisit this error code (we have -EINTR) */
                return -ENOMEM;
        }
        /*
@@ -3432,12 +3300,51 @@ void mem_cgroup_end_migration(struct mem_cgroup *memcg,
        cgroup_release_and_wakeup_rmdir(&memcg->css);
 }
 
+/*
+ * At replace page cache, newpage is not under any memcg but it's on
+ * LRU. So, this function doesn't touch res_counter but handles LRU
+ * in correct way. Both pages are locked so we cannot race with uncharge.
+ */
+void mem_cgroup_replace_page_cache(struct page *oldpage,
+                                 struct page *newpage)
+{
+       struct mem_cgroup *memcg;
+       struct page_cgroup *pc;
+       enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
+
+       if (mem_cgroup_disabled())
+               return;
+
+       pc = lookup_page_cgroup(oldpage);
+       /* fix accounting on old pages */
+       lock_page_cgroup(pc);
+       memcg = pc->mem_cgroup;
+       mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1);
+       ClearPageCgroupUsed(pc);
+       unlock_page_cgroup(pc);
+
+       if (PageSwapBacked(oldpage))
+               type = MEM_CGROUP_CHARGE_TYPE_SHMEM;
+
+       /*
+        * Even if newpage->mapping was NULL before starting replacement,
+        * the newpage may be on LRU(or pagevec for LRU) already. We lock
+        * LRU while we overwrite pc->mem_cgroup.
+        */
+       __mem_cgroup_commit_charge_lrucare(newpage, memcg, type);
+}
+
 #ifdef CONFIG_DEBUG_VM
 static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
 {
        struct page_cgroup *pc;
 
        pc = lookup_page_cgroup(page);
+       /*
+        * Can be NULL while feeding pages into the page allocator for
+        * the first time, i.e. during boot or memory hotplug;
+        * or when mem_cgroup_disabled().
+        */
        if (likely(pc) && PageCgroupUsed(pc))
                return pc;
        return NULL;
@@ -3457,23 +3364,8 @@ void mem_cgroup_print_bad_page(struct page *page)
 
        pc = lookup_page_cgroup_used(page);
        if (pc) {
-               int ret = -1;
-               char *path;
-
-               printk(KERN_ALERT "pc:%p pc->flags:%lx pc->mem_cgroup:%p",
+               printk(KERN_ALERT "pc:%p pc->flags:%lx pc->mem_cgroup:%p\n",
                       pc, pc->flags, pc->mem_cgroup);
-
-               path = kmalloc(PATH_MAX, GFP_KERNEL);
-               if (path) {
-                       rcu_read_lock();
-                       ret = cgroup_path(pc->mem_cgroup->css.cgroup,
-                                                       path, PATH_MAX);
-                       rcu_read_unlock();
-               }
-
-               printk(KERN_CONT "(%s)\n",
-                               (ret < 0) ? "cannot get the path" : path);
-               kfree(path);
        }
 }
 #endif
@@ -3534,9 +3426,8 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
-                                               MEM_CGROUP_RECLAIM_SHRINK,
-                                               NULL);
+               mem_cgroup_reclaim(memcg, GFP_KERNEL,
+                                  MEM_CGROUP_RECLAIM_SHRINK);
                curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3594,10 +3485,9 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                if (!ret)
                        break;
 
-               mem_cgroup_hierarchical_reclaim(memcg, NULL, GFP_KERNEL,
-                                               MEM_CGROUP_RECLAIM_NOSWAP |
-                                               MEM_CGROUP_RECLAIM_SHRINK,
-                                               NULL);
+               mem_cgroup_reclaim(memcg, GFP_KERNEL,
+                                  MEM_CGROUP_RECLAIM_NOSWAP |
+                                  MEM_CGROUP_RECLAIM_SHRINK);
                curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
                /* Usage is reduced ? */
                if (curusage >= oldusage)
@@ -3640,10 +3530,8 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
                        break;
 
                nr_scanned = 0;
-               reclaimed = mem_cgroup_hierarchical_reclaim(mz->mem, zone,
-                                               gfp_mask,
-                                               MEM_CGROUP_RECLAIM_SOFT,
-                                               &nr_scanned);
+               reclaimed = mem_cgroup_soft_reclaim(mz->mem, zone,
+                                                   gfp_mask, &nr_scanned);
                nr_reclaimed += reclaimed;
                *total_scanned += nr_scanned;
                spin_lock(&mctz->lock);
@@ -3711,22 +3599,23 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
 static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
                                int node, int zid, enum lru_list lru)
 {
-       struct zone *zone;
        struct mem_cgroup_per_zone *mz;
-       struct page_cgroup *pc, *busy;
        unsigned long flags, loop;
        struct list_head *list;
+       struct page *busy;
+       struct zone *zone;
        int ret = 0;
 
        zone = &NODE_DATA(node)->node_zones[zid];
        mz = mem_cgroup_zoneinfo(memcg, node, zid);
-       list = &mz->lists[lru];
+       list = &mz->lruvec.lists[lru];
 
        loop = MEM_CGROUP_ZSTAT(mz, lru);
        /* give some margin against EBUSY etc...*/
        loop += 256;
        busy = NULL;
        while (loop--) {
+               struct page_cgroup *pc;
                struct page *page;
 
                ret = 0;
@@ -3735,24 +3624,24 @@ static int mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
                        spin_unlock_irqrestore(&zone->lru_lock, flags);
                        break;
                }
-               pc = list_entry(list->prev, struct page_cgroup, lru);
-               if (busy == pc) {
-                       list_move(&pc->lru, list);
+               page = list_entry(list->prev, struct page, lru);
+               if (busy == page) {
+                       list_move(&page->lru, list);
                        busy = NULL;
                        spin_unlock_irqrestore(&zone->lru_lock, flags);
                        continue;
                }
                spin_unlock_irqrestore(&zone->lru_lock, flags);
 
-               page = lookup_cgroup_page(pc);
+               pc = lookup_page_cgroup(page);
 
                ret = mem_cgroup_move_parent(page, pc, memcg, GFP_KERNEL);
-               if (ret == -ENOMEM)
+               if (ret == -ENOMEM || ret == -EINTR)
                        break;
 
                if (ret == -EBUSY || ret == -EINVAL) {
                        /* found lock contention or "pc" is obsolete. */
-                       busy = pc;
+                       busy = page;
                        cond_resched();
                } else
                        busy = NULL;
@@ -4846,7 +4735,7 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
        for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                mz = &pn->zoneinfo[zone];
                for_each_lru(l)
-                       INIT_LIST_HEAD(&mz->lists[l]);
+                       INIT_LIST_HEAD(&mz->lruvec.lists[l]);
                mz->usage_in_excess = 0;
                mz->on_tree = false;
                mz->mem = memcg;
@@ -4906,7 +4795,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
        mem_cgroup_remove_from_trees(memcg);
        free_css_id(&mem_cgroup_subsys, &memcg->css);
 
-       for_each_node_state(node, N_POSSIBLE)
+       for_each_node(node)
                free_mem_cgroup_per_zone_info(memcg, node);
 
        free_percpu(memcg->stat);
@@ -4965,13 +4854,13 @@ static int mem_cgroup_soft_limit_tree_init(void)
        struct mem_cgroup_tree_per_zone *rtpz;
        int tmp, node, zone;
 
-       for_each_node_state(node, N_POSSIBLE) {
+       for_each_node(node) {
                tmp = node;
                if (!node_state(node, N_NORMAL_MEMORY))
                        tmp = -1;
                rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL, tmp);
                if (!rtpn)
-                       return 1;
+                       goto err_cleanup;
 
                soft_limit_tree.rb_tree_per_node[node] = rtpn;
 
@@ -4982,6 +4871,16 @@ static int mem_cgroup_soft_limit_tree_init(void)
                }
        }
        return 0;
+
+err_cleanup:
+       for_each_node(node) {
+               if (!soft_limit_tree.rb_tree_per_node[node])
+                       break;
+               kfree(soft_limit_tree.rb_tree_per_node[node]);
+               soft_limit_tree.rb_tree_per_node[node] = NULL;
+       }
+       return 1;
+
 }
 
 static struct cgroup_subsys_state * __ref
@@ -4995,7 +4894,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        if (!memcg)
                return ERR_PTR(error);
 
-       for_each_node_state(node, N_POSSIBLE)
+       for_each_node(node)
                if (alloc_mem_cgroup_per_zone_info(memcg, node))
                        goto free_out;
 
@@ -5033,7 +4932,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
                res_counter_init(&memcg->res, NULL);
                res_counter_init(&memcg->memsw, NULL);
        }
-       memcg->last_scanned_child = 0;
        memcg->last_scanned_node = MAX_NUMNODES;
        INIT_LIST_HEAD(&memcg->oom_notify);
 
@@ -5129,9 +5027,9 @@ one_by_one:
                }
                ret = __mem_cgroup_try_charge(NULL,
                                        GFP_KERNEL, 1, &memcg, false);
-               if (ret || !memcg)
+               if (ret)
                        /* mem_cgroup_clear_mc() will do uncharge later */
-                       return -ENOMEM;
+                       return ret;
                mc.precharge++;
        }
        return ret;
@@ -5276,7 +5174,7 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
        }
        /* There is a swap entry and a page doesn't exist or isn't charged */
        if (ent.val && !ret &&
-                       css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
+                       css_id(&mc.from->css) == lookup_swap_cgroup_id(ent)) {
                ret = MC_TARGET_SWAP;
                if (target)
                        target->ent = ent;
index 06d3479513aaa2a3eeff26f0bf25e71c13695fdd..56080ea361406090860493861d5253dc314debc1 100644 (file)
@@ -1557,7 +1557,7 @@ int soft_offline_page(struct page *page, int flags)
                                            page_is_file_cache(page));
                list_add(&page->lru, &pagelist);
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
-                                                               0, true);
+                                                       0, MIGRATE_SYNC);
                if (ret) {
                        putback_lru_pages(&pagelist);
                        pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
index 829d437354022959eeca37082f695e2ee73025ed..5e30583c2605d7b791d907ae8a5e07be2d9ad5b6 100644 (file)
@@ -293,7 +293,7 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        struct mmu_gather_batch *batch;
 
-       tlb->need_flush = 1;
+       VM_BUG_ON(!tlb->need_flush);
 
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
@@ -1231,7 +1231,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                        if (next-addr != HPAGE_PMD_SIZE) {
                                VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem));
                                split_huge_page_pmd(vma->vm_mm, pmd);
-                       } else if (zap_huge_pmd(tlb, vma, pmd))
+                       } else if (zap_huge_pmd(tlb, vma, pmd, addr))
                                continue;
                        /* fall through */
                }
index 2168489c0bc9f309ff3347d6dac05a09039ad7d2..6629fafd6ce4a65eae9421dd9d68b25805bca993 100644 (file)
@@ -809,7 +809,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                }
                /* this function returns # of failed pages */
                ret = migrate_pages(&source, hotremove_migrate_alloc, 0,
-                                                               true, true);
+                                                       true, MIGRATE_SYNC);
                if (ret)
                        putback_lru_pages(&source);
        }
index c3fdbcb17658ce405131e5b0310e1857fd6558bc..06b145fb64ab59a399344bc73ca277be0e39ed7b 100644 (file)
@@ -942,7 +942,7 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
 
        if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_node_page, dest,
-                                                               false, true);
+                                                       false, MIGRATE_SYNC);
                if (err)
                        putback_lru_pages(&pagelist);
        }
@@ -1983,28 +1983,28 @@ struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
 }
 
 /* Slow path of a mempolicy comparison */
-int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
+bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
 {
        if (!a || !b)
-               return 0;
+               return false;
        if (a->mode != b->mode)
-               return 0;
+               return false;
        if (a->flags != b->flags)
-               return 0;
+               return false;
        if (mpol_store_user_nodemask(a))
                if (!nodes_equal(a->w.user_nodemask, b->w.user_nodemask))
-                       return 0;
+                       return false;
 
        switch (a->mode) {
        case MPOL_BIND:
                /* Fall through */
        case MPOL_INTERLEAVE:
-               return nodes_equal(a->v.nodes, b->v.nodes);
+               return !!nodes_equal(a->v.nodes, b->v.nodes);
        case MPOL_PREFERRED:
                return a->v.preferred_node == b->v.preferred_node;
        default:
                BUG();
-               return 0;
+               return false;
        }
 }
 
index e73641b79bb5f08fac06f40380a47eaeb765294f..d9049811f3521bc690ff1535831b87dc3b682fe4 100644 (file)
@@ -27,7 +27,15 @@ static void *remove_element(mempool_t *pool)
        return pool->elements[--pool->curr_nr];
 }
 
-static void free_pool(mempool_t *pool)
+/**
+ * mempool_destroy - deallocate a memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * Free all reserved elements in @pool and @pool itself.  This function
+ * only sleeps if the free_fn() function sleeps.
+ */
+void mempool_destroy(mempool_t *pool)
 {
        while (pool->curr_nr) {
                void *element = remove_element(pool);
@@ -36,6 +44,7 @@ static void free_pool(mempool_t *pool)
        kfree(pool->elements);
        kfree(pool);
 }
+EXPORT_SYMBOL(mempool_destroy);
 
 /**
  * mempool_create - create a memory pool
@@ -86,7 +95,7 @@ mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,
 
                element = pool->alloc(GFP_KERNEL, pool->pool_data);
                if (unlikely(!element)) {
-                       free_pool(pool);
+                       mempool_destroy(pool);
                        return NULL;
                }
                add_element(pool, element);
@@ -171,23 +180,6 @@ out:
 }
 EXPORT_SYMBOL(mempool_resize);
 
-/**
- * mempool_destroy - deallocate a memory pool
- * @pool:      pointer to the memory pool which was allocated via
- *             mempool_create().
- *
- * this function only sleeps if the free_fn() function sleeps. The caller
- * has to guarantee that all elements have been returned to the pool (ie:
- * freed) prior to calling mempool_destroy().
- */
-void mempool_destroy(mempool_t *pool)
-{
-       /* Check for outstanding elements */
-       BUG_ON(pool->curr_nr != pool->min_nr);
-       free_pool(pool);
-}
-EXPORT_SYMBOL(mempool_destroy);
-
 /**
  * mempool_alloc - allocate an element from a specific memory pool
  * @pool:      pointer to the memory pool which was allocated via
@@ -224,28 +216,40 @@ repeat_alloc:
        if (likely(pool->curr_nr)) {
                element = remove_element(pool);
                spin_unlock_irqrestore(&pool->lock, flags);
+               /* paired with rmb in mempool_free(), read comment there */
+               smp_wmb();
                return element;
        }
-       spin_unlock_irqrestore(&pool->lock, flags);
 
-       /* We must not sleep in the GFP_ATOMIC case */
-       if (!(gfp_mask & __GFP_WAIT))
+       /*
+        * We use gfp mask w/o __GFP_WAIT or IO for the first round.  If
+        * alloc failed with that and @pool was empty, retry immediately.
+        */
+       if (gfp_temp != gfp_mask) {
+               spin_unlock_irqrestore(&pool->lock, flags);
+               gfp_temp = gfp_mask;
+               goto repeat_alloc;
+       }
+
+       /* We must not sleep if !__GFP_WAIT */
+       if (!(gfp_mask & __GFP_WAIT)) {
+               spin_unlock_irqrestore(&pool->lock, flags);
                return NULL;
+       }
 
-       /* Now start performing page reclaim */
-       gfp_temp = gfp_mask;
+       /* Let's wait for someone else to return an element to @pool */
        init_wait(&wait);
        prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
-       smp_mb();
-       if (!pool->curr_nr) {
-               /*
-                * FIXME: this should be io_schedule().  The timeout is there
-                * as a workaround for some DM problems in 2.6.18.
-                */
-               io_schedule_timeout(5*HZ);
-       }
-       finish_wait(&pool->wait, &wait);
 
+       spin_unlock_irqrestore(&pool->lock, flags);
+
+       /*
+        * FIXME: this should be io_schedule().  The timeout is there as a
+        * workaround for some DM problems in 2.6.18.
+        */
+       io_schedule_timeout(5*HZ);
+
+       finish_wait(&pool->wait, &wait);
        goto repeat_alloc;
 }
 EXPORT_SYMBOL(mempool_alloc);
@@ -265,7 +269,39 @@ void mempool_free(void *element, mempool_t *pool)
        if (unlikely(element == NULL))
                return;
 
-       smp_mb();
+       /*
+        * Paired with the wmb in mempool_alloc().  The preceding read is
+        * for @element and the following @pool->curr_nr.  This ensures
+        * that the visible value of @pool->curr_nr is from after the
+        * allocation of @element.  This is necessary for fringe cases
+        * where @element was passed to this task without going through
+        * barriers.
+        *
+        * For example, assume @p is %NULL at the beginning and one task
+        * performs "p = mempool_alloc(...);" while another task is doing
+        * "while (!p) cpu_relax(); mempool_free(p, ...);".  This function
+        * may end up using curr_nr value which is from before allocation
+        * of @p without the following rmb.
+        */
+       smp_rmb();
+
+       /*
+        * For correctness, we need a test which is guaranteed to trigger
+        * if curr_nr + #allocated == min_nr.  Testing curr_nr < min_nr
+        * without locking achieves that and refilling as soon as possible
+        * is desirable.
+        *
+        * Because curr_nr visible here is always a value after the
+        * allocation of @element, any task which decremented curr_nr below
+        * min_nr is guaranteed to see curr_nr < min_nr unless curr_nr gets
+        * incremented to min_nr afterwards.  If curr_nr gets incremented
+        * to min_nr after the allocation of @element, the elements
+        * allocated after that are subject to the same guarantee.
+        *
+        * Waiters happen iff curr_nr is 0 and the above guarantee also
+        * ensures that there will be frees which return elements to the
+        * pool waking up the waiters.
+        */
        if (pool->curr_nr < pool->min_nr) {
                spin_lock_irqsave(&pool->lock, flags);
                if (pool->curr_nr < pool->min_nr) {
index 177aca424a069ac1ae1b44d48a8e6d992cd42a4d..9871a56d82c30b1390ea268fddd9b3bc4b83c8da 100644 (file)
@@ -39,8 +39,6 @@
 
 #include "internal.h"
 
-#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
-
 /*
  * migrate_prep() needs to be called before we start compiling a list of pages
  * to be migrated using isolate_lru_page(). If scheduling work on other CPUs is
@@ -181,8 +179,6 @@ static void remove_migration_ptes(struct page *old, struct page *new)
  * Something used the pte of a page under migration. We need to
  * get to the page and wait until migration is finished.
  * When we return from this function the fault will be retried.
- *
- * This function is called from do_swap_page().
  */
 void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
                                unsigned long address)
@@ -220,6 +216,56 @@ out:
        pte_unmap_unlock(ptep, ptl);
 }
 
+#ifdef CONFIG_BLOCK
+/* Returns true if all buffers are successfully locked */
+static bool buffer_migrate_lock_buffers(struct buffer_head *head,
+                                                       enum migrate_mode mode)
+{
+       struct buffer_head *bh = head;
+
+       /* Simple case, sync compaction */
+       if (mode != MIGRATE_ASYNC) {
+               do {
+                       get_bh(bh);
+                       lock_buffer(bh);
+                       bh = bh->b_this_page;
+
+               } while (bh != head);
+
+               return true;
+       }
+
+       /* async case, we cannot block on lock_buffer so use trylock_buffer */
+       do {
+               get_bh(bh);
+               if (!trylock_buffer(bh)) {
+                       /*
+                        * We failed to lock the buffer and cannot stall in
+                        * async migration. Release the taken locks
+                        */
+                       struct buffer_head *failed_bh = bh;
+                       put_bh(failed_bh);
+                       bh = head;
+                       while (bh != failed_bh) {
+                               unlock_buffer(bh);
+                               put_bh(bh);
+                               bh = bh->b_this_page;
+                       }
+                       return false;
+               }
+
+               bh = bh->b_this_page;
+       } while (bh != head);
+       return true;
+}
+#else
+static inline bool buffer_migrate_lock_buffers(struct buffer_head *head,
+                                                       enum migrate_mode mode)
+{
+       return true;
+}
+#endif /* CONFIG_BLOCK */
+
 /*
  * Replace the page in the mapping.
  *
@@ -229,7 +275,8 @@ out:
  * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
  */
 static int migrate_page_move_mapping(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page,
+               struct buffer_head *head, enum migrate_mode mode)
 {
        int expected_count;
        void **pslot;
@@ -258,6 +305,20 @@ static int migrate_page_move_mapping(struct address_space *mapping,
                return -EAGAIN;
        }
 
+       /*
+        * In the async migration case of moving a page with buffers, lock the
+        * buffers using trylock before the mapping is moved. If the mapping
+        * was moved, we later failed to lock the buffers and could not move
+        * the mapping back due to an elevated page count, we would have to
+        * block waiting on other references to be dropped.
+        */
+       if (mode == MIGRATE_ASYNC && head &&
+                       !buffer_migrate_lock_buffers(head, mode)) {
+               page_unfreeze_refs(page, expected_count);
+               spin_unlock_irq(&mapping->tree_lock);
+               return -EAGAIN;
+       }
+
        /*
         * Now we know that no one else is looking at the page.
         */
@@ -269,12 +330,12 @@ static int migrate_page_move_mapping(struct address_space *mapping,
 
        radix_tree_replace_slot(pslot, newpage);
 
-       page_unfreeze_refs(page, expected_count);
        /*
-        * Drop cache reference from old page.
+        * Drop cache reference from old page by unfreezing
+        * to one less reference.
         * We know this isn't the last reference.
         */
-       __put_page(page);
+       page_unfreeze_refs(page, expected_count - 1);
 
        /*
         * If moved to a different zone then also account
@@ -334,9 +395,7 @@ int migrate_huge_page_move_mapping(struct address_space *mapping,
 
        radix_tree_replace_slot(pslot, newpage);
 
-       page_unfreeze_refs(page, expected_count);
-
-       __put_page(page);
+       page_unfreeze_refs(page, expected_count - 1);
 
        spin_unlock_irq(&mapping->tree_lock);
        return 0;
@@ -415,13 +474,14 @@ EXPORT_SYMBOL(fail_migrate_page);
  * Pages are locked upon entry and exit.
  */
 int migrate_page(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page,
+               enum migrate_mode mode)
 {
        int rc;
 
        BUG_ON(PageWriteback(page));    /* Writeback must be complete */
 
-       rc = migrate_page_move_mapping(mapping, newpage, page);
+       rc = migrate_page_move_mapping(mapping, newpage, page, NULL, mode);
 
        if (rc)
                return rc;
@@ -438,28 +498,28 @@ EXPORT_SYMBOL(migrate_page);
  * exist.
  */
 int buffer_migrate_page(struct address_space *mapping,
-               struct page *newpage, struct page *page)
+               struct page *newpage, struct page *page, enum migrate_mode mode)
 {
        struct buffer_head *bh, *head;
        int rc;
 
        if (!page_has_buffers(page))
-               return migrate_page(mapping, newpage, page);
+               return migrate_page(mapping, newpage, page, mode);
 
        head = page_buffers(page);
 
-       rc = migrate_page_move_mapping(mapping, newpage, page);
+       rc = migrate_page_move_mapping(mapping, newpage, page, head, mode);
 
        if (rc)
                return rc;
 
-       bh = head;
-       do {
-               get_bh(bh);
-               lock_buffer(bh);
-               bh = bh->b_this_page;
-
-       } while (bh != head);
+       /*
+        * In the async case, migrate_page_move_mapping locked the buffers
+        * with an IRQ-safe spinlock held. In the sync case, the buffers
+        * need to be locked now
+        */
+       if (mode != MIGRATE_ASYNC)
+               BUG_ON(!buffer_migrate_lock_buffers(head, mode));
 
        ClearPagePrivate(page);
        set_page_private(newpage, page_private(page));
@@ -536,10 +596,14 @@ static int writeout(struct address_space *mapping, struct page *page)
  * Default handling if a filesystem does not provide a migration function.
  */
 static int fallback_migrate_page(struct address_space *mapping,
-       struct page *newpage, struct page *page)
+       struct page *newpage, struct page *page, enum migrate_mode mode)
 {
-       if (PageDirty(page))
+       if (PageDirty(page)) {
+               /* Only writeback pages in full synchronous migration */
+               if (mode != MIGRATE_SYNC)
+                       return -EBUSY;
                return writeout(mapping, page);
+       }
 
        /*
         * Buffers may be managed in a filesystem specific way.
@@ -549,7 +613,7 @@ static int fallback_migrate_page(struct address_space *mapping,
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
 
-       return migrate_page(mapping, newpage, page);
+       return migrate_page(mapping, newpage, page, mode);
 }
 
 /*
@@ -564,7 +628,7 @@ static int fallback_migrate_page(struct address_space *mapping,
  *  == 0 - success
  */
 static int move_to_new_page(struct page *newpage, struct page *page,
-                                       int remap_swapcache, bool sync)
+                               int remap_swapcache, enum migrate_mode mode)
 {
        struct address_space *mapping;
        int rc;
@@ -585,29 +649,18 @@ static int move_to_new_page(struct page *newpage, struct page *page,
 
        mapping = page_mapping(page);
        if (!mapping)
-               rc = migrate_page(mapping, newpage, page);
-       else {
+               rc = migrate_page(mapping, newpage, page, mode);
+       else if (mapping->a_ops->migratepage)
                /*
-                * Do not writeback pages if !sync and migratepage is
-                * not pointing to migrate_page() which is nonblocking
-                * (swapcache/tmpfs uses migratepage = migrate_page).
+                * Most pages have a mapping and most filesystems provide a
+                * migratepage callback. Anonymous pages are part of swap
+                * space which also has its own migratepage callback. This
+                * is the most common path for page migration.
                 */
-               if (PageDirty(page) && !sync &&
-                   mapping->a_ops->migratepage != migrate_page)
-                       rc = -EBUSY;
-               else if (mapping->a_ops->migratepage)
-                       /*
-                        * Most pages have a mapping and most filesystems
-                        * should provide a migration function. Anonymous
-                        * pages are part of swap space which also has its
-                        * own migration function. This is the most common
-                        * path for page migration.
-                        */
-                       rc = mapping->a_ops->migratepage(mapping,
-                                                       newpage, page);
-               else
-                       rc = fallback_migrate_page(mapping, newpage, page);
-       }
+               rc = mapping->a_ops->migratepage(mapping,
+                                               newpage, page, mode);
+       else
+               rc = fallback_migrate_page(mapping, newpage, page, mode);
 
        if (rc) {
                newpage->mapping = NULL;
@@ -622,7 +675,7 @@ static int move_to_new_page(struct page *newpage, struct page *page,
 }
 
 static int __unmap_and_move(struct page *page, struct page *newpage,
-                               int force, bool offlining, bool sync)
+                       int force, bool offlining, enum migrate_mode mode)
 {
        int rc = -EAGAIN;
        int remap_swapcache = 1;
@@ -631,7 +684,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
        struct anon_vma *anon_vma = NULL;
 
        if (!trylock_page(page)) {
-               if (!force || !sync)
+               if (!force || mode == MIGRATE_ASYNC)
                        goto out;
 
                /*
@@ -677,10 +730,12 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 
        if (PageWriteback(page)) {
                /*
-                * For !sync, there is no point retrying as the retry loop
-                * is expected to be too short for PageWriteback to be cleared
+                * Only in the case of a full syncronous migration is it
+                * necessary to wait for PageWriteback. In the async case,
+                * the retry loop is too short and in the sync-light case,
+                * the overhead of stalling is too much
                 */
-               if (!sync) {
+               if (mode != MIGRATE_SYNC) {
                        rc = -EBUSY;
                        goto uncharge;
                }
@@ -751,7 +806,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
 
 skip_unmap:
        if (!page_mapped(page))
-               rc = move_to_new_page(newpage, page, remap_swapcache, sync);
+               rc = move_to_new_page(newpage, page, remap_swapcache, mode);
 
        if (rc && remap_swapcache)
                remove_migration_ptes(page, page);
@@ -774,7 +829,8 @@ out:
  * to the newly allocated page in newpage.
  */
 static int unmap_and_move(new_page_t get_new_page, unsigned long private,
-                       struct page *page, int force, bool offlining, bool sync)
+                       struct page *page, int force, bool offlining,
+                       enum migrate_mode mode)
 {
        int rc = 0;
        int *result = NULL;
@@ -783,6 +839,8 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        if (!newpage)
                return -ENOMEM;
 
+       mem_cgroup_reset_owner(newpage);
+
        if (page_count(page) == 1) {
                /* page was freed from under us. So we are done. */
                goto out;
@@ -792,7 +850,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                if (unlikely(split_huge_page(page)))
                        goto out;
 
-       rc = __unmap_and_move(page, newpage, force, offlining, sync);
+       rc = __unmap_and_move(page, newpage, force, offlining, mode);
 out:
        if (rc != -EAGAIN) {
                /*
@@ -840,7 +898,8 @@ out:
  */
 static int unmap_and_move_huge_page(new_page_t get_new_page,
                                unsigned long private, struct page *hpage,
-                               int force, bool offlining, bool sync)
+                               int force, bool offlining,
+                               enum migrate_mode mode)
 {
        int rc = 0;
        int *result = NULL;
@@ -853,7 +912,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        rc = -EAGAIN;
 
        if (!trylock_page(hpage)) {
-               if (!force || !sync)
+               if (!force || mode != MIGRATE_SYNC)
                        goto out;
                lock_page(hpage);
        }
@@ -864,7 +923,7 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
        if (!page_mapped(hpage))
-               rc = move_to_new_page(new_hpage, hpage, 1, sync);
+               rc = move_to_new_page(new_hpage, hpage, 1, mode);
 
        if (rc)
                remove_migration_ptes(hpage, hpage);
@@ -907,7 +966,7 @@ out:
  */
 int migrate_pages(struct list_head *from,
                new_page_t get_new_page, unsigned long private, bool offlining,
-               bool sync)
+               enum migrate_mode mode)
 {
        int retry = 1;
        int nr_failed = 0;
@@ -928,7 +987,7 @@ int migrate_pages(struct list_head *from,
 
                        rc = unmap_and_move(get_new_page, private,
                                                page, pass > 2, offlining,
-                                               sync);
+                                               mode);
 
                        switch(rc) {
                        case -ENOMEM:
@@ -958,7 +1017,7 @@ out:
 
 int migrate_huge_pages(struct list_head *from,
                new_page_t get_new_page, unsigned long private, bool offlining,
-               bool sync)
+               enum migrate_mode mode)
 {
        int retry = 1;
        int nr_failed = 0;
@@ -975,7 +1034,7 @@ int migrate_huge_pages(struct list_head *from,
 
                        rc = unmap_and_move_huge_page(get_new_page,
                                        private, page, pass > 2, offlining,
-                                       sync);
+                                       mode);
 
                        switch(rc) {
                        case -ENOMEM:
@@ -1104,7 +1163,7 @@ set_status:
        err = 0;
        if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_page_node,
-                               (unsigned long)pm, 0, true);
+                               (unsigned long)pm, 0, MIGRATE_SYNC);
                if (err)
                        putback_lru_pages(&pagelist);
        }
index eae90af60ea62e066defeab345e5079f57a80dc2..3f758c7f4c815c2b0edf494526b2823b41fbc142 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1603,39 +1603,19 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
 
 EXPORT_SYMBOL(find_vma);
 
-/* Same as find_vma, but also return a pointer to the previous VMA in *pprev. */
+/*
+ * Same as find_vma, but also return a pointer to the previous VMA in *pprev.
+ * Note: pprev is set to NULL when return value is NULL.
+ */
 struct vm_area_struct *
 find_vma_prev(struct mm_struct *mm, unsigned long addr,
                        struct vm_area_struct **pprev)
 {
-       struct vm_area_struct *vma = NULL, *prev = NULL;
-       struct rb_node *rb_node;
-       if (!mm)
-               goto out;
-
-       /* Guard against addr being lower than the first VMA */
-       vma = mm->mmap;
-
-       /* Go through the RB tree quickly. */
-       rb_node = mm->mm_rb.rb_node;
-
-       while (rb_node) {
-               struct vm_area_struct *vma_tmp;
-               vma_tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
-
-               if (addr < vma_tmp->vm_end) {
-                       rb_node = rb_node->rb_left;
-               } else {
-                       prev = vma_tmp;
-                       if (!prev->vm_next || (addr < prev->vm_next->vm_end))
-                               break;
-                       rb_node = rb_node->rb_right;
-               }
-       }
+       struct vm_area_struct *vma;
 
-out:
-       *pprev = prev;
-       return prev ? prev->vm_next : vma;
+       vma = find_vma(mm, addr);
+       *pprev = vma ? vma->vm_prev : NULL;
+       return vma;
 }
 
 /*
@@ -2322,13 +2302,16 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
        struct vm_area_struct *new_vma, *prev;
        struct rb_node **rb_link, *rb_parent;
        struct mempolicy *pol;
+       bool faulted_in_anon_vma = true;
 
        /*
         * If anonymous vma has not yet been faulted, update new pgoff
         * to match new location, to increase its chance of merging.
         */
-       if (!vma->vm_file && !vma->anon_vma)
+       if (unlikely(!vma->vm_file && !vma->anon_vma)) {
                pgoff = addr >> PAGE_SHIFT;
+               faulted_in_anon_vma = false;
+       }
 
        find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
        new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
@@ -2337,9 +2320,24 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                /*
                 * Source vma may have been merged into new_vma
                 */
-               if (vma_start >= new_vma->vm_start &&
-                   vma_start < new_vma->vm_end)
+               if (unlikely(vma_start >= new_vma->vm_start &&
+                            vma_start < new_vma->vm_end)) {
+                       /*
+                        * The only way we can get a vma_merge with
+                        * self during an mremap is if the vma hasn't
+                        * been faulted in yet and we were allowed to
+                        * reset the dst vma->vm_pgoff to the
+                        * destination address of the mremap to allow
+                        * the merge to happen. mremap must change the
+                        * vm_pgoff linearity between src and dst vmas
+                        * (in turn preventing a vma_merge) to be
+                        * safe. It is only safe to keep the vm_pgoff
+                        * linear if there are no pages mapped yet.
+                        */
+                       VM_BUG_ON(faulted_in_anon_vma);
                        *vmap = new_vma;
+               } else
+                       anon_vma_moveto_tail(new_vma);
        } else {
                new_vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
                if (new_vma) {
index d6959cb4df58f1d694c179898553bf7e3150cc49..87bb8393e7d238115a450139d24c090347c215a7 100644 (file)
@@ -220,6 +220,15 @@ static unsigned long move_vma(struct vm_area_struct *vma,
 
        moved_len = move_page_tables(vma, old_addr, new_vma, new_addr, old_len);
        if (moved_len < old_len) {
+               /*
+                * Before moving the page tables from the new vma to
+                * the old vma, we need to be sure the old vma is
+                * queued after new vma in the same_anon_vma list to
+                * prevent SMP races with rmap_walk (that could lead
+                * rmap_walk to miss some page table).
+                */
+               anon_vma_moveto_tail(vma);
+
                /*
                 * On error, move entries back from new area to old,
                 * which will succeed since page tables still there,
index eeb27e27dce3d9fe6e745812d79362e099424883..2958fd8e7c9abcfcf6cc7b38e2dac34133905b22 100644 (file)
 #include <linux/security.h>
 #include <linux/ptrace.h>
 #include <linux/freezer.h>
+#include <linux/ftrace.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/oom.h>
 
 int sysctl_panic_on_oom;
 int sysctl_oom_kill_allocating_task;
@@ -55,6 +59,7 @@ void compare_swap_oom_score_adj(int old_val, int new_val)
        spin_lock_irq(&sighand->siglock);
        if (current->signal->oom_score_adj == old_val)
                current->signal->oom_score_adj = new_val;
+       trace_oom_score_adj_update(current);
        spin_unlock_irq(&sighand->siglock);
 }
 
@@ -74,6 +79,7 @@ int test_set_oom_score_adj(int new_val)
        spin_lock_irq(&sighand->siglock);
        old_val = current->signal->oom_score_adj;
        current->signal->oom_score_adj = new_val;
+       trace_oom_score_adj_update(current);
        spin_unlock_irq(&sighand->siglock);
 
        return old_val;
@@ -146,7 +152,7 @@ struct task_struct *find_lock_task_mm(struct task_struct *p)
 
 /* return true if the task is not adequate as candidate victim task. */
 static bool oom_unkillable_task(struct task_struct *p,
-               const struct mem_cgroup *mem, const nodemask_t *nodemask)
+               const struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        if (is_global_init(p))
                return true;
@@ -154,7 +160,7 @@ static bool oom_unkillable_task(struct task_struct *p,
                return true;
 
        /* When mem_cgroup_out_of_memory() and p is not member of the group */
-       if (mem && !task_in_mem_cgroup(p, mem))
+       if (memcg && !task_in_mem_cgroup(p, memcg))
                return true;
 
        /* p may not have freeable memory in nodemask */
@@ -173,12 +179,12 @@ static bool oom_unkillable_task(struct task_struct *p,
  * predictable as possible.  The goal is to return the highest value for the
  * task consuming the most memory to avoid subsequent oom failures.
  */
-unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
+unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
                      const nodemask_t *nodemask, unsigned long totalpages)
 {
        long points;
 
-       if (oom_unkillable_task(p, mem, nodemask))
+       if (oom_unkillable_task(p, memcg, nodemask))
                return 0;
 
        p = find_lock_task_mm(p);
@@ -302,7 +308,7 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist,
  * (not docbooked, we don't want this one cluttering up the manual)
  */
 static struct task_struct *select_bad_process(unsigned int *ppoints,
-               unsigned long totalpages, struct mem_cgroup *mem,
+               unsigned long totalpages, struct mem_cgroup *memcg,
                const nodemask_t *nodemask)
 {
        struct task_struct *g, *p;
@@ -314,7 +320,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
 
                if (p->exit_state)
                        continue;
-               if (oom_unkillable_task(p, mem, nodemask))
+               if (oom_unkillable_task(p, memcg, nodemask))
                        continue;
 
                /*
@@ -358,7 +364,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
                        }
                }
 
-               points = oom_badness(p, mem, nodemask, totalpages);
+               points = oom_badness(p, memcg, nodemask, totalpages);
                if (points > *ppoints) {
                        chosen = p;
                        *ppoints = points;
@@ -381,14 +387,14 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
  *
  * Call with tasklist_lock read-locked.
  */
-static void dump_tasks(const struct mem_cgroup *mem, const nodemask_t *nodemask)
+static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        struct task_struct *p;
        struct task_struct *task;
 
        pr_info("[ pid ]   uid  tgid total_vm      rss cpu oom_adj oom_score_adj name\n");
        for_each_process(p) {
-               if (oom_unkillable_task(p, mem, nodemask))
+               if (oom_unkillable_task(p, memcg, nodemask))
                        continue;
 
                task = find_lock_task_mm(p);
@@ -411,7 +417,7 @@ static void dump_tasks(const struct mem_cgroup *mem, const nodemask_t *nodemask)
 }
 
 static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
-                       struct mem_cgroup *mem, const nodemask_t *nodemask)
+                       struct mem_cgroup *memcg, const nodemask_t *nodemask)
 {
        task_lock(current);
        pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, "
@@ -421,14 +427,14 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
        cpuset_print_task_mems_allowed(current);
        task_unlock(current);
        dump_stack();
-       mem_cgroup_print_oom_info(mem, p);
+       mem_cgroup_print_oom_info(memcg, p);
        show_mem(SHOW_MEM_FILTER_NODES);
        if (sysctl_oom_dump_tasks)
-               dump_tasks(mem, nodemask);
+               dump_tasks(memcg, nodemask);
 }
 
 #define K(x) ((x) << (PAGE_SHIFT-10))
-static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
+static int oom_kill_task(struct task_struct *p)
 {
        struct task_struct *q;
        struct mm_struct *mm;
@@ -478,7 +484,7 @@ static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem)
 
 static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                            unsigned int points, unsigned long totalpages,
-                           struct mem_cgroup *mem, nodemask_t *nodemask,
+                           struct mem_cgroup *memcg, nodemask_t *nodemask,
                            const char *message)
 {
        struct task_struct *victim = p;
@@ -487,7 +493,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        unsigned int victim_points = 0;
 
        if (printk_ratelimit())
-               dump_header(p, gfp_mask, order, mem, nodemask);
+               dump_header(p, gfp_mask, order, memcg, nodemask);
 
        /*
         * If the task is already exiting, don't alarm the sysadmin or kill
@@ -518,7 +524,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                        /*
                         * oom_badness() returns 0 if the thread is unkillable
                         */
-                       child_points = oom_badness(child, mem, nodemask,
+                       child_points = oom_badness(child, memcg, nodemask,
                                                                totalpages);
                        if (child_points > victim_points) {
                                victim = child;
@@ -527,7 +533,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
                }
        } while_each_thread(p, t);
 
-       return oom_kill_task(victim, mem);
+       return oom_kill_task(victim);
 }
 
 /*
@@ -555,7 +561,7 @@ static void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask,
 }
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
-void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
+void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask)
 {
        unsigned long limit;
        unsigned int points = 0;
@@ -572,14 +578,14 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        }
 
        check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, 0, NULL);
-       limit = mem_cgroup_get_limit(mem) >> PAGE_SHIFT;
+       limit = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT;
        read_lock(&tasklist_lock);
 retry:
-       p = select_bad_process(&points, limit, mem, NULL);
+       p = select_bad_process(&points, limit, memcg, NULL);
        if (!p || PTR_ERR(p) == -1UL)
                goto out;
 
-       if (oom_kill_process(p, gfp_mask, 0, points, limit, mem, NULL,
+       if (oom_kill_process(p, gfp_mask, 0, points, limit, memcg, NULL,
                                "Memory cgroup out of memory"))
                goto retry;
 out:
index 8616ef3025a44a80e59448f960620b858b7445e3..363ba7082ef59efab5e90d94184cbf593aeff7ea 100644 (file)
  */
 #define MAX_PAUSE              max(HZ/5, 1)
 
+/*
+ * Try to keep balance_dirty_pages() call intervals higher than this many pages
+ * by raising pause time to max_pause when falls below it.
+ */
+#define DIRTY_POLL_THRESH      (128 >> (PAGE_SHIFT - 10))
+
 /*
  * Estimate write bandwidth at 200ms intervals.
  */
@@ -129,6 +135,191 @@ unsigned long global_dirty_limit;
  */
 static struct prop_descriptor vm_completions;
 
+/*
+ * Work out the current dirty-memory clamping and background writeout
+ * thresholds.
+ *
+ * The main aim here is to lower them aggressively if there is a lot of mapped
+ * memory around.  To avoid stressing page reclaim with lots of unreclaimable
+ * pages.  It is better to clamp down on writers than to start swapping, and
+ * performing lots of scanning.
+ *
+ * We only allow 1/2 of the currently-unmapped memory to be dirtied.
+ *
+ * We don't permit the clamping level to fall below 5% - that is getting rather
+ * excessive.
+ *
+ * We make sure that the background writeout level is below the adjusted
+ * clamping level.
+ */
+
+/*
+ * In a memory zone, there is a certain amount of pages we consider
+ * available for the page cache, which is essentially the number of
+ * free and reclaimable pages, minus some zone reserves to protect
+ * lowmem and the ability to uphold the zone's watermarks without
+ * requiring writeback.
+ *
+ * This number of dirtyable pages is the base value of which the
+ * user-configurable dirty ratio is the effictive number of pages that
+ * are allowed to be actually dirtied.  Per individual zone, or
+ * globally by using the sum of dirtyable pages over all zones.
+ *
+ * Because the user is allowed to specify the dirty limit globally as
+ * absolute number of bytes, calculating the per-zone dirty limit can
+ * require translating the configured limit into a percentage of
+ * global dirtyable memory first.
+ */
+
+static unsigned long highmem_dirtyable_memory(unsigned long total)
+{
+#ifdef CONFIG_HIGHMEM
+       int node;
+       unsigned long x = 0;
+
+       for_each_node_state(node, N_HIGH_MEMORY) {
+               struct zone *z =
+                       &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
+
+               x += zone_page_state(z, NR_FREE_PAGES) +
+                    zone_reclaimable_pages(z) - z->dirty_balance_reserve;
+       }
+       /*
+        * Make sure that the number of highmem pages is never larger
+        * than the number of the total dirtyable memory. This can only
+        * occur in very strange VM situations but we want to make sure
+        * that this does not occur.
+        */
+       return min(x, total);
+#else
+       return 0;
+#endif
+}
+
+/**
+ * global_dirtyable_memory - number of globally dirtyable pages
+ *
+ * Returns the global number of pages potentially available for dirty
+ * page cache.  This is the base value for the global dirty limits.
+ */
+unsigned long global_dirtyable_memory(void)
+{
+       unsigned long x;
+
+       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages() -
+           dirty_balance_reserve;
+
+       if (!vm_highmem_is_dirtyable)
+               x -= highmem_dirtyable_memory(x);
+
+       return x + 1;   /* Ensure that we never return 0 */
+}
+
+/*
+ * global_dirty_limits - background-writeback and dirty-throttling thresholds
+ *
+ * Calculate the dirty thresholds based on sysctl parameters
+ * - vm.dirty_background_ratio  or  vm.dirty_background_bytes
+ * - vm.dirty_ratio             or  vm.dirty_bytes
+ * The dirty limits will be lifted by 1/4 for PF_LESS_THROTTLE (ie. nfsd) and
+ * real-time tasks.
+ */
+void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
+{
+       unsigned long background;
+       unsigned long dirty;
+       unsigned long uninitialized_var(available_memory);
+       struct task_struct *tsk;
+
+       if (!vm_dirty_bytes || !dirty_background_bytes)
+               available_memory = global_dirtyable_memory();
+
+       if (vm_dirty_bytes)
+               dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
+       else
+               dirty = (vm_dirty_ratio * available_memory) / 100;
+
+       if (dirty_background_bytes)
+               background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
+       else
+               background = (dirty_background_ratio * available_memory) / 100;
+
+       if (background >= dirty)
+               background = dirty / 2;
+       tsk = current;
+       if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) {
+               background += background / 4;
+               dirty += dirty / 4;
+       }
+       *pbackground = background;
+       *pdirty = dirty;
+       trace_global_dirty_state(background, dirty);
+}
+
+/**
+ * zone_dirtyable_memory - number of dirtyable pages in a zone
+ * @zone: the zone
+ *
+ * Returns the zone's number of pages potentially available for dirty
+ * page cache.  This is the base value for the per-zone dirty limits.
+ */
+static unsigned long zone_dirtyable_memory(struct zone *zone)
+{
+       /*
+        * The effective global number of dirtyable pages may exclude
+        * highmem as a big-picture measure to keep the ratio between
+        * dirty memory and lowmem reasonable.
+        *
+        * But this function is purely about the individual zone and a
+        * highmem zone can hold its share of dirty pages, so we don't
+        * care about vm_highmem_is_dirtyable here.
+        */
+       return zone_page_state(zone, NR_FREE_PAGES) +
+              zone_reclaimable_pages(zone) -
+              zone->dirty_balance_reserve;
+}
+
+/**
+ * zone_dirty_limit - maximum number of dirty pages allowed in a zone
+ * @zone: the zone
+ *
+ * Returns the maximum number of dirty pages allowed in a zone, based
+ * on the zone's dirtyable memory.
+ */
+static unsigned long zone_dirty_limit(struct zone *zone)
+{
+       unsigned long zone_memory = zone_dirtyable_memory(zone);
+       struct task_struct *tsk = current;
+       unsigned long dirty;
+
+       if (vm_dirty_bytes)
+               dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE) *
+                       zone_memory / global_dirtyable_memory();
+       else
+               dirty = vm_dirty_ratio * zone_memory / 100;
+
+       if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk))
+               dirty += dirty / 4;
+
+       return dirty;
+}
+
+/**
+ * zone_dirty_ok - tells whether a zone is within its dirty limits
+ * @zone: the zone to check
+ *
+ * Returns %true when the dirty pages in @zone are within the zone's
+ * dirty limit, %false if the limit is exceeded.
+ */
+bool zone_dirty_ok(struct zone *zone)
+{
+       unsigned long limit = zone_dirty_limit(zone);
+
+       return zone_page_state(zone, NR_FILE_DIRTY) +
+              zone_page_state(zone, NR_UNSTABLE_NFS) +
+              zone_page_state(zone, NR_WRITEBACK) <= limit;
+}
+
 /*
  * couple the period to the dirty_ratio:
  *
@@ -141,7 +332,7 @@ static int calc_period_shift(void)
        if (vm_dirty_bytes)
                dirty_total = vm_dirty_bytes / PAGE_SIZE;
        else
-               dirty_total = (vm_dirty_ratio * determine_dirtyable_memory()) /
+               dirty_total = (vm_dirty_ratio * global_dirtyable_memory()) /
                                100;
        return 2 + ilog2(dirty_total - 1);
 }
@@ -196,7 +387,6 @@ int dirty_ratio_handler(struct ctl_table *table, int write,
        return ret;
 }
 
-
 int dirty_bytes_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos)
@@ -291,67 +481,6 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
 }
 EXPORT_SYMBOL(bdi_set_max_ratio);
 
-/*
- * Work out the current dirty-memory clamping and background writeout
- * thresholds.
- *
- * The main aim here is to lower them aggressively if there is a lot of mapped
- * memory around.  To avoid stressing page reclaim with lots of unreclaimable
- * pages.  It is better to clamp down on writers than to start swapping, and
- * performing lots of scanning.
- *
- * We only allow 1/2 of the currently-unmapped memory to be dirtied.
- *
- * We don't permit the clamping level to fall below 5% - that is getting rather
- * excessive.
- *
- * We make sure that the background writeout level is below the adjusted
- * clamping level.
- */
-
-static unsigned long highmem_dirtyable_memory(unsigned long total)
-{
-#ifdef CONFIG_HIGHMEM
-       int node;
-       unsigned long x = 0;
-
-       for_each_node_state(node, N_HIGH_MEMORY) {
-               struct zone *z =
-                       &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
-
-               x += zone_page_state(z, NR_FREE_PAGES) +
-                    zone_reclaimable_pages(z);
-       }
-       /*
-        * Make sure that the number of highmem pages is never larger
-        * than the number of the total dirtyable memory. This can only
-        * occur in very strange VM situations but we want to make sure
-        * that this does not occur.
-        */
-       return min(x, total);
-#else
-       return 0;
-#endif
-}
-
-/**
- * determine_dirtyable_memory - amount of memory that may be used
- *
- * Returns the numebr of pages that can currently be freed and used
- * by the kernel for direct mappings.
- */
-unsigned long determine_dirtyable_memory(void)
-{
-       unsigned long x;
-
-       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
-
-       if (!vm_highmem_is_dirtyable)
-               x -= highmem_dirtyable_memory(x);
-
-       return x + 1;   /* Ensure that we never return 0 */
-}
-
 static unsigned long dirty_freerun_ceiling(unsigned long thresh,
                                           unsigned long bg_thresh)
 {
@@ -363,47 +492,6 @@ static unsigned long hard_dirty_limit(unsigned long thresh)
        return max(thresh, global_dirty_limit);
 }
 
-/*
- * global_dirty_limits - background-writeback and dirty-throttling thresholds
- *
- * Calculate the dirty thresholds based on sysctl parameters
- * - vm.dirty_background_ratio  or  vm.dirty_background_bytes
- * - vm.dirty_ratio             or  vm.dirty_bytes
- * The dirty limits will be lifted by 1/4 for PF_LESS_THROTTLE (ie. nfsd) and
- * real-time tasks.
- */
-void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
-{
-       unsigned long background;
-       unsigned long dirty;
-       unsigned long uninitialized_var(available_memory);
-       struct task_struct *tsk;
-
-       if (!vm_dirty_bytes || !dirty_background_bytes)
-               available_memory = determine_dirtyable_memory();
-
-       if (vm_dirty_bytes)
-               dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
-       else
-               dirty = (vm_dirty_ratio * available_memory) / 100;
-
-       if (dirty_background_bytes)
-               background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
-       else
-               background = (dirty_background_ratio * available_memory) / 100;
-
-       if (background >= dirty)
-               background = dirty / 2;
-       tsk = current;
-       if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) {
-               background += background / 4;
-               dirty += dirty / 4;
-       }
-       *pbackground = background;
-       *pdirty = dirty;
-       trace_global_dirty_state(background, dirty);
-}
-
 /**
  * bdi_dirty_limit - @bdi's share of dirty throttling threshold
  * @bdi: the backing_dev_info to query
@@ -816,6 +904,11 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
         */
        balanced_dirty_ratelimit = div_u64((u64)task_ratelimit * write_bw,
                                           dirty_rate | 1);
+       /*
+        * balanced_dirty_ratelimit ~= (write_bw / N) <= write_bw
+        */
+       if (unlikely(balanced_dirty_ratelimit > write_bw))
+               balanced_dirty_ratelimit = write_bw;
 
        /*
         * We could safely do this and return immediately:
@@ -962,40 +1055,98 @@ static unsigned long dirty_poll_interval(unsigned long dirty,
        return 1;
 }
 
-static unsigned long bdi_max_pause(struct backing_dev_info *bdi,
-                                  unsigned long bdi_dirty)
+static long bdi_max_pause(struct backing_dev_info *bdi,
+                         unsigned long bdi_dirty)
+{
+       long bw = bdi->avg_write_bandwidth;
+       long t;
+
+       /*
+        * Limit pause time for small memory systems. If sleeping for too long
+        * time, a small pool of dirty/writeback pages may go empty and disk go
+        * idle.
+        *
+        * 8 serves as the safety ratio.
+        */
+       t = bdi_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8));
+       t++;
+
+       return min_t(long, t, MAX_PAUSE);
+}
+
+static long bdi_min_pause(struct backing_dev_info *bdi,
+                         long max_pause,
+                         unsigned long task_ratelimit,
+                         unsigned long dirty_ratelimit,
+                         int *nr_dirtied_pause)
 {
-       unsigned long bw = bdi->avg_write_bandwidth;
-       unsigned long hi = ilog2(bw);
-       unsigned long lo = ilog2(bdi->dirty_ratelimit);
-       unsigned long t;
+       long hi = ilog2(bdi->avg_write_bandwidth);
+       long lo = ilog2(bdi->dirty_ratelimit);
+       long t;         /* target pause */
+       long pause;     /* estimated next pause */
+       int pages;      /* target nr_dirtied_pause */
 
-       /* target for 20ms max pause on 1-dd case */
-       t = HZ / 50;
+       /* target for 10ms pause on 1-dd case */
+       t = max(1, HZ / 100);
 
        /*
         * Scale up pause time for concurrent dirtiers in order to reduce CPU
         * overheads.
         *
-        * (N * 20ms) on 2^N concurrent tasks.
+        * (N * 10ms) on 2^N concurrent tasks.
         */
        if (hi > lo)
-               t += (hi - lo) * (20 * HZ) / 1024;
+               t += (hi - lo) * (10 * HZ) / 1024;
 
        /*
-        * Limit pause time for small memory systems. If sleeping for too long
-        * time, a small pool of dirty/writeback pages may go empty and disk go
-        * idle.
+        * This is a bit convoluted. We try to base the next nr_dirtied_pause
+        * on the much more stable dirty_ratelimit. However the next pause time
+        * will be computed based on task_ratelimit and the two rate limits may
+        * depart considerably at some time. Especially if task_ratelimit goes
+        * below dirty_ratelimit/2 and the target pause is max_pause, the next
+        * pause time will be max_pause*2 _trimmed down_ to max_pause.  As a
+        * result task_ratelimit won't be executed faithfully, which could
+        * eventually bring down dirty_ratelimit.
         *
-        * 8 serves as the safety ratio.
+        * We apply two rules to fix it up:
+        * 1) try to estimate the next pause time and if necessary, use a lower
+        *    nr_dirtied_pause so as not to exceed max_pause. When this happens,
+        *    nr_dirtied_pause will be "dancing" with task_ratelimit.
+        * 2) limit the target pause time to max_pause/2, so that the normal
+        *    small fluctuations of task_ratelimit won't trigger rule (1) and
+        *    nr_dirtied_pause will remain as stable as dirty_ratelimit.
         */
-       t = min(t, bdi_dirty * HZ / (8 * bw + 1));
+       t = min(t, 1 + max_pause / 2);
+       pages = dirty_ratelimit * t / roundup_pow_of_two(HZ);
 
        /*
-        * The pause time will be settled within range (max_pause/4, max_pause).
-        * Apply a minimal value of 4 to get a non-zero max_pause/4.
+        * Tiny nr_dirtied_pause is found to hurt I/O performance in the test
+        * case fio-mmap-randwrite-64k, which does 16*{sync read, async write}.
+        * When the 16 consecutive reads are often interrupted by some dirty
+        * throttling pause during the async writes, cfq will go into idles
+        * (deadline is fine). So push nr_dirtied_pause as high as possible
+        * until reaches DIRTY_POLL_THRESH=32 pages.
         */
-       return clamp_val(t, 4, MAX_PAUSE);
+       if (pages < DIRTY_POLL_THRESH) {
+               t = max_pause;
+               pages = dirty_ratelimit * t / roundup_pow_of_two(HZ);
+               if (pages > DIRTY_POLL_THRESH) {
+                       pages = DIRTY_POLL_THRESH;
+                       t = HZ * DIRTY_POLL_THRESH / dirty_ratelimit;
+               }
+       }
+
+       pause = HZ * pages / (task_ratelimit + 1);
+       if (pause > max_pause) {
+               t = max_pause;
+               pages = task_ratelimit * t / roundup_pow_of_two(HZ);
+       }
+
+       *nr_dirtied_pause = pages;
+       /*
+        * The minimal pause time will normally be half the target pause time.
+        */
+       return pages >= DIRTY_POLL_THRESH ? 1 + t / 2 : t;
 }
 
 /*
@@ -1016,16 +1167,21 @@ static void balance_dirty_pages(struct address_space *mapping,
        unsigned long background_thresh;
        unsigned long dirty_thresh;
        unsigned long bdi_thresh;
-       long pause = 0;
-       long uninitialized_var(max_pause);
+       long period;
+       long pause;
+       long max_pause;
+       long min_pause;
+       int nr_dirtied_pause;
        bool dirty_exceeded = false;
        unsigned long task_ratelimit;
-       unsigned long uninitialized_var(dirty_ratelimit);
+       unsigned long dirty_ratelimit;
        unsigned long pos_ratio;
        struct backing_dev_info *bdi = mapping->backing_dev_info;
        unsigned long start_time = jiffies;
 
        for (;;) {
+               unsigned long now = jiffies;
+
                /*
                 * Unstable writes are a feature of certain networked
                 * filesystems (i.e. NFS) in which data may have been
@@ -1045,8 +1201,13 @@ static void balance_dirty_pages(struct address_space *mapping,
                 */
                freerun = dirty_freerun_ceiling(dirty_thresh,
                                                background_thresh);
-               if (nr_dirty <= freerun)
+               if (nr_dirty <= freerun) {
+                       current->dirty_paused_when = now;
+                       current->nr_dirtied = 0;
+                       current->nr_dirtied_pause =
+                               dirty_poll_interval(nr_dirty, dirty_thresh);
                        break;
+               }
 
                if (unlikely(!writeback_in_progress(bdi)))
                        bdi_start_background_writeback(bdi);
@@ -1086,7 +1247,7 @@ static void balance_dirty_pages(struct address_space *mapping,
                                    bdi_stat(bdi, BDI_WRITEBACK);
                }
 
-               dirty_exceeded = (bdi_dirty > bdi_thresh) ||
+               dirty_exceeded = (bdi_dirty > bdi_thresh) &&
                                  (nr_dirty > dirty_thresh);
                if (dirty_exceeded && !bdi->dirty_exceeded)
                        bdi->dirty_exceeded = 1;
@@ -1095,20 +1256,34 @@ static void balance_dirty_pages(struct address_space *mapping,
                                     nr_dirty, bdi_thresh, bdi_dirty,
                                     start_time);
 
-               max_pause = bdi_max_pause(bdi, bdi_dirty);
-
                dirty_ratelimit = bdi->dirty_ratelimit;
                pos_ratio = bdi_position_ratio(bdi, dirty_thresh,
                                               background_thresh, nr_dirty,
                                               bdi_thresh, bdi_dirty);
                task_ratelimit = ((u64)dirty_ratelimit * pos_ratio) >>
                                                        RATELIMIT_CALC_SHIFT;
+               max_pause = bdi_max_pause(bdi, bdi_dirty);
+               min_pause = bdi_min_pause(bdi, max_pause,
+                                         task_ratelimit, dirty_ratelimit,
+                                         &nr_dirtied_pause);
+
                if (unlikely(task_ratelimit == 0)) {
+                       period = max_pause;
                        pause = max_pause;
                        goto pause;
                }
-               pause = HZ * pages_dirtied / task_ratelimit;
-               if (unlikely(pause <= 0)) {
+               period = HZ * pages_dirtied / task_ratelimit;
+               pause = period;
+               if (current->dirty_paused_when)
+                       pause -= now - current->dirty_paused_when;
+               /*
+                * For less than 1s think time (ext3/4 may block the dirtier
+                * for up to 800ms from time to time on 1-HDD; so does xfs,
+                * however at much less frequency), try to compensate it in
+                * future periods by updating the virtual time; otherwise just
+                * do a reset, as it may be a light dirtier.
+                */
+               if (pause < min_pause) {
                        trace_balance_dirty_pages(bdi,
                                                  dirty_thresh,
                                                  background_thresh,
@@ -1118,12 +1293,24 @@ static void balance_dirty_pages(struct address_space *mapping,
                                                  dirty_ratelimit,
                                                  task_ratelimit,
                                                  pages_dirtied,
-                                                 pause,
+                                                 period,
+                                                 min(pause, 0L),
                                                  start_time);
-                       pause = 1; /* avoid resetting nr_dirtied_pause below */
+                       if (pause < -HZ) {
+                               current->dirty_paused_when = now;
+                               current->nr_dirtied = 0;
+                       } else if (period) {
+                               current->dirty_paused_when += period;
+                               current->nr_dirtied = 0;
+                       } else if (current->nr_dirtied_pause <= pages_dirtied)
+                               current->nr_dirtied_pause += pages_dirtied;
                        break;
                }
-               pause = min(pause, max_pause);
+               if (unlikely(pause > max_pause)) {
+                       /* for occasional dropped task_ratelimit */
+                       now += min(pause - max_pause, max_pause);
+                       pause = max_pause;
+               }
 
 pause:
                trace_balance_dirty_pages(bdi,
@@ -1135,11 +1322,16 @@ pause:
                                          dirty_ratelimit,
                                          task_ratelimit,
                                          pages_dirtied,
+                                         period,
                                          pause,
                                          start_time);
                __set_current_state(TASK_KILLABLE);
                io_schedule_timeout(pause);
 
+               current->dirty_paused_when = now + pause;
+               current->nr_dirtied = 0;
+               current->nr_dirtied_pause = nr_dirtied_pause;
+
                /*
                 * This is typically equal to (nr_dirty < dirty_thresh) and can
                 * also keep "1000+ dd on a slow USB stick" under control.
@@ -1167,23 +1359,6 @@ pause:
        if (!dirty_exceeded && bdi->dirty_exceeded)
                bdi->dirty_exceeded = 0;
 
-       current->nr_dirtied = 0;
-       if (pause == 0) { /* in freerun area */
-               current->nr_dirtied_pause =
-                               dirty_poll_interval(nr_dirty, dirty_thresh);
-       } else if (pause <= max_pause / 4 &&
-                  pages_dirtied >= current->nr_dirtied_pause) {
-               current->nr_dirtied_pause = clamp_val(
-                                       dirty_ratelimit * (max_pause / 2) / HZ,
-                                       pages_dirtied + pages_dirtied / 8,
-                                       pages_dirtied * 4);
-       } else if (pause >= max_pause) {
-               current->nr_dirtied_pause = 1 | clamp_val(
-                                       dirty_ratelimit * (max_pause / 2) / HZ,
-                                       pages_dirtied / 4,
-                                       pages_dirtied - pages_dirtied / 8);
-       }
-
        if (writeback_in_progress(bdi))
                return;
 
@@ -1214,6 +1389,22 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite)
 
 static DEFINE_PER_CPU(int, bdp_ratelimits);
 
+/*
+ * Normal tasks are throttled by
+ *     loop {
+ *             dirty tsk->nr_dirtied_pause pages;
+ *             take a snap in balance_dirty_pages();
+ *     }
+ * However there is a worst case. If every task exit immediately when dirtied
+ * (tsk->nr_dirtied_pause - 1) pages, balance_dirty_pages() will never be
+ * called to throttle the page dirties. The solution is to save the not yet
+ * throttled page dirties in dirty_throttle_leaks on task exit and charge them
+ * randomly into the running tasks. This works well for the above worst case,
+ * as the new task will pick up and accumulate the old task's leaked dirty
+ * count and eventually get throttled.
+ */
+DEFINE_PER_CPU(int, dirty_throttle_leaks) = 0;
+
 /**
  * balance_dirty_pages_ratelimited_nr - balance dirty memory state
  * @mapping: address_space which was dirtied
@@ -1242,8 +1433,6 @@ void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
        if (bdi->dirty_exceeded)
                ratelimit = min(ratelimit, 32 >> (PAGE_SHIFT - 10));
 
-       current->nr_dirtied += nr_pages_dirtied;
-
        preempt_disable();
        /*
         * This prevents one CPU to accumulate too many dirtied pages without
@@ -1254,12 +1443,20 @@ void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
        p =  &__get_cpu_var(bdp_ratelimits);
        if (unlikely(current->nr_dirtied >= ratelimit))
                *p = 0;
-       else {
-               *p += nr_pages_dirtied;
-               if (unlikely(*p >= ratelimit_pages)) {
-                       *p = 0;
-                       ratelimit = 0;
-               }
+       else if (unlikely(*p >= ratelimit_pages)) {
+               *p = 0;
+               ratelimit = 0;
+       }
+       /*
+        * Pick up the dirtied pages by the exited tasks. This avoids lots of
+        * short-lived tasks (eg. gcc invocations in a kernel build) escaping
+        * the dirty throttling and livelock other long-run dirtiers.
+        */
+       p = &__get_cpu_var(dirty_throttle_leaks);
+       if (*p > 0 && current->nr_dirtied < ratelimit) {
+               nr_pages_dirtied = min(*p, ratelimit - current->nr_dirtied);
+               *p -= nr_pages_dirtied;
+               current->nr_dirtied += nr_pages_dirtied;
        }
        preempt_enable();
 
@@ -1741,6 +1938,8 @@ void account_page_dirtied(struct page *page, struct address_space *mapping)
                __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
                __inc_bdi_stat(mapping->backing_dev_info, BDI_DIRTIED);
                task_io_account_write(PAGE_CACHE_SIZE);
+               current->nr_dirtied++;
+               this_cpu_inc(bdp_ratelimits);
        }
 }
 EXPORT_SYMBOL(account_page_dirtied);
@@ -1800,6 +1999,24 @@ int __set_page_dirty_nobuffers(struct page *page)
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 
+/*
+ * Call this whenever redirtying a page, to de-account the dirty counters
+ * (NR_DIRTIED, BDI_DIRTIED, tsk->nr_dirtied), so that they match the written
+ * counters (NR_WRITTEN, BDI_WRITTEN) in long term. The mismatches will lead to
+ * systematic errors in balanced_dirty_ratelimit and the dirty pages position
+ * control.
+ */
+void account_page_redirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       if (mapping && mapping_cap_account_dirty(mapping)) {
+               current->nr_dirtied--;
+               dec_zone_page_state(page, NR_DIRTIED);
+               dec_bdi_stat(mapping->backing_dev_info, BDI_DIRTIED);
+       }
+}
+EXPORT_SYMBOL(account_page_redirty);
+
 /*
  * When a writepage implementation decides that it doesn't want to write this
  * page for some reason, it should redirty the locked page via
@@ -1808,6 +2025,7 @@ EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page)
 {
        wbc->pages_skipped++;
+       account_page_redirty(page);
        return __set_page_dirty_nobuffers(page);
 }
 EXPORT_SYMBOL(redirty_page_for_writepage);
index 7990ca154d1b602408993f18c433831dab168d06..0027d8f4a1bb8b1423f42e4d52cb3547debc315f 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/memcontrol.h>
 #include <linux/prefetch.h>
+#include <linux/page-debug-flags.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -96,6 +97,14 @@ EXPORT_SYMBOL(node_states);
 
 unsigned long totalram_pages __read_mostly;
 unsigned long totalreserve_pages __read_mostly;
+/*
+ * When calculating the number of globally allowed dirty pages, there
+ * is a certain number of per-zone reserves that should not be
+ * considered dirtyable memory.  This is the sum of those reserves
+ * over all existing zones that contribute dirtyable memory.
+ */
+unsigned long dirty_balance_reserve __read_mostly;
+
 int percpu_pagelist_fraction;
 gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK;
 
@@ -127,6 +136,13 @@ void pm_restrict_gfp_mask(void)
        saved_gfp_mask = gfp_allowed_mask;
        gfp_allowed_mask &= ~GFP_IOFS;
 }
+
+bool pm_suspended_storage(void)
+{
+       if ((gfp_allowed_mask & GFP_IOFS) == GFP_IOFS)
+               return false;
+       return true;
+}
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
@@ -381,6 +397,37 @@ static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags)
                clear_highpage(page + i);
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+unsigned int _debug_guardpage_minorder;
+
+static int __init debug_guardpage_minorder_setup(char *buf)
+{
+       unsigned long res;
+
+       if (kstrtoul(buf, 10, &res) < 0 ||  res > MAX_ORDER / 2) {
+               printk(KERN_ERR "Bad debug_guardpage_minorder value\n");
+               return 0;
+       }
+       _debug_guardpage_minorder = res;
+       printk(KERN_INFO "Setting debug_guardpage_minorder to %lu\n", res);
+       return 0;
+}
+__setup("debug_guardpage_minorder=", debug_guardpage_minorder_setup);
+
+static inline void set_page_guard_flag(struct page *page)
+{
+       __set_bit(PAGE_DEBUG_FLAG_GUARD, &page->debug_flags);
+}
+
+static inline void clear_page_guard_flag(struct page *page)
+{
+       __clear_bit(PAGE_DEBUG_FLAG_GUARD, &page->debug_flags);
+}
+#else
+static inline void set_page_guard_flag(struct page *page) { }
+static inline void clear_page_guard_flag(struct page *page) { }
+#endif
+
 static inline void set_page_order(struct page *page, int order)
 {
        set_page_private(page, order);
@@ -438,6 +485,11 @@ static inline int page_is_buddy(struct page *page, struct page *buddy,
        if (page_zone_id(page) != page_zone_id(buddy))
                return 0;
 
+       if (page_is_guard(buddy) && page_order(buddy) == order) {
+               VM_BUG_ON(page_count(buddy) != 0);
+               return 1;
+       }
+
        if (PageBuddy(buddy) && page_order(buddy) == order) {
                VM_BUG_ON(page_count(buddy) != 0);
                return 1;
@@ -494,11 +546,19 @@ static inline void __free_one_page(struct page *page,
                buddy = page + (buddy_idx - page_idx);
                if (!page_is_buddy(page, buddy, order))
                        break;
-
-               /* Our buddy is free, merge with it and move up one order. */
-               list_del(&buddy->lru);
-               zone->free_area[order].nr_free--;
-               rmv_page_order(buddy);
+               /*
+                * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
+                * merge with it and move up one order.
+                */
+               if (page_is_guard(buddy)) {
+                       clear_page_guard_flag(buddy);
+                       set_page_private(page, 0);
+                       __mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order);
+               } else {
+                       list_del(&buddy->lru);
+                       zone->free_area[order].nr_free--;
+                       rmv_page_order(buddy);
+               }
                combined_idx = buddy_idx & page_idx;
                page = page + (combined_idx - page_idx);
                page_idx = combined_idx;
@@ -632,7 +692,7 @@ static bool free_pages_prepare(struct page *page, unsigned int order)
        int i;
        int bad = 0;
 
-       trace_mm_page_free_direct(page, order);
+       trace_mm_page_free(page, order);
        kmemcheck_free_shadow(page, order);
 
        if (PageAnon(page))
@@ -670,32 +730,23 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        local_irq_restore(flags);
 }
 
-/*
- * permit the bootmem allocator to evade page validation on high-order frees
- */
 void __meminit __free_pages_bootmem(struct page *page, unsigned int order)
 {
-       if (order == 0) {
-               __ClearPageReserved(page);
-               set_page_count(page, 0);
-               set_page_refcounted(page);
-               __free_page(page);
-       } else {
-               int loop;
-
-               prefetchw(page);
-               for (loop = 0; loop < (1 << order); loop++) {
-                       struct page *p = &page[loop];
+       unsigned int nr_pages = 1 << order;
+       unsigned int loop;
 
-                       if (loop + 1 < (1 << order))
-                               prefetchw(p + 1);
-                       __ClearPageReserved(p);
-                       set_page_count(p, 0);
-               }
+       prefetchw(page);
+       for (loop = 0; loop < nr_pages; loop++) {
+               struct page *p = &page[loop];
 
-               set_page_refcounted(page);
-               __free_pages(page, order);
+               if (loop + 1 < nr_pages)
+                       prefetchw(p + 1);
+               __ClearPageReserved(p);
+               set_page_count(p, 0);
        }
+
+       set_page_refcounted(page);
+       __free_pages(page, order);
 }
 
 
@@ -724,6 +775,23 @@ static inline void expand(struct zone *zone, struct page *page,
                high--;
                size >>= 1;
                VM_BUG_ON(bad_range(zone, &page[size]));
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+               if (high < debug_guardpage_minorder()) {
+                       /*
+                        * Mark as guard pages (or page), that will allow to
+                        * merge back to allocator when buddy will be freed.
+                        * Corresponding page table entries will not be touched,
+                        * pages will stay not present in virtual address space
+                        */
+                       INIT_LIST_HEAD(&page[size].lru);
+                       set_page_guard_flag(&page[size]);
+                       set_page_private(&page[size], high);
+                       /* Guard pages are not available for any usage */
+                       __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << high));
+                       continue;
+               }
+#endif
                list_add(&page[size].lru, &area->free_list[migratetype]);
                area->nr_free++;
                set_page_order(&page[size], high);
@@ -1188,6 +1256,19 @@ out:
        local_irq_restore(flags);
 }
 
+/*
+ * Free a list of 0-order pages
+ */
+void free_hot_cold_page_list(struct list_head *list, int cold)
+{
+       struct page *page, *next;
+
+       list_for_each_entry_safe(page, next, list, lru) {
+               trace_mm_page_free_batched(page, cold);
+               free_hot_cold_page(page, cold);
+       }
+}
+
 /*
  * split_page takes a non-compound higher-order page, and splits it into
  * n (1<<order) sub-pages: page[0..n]
@@ -1435,7 +1516,7 @@ static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark,
        long min = mark;
        int o;
 
-       free_pages -= (1 << order) + 1;
+       free_pages -= (1 << order) - 1;
        if (alloc_flags & ALLOC_HIGH)
                min -= min / 2;
        if (alloc_flags & ALLOC_HARDER)
@@ -1645,6 +1726,35 @@ zonelist_scan:
                if ((alloc_flags & ALLOC_CPUSET) &&
                        !cpuset_zone_allowed_softwall(zone, gfp_mask))
                                continue;
+               /*
+                * When allocating a page cache page for writing, we
+                * want to get it from a zone that is within its dirty
+                * limit, such that no single zone holds more than its
+                * proportional share of globally allowed dirty pages.
+                * The dirty limits take into account the zone's
+                * lowmem reserves and high watermark so that kswapd
+                * should be able to balance it without having to
+                * write pages from its LRU list.
+                *
+                * This may look like it could increase pressure on
+                * lower zones by failing allocations in higher zones
+                * before they are full.  But the pages that do spill
+                * over are limited as the lower zones are protected
+                * by this very same mechanism.  It should not become
+                * a practical burden to them.
+                *
+                * XXX: For now, allow allocations to potentially
+                * exceed the per-zone dirty limit in the slowpath
+                * (ALLOC_WMARK_LOW unset) before going into reclaim,
+                * which is important when on a NUMA setup the allowed
+                * zones are together not big enough to reach the
+                * global limit.  The proper fix for these situations
+                * will require awareness of zones in the
+                * dirty-throttling and the flusher threads.
+                */
+               if ((alloc_flags & ALLOC_WMARK_LOW) &&
+                   (gfp_mask & __GFP_WRITE) && !zone_dirty_ok(zone))
+                       goto this_zone_full;
 
                BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
                if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
@@ -1734,7 +1844,8 @@ void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
 {
        unsigned int filter = SHOW_MEM_FILTER_NODES;
 
-       if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+       if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) ||
+           debug_guardpage_minorder() > 0)
                return;
 
        /*
@@ -1773,12 +1884,25 @@ void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
 
 static inline int
 should_alloc_retry(gfp_t gfp_mask, unsigned int order,
+                               unsigned long did_some_progress,
                                unsigned long pages_reclaimed)
 {
        /* Do not loop if specifically requested */
        if (gfp_mask & __GFP_NORETRY)
                return 0;
 
+       /* Always retry if specifically requested */
+       if (gfp_mask & __GFP_NOFAIL)
+               return 1;
+
+       /*
+        * Suspend converts GFP_KERNEL to __GFP_WAIT which can prevent reclaim
+        * making forward progress without invoking OOM. Suspend also disables
+        * storage devices so kswapd will not help. Bail if we are suspending.
+        */
+       if (!did_some_progress && pm_suspended_storage())
+               return 0;
+
        /*
         * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER
         * means __GFP_NOFAIL, but that may not be true in other
@@ -1797,13 +1921,6 @@ should_alloc_retry(gfp_t gfp_mask, unsigned int order,
        if (gfp_mask & __GFP_REPEAT && pages_reclaimed < (1 << order))
                return 1;
 
-       /*
-        * Don't let big-order allocations loop unless the caller
-        * explicitly requests that.
-        */
-       if (gfp_mask & __GFP_NOFAIL)
-               return 1;
-
        return 0;
 }
 
@@ -1864,14 +1981,20 @@ static struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
-       int migratetype, unsigned long *did_some_progress,
-       bool sync_migration)
+       int migratetype, bool sync_migration,
+       bool *deferred_compaction,
+       unsigned long *did_some_progress)
 {
        struct page *page;
 
-       if (!order || compaction_deferred(preferred_zone))
+       if (!order)
                return NULL;
 
+       if (compaction_deferred(preferred_zone)) {
+               *deferred_compaction = true;
+               return NULL;
+       }
+
        current->flags |= PF_MEMALLOC;
        *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
                                                nodemask, sync_migration);
@@ -1899,7 +2022,13 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                 * but not enough to satisfy watermarks.
                 */
                count_vm_event(COMPACTFAIL);
-               defer_compaction(preferred_zone);
+
+               /*
+                * As async compaction considers a subset of pageblocks, only
+                * defer if the failure was a sync compaction failure.
+                */
+               if (sync_migration)
+                       defer_compaction(preferred_zone);
 
                cond_resched();
        }
@@ -1911,8 +2040,9 @@ static inline struct page *
 __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
-       int migratetype, unsigned long *did_some_progress,
-       bool sync_migration)
+       int migratetype, bool sync_migration,
+       bool *deferred_compaction,
+       unsigned long *did_some_progress)
 {
        return NULL;
 }
@@ -2062,6 +2192,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
        unsigned long pages_reclaimed = 0;
        unsigned long did_some_progress;
        bool sync_migration = false;
+       bool deferred_compaction = false;
 
        /*
         * In the slowpath, we sanity check order to avoid ever trying to
@@ -2142,12 +2273,22 @@ rebalance:
                                        zonelist, high_zoneidx,
                                        nodemask,
                                        alloc_flags, preferred_zone,
-                                       migratetype, &did_some_progress,
-                                       sync_migration);
+                                       migratetype, sync_migration,
+                                       &deferred_compaction,
+                                       &did_some_progress);
        if (page)
                goto got_pg;
        sync_migration = true;
 
+       /*
+        * If compaction is deferred for high-order allocations, it is because
+        * sync compaction recently failed. In this is the case and the caller
+        * has requested the system not be heavily disrupted, fail the
+        * allocation now instead of entering direct reclaim
+        */
+       if (deferred_compaction && (gfp_mask & __GFP_NO_KSWAPD))
+               goto nopage;
+
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
                                        zonelist, high_zoneidx,
@@ -2196,7 +2337,8 @@ rebalance:
 
        /* Check if we should retry the allocation */
        pages_reclaimed += did_some_progress;
-       if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
+       if (should_alloc_retry(gfp_mask, order, did_some_progress,
+                                               pages_reclaimed)) {
                /* Wait for some write requests to complete then retry */
                wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
                goto rebalance;
@@ -2210,8 +2352,9 @@ rebalance:
                                        zonelist, high_zoneidx,
                                        nodemask,
                                        alloc_flags, preferred_zone,
-                                       migratetype, &did_some_progress,
-                                       sync_migration);
+                                       migratetype, sync_migration,
+                                       &deferred_compaction,
+                                       &did_some_progress);
                if (page)
                        goto got_pg;
        }
@@ -2306,16 +2449,6 @@ unsigned long get_zeroed_page(gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(get_zeroed_page);
 
-void __pagevec_free(struct pagevec *pvec)
-{
-       int i = pagevec_count(pvec);
-
-       while (--i >= 0) {
-               trace_mm_pagevec_free(pvec->pages[i], pvec->cold);
-               free_hot_cold_page(pvec->pages[i], pvec->cold);
-       }
-}
-
 void __free_pages(struct page *page, unsigned int order)
 {
        if (put_page_testzero(page)) {
@@ -3385,25 +3518,33 @@ static void setup_zone_migrate_reserve(struct zone *zone)
                if (page_to_nid(page) != zone_to_nid(zone))
                        continue;
 
-               /* Blocks with reserved pages will never free, skip them. */
-               block_end_pfn = min(pfn + pageblock_nr_pages, end_pfn);
-               if (pageblock_is_reserved(pfn, block_end_pfn))
-                       continue;
-
                block_migratetype = get_pageblock_migratetype(page);
 
-               /* If this block is reserved, account for it */
-               if (reserve > 0 && block_migratetype == MIGRATE_RESERVE) {
-                       reserve--;
-                       continue;
-               }
+               /* Only test what is necessary when the reserves are not met */
+               if (reserve > 0) {
+                       /*
+                        * Blocks with reserved pages will never free, skip
+                        * them.
+                        */
+                       block_end_pfn = min(pfn + pageblock_nr_pages, end_pfn);
+                       if (pageblock_is_reserved(pfn, block_end_pfn))
+                               continue;
 
-               /* Suitable for reserving if this block is movable */
-               if (reserve > 0 && block_migratetype == MIGRATE_MOVABLE) {
-                       set_pageblock_migratetype(page, MIGRATE_RESERVE);
-                       move_freepages_block(zone, page, MIGRATE_RESERVE);
-                       reserve--;
-                       continue;
+                       /* If this block is reserved, account for it */
+                       if (block_migratetype == MIGRATE_RESERVE) {
+                               reserve--;
+                               continue;
+                       }
+
+                       /* Suitable for reserving if this block is movable */
+                       if (block_migratetype == MIGRATE_MOVABLE) {
+                               set_pageblock_migratetype(page,
+                                                       MIGRATE_RESERVE);
+                               move_freepages_block(zone, page,
+                                                       MIGRATE_RESERVE);
+                               reserve--;
+                               continue;
+                       }
                }
 
                /*
@@ -4121,7 +4262,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
        for (j = 0; j < MAX_NR_ZONES; j++) {
                struct zone *zone = pgdat->node_zones + j;
                unsigned long size, realsize, memmap_pages;
-               enum lru_list l;
+               enum lru_list lru;
 
                size = zone_spanned_pages_in_node(nid, j, zones_size);
                realsize = size - zone_absent_pages_in_node(nid, j,
@@ -4171,8 +4312,8 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                zone->zone_pgdat = pgdat;
 
                zone_pcp_init(zone);
-               for_each_lru(l)
-                       INIT_LIST_HEAD(&zone->lru[l].list);
+               for_each_lru(lru)
+                       INIT_LIST_HEAD(&zone->lruvec.lists[lru]);
                zone->reclaim_stat.recent_rotated[0] = 0;
                zone->reclaim_stat.recent_rotated[1] = 0;
                zone->reclaim_stat.recent_scanned[0] = 0;
@@ -4526,8 +4667,10 @@ static void check_for_regular_memory(pg_data_t *pgdat)
 
        for (zone_type = 0; zone_type <= ZONE_NORMAL; zone_type++) {
                struct zone *zone = &pgdat->node_zones[zone_type];
-               if (zone->present_pages)
+               if (zone->present_pages) {
                        node_set_state(zone_to_nid(zone), N_NORMAL_MEMORY);
+                       break;
+               }
        }
 #endif
 }
@@ -4734,8 +4877,19 @@ static void calculate_totalreserve_pages(void)
                        if (max > zone->present_pages)
                                max = zone->present_pages;
                        reserve_pages += max;
+                       /*
+                        * Lowmem reserves are not available to
+                        * GFP_HIGHUSER page cache allocations and
+                        * kswapd tries to balance zones to their high
+                        * watermark.  As a result, neither should be
+                        * regarded as dirtyable memory, to prevent a
+                        * situation where reclaim has to clean pages
+                        * in order to balance the zones.
+                        */
+                       zone->dirty_balance_reserve = max;
                }
        }
+       dirty_balance_reserve = reserve_pages;
        totalreserve_pages = reserve_pages;
 }
 
index 2d123f94a8df49addd2ee3167d31861073da9f84..de1616aa9b1e2b3fac054ce4077073cbb05a3c62 100644 (file)
 #include <linux/swapops.h>
 #include <linux/kmemleak.h>
 
-static void __meminit init_page_cgroup(struct page_cgroup *pc, unsigned long id)
-{
-       pc->flags = 0;
-       set_page_cgroup_array_id(pc, id);
-       pc->mem_cgroup = NULL;
-       INIT_LIST_HEAD(&pc->lru);
-}
 static unsigned long total_usage;
 
 #if !defined(CONFIG_SPARSEMEM)
@@ -35,35 +28,27 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
        struct page_cgroup *base;
 
        base = NODE_DATA(page_to_nid(page))->node_page_cgroup;
+#ifdef CONFIG_DEBUG_VM
+       /*
+        * The sanity checks the page allocator does upon freeing a
+        * page can reach here before the page_cgroup arrays are
+        * allocated when feeding a range of pages to the allocator
+        * for the first time during bootup or memory hotplug.
+        */
        if (unlikely(!base))
                return NULL;
-
+#endif
        offset = pfn - NODE_DATA(page_to_nid(page))->node_start_pfn;
        return base + offset;
 }
 
-struct page *lookup_cgroup_page(struct page_cgroup *pc)
-{
-       unsigned long pfn;
-       struct page *page;
-       pg_data_t *pgdat;
-
-       pgdat = NODE_DATA(page_cgroup_array_id(pc));
-       pfn = pc - pgdat->node_page_cgroup + pgdat->node_start_pfn;
-       page = pfn_to_page(pfn);
-       VM_BUG_ON(pc != lookup_page_cgroup(page));
-       return page;
-}
-
 static int __init alloc_node_page_cgroup(int nid)
 {
-       struct page_cgroup *base, *pc;
+       struct page_cgroup *base;
        unsigned long table_size;
-       unsigned long start_pfn, nr_pages, index;
+       unsigned long nr_pages;
 
-       start_pfn = NODE_DATA(nid)->node_start_pfn;
        nr_pages = NODE_DATA(nid)->node_spanned_pages;
-
        if (!nr_pages)
                return 0;
 
@@ -73,10 +58,6 @@ static int __init alloc_node_page_cgroup(int nid)
                        table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
        if (!base)
                return -ENOMEM;
-       for (index = 0; index < nr_pages; index++) {
-               pc = base + index;
-               init_page_cgroup(pc, nid);
-       }
        NODE_DATA(nid)->node_page_cgroup = base;
        total_usage += table_size;
        return 0;
@@ -111,29 +92,23 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
 {
        unsigned long pfn = page_to_pfn(page);
        struct mem_section *section = __pfn_to_section(pfn);
-
+#ifdef CONFIG_DEBUG_VM
+       /*
+        * The sanity checks the page allocator does upon freeing a
+        * page can reach here before the page_cgroup arrays are
+        * allocated when feeding a range of pages to the allocator
+        * for the first time during bootup or memory hotplug.
+        */
        if (!section->page_cgroup)
                return NULL;
+#endif
        return section->page_cgroup + pfn;
 }
 
-struct page *lookup_cgroup_page(struct page_cgroup *pc)
-{
-       struct mem_section *section;
-       struct page *page;
-       unsigned long nr;
-
-       nr = page_cgroup_array_id(pc);
-       section = __nr_to_section(nr);
-       page = pfn_to_page(pc - section->page_cgroup);
-       VM_BUG_ON(pc != lookup_page_cgroup(page));
-       return page;
-}
-
 static void *__meminit alloc_page_cgroup(size_t size, int nid)
 {
+       gfp_t flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN;
        void *addr = NULL;
-       gfp_t flags = GFP_KERNEL | __GFP_NOWARN;
 
        addr = alloc_pages_exact_nid(nid, size, flags);
        if (addr) {
@@ -142,39 +117,20 @@ static void *__meminit alloc_page_cgroup(size_t size, int nid)
        }
 
        if (node_state(nid, N_HIGH_MEMORY))
-               addr = vmalloc_node(size, nid);
+               addr = vzalloc_node(size, nid);
        else
-               addr = vmalloc(size);
+               addr = vzalloc(size);
 
        return addr;
 }
 
-#ifdef CONFIG_MEMORY_HOTPLUG
-static void free_page_cgroup(void *addr)
-{
-       if (is_vmalloc_addr(addr)) {
-               vfree(addr);
-       } else {
-               struct page *page = virt_to_page(addr);
-               size_t table_size =
-                       sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-
-               BUG_ON(PageReserved(page));
-               free_pages_exact(addr, table_size);
-       }
-}
-#endif
-
 static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
 {
-       struct page_cgroup *base, *pc;
        struct mem_section *section;
+       struct page_cgroup *base;
        unsigned long table_size;
-       unsigned long nr;
-       int index;
 
-       nr = pfn_to_section_nr(pfn);
-       section = __nr_to_section(nr);
+       section = __pfn_to_section(pfn);
 
        if (section->page_cgroup)
                return 0;
@@ -194,10 +150,6 @@ static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
                return -ENOMEM;
        }
 
-       for (index = 0; index < PAGES_PER_SECTION; index++) {
-               pc = base + index;
-               init_page_cgroup(pc, nr);
-       }
        /*
         * The passed "pfn" may not be aligned to SECTION.  For the calculation
         * we need to apply a mask.
@@ -208,6 +160,20 @@ static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
        return 0;
 }
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void free_page_cgroup(void *addr)
+{
+       if (is_vmalloc_addr(addr)) {
+               vfree(addr);
+       } else {
+               struct page *page = virt_to_page(addr);
+               size_t table_size =
+                       sizeof(struct page_cgroup) * PAGES_PER_SECTION;
+
+               BUG_ON(PageReserved(page));
+               free_pages_exact(addr, table_size);
+       }
+}
+
 void __free_page_cgroup(unsigned long pfn)
 {
        struct mem_section *ms;
@@ -366,7 +332,6 @@ struct swap_cgroup {
        unsigned short          id;
 };
 #define SC_PER_PAGE    (PAGE_SIZE/sizeof(struct swap_cgroup))
-#define SC_POS_MASK    (SC_PER_PAGE - 1)
 
 /*
  * SwapCgroup implements "lookup" and "exchange" operations.
@@ -408,6 +373,21 @@ not_enough_page:
        return -ENOMEM;
 }
 
+static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
+                                       struct swap_cgroup_ctrl **ctrlp)
+{
+       pgoff_t offset = swp_offset(ent);
+       struct swap_cgroup_ctrl *ctrl;
+       struct page *mappage;
+
+       ctrl = &swap_cgroup_ctrl[swp_type(ent)];
+       if (ctrlp)
+               *ctrlp = ctrl;
+
+       mappage = ctrl->map[offset / SC_PER_PAGE];
+       return page_address(mappage) + offset % SC_PER_PAGE;
+}
+
 /**
  * swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
  * @end: swap entry to be cmpxchged
@@ -420,21 +400,13 @@ not_enough_page:
 unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
                                        unsigned short old, unsigned short new)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
        struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
        struct swap_cgroup *sc;
        unsigned long flags;
        unsigned short retval;
 
-       ctrl = &swap_cgroup_ctrl[type];
+       sc = lookup_swap_cgroup(ent, &ctrl);
 
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
        spin_lock_irqsave(&ctrl->lock, flags);
        retval = sc->id;
        if (retval == old)
@@ -455,21 +427,13 @@ unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
  */
 unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
        struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
        struct swap_cgroup *sc;
        unsigned short old;
        unsigned long flags;
 
-       ctrl = &swap_cgroup_ctrl[type];
+       sc = lookup_swap_cgroup(ent, &ctrl);
 
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
        spin_lock_irqsave(&ctrl->lock, flags);
        old = sc->id;
        sc->id = id;
@@ -479,28 +443,14 @@ unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
 }
 
 /**
- * lookup_swap_cgroup - lookup mem_cgroup tied to swap entry
+ * lookup_swap_cgroup_id - lookup mem_cgroup id tied to swap entry
  * @ent: swap entry to be looked up.
  *
  * Returns CSS ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
  */
-unsigned short lookup_swap_cgroup(swp_entry_t ent)
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
 {
-       int type = swp_type(ent);
-       unsigned long offset = swp_offset(ent);
-       unsigned long idx = offset / SC_PER_PAGE;
-       unsigned long pos = offset & SC_POS_MASK;
-       struct swap_cgroup_ctrl *ctrl;
-       struct page *mappage;
-       struct swap_cgroup *sc;
-       unsigned short ret;
-
-       ctrl = &swap_cgroup_ctrl[type];
-       mappage = ctrl->map[idx];
-       sc = page_address(mappage);
-       sc += pos;
-       ret = sc->id;
-       return ret;
+       return lookup_swap_cgroup(ent, NULL)->id;
 }
 
 int swap_cgroup_swapon(int type, unsigned long max_pages)
index a4fd3680038be499a47cf747d1ba657646e5d36c..c8454e06b6c84b424de3952c567fbbcc8264ff75 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -271,6 +271,51 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
        return -ENOMEM;
 }
 
+/*
+ * Some rmap walk that needs to find all ptes/hugepmds without false
+ * negatives (like migrate and split_huge_page) running concurrent
+ * with operations that copy or move pagetables (like mremap() and
+ * fork()) to be safe. They depend on the anon_vma "same_anon_vma"
+ * list to be in a certain order: the dst_vma must be placed after the
+ * src_vma in the list. This is always guaranteed by fork() but
+ * mremap() needs to call this function to enforce it in case the
+ * dst_vma isn't newly allocated and chained with the anon_vma_clone()
+ * function but just an extension of a pre-existing vma through
+ * vma_merge.
+ *
+ * NOTE: the same_anon_vma list can still be changed by other
+ * processes while mremap runs because mremap doesn't hold the
+ * anon_vma mutex to prevent modifications to the list while it
+ * runs. All we need to enforce is that the relative order of this
+ * process vmas isn't changing (we don't care about other vmas
+ * order). Each vma corresponds to an anon_vma_chain structure so
+ * there's no risk that other processes calling anon_vma_moveto_tail()
+ * and changing the same_anon_vma list under mremap() will screw with
+ * the relative order of this process vmas in the list, because we
+ * they can't alter the order of any vma that belongs to this
+ * process. And there can't be another anon_vma_moveto_tail() running
+ * concurrently with mremap() coming from this process because we hold
+ * the mmap_sem for the whole mremap(). fork() ordering dependency
+ * also shouldn't be affected because fork() only cares that the
+ * parent vmas are placed in the list before the child vmas and
+ * anon_vma_moveto_tail() won't reorder vmas from either the fork()
+ * parent or child.
+ */
+void anon_vma_moveto_tail(struct vm_area_struct *dst)
+{
+       struct anon_vma_chain *pavc;
+       struct anon_vma *root = NULL;
+
+       list_for_each_entry_reverse(pavc, &dst->anon_vma_chain, same_vma) {
+               struct anon_vma *anon_vma = pavc->anon_vma;
+               VM_BUG_ON(pavc->vma != dst);
+               root = lock_anon_vma_root(root, anon_vma);
+               list_del(&pavc->same_anon_vma);
+               list_add_tail(&pavc->same_anon_vma, &anon_vma->head);
+       }
+       unlock_anon_vma_root(root);
+}
+
 /*
  * Attach vma to its own anon_vma, as well as to the anon_vmas that
  * the corresponding VMA in the parent process is attached to.
@@ -728,7 +773,7 @@ out:
 }
 
 static int page_referenced_anon(struct page *page,
-                               struct mem_cgroup *mem_cont,
+                               struct mem_cgroup *memcg,
                                unsigned long *vm_flags)
 {
        unsigned int mapcount;
@@ -751,7 +796,7 @@ static int page_referenced_anon(struct page *page,
                 * counting on behalf of references from different
                 * cgroups
                 */
-               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+               if (memcg && !mm_match_cgroup(vma->vm_mm, memcg))
                        continue;
                referenced += page_referenced_one(page, vma, address,
                                                  &mapcount, vm_flags);
@@ -766,7 +811,7 @@ static int page_referenced_anon(struct page *page,
 /**
  * page_referenced_file - referenced check for object-based rmap
  * @page: the page we're checking references on.
- * @mem_cont: target memory controller
+ * @memcg: target memory control group
  * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * For an object-based mapped page, find all the places it is mapped and
@@ -777,7 +822,7 @@ static int page_referenced_anon(struct page *page,
  * This function is only called from page_referenced for object-based pages.
  */
 static int page_referenced_file(struct page *page,
-                               struct mem_cgroup *mem_cont,
+                               struct mem_cgroup *memcg,
                                unsigned long *vm_flags)
 {
        unsigned int mapcount;
@@ -819,7 +864,7 @@ static int page_referenced_file(struct page *page,
                 * counting on behalf of references from different
                 * cgroups
                 */
-               if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
+               if (memcg && !mm_match_cgroup(vma->vm_mm, memcg))
                        continue;
                referenced += page_referenced_one(page, vma, address,
                                                  &mapcount, vm_flags);
@@ -835,7 +880,7 @@ static int page_referenced_file(struct page *page,
  * page_referenced - test if the page was referenced
  * @page: the page to test
  * @is_locked: caller holds lock on the page
- * @mem_cont: target memory controller
+ * @memcg: target memory cgroup
  * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * Quick test_and_clear_referenced for all mappings to a page,
@@ -843,7 +888,7 @@ static int page_referenced_file(struct page *page,
  */
 int page_referenced(struct page *page,
                    int is_locked,
-                   struct mem_cgroup *mem_cont,
+                   struct mem_cgroup *memcg,
                    unsigned long *vm_flags)
 {
        int referenced = 0;
@@ -859,13 +904,13 @@ int page_referenced(struct page *page,
                        }
                }
                if (unlikely(PageKsm(page)))
-                       referenced += page_referenced_ksm(page, mem_cont,
+                       referenced += page_referenced_ksm(page, memcg,
                                                                vm_flags);
                else if (PageAnon(page))
-                       referenced += page_referenced_anon(page, mem_cont,
+                       referenced += page_referenced_anon(page, memcg,
                                                                vm_flags);
                else if (page->mapping)
-                       referenced += page_referenced_file(page, mem_cont,
+                       referenced += page_referenced_file(page, memcg,
                                                                vm_flags);
                if (we_locked)
                        unlock_page(page);
index 2acfa0d9094379ae999c1937dd9d4ed475af1837..f0bd7857ab3bed2adf6649e60dda6ad712ef0b92 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -481,11 +481,13 @@ EXPORT_SYMBOL(slab_buffer_size);
 #endif
 
 /*
- * Do not go above this order unless 0 objects fit into the slab.
+ * Do not go above this order unless 0 objects fit into the slab or
+ * overridden on the command line.
  */
-#define        BREAK_GFP_ORDER_HI      1
-#define        BREAK_GFP_ORDER_LO      0
-static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
+#define        SLAB_MAX_ORDER_HI       1
+#define        SLAB_MAX_ORDER_LO       0
+static int slab_max_order = SLAB_MAX_ORDER_LO;
+static bool slab_max_order_set __initdata;
 
 /*
  * Functions for storing/retrieving the cachep and or slab from the page
@@ -854,6 +856,17 @@ static int __init noaliencache_setup(char *s)
 }
 __setup("noaliencache", noaliencache_setup);
 
+static int __init slab_max_order_setup(char *str)
+{
+       get_option(&str, &slab_max_order);
+       slab_max_order = slab_max_order < 0 ? 0 :
+                               min(slab_max_order, MAX_ORDER - 1);
+       slab_max_order_set = true;
+
+       return 1;
+}
+__setup("slab_max_order=", slab_max_order_setup);
+
 #ifdef CONFIG_NUMA
 /*
  * Special reaping functions for NUMA systems called from cache_reap().
@@ -1502,10 +1515,11 @@ void __init kmem_cache_init(void)
 
        /*
         * Fragmentation resistance on low memory - only use bigger
-        * page orders on machines with more than 32MB of memory.
+        * page orders on machines with more than 32MB of memory if
+        * not overridden on the command line.
         */
-       if (totalram_pages > (32 << 20) >> PAGE_SHIFT)
-               slab_break_gfp_order = BREAK_GFP_ORDER_HI;
+       if (!slab_max_order_set && totalram_pages > (32 << 20) >> PAGE_SHIFT)
+               slab_max_order = SLAB_MAX_ORDER_HI;
 
        /* Bootstrap is tricky, because several objects are allocated
         * from caches that do not exist yet:
@@ -1932,8 +1946,8 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
                        /* Print header */
                        if (lines == 0) {
                                printk(KERN_ERR
-                                       "Slab corruption: %s start=%p, len=%d\n",
-                                       cachep->name, realobj, size);
+                                       "Slab corruption (%s): %s start=%p, len=%d\n",
+                                       print_tainted(), cachep->name, realobj, size);
                                print_objinfo(cachep, objp, 0);
                        }
                        /* Hexdump the affected line */
@@ -2117,7 +2131,7 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
                 * Large number of objects is good, but very large slabs are
                 * currently bad for the gfp()s.
                 */
-               if (gfporder >= slab_break_gfp_order)
+               if (gfporder >= slab_max_order)
                        break;
 
                /*
@@ -3042,8 +3056,9 @@ static void check_slabp(struct kmem_cache *cachep, struct slab *slabp)
        if (entries != cachep->num - slabp->inuse) {
 bad:
                printk(KERN_ERR "slab: Internal list corruption detected in "
-                               "cache '%s'(%d), slabp %p(%d). Hexdump:\n",
-                       cachep->name, cachep->num, slabp, slabp->inuse);
+                       "cache '%s'(%d), slabp %p(%d). Tainted(%s). Hexdump:\n",
+                       cachep->name, cachep->num, slabp, slabp->inuse,
+                       print_tainted());
                print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, slabp,
                        sizeof(*slabp) + cachep->num * sizeof(kmem_bufctl_t),
                        1);
index 025f6ac515697354f171140cec6dfaed6eb4a7cb..4907563ef7ff7e199577f5d2ffedda6fa358271e 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -366,7 +366,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
                const char *n)
 {
        VM_BUG_ON(!irqs_disabled());
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
                if (cmpxchg_double(&page->freelist, &page->counters,
                        freelist_old, counters_old,
@@ -400,7 +401,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                void *freelist_new, unsigned long counters_new,
                const char *n)
 {
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (s->flags & __CMPXCHG_DOUBLE) {
                if (cmpxchg_double(&page->freelist, &page->counters,
                        freelist_old, counters_old,
@@ -570,7 +572,7 @@ static void slab_bug(struct kmem_cache *s, char *fmt, ...)
        va_end(args);
        printk(KERN_ERR "========================================"
                        "=====================================\n");
-       printk(KERN_ERR "BUG %s: %s\n", s->name, buf);
+       printk(KERN_ERR "BUG %s (%s): %s\n", s->name, print_tainted(), buf);
        printk(KERN_ERR "----------------------------------------"
                        "-------------------------------------\n\n");
 }
@@ -1901,11 +1903,14 @@ static void unfreeze_partials(struct kmem_cache *s)
                        }
 
                        if (l != m) {
-                               if (l == M_PARTIAL)
+                               if (l == M_PARTIAL) {
                                        remove_partial(n, page);
-                               else
+                                       stat(s, FREE_REMOVE_PARTIAL);
+                               } else {
                                        add_partial(n, page,
                                                DEACTIVATE_TO_TAIL);
+                                       stat(s, FREE_ADD_PARTIAL);
+                               }
 
                                l = m;
                        }
@@ -2123,6 +2128,37 @@ static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
        return object;
 }
 
+/*
+ * Check the page->freelist of a page and either transfer the freelist to the per cpu freelist
+ * or deactivate the page.
+ *
+ * The page is still frozen if the return value is not NULL.
+ *
+ * If this function returns NULL then the page has been unfrozen.
+ */
+static inline void *get_freelist(struct kmem_cache *s, struct page *page)
+{
+       struct page new;
+       unsigned long counters;
+       void *freelist;
+
+       do {
+               freelist = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               VM_BUG_ON(!new.frozen);
+
+               new.inuse = page->objects;
+               new.frozen = freelist != NULL;
+
+       } while (!cmpxchg_double_slab(s, page,
+               freelist, counters,
+               NULL, new.counters,
+               "get_freelist"));
+
+       return freelist;
+}
+
 /*
  * Slow path. The lockless freelist is empty or we need to perform
  * debugging duties.
@@ -2144,8 +2180,6 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 {
        void **object;
        unsigned long flags;
-       struct page new;
-       unsigned long counters;
 
        local_irq_save(flags);
 #ifdef CONFIG_PREEMPT
@@ -2166,31 +2200,14 @@ redo:
                goto new_slab;
        }
 
-       stat(s, ALLOC_SLOWPATH);
-
-       do {
-               object = c->page->freelist;
-               counters = c->page->counters;
-               new.counters = counters;
-               VM_BUG_ON(!new.frozen);
-
-               /*
-                * If there is no object left then we use this loop to
-                * deactivate the slab which is simple since no objects
-                * are left in the slab and therefore we do not need to
-                * put the page back onto the partial list.
-                *
-                * If there are objects left then we retrieve them
-                * and use them to refill the per cpu queue.
-                */
+       /* must check again c->freelist in case of cpu migration or IRQ */
+       object = c->freelist;
+       if (object)
+               goto load_freelist;
 
-               new.inuse = c->page->objects;
-               new.frozen = object != NULL;
+       stat(s, ALLOC_SLOWPATH);
 
-       } while (!__cmpxchg_double_slab(s, c->page,
-                       object, counters,
-                       NULL, new.counters,
-                       "__slab_alloc"));
+       object = get_freelist(s, c->page);
 
        if (!object) {
                c->page = NULL;
@@ -2999,7 +3016,8 @@ static int kmem_cache_open(struct kmem_cache *s,
                }
        }
 
-#ifdef CONFIG_CMPXCHG_DOUBLE
+#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
+    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
        if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
                /* Enable fast mode */
                s->flags |= __CMPXCHG_DOUBLE;
@@ -3028,7 +3046,9 @@ static int kmem_cache_open(struct kmem_cache *s,
         *    per node list when we run out of per cpu objects. We only fetch 50%
         *    to keep some capacity around for frees.
         */
-       if (s->size >= PAGE_SIZE)
+       if (kmem_cache_debug(s))
+               s->cpu_partial = 0;
+       else if (s->size >= PAGE_SIZE)
                s->cpu_partial = 2;
        else if (s->size >= 1024)
                s->cpu_partial = 6;
@@ -3654,6 +3674,9 @@ void __init kmem_cache_init(void)
        struct kmem_cache *temp_kmem_cache_node;
        unsigned long kmalloc_size;
 
+       if (debug_guardpage_minorder())
+               slub_max_order = 0;
+
        kmem_size = offsetof(struct kmem_cache, node) +
                                nr_node_ids * sizeof(struct kmem_cache_node *);
 
@@ -4634,6 +4657,8 @@ static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf,
        err = strict_strtoul(buf, 10, &objects);
        if (err)
                return err;
+       if (objects && kmem_cache_debug(s))
+               return -EINVAL;
 
        s->cpu_partial = objects;
        flush_all(s);
index a91caf754d9badb5f0b1f3c54b8e86be4723ff84..b0f529b38979447d0ec192f8b6434af5bab28e02 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/export.h>
 #include <linux/mm_inline.h>
-#include <linux/buffer_head.h> /* for try_to_release_page() */
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
 #include <linux/cpu.h>
@@ -54,7 +53,7 @@ static void __page_cache_release(struct page *page)
                spin_lock_irqsave(&zone->lru_lock, flags);
                VM_BUG_ON(!PageLRU(page));
                __ClearPageLRU(page);
-               del_page_from_lru(zone, page);
+               del_page_from_lru_list(zone, page, page_off_lru(page));
                spin_unlock_irqrestore(&zone->lru_lock, flags);
        }
 }
@@ -232,12 +231,14 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
 static void pagevec_move_tail_fn(struct page *page, void *arg)
 {
        int *pgmoved = arg;
-       struct zone *zone = page_zone(page);
 
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
                enum lru_list lru = page_lru_base_type(page);
-               list_move_tail(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_rotate_reclaimable_page(page);
+               struct lruvec *lruvec;
+
+               lruvec = mem_cgroup_lru_move_lists(page_zone(page),
+                                                  page, lru, lru);
+               list_move_tail(&page->lru, &lruvec->lists[lru]);
                (*pgmoved)++;
        }
 }
@@ -368,7 +369,6 @@ void mark_page_accessed(struct page *page)
                SetPageReferenced(page);
        }
 }
-
 EXPORT_SYMBOL(mark_page_accessed);
 
 void __lru_cache_add(struct page *page, enum lru_list lru)
@@ -377,7 +377,7 @@ void __lru_cache_add(struct page *page, enum lru_list lru)
 
        page_cache_get(page);
        if (!pagevec_add(pvec, page))
-               ____pagevec_lru_add(pvec, lru);
+               __pagevec_lru_add(pvec, lru);
        put_cpu_var(lru_add_pvecs);
 }
 EXPORT_SYMBOL(__lru_cache_add);
@@ -476,12 +476,13 @@ static void lru_deactivate_fn(struct page *page, void *arg)
                 */
                SetPageReclaim(page);
        } else {
+               struct lruvec *lruvec;
                /*
                 * The page's writeback ends up during pagevec
                 * We moves tha page into tail of inactive.
                 */
-               list_move_tail(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_rotate_reclaimable_page(page);
+               lruvec = mem_cgroup_lru_move_lists(zone, page, lru, lru);
+               list_move_tail(&page->lru, &lruvec->lists[lru]);
                __count_vm_event(PGROTATED);
        }
 
@@ -504,7 +505,7 @@ static void drain_cpu_pagevecs(int cpu)
        for_each_lru(lru) {
                pvec = &pvecs[lru - LRU_BASE];
                if (pagevec_count(pvec))
-                       ____pagevec_lru_add(pvec, lru);
+                       __pagevec_lru_add(pvec, lru);
        }
 
        pvec = &per_cpu(lru_rotate_pvecs, cpu);
@@ -585,11 +586,10 @@ int lru_add_drain_all(void)
 void release_pages(struct page **pages, int nr, int cold)
 {
        int i;
-       struct pagevec pages_to_free;
+       LIST_HEAD(pages_to_free);
        struct zone *zone = NULL;
        unsigned long uninitialized_var(flags);
 
-       pagevec_init(&pages_to_free, cold);
        for (i = 0; i < nr; i++) {
                struct page *page = pages[i];
 
@@ -617,22 +617,15 @@ void release_pages(struct page **pages, int nr, int cold)
                        }
                        VM_BUG_ON(!PageLRU(page));
                        __ClearPageLRU(page);
-                       del_page_from_lru(zone, page);
+                       del_page_from_lru_list(zone, page, page_off_lru(page));
                }
 
-               if (!pagevec_add(&pages_to_free, page)) {
-                       if (zone) {
-                               spin_unlock_irqrestore(&zone->lru_lock, flags);
-                               zone = NULL;
-                       }
-                       __pagevec_free(&pages_to_free);
-                       pagevec_reinit(&pages_to_free);
-               }
+               list_add(&page->lru, &pages_to_free);
        }
        if (zone)
                spin_unlock_irqrestore(&zone->lru_lock, flags);
 
-       pagevec_free(&pages_to_free);
+       free_hot_cold_page_list(&pages_to_free, cold);
 }
 EXPORT_SYMBOL(release_pages);
 
@@ -652,9 +645,9 @@ void __pagevec_release(struct pagevec *pvec)
        release_pages(pvec->pages, pagevec_count(pvec), pvec->cold);
        pagevec_reinit(pvec);
 }
-
 EXPORT_SYMBOL(__pagevec_release);
 
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 /* used by __split_huge_page_refcount() */
 void lru_add_page_tail(struct zone* zone,
                       struct page *page, struct page *page_tail)
@@ -662,7 +655,6 @@ void lru_add_page_tail(struct zone* zone,
        int active;
        enum lru_list lru;
        const int file = 0;
-       struct list_head *head;
 
        VM_BUG_ON(!PageHead(page));
        VM_BUG_ON(PageCompound(page_tail));
@@ -681,18 +673,30 @@ void lru_add_page_tail(struct zone* zone,
                        lru = LRU_INACTIVE_ANON;
                }
                update_page_reclaim_stat(zone, page_tail, file, active);
-               if (likely(PageLRU(page)))
-                       head = page->lru.prev;
-               else
-                       head = &zone->lru[lru].list;
-               __add_page_to_lru_list(zone, page_tail, lru, head);
        } else {
                SetPageUnevictable(page_tail);
-               add_page_to_lru_list(zone, page_tail, LRU_UNEVICTABLE);
+               lru = LRU_UNEVICTABLE;
+       }
+
+       if (likely(PageLRU(page)))
+               list_add_tail(&page_tail->lru, &page->lru);
+       else {
+               struct list_head *list_head;
+               /*
+                * Head page has not yet been counted, as an hpage,
+                * so we must account for each subpage individually.
+                *
+                * Use the standard add function to put page_tail on the list,
+                * but then correct its position so they all end up in order.
+                */
+               add_page_to_lru_list(zone, page_tail, lru);
+               list_head = page_tail->lru.prev;
+               list_move_tail(&page_tail->lru, list_head);
        }
 }
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static void ____pagevec_lru_add_fn(struct page *page, void *arg)
+static void __pagevec_lru_add_fn(struct page *page, void *arg)
 {
        enum lru_list lru = (enum lru_list)arg;
        struct zone *zone = page_zone(page);
@@ -714,32 +718,13 @@ static void ____pagevec_lru_add_fn(struct page *page, void *arg)
  * Add the passed pages to the LRU, then drop the caller's refcount
  * on them.  Reinitialises the caller's pagevec.
  */
-void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
+void __pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
 {
        VM_BUG_ON(is_unevictable_lru(lru));
 
-       pagevec_lru_move_fn(pvec, ____pagevec_lru_add_fn, (void *)lru);
-}
-
-EXPORT_SYMBOL(____pagevec_lru_add);
-
-/*
- * Try to drop buffers from the pages in a pagevec
- */
-void pagevec_strip(struct pagevec *pvec)
-{
-       int i;
-
-       for (i = 0; i < pagevec_count(pvec); i++) {
-               struct page *page = pvec->pages[i];
-
-               if (page_has_private(page) && trylock_page(page)) {
-                       if (page_has_private(page))
-                               try_to_release_page(page, 0);
-                       unlock_page(page);
-               }
-       }
+       pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, (void *)lru);
 }
+EXPORT_SYMBOL(__pagevec_lru_add);
 
 /**
  * pagevec_lookup - gang pagecache lookup
@@ -763,7 +748,6 @@ unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
        pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages);
        return pagevec_count(pvec);
 }
-
 EXPORT_SYMBOL(pagevec_lookup);
 
 unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
@@ -773,7 +757,6 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
                                        nr_pages, pvec->pages);
        return pagevec_count(pvec);
 }
-
 EXPORT_SYMBOL(pagevec_lookup_tag);
 
 /*
index ea6b32d61873185f59db1eb9ae303488ec6de471..470038a9187383790751817cda61a07cb50f9512 100644 (file)
@@ -300,6 +300,16 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                        new_page = alloc_page_vma(gfp_mask, vma, addr);
                        if (!new_page)
                                break;          /* Out of memory */
+                       /*
+                        * The memcg-specific accounting when moving
+                        * pages around the LRU lists relies on the
+                        * page's owner (memcg) to be valid.  Usually,
+                        * pages are assigned to a new owner before
+                        * being put on the LRU list, but since this
+                        * is not the case here, the stale owner from
+                        * a previous allocation cycle must be reset.
+                        */
+                       mem_cgroup_reset_owner(new_page);
                }
 
                /*
index b1cd120607230b0770c35e0823d6389782ae734a..d999f090dfdabb6e5282aaaf3429029c5e3f839d 100644 (file)
@@ -667,10 +667,10 @@ int try_to_free_swap(struct page *page)
         * original page might be freed under memory pressure, then
         * later read back in from swap, now with the wrong data.
         *
-        * Hibernation clears bits from gfp_allowed_mask to prevent
-        * memory reclaim from writing to disk, so check that here.
+        * Hibration suspends storage while it is writing the image
+        * to disk so check that here.
         */
-       if (!(gfp_allowed_mask & __GFP_IO))
+       if (pm_suspended_storage())
                return 0;
 
        delete_from_swap_cache(page);
@@ -847,12 +847,13 @@ unsigned int count_swap_pages(int type, int free)
 static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, swp_entry_t entry, struct page *page)
 {
-       struct mem_cgroup *ptr;
+       struct mem_cgroup *memcg;
        spinlock_t *ptl;
        pte_t *pte;
        int ret = 1;
 
-       if (mem_cgroup_try_charge_swapin(vma->vm_mm, page, GFP_KERNEL, &ptr)) {
+       if (mem_cgroup_try_charge_swapin(vma->vm_mm, page,
+                                        GFP_KERNEL, &memcg)) {
                ret = -ENOMEM;
                goto out_nolock;
        }
@@ -860,7 +861,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
                if (ret > 0)
-                       mem_cgroup_cancel_charge_swapin(ptr);
+                       mem_cgroup_cancel_charge_swapin(memcg);
                ret = 0;
                goto out;
        }
@@ -871,7 +872,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        set_pte_at(vma->vm_mm, addr, pte,
                   pte_mkold(mk_pte(page, vma->vm_page_prot)));
        page_add_anon_rmap(page, vma, addr);
-       mem_cgroup_commit_charge_swapin(page, ptr);
+       mem_cgroup_commit_charge_swapin(page, memcg);
        swap_free(entry);
        /*
         * Move the page to the active list so it is not
index 21fdf46ad5aac727111834d0955af07472daaec2..86ce9a526c17f4e752a03358c4bf0c74432fd8e1 100644 (file)
@@ -256,7 +256,7 @@ struct vmap_area {
        struct rb_node rb_node;         /* address sorted rbtree */
        struct list_head list;          /* address sorted list */
        struct list_head purge_list;    /* "lazy purge" list */
-       void *private;
+       struct vm_struct *vm;
        struct rcu_head rcu_head;
 };
 
@@ -1285,7 +1285,7 @@ static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
        vm->addr = (void *)va->va_start;
        vm->size = va->va_end - va->va_start;
        vm->caller = caller;
-       va->private = vm;
+       va->vm = vm;
        va->flags |= VM_VM_AREA;
 }
 
@@ -1408,7 +1408,7 @@ static struct vm_struct *find_vm_area(const void *addr)
 
        va = find_vmap_area((unsigned long)addr);
        if (va && va->flags & VM_VM_AREA)
-               return va->private;
+               return va->vm;
 
        return NULL;
 }
@@ -1427,7 +1427,7 @@ struct vm_struct *remove_vm_area(const void *addr)
 
        va = find_vmap_area((unsigned long)addr);
        if (va && va->flags & VM_VM_AREA) {
-               struct vm_struct *vm = va->private;
+               struct vm_struct *vm = va->vm;
 
                if (!(vm->flags & VM_UNLIST)) {
                        struct vm_struct *tmp, **p;
@@ -2378,7 +2378,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
        vms = kzalloc(sizeof(vms[0]) * nr_vms, GFP_KERNEL);
        vas = kzalloc(sizeof(vas[0]) * nr_vms, GFP_KERNEL);
        if (!vas || !vms)
-               goto err_free;
+               goto err_free2;
 
        for (area = 0; area < nr_vms; area++) {
                vas[area] = kzalloc(sizeof(struct vmap_area), GFP_KERNEL);
@@ -2476,11 +2476,10 @@ found:
 
 err_free:
        for (area = 0; area < nr_vms; area++) {
-               if (vas)
-                       kfree(vas[area]);
-               if (vms)
-                       kfree(vms[area]);
+               kfree(vas[area]);
+               kfree(vms[area]);
        }
+err_free2:
        kfree(vas);
        kfree(vms);
        return NULL;
index 11adc890ce30bb5f09c3a53765ce0b57474a893a..2880396f7953b03476db86957c66a3787b40cb8c 100644 (file)
@@ -103,8 +103,11 @@ struct scan_control {
         */
        reclaim_mode_t reclaim_mode;
 
-       /* Which cgroup do we reclaim from */
-       struct mem_cgroup *mem_cgroup;
+       /*
+        * The memory cgroup that hit its limit and as a result is the
+        * primary target of this reclaim invocation.
+        */
+       struct mem_cgroup *target_mem_cgroup;
 
        /*
         * Nodemask of nodes allowed by the caller. If NULL, all nodes
@@ -113,6 +116,11 @@ struct scan_control {
        nodemask_t      *nodemask;
 };
 
+struct mem_cgroup_zone {
+       struct mem_cgroup *mem_cgroup;
+       struct zone *zone;
+};
+
 #define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
 
 #ifdef ARCH_HAS_PREFETCH
@@ -153,28 +161,45 @@ static LIST_HEAD(shrinker_list);
 static DECLARE_RWSEM(shrinker_rwsem);
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
-#define scanning_global_lru(sc)        (!(sc)->mem_cgroup)
+static bool global_reclaim(struct scan_control *sc)
+{
+       return !sc->target_mem_cgroup;
+}
+
+static bool scanning_global_lru(struct mem_cgroup_zone *mz)
+{
+       return !mz->mem_cgroup;
+}
 #else
-#define scanning_global_lru(sc)        (1)
+static bool global_reclaim(struct scan_control *sc)
+{
+       return true;
+}
+
+static bool scanning_global_lru(struct mem_cgroup_zone *mz)
+{
+       return true;
+}
 #endif
 
-static struct zone_reclaim_stat *get_reclaim_stat(struct zone *zone,
-                                                 struct scan_control *sc)
+static struct zone_reclaim_stat *get_reclaim_stat(struct mem_cgroup_zone *mz)
 {
-       if (!scanning_global_lru(sc))
-               return mem_cgroup_get_reclaim_stat(sc->mem_cgroup, zone);
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_get_reclaim_stat(mz->mem_cgroup, mz->zone);
 
-       return &zone->reclaim_stat;
+       return &mz->zone->reclaim_stat;
 }
 
-static unsigned long zone_nr_lru_pages(struct zone *zone,
-                               struct scan_control *sc, enum lru_list lru)
+static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
+                                      enum lru_list lru)
 {
-       if (!scanning_global_lru(sc))
-               return mem_cgroup_zone_nr_lru_pages(sc->mem_cgroup,
-                               zone_to_nid(zone), zone_idx(zone), BIT(lru));
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
+                                                   zone_to_nid(mz->zone),
+                                                   zone_idx(mz->zone),
+                                                   BIT(lru));
 
-       return zone_page_state(zone, NR_LRU_BASE + lru);
+       return zone_page_state(mz->zone, NR_LRU_BASE + lru);
 }
 
 
@@ -677,12 +702,13 @@ enum page_references {
 };
 
 static enum page_references page_check_references(struct page *page,
+                                                 struct mem_cgroup_zone *mz,
                                                  struct scan_control *sc)
 {
        int referenced_ptes, referenced_page;
        unsigned long vm_flags;
 
-       referenced_ptes = page_referenced(page, 1, sc->mem_cgroup, &vm_flags);
+       referenced_ptes = page_referenced(page, 1, mz->mem_cgroup, &vm_flags);
        referenced_page = TestClearPageReferenced(page);
 
        /* Lumpy reclaim - ignore references */
@@ -715,7 +741,13 @@ static enum page_references page_check_references(struct page *page,
                 */
                SetPageReferenced(page);
 
-               if (referenced_page)
+               if (referenced_page || referenced_ptes > 1)
+                       return PAGEREF_ACTIVATE;
+
+               /*
+                * Activate file-backed executable pages after first usage.
+                */
+               if (vm_flags & VM_EXEC)
                        return PAGEREF_ACTIVATE;
 
                return PAGEREF_KEEP;
@@ -728,29 +760,11 @@ static enum page_references page_check_references(struct page *page,
        return PAGEREF_RECLAIM;
 }
 
-static noinline_for_stack void free_page_list(struct list_head *free_pages)
-{
-       struct pagevec freed_pvec;
-       struct page *page, *tmp;
-
-       pagevec_init(&freed_pvec, 1);
-
-       list_for_each_entry_safe(page, tmp, free_pages, lru) {
-               list_del(&page->lru);
-               if (!pagevec_add(&freed_pvec, page)) {
-                       __pagevec_free(&freed_pvec);
-                       pagevec_reinit(&freed_pvec);
-               }
-       }
-
-       pagevec_free(&freed_pvec);
-}
-
 /*
  * shrink_page_list() returns the number of reclaimed pages
  */
 static unsigned long shrink_page_list(struct list_head *page_list,
-                                     struct zone *zone,
+                                     struct mem_cgroup_zone *mz,
                                      struct scan_control *sc,
                                      int priority,
                                      unsigned long *ret_nr_dirty,
@@ -781,7 +795,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        goto keep;
 
                VM_BUG_ON(PageActive(page));
-               VM_BUG_ON(page_zone(page) != zone);
+               VM_BUG_ON(page_zone(page) != mz->zone);
 
                sc->nr_scanned++;
 
@@ -815,7 +829,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                        }
                }
 
-               references = page_check_references(page, sc);
+               references = page_check_references(page, mz, sc);
                switch (references) {
                case PAGEREF_ACTIVATE:
                        goto activate_locked;
@@ -1006,10 +1020,10 @@ keep_lumpy:
         * back off and wait for congestion to clear because further reclaim
         * will encounter the same problem
         */
-       if (nr_dirty && nr_dirty == nr_congested && scanning_global_lru(sc))
-               zone_set_flag(zone, ZONE_CONGESTED);
+       if (nr_dirty && nr_dirty == nr_congested && global_reclaim(sc))
+               zone_set_flag(mz->zone, ZONE_CONGESTED);
 
-       free_page_list(&free_pages);
+       free_hot_cold_page_list(&free_pages, 1);
 
        list_splice(&ret_pages, page_list);
        count_vm_events(PGACTIVATE, pgactivate);
@@ -1061,8 +1075,39 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
 
        ret = -EBUSY;
 
-       if ((mode & ISOLATE_CLEAN) && (PageDirty(page) || PageWriteback(page)))
-               return ret;
+       /*
+        * To minimise LRU disruption, the caller can indicate that it only
+        * wants to isolate pages it will be able to operate on without
+        * blocking - clean pages for the most part.
+        *
+        * ISOLATE_CLEAN means that only clean pages should be isolated. This
+        * is used by reclaim when it is cannot write to backing storage
+        *
+        * ISOLATE_ASYNC_MIGRATE is used to indicate that it only wants to pages
+        * that it is possible to migrate without blocking
+        */
+       if (mode & (ISOLATE_CLEAN|ISOLATE_ASYNC_MIGRATE)) {
+               /* All the caller can do on PageWriteback is block */
+               if (PageWriteback(page))
+                       return ret;
+
+               if (PageDirty(page)) {
+                       struct address_space *mapping;
+
+                       /* ISOLATE_CLEAN means only clean pages */
+                       if (mode & ISOLATE_CLEAN)
+                               return ret;
+
+                       /*
+                        * Only pages without mappings or that have a
+                        * ->migratepage callback are possible to migrate
+                        * without blocking
+                        */
+                       mapping = page_mapping(page);
+                       if (mapping && !mapping->a_ops->migratepage)
+                               return ret;
+               }
+       }
 
        if ((mode & ISOLATE_UNMAPPED) && page_mapped(page))
                return ret;
@@ -1091,25 +1136,36 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
  * Appropriate locks must be held before calling this function.
  *
  * @nr_to_scan:        The number of pages to look through on the list.
- * @src:       The LRU list to pull pages off.
+ * @mz:                The mem_cgroup_zone to pull pages from.
  * @dst:       The temp list to put pages on to.
- * @scanned:   The number of pages that were scanned.
+ * @nr_scanned:        The number of pages that were scanned.
  * @order:     The caller's attempted allocation order
  * @mode:      One of the LRU isolation modes
+ * @active:    True [1] if isolating active pages
  * @file:      True [1] if isolating file [!anon] pages
  *
  * returns how many pages were moved onto *@dst.
  */
 static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
-               struct list_head *src, struct list_head *dst,
-               unsigned long *scanned, int order, isolate_mode_t mode,
-               int file)
+               struct mem_cgroup_zone *mz, struct list_head *dst,
+               unsigned long *nr_scanned, int order, isolate_mode_t mode,
+               int active, int file)
 {
+       struct lruvec *lruvec;
+       struct list_head *src;
        unsigned long nr_taken = 0;
        unsigned long nr_lumpy_taken = 0;
        unsigned long nr_lumpy_dirty = 0;
        unsigned long nr_lumpy_failed = 0;
        unsigned long scan;
+       int lru = LRU_BASE;
+
+       lruvec = mem_cgroup_zone_lruvec(mz->zone, mz->mem_cgroup);
+       if (active)
+               lru += LRU_ACTIVE;
+       if (file)
+               lru += LRU_FILE;
+       src = &lruvec->lists[lru];
 
        for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) {
                struct page *page;
@@ -1125,15 +1181,14 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
 
                switch (__isolate_lru_page(page, mode, file)) {
                case 0:
+                       mem_cgroup_lru_del(page);
                        list_move(&page->lru, dst);
-                       mem_cgroup_del_lru(page);
                        nr_taken += hpage_nr_pages(page);
                        break;
 
                case -EBUSY:
                        /* else it is being freed elsewhere */
                        list_move(&page->lru, src);
-                       mem_cgroup_rotate_lru_list(page, page_lru(page));
                        continue;
 
                default:
@@ -1178,18 +1233,22 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                         * anon page which don't already have a swap slot is
                         * pointless.
                         */
-                       if (nr_swap_pages <= 0 && PageAnon(cursor_page) &&
+                       if (nr_swap_pages <= 0 && PageSwapBacked(cursor_page) &&
                            !PageSwapCache(cursor_page))
                                break;
 
                        if (__isolate_lru_page(cursor_page, mode, file) == 0) {
+                               unsigned int isolated_pages;
+
+                               mem_cgroup_lru_del(cursor_page);
                                list_move(&cursor_page->lru, dst);
-                               mem_cgroup_del_lru(cursor_page);
-                               nr_taken += hpage_nr_pages(page);
-                               nr_lumpy_taken++;
+                               isolated_pages = hpage_nr_pages(cursor_page);
+                               nr_taken += isolated_pages;
+                               nr_lumpy_taken += isolated_pages;
                                if (PageDirty(cursor_page))
-                                       nr_lumpy_dirty++;
+                                       nr_lumpy_dirty += isolated_pages;
                                scan++;
+                               pfn += isolated_pages - 1;
                        } else {
                                /*
                                 * Check if the page is freed already.
@@ -1215,57 +1274,16 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                        nr_lumpy_failed++;
        }
 
-       *scanned = scan;
+       *nr_scanned = scan;
 
        trace_mm_vmscan_lru_isolate(order,
                        nr_to_scan, scan,
                        nr_taken,
                        nr_lumpy_taken, nr_lumpy_dirty, nr_lumpy_failed,
-                       mode);
+                       mode, file);
        return nr_taken;
 }
 
-static unsigned long isolate_pages_global(unsigned long nr,
-                                       struct list_head *dst,
-                                       unsigned long *scanned, int order,
-                                       isolate_mode_t mode,
-                                       struct zone *z, int active, int file)
-{
-       int lru = LRU_BASE;
-       if (active)
-               lru += LRU_ACTIVE;
-       if (file)
-               lru += LRU_FILE;
-       return isolate_lru_pages(nr, &z->lru[lru].list, dst, scanned, order,
-                                                               mode, file);
-}
-
-/*
- * clear_active_flags() is a helper for shrink_active_list(), clearing
- * any active bits from the pages in the list.
- */
-static unsigned long clear_active_flags(struct list_head *page_list,
-                                       unsigned int *count)
-{
-       int nr_active = 0;
-       int lru;
-       struct page *page;
-
-       list_for_each_entry(page, page_list, lru) {
-               int numpages = hpage_nr_pages(page);
-               lru = page_lru_base_type(page);
-               if (PageActive(page)) {
-                       lru += LRU_ACTIVE;
-                       ClearPageActive(page);
-                       nr_active += numpages;
-               }
-               if (count)
-                       count[lru] += numpages;
-       }
-
-       return nr_active;
-}
-
 /**
  * isolate_lru_page - tries to isolate a page from its LRU list
  * @page: page to isolate from its LRU list
@@ -1325,7 +1343,7 @@ static int too_many_isolated(struct zone *zone, int file,
        if (current_is_kswapd())
                return 0;
 
-       if (!scanning_global_lru(sc))
+       if (!global_reclaim(sc))
                return 0;
 
        if (file) {
@@ -1339,27 +1357,21 @@ static int too_many_isolated(struct zone *zone, int file,
        return isolated > inactive;
 }
 
-/*
- * TODO: Try merging with migrations version of putback_lru_pages
- */
 static noinline_for_stack void
-putback_lru_pages(struct zone *zone, struct scan_control *sc,
-                               unsigned long nr_anon, unsigned long nr_file,
-                               struct list_head *page_list)
+putback_inactive_pages(struct mem_cgroup_zone *mz,
+                      struct list_head *page_list)
 {
-       struct page *page;
-       struct pagevec pvec;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
-
-       pagevec_init(&pvec, 1);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+       struct zone *zone = mz->zone;
+       LIST_HEAD(pages_to_free);
 
        /*
         * Put back any unfreeable pages.
         */
-       spin_lock(&zone->lru_lock);
        while (!list_empty(page_list)) {
+               struct page *page = lru_to_page(page_list);
                int lru;
-               page = lru_to_page(page_list);
+
                VM_BUG_ON(PageLRU(page));
                list_del(&page->lru);
                if (unlikely(!page_evictable(page, NULL))) {
@@ -1376,30 +1388,53 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc,
                        int numpages = hpage_nr_pages(page);
                        reclaim_stat->recent_rotated[file] += numpages;
                }
-               if (!pagevec_add(&pvec, page)) {
-                       spin_unlock_irq(&zone->lru_lock);
-                       __pagevec_release(&pvec);
-                       spin_lock_irq(&zone->lru_lock);
+               if (put_page_testzero(page)) {
+                       __ClearPageLRU(page);
+                       __ClearPageActive(page);
+                       del_page_from_lru_list(zone, page, lru);
+
+                       if (unlikely(PageCompound(page))) {
+                               spin_unlock_irq(&zone->lru_lock);
+                               (*get_compound_page_dtor(page))(page);
+                               spin_lock_irq(&zone->lru_lock);
+                       } else
+                               list_add(&page->lru, &pages_to_free);
                }
        }
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
 
-       spin_unlock_irq(&zone->lru_lock);
-       pagevec_release(&pvec);
+       /*
+        * To save our caller's stack, now use input list for pages to free.
+        */
+       list_splice(&pages_to_free, page_list);
 }
 
-static noinline_for_stack void update_isolated_counts(struct zone *zone,
-                                       struct scan_control *sc,
-                                       unsigned long *nr_anon,
-                                       unsigned long *nr_file,
-                                       struct list_head *isolated_list)
+static noinline_for_stack void
+update_isolated_counts(struct mem_cgroup_zone *mz,
+                      struct list_head *page_list,
+                      unsigned long *nr_anon,
+                      unsigned long *nr_file)
 {
-       unsigned long nr_active;
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
+       struct zone *zone = mz->zone;
        unsigned int count[NR_LRU_LISTS] = { 0, };
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       unsigned long nr_active = 0;
+       struct page *page;
+       int lru;
+
+       /*
+        * Count pages and clear active flags
+        */
+       list_for_each_entry(page, page_list, lru) {
+               int numpages = hpage_nr_pages(page);
+               lru = page_lru_base_type(page);
+               if (PageActive(page)) {
+                       lru += LRU_ACTIVE;
+                       ClearPageActive(page);
+                       nr_active += numpages;
+               }
+               count[lru] += numpages;
+       }
 
-       nr_active = clear_active_flags(isolated_list, count);
        __count_vm_events(PGDEACTIVATE, nr_active);
 
        __mod_zone_page_state(zone, NR_ACTIVE_FILE,
@@ -1413,8 +1448,6 @@ static noinline_for_stack void update_isolated_counts(struct zone *zone,
 
        *nr_anon = count[LRU_ACTIVE_ANON] + count[LRU_INACTIVE_ANON];
        *nr_file = count[LRU_ACTIVE_FILE] + count[LRU_INACTIVE_FILE];
-       __mod_zone_page_state(zone, NR_ISOLATED_ANON, *nr_anon);
-       __mod_zone_page_state(zone, NR_ISOLATED_FILE, *nr_file);
 
        reclaim_stat->recent_scanned[0] += *nr_anon;
        reclaim_stat->recent_scanned[1] += *nr_file;
@@ -1466,8 +1499,8 @@ static inline bool should_reclaim_stall(unsigned long nr_taken,
  * of reclaimed pages
  */
 static noinline_for_stack unsigned long
-shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
-                       struct scan_control *sc, int priority, int file)
+shrink_inactive_list(unsigned long nr_to_scan, struct mem_cgroup_zone *mz,
+                    struct scan_control *sc, int priority, int file)
 {
        LIST_HEAD(page_list);
        unsigned long nr_scanned;
@@ -1478,6 +1511,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
        unsigned long nr_dirty = 0;
        unsigned long nr_writeback = 0;
        isolate_mode_t reclaim_mode = ISOLATE_INACTIVE;
+       struct zone *zone = mz->zone;
 
        while (unlikely(too_many_isolated(zone, file, sc))) {
                congestion_wait(BLK_RW_ASYNC, HZ/10);
@@ -1500,9 +1534,10 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
 
        spin_lock_irq(&zone->lru_lock);
 
-       if (scanning_global_lru(sc)) {
-               nr_taken = isolate_pages_global(nr_to_scan, &page_list,
-                       &nr_scanned, sc->order, reclaim_mode, zone, 0, file);
+       nr_taken = isolate_lru_pages(nr_to_scan, mz, &page_list,
+                                    &nr_scanned, sc->order,
+                                    reclaim_mode, 0, file);
+       if (global_reclaim(sc)) {
                zone->pages_scanned += nr_scanned;
                if (current_is_kswapd())
                        __count_zone_vm_events(PGSCAN_KSWAPD, zone,
@@ -1510,14 +1545,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                else
                        __count_zone_vm_events(PGSCAN_DIRECT, zone,
                                               nr_scanned);
-       } else {
-               nr_taken = mem_cgroup_isolate_pages(nr_to_scan, &page_list,
-                       &nr_scanned, sc->order, reclaim_mode, zone,
-                       sc->mem_cgroup, 0, file);
-               /*
-                * mem_cgroup_isolate_pages() keeps track of
-                * scanned pages on its own.
-                */
        }
 
        if (nr_taken == 0) {
@@ -1525,26 +1552,37 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
                return 0;
        }
 
-       update_isolated_counts(zone, sc, &nr_anon, &nr_file, &page_list);
+       update_isolated_counts(mz, &page_list, &nr_anon, &nr_file);
+
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, nr_anon);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, nr_file);
 
        spin_unlock_irq(&zone->lru_lock);
 
-       nr_reclaimed = shrink_page_list(&page_list, zone, sc, priority,
+       nr_reclaimed = shrink_page_list(&page_list, mz, sc, priority,
                                                &nr_dirty, &nr_writeback);
 
        /* Check if we should syncronously wait for writeback */
        if (should_reclaim_stall(nr_taken, nr_reclaimed, priority, sc)) {
                set_reclaim_mode(priority, sc, true);
-               nr_reclaimed += shrink_page_list(&page_list, zone, sc,
+               nr_reclaimed += shrink_page_list(&page_list, mz, sc,
                                        priority, &nr_dirty, &nr_writeback);
        }
 
-       local_irq_disable();
+       spin_lock_irq(&zone->lru_lock);
+
        if (current_is_kswapd())
                __count_vm_events(KSWAPD_STEAL, nr_reclaimed);
        __count_zone_vm_events(PGSTEAL, zone, nr_reclaimed);
 
-       putback_lru_pages(zone, sc, nr_anon, nr_file, &page_list);
+       putback_inactive_pages(mz, &page_list);
+
+       __mod_zone_page_state(zone, NR_ISOLATED_ANON, -nr_anon);
+       __mod_zone_page_state(zone, NR_ISOLATED_FILE, -nr_file);
+
+       spin_unlock_irq(&zone->lru_lock);
+
+       free_hot_cold_page_list(&page_list, 1);
 
        /*
         * If reclaim is isolating dirty pages under writeback, it implies
@@ -1600,30 +1638,47 @@ shrink_inactive_list(unsigned long nr_to_scan, struct zone *zone,
 
 static void move_active_pages_to_lru(struct zone *zone,
                                     struct list_head *list,
+                                    struct list_head *pages_to_free,
                                     enum lru_list lru)
 {
        unsigned long pgmoved = 0;
-       struct pagevec pvec;
        struct page *page;
 
-       pagevec_init(&pvec, 1);
+       if (buffer_heads_over_limit) {
+               spin_unlock_irq(&zone->lru_lock);
+               list_for_each_entry(page, list, lru) {
+                       if (page_has_private(page) && trylock_page(page)) {
+                               if (page_has_private(page))
+                                       try_to_release_page(page, 0);
+                               unlock_page(page);
+                       }
+               }
+               spin_lock_irq(&zone->lru_lock);
+       }
 
        while (!list_empty(list)) {
+               struct lruvec *lruvec;
+
                page = lru_to_page(list);
 
                VM_BUG_ON(PageLRU(page));
                SetPageLRU(page);
 
-               list_move(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_add_lru_list(page, lru);
+               lruvec = mem_cgroup_lru_add_list(zone, page, lru);
+               list_move(&page->lru, &lruvec->lists[lru]);
                pgmoved += hpage_nr_pages(page);
 
-               if (!pagevec_add(&pvec, page) || list_empty(list)) {
-                       spin_unlock_irq(&zone->lru_lock);
-                       if (buffer_heads_over_limit)
-                               pagevec_strip(&pvec);
-                       __pagevec_release(&pvec);
-                       spin_lock_irq(&zone->lru_lock);
+               if (put_page_testzero(page)) {
+                       __ClearPageLRU(page);
+                       __ClearPageActive(page);
+                       del_page_from_lru_list(zone, page, lru);
+
+                       if (unlikely(PageCompound(page))) {
+                               spin_unlock_irq(&zone->lru_lock);
+                               (*get_compound_page_dtor(page))(page);
+                               spin_lock_irq(&zone->lru_lock);
+                       } else
+                               list_add(&page->lru, pages_to_free);
                }
        }
        __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
@@ -1631,19 +1686,22 @@ static void move_active_pages_to_lru(struct zone *zone,
                __count_vm_events(PGDEACTIVATE, pgmoved);
 }
 
-static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
-                       struct scan_control *sc, int priority, int file)
+static void shrink_active_list(unsigned long nr_to_scan,
+                              struct mem_cgroup_zone *mz,
+                              struct scan_control *sc,
+                              int priority, int file)
 {
        unsigned long nr_taken;
-       unsigned long pgscanned;
+       unsigned long nr_scanned;
        unsigned long vm_flags;
        LIST_HEAD(l_hold);      /* The pages which were snipped off */
        LIST_HEAD(l_active);
        LIST_HEAD(l_inactive);
        struct page *page;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
        unsigned long nr_rotated = 0;
        isolate_mode_t reclaim_mode = ISOLATE_ACTIVE;
+       struct zone *zone = mz->zone;
 
        lru_add_drain();
 
@@ -1653,26 +1711,16 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                reclaim_mode |= ISOLATE_CLEAN;
 
        spin_lock_irq(&zone->lru_lock);
-       if (scanning_global_lru(sc)) {
-               nr_taken = isolate_pages_global(nr_pages, &l_hold,
-                                               &pgscanned, sc->order,
-                                               reclaim_mode, zone,
-                                               1, file);
-               zone->pages_scanned += pgscanned;
-       } else {
-               nr_taken = mem_cgroup_isolate_pages(nr_pages, &l_hold,
-                                               &pgscanned, sc->order,
-                                               reclaim_mode, zone,
-                                               sc->mem_cgroup, 1, file);
-               /*
-                * mem_cgroup_isolate_pages() keeps track of
-                * scanned pages on its own.
-                */
-       }
+
+       nr_taken = isolate_lru_pages(nr_to_scan, mz, &l_hold,
+                                    &nr_scanned, sc->order,
+                                    reclaim_mode, 1, file);
+       if (global_reclaim(sc))
+               zone->pages_scanned += nr_scanned;
 
        reclaim_stat->recent_scanned[file] += nr_taken;
 
-       __count_zone_vm_events(PGREFILL, zone, pgscanned);
+       __count_zone_vm_events(PGREFILL, zone, nr_scanned);
        if (file)
                __mod_zone_page_state(zone, NR_ACTIVE_FILE, -nr_taken);
        else
@@ -1690,7 +1738,7 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                        continue;
                }
 
-               if (page_referenced(page, 0, sc->mem_cgroup, &vm_flags)) {
+               if (page_referenced(page, 0, mz->mem_cgroup, &vm_flags)) {
                        nr_rotated += hpage_nr_pages(page);
                        /*
                         * Identify referenced, file-backed active pages and
@@ -1723,12 +1771,14 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
         */
        reclaim_stat->recent_rotated[file] += nr_rotated;
 
-       move_active_pages_to_lru(zone, &l_active,
+       move_active_pages_to_lru(zone, &l_active, &l_hold,
                                                LRU_ACTIVE + file * LRU_FILE);
-       move_active_pages_to_lru(zone, &l_inactive,
+       move_active_pages_to_lru(zone, &l_inactive, &l_hold,
                                                LRU_BASE   + file * LRU_FILE);
        __mod_zone_page_state(zone, NR_ISOLATED_ANON + file, -nr_taken);
        spin_unlock_irq(&zone->lru_lock);
+
+       free_hot_cold_page_list(&l_hold, 1);
 }
 
 #ifdef CONFIG_SWAP
@@ -1753,10 +1803,8 @@ static int inactive_anon_is_low_global(struct zone *zone)
  * Returns true if the zone does not have enough inactive anon pages,
  * meaning some active anon pages need to be deactivated.
  */
-static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
+static int inactive_anon_is_low(struct mem_cgroup_zone *mz)
 {
-       int low;
-
        /*
         * If we don't have swap space, anonymous page deactivation
         * is pointless.
@@ -1764,15 +1812,14 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
        if (!total_swap_pages)
                return 0;
 
-       if (scanning_global_lru(sc))
-               low = inactive_anon_is_low_global(zone);
-       else
-               low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup, zone);
-       return low;
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_inactive_anon_is_low(mz->mem_cgroup,
+                                                      mz->zone);
+
+       return inactive_anon_is_low_global(mz->zone);
 }
 #else
-static inline int inactive_anon_is_low(struct zone *zone,
-                                       struct scan_control *sc)
+static inline int inactive_anon_is_low(struct mem_cgroup_zone *mz)
 {
        return 0;
 }
@@ -1790,8 +1837,7 @@ static int inactive_file_is_low_global(struct zone *zone)
 
 /**
  * inactive_file_is_low - check if file pages need to be deactivated
- * @zone: zone to check
- * @sc:   scan control of this context
+ * @mz: memory cgroup and zone to check
  *
  * When the system is doing streaming IO, memory pressure here
  * ensures that active file pages get deactivated, until more
@@ -1803,45 +1849,44 @@ static int inactive_file_is_low_global(struct zone *zone)
  * This uses a different ratio than the anonymous pages, because
  * the page cache uses a use-once replacement algorithm.
  */
-static int inactive_file_is_low(struct zone *zone, struct scan_control *sc)
+static int inactive_file_is_low(struct mem_cgroup_zone *mz)
 {
-       int low;
+       if (!scanning_global_lru(mz))
+               return mem_cgroup_inactive_file_is_low(mz->mem_cgroup,
+                                                      mz->zone);
 
-       if (scanning_global_lru(sc))
-               low = inactive_file_is_low_global(zone);
-       else
-               low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup, zone);
-       return low;
+       return inactive_file_is_low_global(mz->zone);
 }
 
-static int inactive_list_is_low(struct zone *zone, struct scan_control *sc,
-                               int file)
+static int inactive_list_is_low(struct mem_cgroup_zone *mz, int file)
 {
        if (file)
-               return inactive_file_is_low(zone, sc);
+               return inactive_file_is_low(mz);
        else
-               return inactive_anon_is_low(zone, sc);
+               return inactive_anon_is_low(mz);
 }
 
 static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
-       struct zone *zone, struct scan_control *sc, int priority)
+                                struct mem_cgroup_zone *mz,
+                                struct scan_control *sc, int priority)
 {
        int file = is_file_lru(lru);
 
        if (is_active_lru(lru)) {
-               if (inactive_list_is_low(zone, sc, file))
-                   shrink_active_list(nr_to_scan, zone, sc, priority, file);
+               if (inactive_list_is_low(mz, file))
+                       shrink_active_list(nr_to_scan, mz, sc, priority, file);
                return 0;
        }
 
-       return shrink_inactive_list(nr_to_scan, zone, sc, priority, file);
+       return shrink_inactive_list(nr_to_scan, mz, sc, priority, file);
 }
 
-static int vmscan_swappiness(struct scan_control *sc)
+static int vmscan_swappiness(struct mem_cgroup_zone *mz,
+                            struct scan_control *sc)
 {
-       if (scanning_global_lru(sc))
+       if (global_reclaim(sc))
                return vm_swappiness;
-       return mem_cgroup_swappiness(sc->mem_cgroup);
+       return mem_cgroup_swappiness(mz->mem_cgroup);
 }
 
 /*
@@ -1852,15 +1897,15 @@ static int vmscan_swappiness(struct scan_control *sc)
  *
  * nr[0] = anon pages to scan; nr[1] = file pages to scan
  */
-static void get_scan_count(struct zone *zone, struct scan_control *sc,
-                                       unsigned long *nr, int priority)
+static void get_scan_count(struct mem_cgroup_zone *mz, struct scan_control *sc,
+                          unsigned long *nr, int priority)
 {
        unsigned long anon, file, free;
        unsigned long anon_prio, file_prio;
        unsigned long ap, fp;
-       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(mz);
        u64 fraction[2], denominator;
-       enum lru_list l;
+       enum lru_list lru;
        int noswap = 0;
        bool force_scan = false;
 
@@ -1874,9 +1919,9 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         * latencies, so it's better to scan a minimum amount there as
         * well.
         */
-       if (scanning_global_lru(sc) && current_is_kswapd())
+       if (current_is_kswapd() && mz->zone->all_unreclaimable)
                force_scan = true;
-       if (!scanning_global_lru(sc))
+       if (!global_reclaim(sc))
                force_scan = true;
 
        /* If we have no swap space, do not bother scanning anon pages. */
@@ -1888,16 +1933,16 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
                goto out;
        }
 
-       anon  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_ANON) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON);
-       file  = zone_nr_lru_pages(zone, sc, LRU_ACTIVE_FILE) +
-               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+       anon  = zone_nr_lru_pages(mz, LRU_ACTIVE_ANON) +
+               zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
+       file  = zone_nr_lru_pages(mz, LRU_ACTIVE_FILE) +
+               zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
 
-       if (scanning_global_lru(sc)) {
-               free  = zone_page_state(zone, NR_FREE_PAGES);
+       if (global_reclaim(sc)) {
+               free  = zone_page_state(mz->zone, NR_FREE_PAGES);
                /* If we have very few page cache pages,
                   force-scan anon pages. */
-               if (unlikely(file + free <= high_wmark_pages(zone))) {
+               if (unlikely(file + free <= high_wmark_pages(mz->zone))) {
                        fraction[0] = 1;
                        fraction[1] = 0;
                        denominator = 1;
@@ -1909,8 +1954,8 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         * With swappiness at 100, anonymous and file have the same priority.
         * This scanning priority is essentially the inverse of IO cost.
         */
-       anon_prio = vmscan_swappiness(sc);
-       file_prio = 200 - vmscan_swappiness(sc);
+       anon_prio = vmscan_swappiness(mz, sc);
+       file_prio = 200 - vmscan_swappiness(mz, sc);
 
        /*
         * OK, so we have swap space and a fair amount of page cache
@@ -1923,7 +1968,7 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
         *
         * anon in [0], file in [1]
         */
-       spin_lock_irq(&zone->lru_lock);
+       spin_lock_irq(&mz->zone->lru_lock);
        if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
                reclaim_stat->recent_scanned[0] /= 2;
                reclaim_stat->recent_rotated[0] /= 2;
@@ -1944,24 +1989,24 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc,
 
        fp = (file_prio + 1) * (reclaim_stat->recent_scanned[1] + 1);
        fp /= reclaim_stat->recent_rotated[1] + 1;
-       spin_unlock_irq(&zone->lru_lock);
+       spin_unlock_irq(&mz->zone->lru_lock);
 
        fraction[0] = ap;
        fraction[1] = fp;
        denominator = ap + fp + 1;
 out:
-       for_each_evictable_lru(l) {
-               int file = is_file_lru(l);
+       for_each_evictable_lru(lru) {
+               int file = is_file_lru(lru);
                unsigned long scan;
 
-               scan = zone_nr_lru_pages(zone, sc, l);
+               scan = zone_nr_lru_pages(mz, lru);
                if (priority || noswap) {
                        scan >>= priority;
                        if (!scan && force_scan)
                                scan = SWAP_CLUSTER_MAX;
                        scan = div64_u64(scan * fraction[file], denominator);
                }
-               nr[l] = scan;
+               nr[lru] = scan;
        }
 }
 
@@ -1972,7 +2017,7 @@ out:
  * back to the allocator and call try_to_compact_zone(), we ensure that
  * there are enough free pages for it to be likely successful
  */
-static inline bool should_continue_reclaim(struct zone *zone,
+static inline bool should_continue_reclaim(struct mem_cgroup_zone *mz,
                                        unsigned long nr_reclaimed,
                                        unsigned long nr_scanned,
                                        struct scan_control *sc)
@@ -2012,14 +2057,15 @@ static inline bool should_continue_reclaim(struct zone *zone,
         * inactive lists are large enough, continue reclaiming
         */
        pages_for_compaction = (2UL << sc->order);
-       inactive_lru_pages = zone_nr_lru_pages(zone, sc, LRU_INACTIVE_ANON) +
-                               zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE);
+       inactive_lru_pages = zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
+       if (nr_swap_pages > 0)
+               inactive_lru_pages += zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
        if (sc->nr_reclaimed < pages_for_compaction &&
                        inactive_lru_pages > pages_for_compaction)
                return true;
 
        /* If compaction would go ahead or the allocation would succeed, stop */
-       switch (compaction_suitable(zone, sc->order)) {
+       switch (compaction_suitable(mz->zone, sc->order)) {
        case COMPACT_PARTIAL:
        case COMPACT_CONTINUE:
                return false;
@@ -2031,12 +2077,12 @@ static inline bool should_continue_reclaim(struct zone *zone,
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
-static void shrink_zone(int priority, struct zone *zone,
-                               struct scan_control *sc)
+static void shrink_mem_cgroup_zone(int priority, struct mem_cgroup_zone *mz,
+                                  struct scan_control *sc)
 {
        unsigned long nr[NR_LRU_LISTS];
        unsigned long nr_to_scan;
-       enum lru_list l;
+       enum lru_list lru;
        unsigned long nr_reclaimed, nr_scanned;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
        struct blk_plug plug;
@@ -2044,19 +2090,19 @@ static void shrink_zone(int priority, struct zone *zone,
 restart:
        nr_reclaimed = 0;
        nr_scanned = sc->nr_scanned;
-       get_scan_count(zone, sc, nr, priority);
+       get_scan_count(mz, sc, nr, priority);
 
        blk_start_plug(&plug);
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
                                        nr[LRU_INACTIVE_FILE]) {
-               for_each_evictable_lru(l) {
-                       if (nr[l]) {
+               for_each_evictable_lru(lru) {
+                       if (nr[lru]) {
                                nr_to_scan = min_t(unsigned long,
-                                                  nr[l], SWAP_CLUSTER_MAX);
-                               nr[l] -= nr_to_scan;
+                                                  nr[lru], SWAP_CLUSTER_MAX);
+                               nr[lru] -= nr_to_scan;
 
-                               nr_reclaimed += shrink_list(l, nr_to_scan,
-                                                           zone, sc, priority);
+                               nr_reclaimed += shrink_list(lru, nr_to_scan,
+                                                           mz, sc, priority);
                        }
                }
                /*
@@ -2077,17 +2123,89 @@ restart:
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_anon_is_low(zone, sc))
-               shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0);
+       if (inactive_anon_is_low(mz))
+               shrink_active_list(SWAP_CLUSTER_MAX, mz, sc, priority, 0);
 
        /* reclaim/compaction might need reclaim to continue */
-       if (should_continue_reclaim(zone, nr_reclaimed,
+       if (should_continue_reclaim(mz, nr_reclaimed,
                                        sc->nr_scanned - nr_scanned, sc))
                goto restart;
 
        throttle_vm_writeout(sc->gfp_mask);
 }
 
+static void shrink_zone(int priority, struct zone *zone,
+                       struct scan_control *sc)
+{
+       struct mem_cgroup *root = sc->target_mem_cgroup;
+       struct mem_cgroup_reclaim_cookie reclaim = {
+               .zone = zone,
+               .priority = priority,
+       };
+       struct mem_cgroup *memcg;
+
+       memcg = mem_cgroup_iter(root, NULL, &reclaim);
+       do {
+               struct mem_cgroup_zone mz = {
+                       .mem_cgroup = memcg,
+                       .zone = zone,
+               };
+
+               shrink_mem_cgroup_zone(priority, &mz, sc);
+               /*
+                * Limit reclaim has historically picked one memcg and
+                * scanned it with decreasing priority levels until
+                * nr_to_reclaim had been reclaimed.  This priority
+                * cycle is thus over after a single memcg.
+                *
+                * Direct reclaim and kswapd, on the other hand, have
+                * to scan all memory cgroups to fulfill the overall
+                * scan target for the zone.
+                */
+               if (!global_reclaim(sc)) {
+                       mem_cgroup_iter_break(root, memcg);
+                       break;
+               }
+               memcg = mem_cgroup_iter(root, memcg, &reclaim);
+       } while (memcg);
+}
+
+/* Returns true if compaction should go ahead for a high-order request */
+static inline bool compaction_ready(struct zone *zone, struct scan_control *sc)
+{
+       unsigned long balance_gap, watermark;
+       bool watermark_ok;
+
+       /* Do not consider compaction for orders reclaim is meant to satisfy */
+       if (sc->order <= PAGE_ALLOC_COSTLY_ORDER)
+               return false;
+
+       /*
+        * Compaction takes time to run and there are potentially other
+        * callers using the pages just freed. Continue reclaiming until
+        * there is a buffer of free pages available to give compaction
+        * a reasonable chance of completing and allocating the page
+        */
+       balance_gap = min(low_wmark_pages(zone),
+               (zone->present_pages + KSWAPD_ZONE_BALANCE_GAP_RATIO-1) /
+                       KSWAPD_ZONE_BALANCE_GAP_RATIO);
+       watermark = high_wmark_pages(zone) + balance_gap + (2UL << sc->order);
+       watermark_ok = zone_watermark_ok_safe(zone, 0, watermark, 0, 0);
+
+       /*
+        * If compaction is deferred, reclaim up to a point where
+        * compaction will have a chance of success when re-enabled
+        */
+       if (compaction_deferred(zone))
+               return watermark_ok;
+
+       /* If compaction is not ready to start, keep reclaiming */
+       if (!compaction_suitable(zone, sc->order))
+               return false;
+
+       return watermark_ok;
+}
+
 /*
  * This is the direct reclaim path, for page-allocating processes.  We only
  * try to reclaim pages from zones which will satisfy the caller's allocation
@@ -2105,8 +2223,9 @@ restart:
  * scan then give up on it.
  *
  * This function returns true if a zone is being reclaimed for a costly
- * high-order allocation and compaction is either ready to begin or deferred.
- * This indicates to the caller that it should retry the allocation or fail.
+ * high-order allocation and compaction is ready to begin. This indicates to
+ * the caller that it should consider retrying the allocation instead of
+ * further reclaim.
  */
 static bool shrink_zones(int priority, struct zonelist *zonelist,
                                        struct scan_control *sc)
@@ -2115,7 +2234,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
        struct zone *zone;
        unsigned long nr_soft_reclaimed;
        unsigned long nr_soft_scanned;
-       bool should_abort_reclaim = false;
+       bool aborted_reclaim = false;
 
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask), sc->nodemask) {
@@ -2125,7 +2244,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                 * Take care memory controller reclaiming has small influence
                 * to global LRU.
                 */
-               if (scanning_global_lru(sc)) {
+               if (global_reclaim(sc)) {
                        if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                                continue;
                        if (zone->all_unreclaimable && priority != DEF_PRIORITY)
@@ -2140,10 +2259,8 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                                 * noticable problem, like transparent huge page
                                 * allocations.
                                 */
-                               if (sc->order > PAGE_ALLOC_COSTLY_ORDER &&
-                                       (compaction_suitable(zone, sc->order) ||
-                                        compaction_deferred(zone))) {
-                                       should_abort_reclaim = true;
+                               if (compaction_ready(zone, sc)) {
+                                       aborted_reclaim = true;
                                        continue;
                                }
                        }
@@ -2165,7 +2282,7 @@ static bool shrink_zones(int priority, struct zonelist *zonelist,
                shrink_zone(priority, zone, sc);
        }
 
-       return should_abort_reclaim;
+       return aborted_reclaim;
 }
 
 static bool zone_reclaimable(struct zone *zone)
@@ -2219,25 +2336,25 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
        struct zoneref *z;
        struct zone *zone;
        unsigned long writeback_threshold;
+       bool aborted_reclaim;
 
        get_mems_allowed();
        delayacct_freepages_start();
 
-       if (scanning_global_lru(sc))
+       if (global_reclaim(sc))
                count_vm_event(ALLOCSTALL);
 
        for (priority = DEF_PRIORITY; priority >= 0; priority--) {
                sc->nr_scanned = 0;
                if (!priority)
-                       disable_swap_token(sc->mem_cgroup);
-               if (shrink_zones(priority, zonelist, sc))
-                       break;
+                       disable_swap_token(sc->target_mem_cgroup);
+               aborted_reclaim = shrink_zones(priority, zonelist, sc);
 
                /*
                 * Don't shrink slabs when reclaiming memory from
                 * over limit cgroups
                 */
-               if (scanning_global_lru(sc)) {
+               if (global_reclaim(sc)) {
                        unsigned long lru_pages = 0;
                        for_each_zone_zonelist(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask)) {
@@ -2298,8 +2415,12 @@ out:
        if (oom_killer_disabled)
                return 0;
 
+       /* Aborted reclaim to try compaction? don't OOM, then */
+       if (aborted_reclaim)
+               return 1;
+
        /* top priority shrink_zones still had more to do? don't OOM, then */
-       if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc))
+       if (global_reclaim(sc) && !all_unreclaimable(zonelist, sc))
                return 1;
 
        return 0;
@@ -2316,7 +2437,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .may_unmap = 1,
                .may_swap = 1,
                .order = order,
-               .mem_cgroup = NULL,
+               .target_mem_cgroup = NULL,
                .nodemask = nodemask,
        };
        struct shrink_control shrink = {
@@ -2336,7 +2457,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR
 
-unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
+unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *memcg,
                                                gfp_t gfp_mask, bool noswap,
                                                struct zone *zone,
                                                unsigned long *nr_scanned)
@@ -2348,7 +2469,11 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
                .may_unmap = 1,
                .may_swap = !noswap,
                .order = 0,
-               .mem_cgroup = mem,
+               .target_mem_cgroup = memcg,
+       };
+       struct mem_cgroup_zone mz = {
+               .mem_cgroup = memcg,
+               .zone = zone,
        };
 
        sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
@@ -2365,7 +2490,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
         * will pick up pages from other mem cgroup's as well. We hack
         * the priority and make it zero.
         */
-       shrink_zone(0, zone, &sc);
+       shrink_mem_cgroup_zone(0, &mz, &sc);
 
        trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
 
@@ -2373,7 +2498,7 @@ unsigned long mem_cgroup_shrink_node_zone(struct mem_cgroup *mem,
        return sc.nr_reclaimed;
 }
 
-unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
+unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                           gfp_t gfp_mask,
                                           bool noswap)
 {
@@ -2386,7 +2511,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
                .may_swap = !noswap,
                .nr_to_reclaim = SWAP_CLUSTER_MAX,
                .order = 0,
-               .mem_cgroup = mem_cont,
+               .target_mem_cgroup = memcg,
                .nodemask = NULL, /* we don't care the placement */
                .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
                                (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
@@ -2400,7 +2525,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
         * take care of from where we get pages. So the node where we start the
         * scan does not need to be the current node.
         */
-       nid = mem_cgroup_select_victim_node(mem_cont);
+       nid = mem_cgroup_select_victim_node(memcg);
 
        zonelist = NODE_DATA(nid)->node_zonelists;
 
@@ -2416,6 +2541,29 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 }
 #endif
 
+static void age_active_anon(struct zone *zone, struct scan_control *sc,
+                           int priority)
+{
+       struct mem_cgroup *memcg;
+
+       if (!total_swap_pages)
+               return;
+
+       memcg = mem_cgroup_iter(NULL, NULL, NULL);
+       do {
+               struct mem_cgroup_zone mz = {
+                       .mem_cgroup = memcg,
+                       .zone = zone,
+               };
+
+               if (inactive_anon_is_low(&mz))
+                       shrink_active_list(SWAP_CLUSTER_MAX, &mz,
+                                          sc, priority, 0);
+
+               memcg = mem_cgroup_iter(NULL, memcg, NULL);
+       } while (memcg);
+}
+
 /*
  * pgdat_balanced is used when checking if a node is balanced for high-order
  * allocations. Only zones that meet watermarks and are in a zone allowed
@@ -2536,7 +2684,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                 */
                .nr_to_reclaim = ULONG_MAX,
                .order = order,
-               .mem_cgroup = NULL,
+               .target_mem_cgroup = NULL,
        };
        struct shrink_control shrink = {
                .gfp_mask = sc.gfp_mask,
@@ -2575,9 +2723,7 @@ loop_again:
                         * Do some background aging of the anon list, to give
                         * pages a chance to be referenced before reclaiming.
                         */
-                       if (inactive_anon_is_low(zone, &sc))
-                               shrink_active_list(SWAP_CLUSTER_MAX, zone,
-                                                       &sc, priority, 0);
+                       age_active_anon(zone, &sc, priority);
 
                        if (!zone_watermark_ok_safe(zone, order,
                                        high_wmark_pages(zone), 0, 0)) {
@@ -3366,16 +3512,18 @@ int page_evictable(struct page *page, struct vm_area_struct *vma)
  */
 static void check_move_unevictable_page(struct page *page, struct zone *zone)
 {
-       VM_BUG_ON(PageActive(page));
+       struct lruvec *lruvec;
 
+       VM_BUG_ON(PageActive(page));
 retry:
        ClearPageUnevictable(page);
        if (page_evictable(page, NULL)) {
                enum lru_list l = page_lru_base_type(page);
 
                __dec_zone_state(zone, NR_UNEVICTABLE);
-               list_move(&page->lru, &zone->lru[l].list);
-               mem_cgroup_move_lists(page, LRU_UNEVICTABLE, l);
+               lruvec = mem_cgroup_lru_move_lists(zone, page,
+                                                  LRU_UNEVICTABLE, l);
+               list_move(&page->lru, &lruvec->lists[l]);
                __inc_zone_state(zone, NR_INACTIVE_ANON + l);
                __count_vm_event(UNEVICTABLE_PGRESCUED);
        } else {
@@ -3383,8 +3531,9 @@ retry:
                 * rotate unevictable list
                 */
                SetPageUnevictable(page);
-               list_move(&page->lru, &zone->lru[LRU_UNEVICTABLE].list);
-               mem_cgroup_rotate_lru_list(page, LRU_UNEVICTABLE);
+               lruvec = mem_cgroup_lru_move_lists(zone, page, LRU_UNEVICTABLE,
+                                                  LRU_UNEVICTABLE);
+               list_move(&page->lru, &lruvec->lists[LRU_UNEVICTABLE]);
                if (page_evictable(page, NULL))
                        goto retry;
        }
@@ -3448,9 +3597,10 @@ void scan_mapping_unevictable_pages(struct address_space *mapping)
 static void warn_scan_unevictable_pages(void)
 {
        printk_once(KERN_WARNING
-                   "The scan_unevictable_pages sysctl/node-interface has been "
+                   "%s: The scan_unevictable_pages sysctl/node-interface has been "
                    "disabled for lack of a legitimate use case.  If you have "
-                   "one, please send an email to linux-mm@kvack.org.\n");
+                   "one, please send an email to linux-mm@kvack.org.\n",
+                   current->comm);
 }
 
 /*
index 8fd603b1665e5be65bc10c93f146b860f706925d..f600557a76596231ef659fdff0c9f2ea8aed71ae 100644 (file)
@@ -295,7 +295,7 @@ void __dec_zone_page_state(struct page *page, enum zone_stat_item item)
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
-#ifdef CONFIG_CMPXCHG_LOCAL
+#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
 /*
  * If we have cmpxchg_local support then we do not need to incur the overhead
  * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
index 854ca7a911c427f753ebe2b5d93a71a1c10df041..776618cd2be5c122fecaf31934f06d74fff2b450 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -81,15 +83,15 @@ static int get_protocol_version(char *s)
 
        if (!strcmp(s, "9p2000")) {
                version = p9_proto_legacy;
-               P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
+               p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n");
        } else if (!strcmp(s, "9p2000.u")) {
                version = p9_proto_2000u;
-               P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
+               p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
        } else if (!strcmp(s, "9p2000.L")) {
                version = p9_proto_2000L;
-               P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
+               p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
        } else
-               printk(KERN_INFO "9p: Unknown protocol version %s.\n", s);
+               pr_info("Unknown protocol version %s\n", s);
 
        return version;
 }
@@ -119,8 +121,8 @@ static int parse_opts(char *opts, struct p9_client *clnt)
 
        tmp_options = kstrdup(opts, GFP_KERNEL);
        if (!tmp_options) {
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "failed to allocate copy of option string\n");
+               p9_debug(P9_DEBUG_ERROR,
+                        "failed to allocate copy of option string\n");
                return -ENOMEM;
        }
        options = tmp_options;
@@ -134,8 +136,8 @@ static int parse_opts(char *opts, struct p9_client *clnt)
                case Opt_msize:
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                          "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                ret = r;
                                continue;
                        }
@@ -145,15 +147,14 @@ static int parse_opts(char *opts, struct p9_client *clnt)
                        s = match_strdup(&args[0]);
                        if (!s) {
                                ret = -ENOMEM;
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                       "problem allocating copy of trans arg\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "problem allocating copy of trans arg\n");
                                goto free_and_return;
                         }
                        clnt->trans_mod = v9fs_get_trans_by_name(s);
                        if (clnt->trans_mod == NULL) {
-                               printk(KERN_INFO
-                                       "9p: Could not find "
-                                       "request transport: %s\n", s);
+                               pr_info("Could not find request transport: %s\n",
+                                       s);
                                ret = -EINVAL;
                                kfree(s);
                                goto free_and_return;
@@ -167,8 +168,8 @@ static int parse_opts(char *opts, struct p9_client *clnt)
                        s = match_strdup(&args[0]);
                        if (!s) {
                                ret = -ENOMEM;
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                                       "problem allocating copy of version arg\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "problem allocating copy of version arg\n");
                                goto free_and_return;
                        }
                        ret = get_protocol_version(s);
@@ -225,7 +226,7 @@ p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
                                        sizeof(struct p9_req_t), GFP_ATOMIC);
 
                        if (!c->reqs[row]) {
-                               printk(KERN_ERR "Couldn't grow tag array\n");
+                               pr_err("Couldn't grow tag array\n");
                                spin_unlock_irqrestore(&c->lock, flags);
                                return ERR_PTR(-ENOMEM);
                        }
@@ -244,7 +245,7 @@ p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
        if (!req->tc) {
                req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS);
                if (!req->wq) {
-                       printk(KERN_ERR "Couldn't grow tag array\n");
+                       pr_err("Couldn't grow tag array\n");
                        return ERR_PTR(-ENOMEM);
                }
                init_waitqueue_head(req->wq);
@@ -253,7 +254,7 @@ p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
                req->rc = kmalloc(sizeof(struct p9_fcall) + alloc_msize,
                                  GFP_NOFS);
                if ((!req->tc) || (!req->rc)) {
-                       printk(KERN_ERR "Couldn't grow tag array\n");
+                       pr_err("Couldn't grow tag array\n");
                        kfree(req->tc);
                        kfree(req->rc);
                        kfree(req->wq);
@@ -343,9 +344,9 @@ static void p9_tag_cleanup(struct p9_client *c)
        for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
                for (col = 0; col < P9_ROW_MAXTAG; col++) {
                        if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
-                               P9_DPRINTK(P9_DEBUG_MUX,
-                                 "Attempting to cleanup non-free tag %d,%d\n",
-                                 row, col);
+                               p9_debug(P9_DEBUG_MUX,
+                                        "Attempting to cleanup non-free tag %d,%d\n",
+                                        row, col);
                                /* TODO: delay execution of cleanup */
                                return;
                        }
@@ -379,7 +380,7 @@ static void p9_tag_cleanup(struct p9_client *c)
 static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
 {
        int tag = r->tc->tag;
-       P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
+       p9_debug(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
 
        r->status = REQ_STATUS_IDLE;
        if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
@@ -394,9 +395,9 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
  */
 void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
 {
-       P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
+       p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
        wake_up(req->wq);
-       P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
+       p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
 }
 EXPORT_SYMBOL(p9_client_cb);
 
@@ -431,8 +432,8 @@ p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag,
        pdu->id = r_type;
        pdu->tag = r_tag;
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", pdu->size,
-                                                       pdu->id, pdu->tag);
+       p9_debug(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n",
+                pdu->size, pdu->id, pdu->tag);
 
        if (type)
                *type = r_type;
@@ -473,7 +474,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
         */
        trace_9p_protocol_dump(c, req->rc);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
+               p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
                return err;
        }
        if (type != P9_RERROR && type != P9_RLERROR)
@@ -492,21 +493,21 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
                if (!err || !IS_ERR_VALUE(err)) {
                        err = p9_errstr2errno(ename, strlen(ename));
 
-                       P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
-                                  -ecode, ename);
+                       p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
+                                -ecode, ename);
                }
                kfree(ename);
        } else {
                err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
                err = -ecode;
 
-               P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+               p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
        }
 
        return err;
 
 out_err:
-       P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
+       p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
 
        return err;
 }
@@ -538,7 +539,7 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
         */
        trace_9p_protocol_dump(c, req->rc);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
+               p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
                return err;
        }
 
@@ -601,22 +602,22 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
                if (!err || !IS_ERR_VALUE(err)) {
                        err = p9_errstr2errno(ename, strlen(ename));
 
-                       P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
-                                  -ecode, ename);
+                       p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
+                                -ecode, ename);
                }
                kfree(ename);
        } else {
                err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
                err = -ecode;
 
-               P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
+               p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
        }
        return err;
 
 out_free:
        kfree(ename);
 out_err:
-       P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
+       p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
        return err;
 }
 
@@ -645,7 +646,7 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
        if (err)
                return err;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
+       p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
 
        req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
        if (IS_ERR(req))
@@ -670,7 +671,7 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
        int tag, err;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
+       p9_debug(P9_DEBUG_MUX, "client %p op %d\n", c, type);
 
        /* we allow for any status other than disconnected */
        if (c->status == Disconnected)
@@ -744,11 +745,11 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
                                       req->status >= REQ_STATUS_RCVD);
 
        if (req->status == REQ_STATUS_ERROR) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
+               p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
                err = req->t_err;
        }
        if ((err == -ERESTARTSYS) && (c->status == Connected)) {
-               P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
+               p9_debug(P9_DEBUG_MUX, "flushing\n");
                sigpending = 1;
                clear_thread_flag(TIF_SIGPENDING);
 
@@ -827,11 +828,11 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
                goto reterr;
        }
        if (req->status == REQ_STATUS_ERROR) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
+               p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
                err = req->t_err;
        }
        if ((err == -ERESTARTSYS) && (c->status == Connected)) {
-               P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
+               p9_debug(P9_DEBUG_MUX, "flushing\n");
                sigpending = 1;
                clear_thread_flag(TIF_SIGPENDING);
 
@@ -865,7 +866,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
        struct p9_fid *fid;
        unsigned long flags;
 
-       P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt);
+       p9_debug(P9_DEBUG_FID, "clnt %p\n", clnt);
        fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
        if (!fid)
                return ERR_PTR(-ENOMEM);
@@ -898,7 +899,7 @@ static void p9_fid_destroy(struct p9_fid *fid)
        struct p9_client *clnt;
        unsigned long flags;
 
-       P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
        clnt = fid->clnt;
        p9_idpool_put(fid->fid, clnt->fidpool);
        spin_lock_irqsave(&clnt->lock, flags);
@@ -915,8 +916,8 @@ static int p9_client_version(struct p9_client *c)
        char *version;
        int msize;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
-                                               c->msize, c->proto_version);
+       p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
+                c->msize, c->proto_version);
 
        switch (c->proto_version) {
        case p9_proto_2000L:
@@ -941,12 +942,12 @@ static int p9_client_version(struct p9_client *c)
 
        err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
        if (err) {
-               P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
+               p9_debug(P9_DEBUG_9P, "version error %d\n", err);
                trace_9p_protocol_dump(c, req->rc);
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
+       p9_debug(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
        if (!strncmp(version, "9P2000.L", 8))
                c->proto_version = p9_proto_2000L;
        else if (!strncmp(version, "9P2000.u", 8))
@@ -996,8 +997,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 
        if (clnt->trans_mod == NULL) {
                err = -EPROTONOSUPPORT;
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "No transport defined or default transport\n");
+               p9_debug(P9_DEBUG_ERROR,
+                        "No transport defined or default transport\n");
                goto destroy_tagpool;
        }
 
@@ -1007,8 +1008,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
                goto put_trans;
        }
 
-       P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
-               clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
+       p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
+                clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
 
        err = clnt->trans_mod->create(clnt, dev_name, options);
        if (err)
@@ -1041,7 +1042,7 @@ void p9_client_destroy(struct p9_client *clnt)
 {
        struct p9_fid *fid, *fidptr;
 
-       P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt);
+       p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
 
        if (clnt->trans_mod)
                clnt->trans_mod->close(clnt);
@@ -1049,7 +1050,7 @@ void p9_client_destroy(struct p9_client *clnt)
        v9fs_put_trans(clnt->trans_mod);
 
        list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) {
-               printk(KERN_INFO "Found fid %d not clunked\n", fid->fid);
+               pr_info("Found fid %d not clunked\n", fid->fid);
                p9_fid_destroy(fid);
        }
 
@@ -1064,14 +1065,14 @@ EXPORT_SYMBOL(p9_client_destroy);
 
 void p9_client_disconnect(struct p9_client *clnt)
 {
-       P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+       p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
        clnt->status = Disconnected;
 }
 EXPORT_SYMBOL(p9_client_disconnect);
 
 void p9_client_begin_disconnect(struct p9_client *clnt)
 {
-       P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+       p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
        clnt->status = BeginDisconnect;
 }
 EXPORT_SYMBOL(p9_client_begin_disconnect);
@@ -1085,8 +1086,8 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
        struct p9_qid qid;
 
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
-                  afid ? afid->fid : -1, uname, aname);
+       p9_debug(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
+                afid ? afid->fid : -1, uname, aname);
        fid = p9_fid_create(clnt);
        if (IS_ERR(fid)) {
                err = PTR_ERR(fid);
@@ -1108,10 +1109,8 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
-                                       qid.type,
-                                       (unsigned long long)qid.path,
-                                       qid.version);
+       p9_debug(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
+                qid.type, (unsigned long long)qid.path, qid.version);
 
        memmove(&fid->qid, &qid, sizeof(struct p9_qid));
 
@@ -1151,8 +1150,8 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
                fid = oldfid;
 
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
-               oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
+       p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
+                oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
 
        req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
                                                                nwname, wnames);
@@ -1169,7 +1168,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
        }
        p9_free_req(clnt, req);
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
+       p9_debug(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
 
        if (nwqids != nwname) {
                err = -ENOENT;
@@ -1177,7 +1176,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
        }
 
        for (count = 0; count < nwqids; count++)
-               P9_DPRINTK(P9_DEBUG_9P, "<<<     [%d] %x.%llx.%x\n",
+               p9_debug(P9_DEBUG_9P, "<<<     [%d] %x.%llx.%x\n",
                        count, wqids[count].type,
                        (unsigned long long)wqids[count].path,
                        wqids[count].version);
@@ -1212,7 +1211,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
        int iounit;
 
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
                p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
        err = 0;
 
@@ -1234,7 +1233,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
+       p9_debug(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
                p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN",  qid.type,
                (unsigned long long)qid.path, qid.version, iounit);
 
@@ -1256,7 +1255,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
        struct p9_req_t *req;
        int iounit;
 
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P,
                        ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
                        ofid->fid, name, flags, mode, gid);
        clnt = ofid->clnt;
@@ -1277,7 +1276,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
+       p9_debug(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
                        qid->type,
                        (unsigned long long)qid->path,
                        qid->version, iounit);
@@ -1301,7 +1300,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
        struct p9_qid qid;
        int iounit;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
                                                fid->fid, name, perm, mode);
        err = 0;
        clnt = fid->clnt;
@@ -1322,7 +1321,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
+       p9_debug(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
                                qid.type,
                                (unsigned long long)qid.path,
                                qid.version, iounit);
@@ -1344,7 +1343,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
        struct p9_client *clnt;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s  symtgt %s\n",
+       p9_debug(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s  symtgt %s\n",
                        dfid->fid, name, symtgt);
        clnt = dfid->clnt;
 
@@ -1361,7 +1360,7 @@ int p9_client_symlink(struct p9_fid *dfid, char *name, char *symtgt, gid_t gid,
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
+       p9_debug(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
                        qid->type, (unsigned long long)qid->path, qid->version);
 
 free_and_error:
@@ -1376,7 +1375,7 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
        struct p9_client *clnt;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
+       p9_debug(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
                        dfid->fid, oldfid->fid, newname);
        clnt = dfid->clnt;
        req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
@@ -1384,7 +1383,7 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
+       p9_debug(P9_DEBUG_9P, "<<< RLINK\n");
        p9_free_req(clnt, req);
        return 0;
 }
@@ -1396,7 +1395,7 @@ int p9_client_fsync(struct p9_fid *fid, int datasync)
        struct p9_client *clnt;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
                        fid->fid, datasync);
        err = 0;
        clnt = fid->clnt;
@@ -1407,7 +1406,7 @@ int p9_client_fsync(struct p9_fid *fid, int datasync)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
 
@@ -1423,12 +1422,13 @@ int p9_client_clunk(struct p9_fid *fid)
        struct p9_req_t *req;
 
        if (!fid) {
-               P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n");
+               pr_warn("%s (%d): Trying to clunk with NULL fid\n",
+                       __func__, task_pid_nr(current));
                dump_stack();
                return 0;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
        err = 0;
        clnt = fid->clnt;
 
@@ -1438,7 +1438,7 @@ int p9_client_clunk(struct p9_fid *fid)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
 error:
@@ -1456,7 +1456,7 @@ int p9_client_remove(struct p9_fid *fid)
        struct p9_client *clnt;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
        err = 0;
        clnt = fid->clnt;
 
@@ -1466,7 +1466,7 @@ int p9_client_remove(struct p9_fid *fid)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
 error:
@@ -1481,7 +1481,7 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
        struct p9_req_t *req;
        struct p9_client *clnt;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n",
                   dfid->fid, name, flags);
 
        clnt = dfid->clnt;
@@ -1490,7 +1490,7 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
                err = PTR_ERR(req);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
+       p9_debug(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
 
        p9_free_req(clnt, req);
 error:
@@ -1509,7 +1509,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
        int err, rsize, non_zc = 0;
 
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n",
                   fid->fid, (long long unsigned) offset, count);
        err = 0;
        clnt = fid->clnt;
@@ -1552,7 +1552,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
+       p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
 
        if (non_zc) {
                if (data) {
@@ -1584,7 +1584,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
        struct p9_client *clnt;
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n",
                                fid->fid, (long long unsigned) offset, count);
        err = 0;
        clnt = fid->clnt;
@@ -1626,7 +1626,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
+       p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
 
        p9_free_req(clnt, req);
        return count;
@@ -1646,7 +1646,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
        struct p9_req_t *req;
        u16 ignored;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
 
        if (!ret)
                return ERR_PTR(-ENOMEM);
@@ -1667,7 +1667,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P,
                "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
                "<<<    mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
                "<<<    name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
@@ -1696,7 +1696,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
                                                                GFP_KERNEL);
        struct p9_req_t *req;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
+       p9_debug(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
                                                        fid->fid, request_mask);
 
        if (!ret)
@@ -1718,7 +1718,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P,
                "<<< RGETATTR st_result_mask=%lld\n"
                "<<< qid=%x.%llx.%x\n"
                "<<< st_mode=%8.8x st_nlink=%llu\n"
@@ -1784,8 +1784,8 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
        err = 0;
        clnt = fid->clnt;
        wst->size = p9_client_statsize(wst, clnt->proto_version);
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P,
                "     sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
                "     mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
                "     name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
@@ -1802,7 +1802,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
 error:
@@ -1818,8 +1818,8 @@ int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P,
                "    valid=%x mode=%x uid=%d gid=%d size=%lld\n"
                "    atime_sec=%lld atime_nsec=%lld\n"
                "    mtime_sec=%lld mtime_nsec=%lld\n",
@@ -1833,7 +1833,7 @@ int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
                err = PTR_ERR(req);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
        p9_free_req(clnt, req);
 error:
        return err;
@@ -1849,7 +1849,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
        err = 0;
        clnt = fid->clnt;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
 
        req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
        if (IS_ERR(req)) {
@@ -1866,7 +1866,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
+       p9_debug(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld "
                "blocks %llu bfree %llu bavail %llu files %llu ffree %llu "
                "fsid %llu namelen %ld\n",
                fid->fid, (long unsigned int)sb->type, (long int)sb->bsize,
@@ -1889,7 +1889,7 @@ int p9_client_rename(struct p9_fid *fid,
        err = 0;
        clnt = fid->clnt;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
+       p9_debug(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
                        fid->fid, newdirfid->fid, name);
 
        req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
@@ -1899,7 +1899,7 @@ int p9_client_rename(struct p9_fid *fid,
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
 
        p9_free_req(clnt, req);
 error:
@@ -1917,7 +1917,7 @@ int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
        err = 0;
        clnt = olddirfid->clnt;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s"
+       p9_debug(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s"
                   " newdirfid %d new name %s\n", olddirfid->fid, old_name,
                   newdirfid->fid, new_name);
 
@@ -1928,7 +1928,7 @@ int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
                goto error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
+       p9_debug(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
                   newdirfid->fid, new_name);
 
        p9_free_req(clnt, req);
@@ -1956,7 +1956,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
                attr_fid = NULL;
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P,
                ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
                file_fid->fid, attr_fid->fid, attr_name);
 
@@ -1973,7 +1973,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
                goto clunk_fid;
        }
        p9_free_req(clnt, req);
-       P9_DPRINTK(P9_DEBUG_9P, "<<<  RXATTRWALK fid %d size %llu\n",
+       p9_debug(P9_DEBUG_9P, "<<<  RXATTRWALK fid %d size %llu\n",
                attr_fid->fid, *attr_size);
        return attr_fid;
 clunk_fid:
@@ -1994,7 +1994,7 @@ int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
        struct p9_req_t *req;
        struct p9_client *clnt;
 
-       P9_DPRINTK(P9_DEBUG_9P,
+       p9_debug(P9_DEBUG_9P,
                ">>> TXATTRCREATE fid %d name  %s size %lld flag %d\n",
                fid->fid, name, (long long)attr_size, flags);
        err = 0;
@@ -2005,7 +2005,7 @@ int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
                err = PTR_ERR(req);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
        p9_free_req(clnt, req);
 error:
        return err;
@@ -2019,7 +2019,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
        struct p9_req_t *req;
        char *dataptr;
 
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
                                fid->fid, (long long unsigned) offset, count);
 
        err = 0;
@@ -2056,7 +2056,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
                goto free_and_error;
        }
 
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
+       p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
 
        if (non_zc)
                memmove(data, dataptr, count);
@@ -2080,7 +2080,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
+       p9_debug(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d "
                "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
        req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddd", fid->fid, name, mode,
                MAJOR(rdev), MINOR(rdev), gid);
@@ -2092,7 +2092,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, char *name, int mode,
                trace_9p_protocol_dump(clnt, req->rc);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
+       p9_debug(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
                                (unsigned long long)qid->path, qid->version);
 
 error:
@@ -2111,7 +2111,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
+       p9_debug(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
                 fid->fid, name, mode, gid);
        req = p9_client_rpc(clnt, P9_TMKDIR, "dsdd", fid->fid, name, mode,
                gid);
@@ -2123,7 +2123,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
                trace_9p_protocol_dump(clnt, req->rc);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
+       p9_debug(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
                                (unsigned long long)qid->path, qid->version);
 
 error:
@@ -2141,7 +2141,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
+       p9_debug(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
                        "start %lld length %lld proc_id %d client_id %s\n",
                        fid->fid, flock->type, flock->flags, flock->start,
                        flock->length, flock->proc_id, flock->client_id);
@@ -2158,7 +2158,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
                trace_9p_protocol_dump(clnt, req->rc);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
+       p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
 error:
        p9_free_req(clnt, req);
        return err;
@@ -2174,7 +2174,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
+       p9_debug(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
                "length %lld proc_id %d client_id %s\n", fid->fid, glock->type,
                glock->start, glock->length, glock->proc_id, glock->client_id);
 
@@ -2191,7 +2191,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
                trace_9p_protocol_dump(clnt, req->rc);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
+       p9_debug(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
                "proc_id %d client_id %s\n", glock->type, glock->start,
                glock->length, glock->proc_id, glock->client_id);
 error:
@@ -2208,7 +2208,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
 
        err = 0;
        clnt = fid->clnt;
-       P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
+       p9_debug(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
 
        req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
        if (IS_ERR(req))
@@ -2219,7 +2219,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
                trace_9p_protocol_dump(clnt, req->rc);
                goto error;
        }
-       P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
+       p9_debug(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
 error:
        p9_free_req(clnt, req);
        return err;
index 52518512a93e86eb261b34af3dddf6778a9ea50f..2ab2de76010f0d47f67ee4a79aaf567f97026ed9 100644 (file)
@@ -27,6 +27,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/jhash.h>
@@ -237,8 +239,8 @@ int p9_errstr2errno(char *errstr, int len)
        if (errno == 0) {
                /* TODO: if error isn't found, add it dynamically */
                errstr[len] = 0;
-               printk(KERN_ERR "%s: server reported unknown error %s\n",
-                       __func__, errstr);
+               pr_err("%s: server reported unknown error %s\n",
+                      __func__, errstr);
                errno = ESERVERFAULT;
        }
 
index 2664d1292291344e6a43964334df681d4e49e372..6ab36aea77275ef342b88f8e66e0e5c294086fd0 100644 (file)
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/moduleparam.h>
 #include <net/9p/9p.h>
 #include <linux/fs.h>
@@ -39,6 +43,29 @@ unsigned int p9_debug_level = 0;     /* feature-rific global debug level  */
 EXPORT_SYMBOL(p9_debug_level);
 module_param_named(debug, p9_debug_level, uint, 0);
 MODULE_PARM_DESC(debug, "9P debugging level");
+
+void _p9_debug(enum p9_debug_flags level, const char *func,
+               const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       if ((p9_debug_level & level) != level)
+               return;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       if (level == P9_DEBUG_9P)
+               pr_notice("(%8.8d) %pV", task_pid_nr(current), &vaf);
+       else
+               pr_notice("-- %s (%d): %pV", func, task_pid_nr(current), &vaf);
+
+       va_end(args);
+}
+EXPORT_SYMBOL(_p9_debug);
 #endif
 
 /*
@@ -147,7 +174,7 @@ static int __init init_p9(void)
        int ret = 0;
 
        p9_error_init();
-       printk(KERN_INFO "Installing 9P2000 support\n");
+       pr_info("Installing 9P2000 support\n");
        p9_trans_fd_init();
 
        return ret;
@@ -160,7 +187,7 @@ static int __init init_p9(void)
 
 static void __exit exit_p9(void)
 {
-       printk(KERN_INFO "Unloading 9P2000 support\n");
+       pr_info("Unloading 9P2000 support\n");
 
        p9_trans_fd_exit();
 }
index 55e10a96c9025e135c869fafbc328bfc6123c521..9ee48cb3017998f47928a3d8413c5df44ec4ac73 100644 (file)
@@ -534,7 +534,7 @@ int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
 
        ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
        if (ret) {
-               P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
+               p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
                trace_9p_protocol_dump(clnt, &fake_pdu);
        }
 
@@ -558,8 +558,8 @@ int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
        pdu->size = size;
 
        trace_9p_protocol_dump(clnt, pdu);
-       P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
-                                                       pdu->id, pdu->tag);
+       p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
+                pdu->size, pdu->id, pdu->tag);
 
        return err;
 }
@@ -585,7 +585,7 @@ int p9dirent_read(struct p9_client *clnt, char *buf, int len,
        ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
                          &dirent->d_off, &dirent->d_type, &nameptr);
        if (ret) {
-               P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
+               p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
                trace_9p_protocol_dump(clnt, &fake_pdu);
                goto out;
        }
index fdfdb5747f63b6492fc23eafa000dcd7d93c9c5b..fccae26fa67441bbdb5b239eda94fb09417d87a7 100644 (file)
@@ -25,6 +25,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/net.h>
@@ -191,7 +193,7 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
        unsigned long flags;
        LIST_HEAD(cancel_list);
 
-       P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
+       p9_debug(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
 
        spin_lock_irqsave(&m->client->lock, flags);
 
@@ -217,7 +219,7 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
        spin_unlock_irqrestore(&m->client->lock, flags);
 
        list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "call back req %p\n", req);
+               p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req);
                list_del(&req->req_list);
                p9_client_cb(m->client, req);
        }
@@ -275,7 +277,7 @@ static int p9_fd_read(struct p9_client *client, void *v, int len)
                return -EREMOTEIO;
 
        if (!(ts->rd->f_flags & O_NONBLOCK))
-               P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
+               p9_debug(P9_DEBUG_ERROR, "blocking read ...\n");
 
        ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
        if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
@@ -299,7 +301,7 @@ static void p9_read_work(struct work_struct *work)
        if (m->err < 0)
                return;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos);
+       p9_debug(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos);
 
        if (!m->rbuf) {
                m->rbuf = m->tmp_buf;
@@ -308,11 +310,11 @@ static void p9_read_work(struct work_struct *work)
        }
 
        clear_bit(Rpending, &m->wsched);
-       P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m,
-                                       m->rpos, m->rsize, m->rsize-m->rpos);
+       p9_debug(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n",
+                m, m->rpos, m->rsize, m->rsize-m->rpos);
        err = p9_fd_read(m->client, m->rbuf + m->rpos,
                                                m->rsize - m->rpos);
-       P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
+       p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
        if (err == -EAGAIN) {
                clear_bit(Rworksched, &m->wsched);
                return;
@@ -325,25 +327,25 @@ static void p9_read_work(struct work_struct *work)
 
        if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */
                u16 tag;
-               P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n");
+               p9_debug(P9_DEBUG_TRANS, "got new header\n");
 
                n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */
                if (n >= m->client->msize) {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                               "requested packet size too big: %d\n", n);
+                       p9_debug(P9_DEBUG_ERROR,
+                                "requested packet size too big: %d\n", n);
                        err = -EIO;
                        goto error;
                }
 
                tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */
-               P9_DPRINTK(P9_DEBUG_TRANS,
-                       "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag);
+               p9_debug(P9_DEBUG_TRANS,
+                        "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag);
 
                m->req = p9_tag_lookup(m->client, tag);
                if (!m->req || (m->req->status != REQ_STATUS_SENT &&
                                        m->req->status != REQ_STATUS_FLSH)) {
-                       P9_DPRINTK(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
-                                                                tag);
+                       p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
+                                tag);
                        err = -EIO;
                        goto error;
                }
@@ -364,7 +366,7 @@ static void p9_read_work(struct work_struct *work)
 
        /* not an else because some packets (like clunk) have no payload */
        if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */
-               P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n");
+               p9_debug(P9_DEBUG_TRANS, "got new packet\n");
                spin_lock(&m->client->lock);
                if (m->req->status != REQ_STATUS_ERROR)
                        m->req->status = REQ_STATUS_RCVD;
@@ -384,7 +386,7 @@ static void p9_read_work(struct work_struct *work)
                        n = p9_fd_poll(m->client, NULL);
 
                if (n & POLLIN) {
-                       P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
+                       p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
                        schedule_work(&m->rq);
                } else
                        clear_bit(Rworksched, &m->wsched);
@@ -418,7 +420,7 @@ static int p9_fd_write(struct p9_client *client, void *v, int len)
                return -EREMOTEIO;
 
        if (!(ts->wr->f_flags & O_NONBLOCK))
-               P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
+               p9_debug(P9_DEBUG_ERROR, "blocking write ...\n");
 
        oldfs = get_fs();
        set_fs(get_ds());
@@ -460,7 +462,7 @@ static void p9_write_work(struct work_struct *work)
                req = list_entry(m->unsent_req_list.next, struct p9_req_t,
                               req_list);
                req->status = REQ_STATUS_SENT;
-               P9_DPRINTK(P9_DEBUG_TRANS, "move req %p\n", req);
+               p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
                list_move_tail(&req->req_list, &m->req_list);
 
                m->wbuf = req->tc->sdata;
@@ -469,11 +471,11 @@ static void p9_write_work(struct work_struct *work)
                spin_unlock(&m->client->lock);
        }
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos,
-                                                               m->wsize);
+       p9_debug(P9_DEBUG_TRANS, "mux %p pos %d size %d\n",
+                m, m->wpos, m->wsize);
        clear_bit(Wpending, &m->wsched);
        err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
-       P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
+       p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
        if (err == -EAGAIN) {
                clear_bit(Wworksched, &m->wsched);
                return;
@@ -497,7 +499,7 @@ static void p9_write_work(struct work_struct *work)
                        n = p9_fd_poll(m->client, NULL);
 
                if (n & POLLOUT) {
-                       P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
+                       p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
                        schedule_work(&m->wq);
                } else
                        clear_bit(Wworksched, &m->wsched);
@@ -551,7 +553,7 @@ p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
        }
 
        if (!pwait) {
-               P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
+               p9_debug(P9_DEBUG_ERROR, "not enough wait_address slots\n");
                return;
        }
 
@@ -573,8 +575,7 @@ static struct p9_conn *p9_conn_create(struct p9_client *client)
        int n;
        struct p9_conn *m;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client,
-                                                               client->msize);
+       p9_debug(P9_DEBUG_TRANS, "client %p msize %d\n", client, client->msize);
        m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
        if (!m)
                return ERR_PTR(-ENOMEM);
@@ -591,12 +592,12 @@ static struct p9_conn *p9_conn_create(struct p9_client *client)
 
        n = p9_fd_poll(client, &m->pt);
        if (n & POLLIN) {
-               P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m);
+               p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m);
                set_bit(Rpending, &m->wsched);
        }
 
        if (n & POLLOUT) {
-               P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m);
+               p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m);
                set_bit(Wpending, &m->wsched);
        }
 
@@ -618,7 +619,7 @@ static void p9_poll_mux(struct p9_conn *m)
 
        n = p9_fd_poll(m->client, NULL);
        if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
-               P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n);
+               p9_debug(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n);
                if (n >= 0)
                        n = -ECONNRESET;
                p9_conn_cancel(m, n);
@@ -626,19 +627,19 @@ static void p9_poll_mux(struct p9_conn *m)
 
        if (n & POLLIN) {
                set_bit(Rpending, &m->wsched);
-               P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m);
+               p9_debug(P9_DEBUG_TRANS, "mux %p can read\n", m);
                if (!test_and_set_bit(Rworksched, &m->wsched)) {
-                       P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
+                       p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
                        schedule_work(&m->rq);
                }
        }
 
        if (n & POLLOUT) {
                set_bit(Wpending, &m->wsched);
-               P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m);
+               p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m);
                if ((m->wsize || !list_empty(&m->unsent_req_list)) &&
                    !test_and_set_bit(Wworksched, &m->wsched)) {
-                       P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
+                       p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
                        schedule_work(&m->wq);
                }
        }
@@ -661,8 +662,8 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
        struct p9_trans_fd *ts = client->trans;
        struct p9_conn *m = ts->conn;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m,
-                                               current, req->tc, req->tc->id);
+       p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",
+                m, current, req->tc, req->tc->id);
        if (m->err < 0)
                return m->err;
 
@@ -686,7 +687,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
 {
        int ret = 1;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "client %p req %p\n", client, req);
+       p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req);
 
        spin_lock(&client->lock);
 
@@ -726,8 +727,8 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
 
        tmp_options = kstrdup(params, GFP_KERNEL);
        if (!tmp_options) {
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "failed to allocate copy of option string\n");
+               p9_debug(P9_DEBUG_ERROR,
+                        "failed to allocate copy of option string\n");
                return -ENOMEM;
        }
        options = tmp_options;
@@ -741,8 +742,8 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
                if (token != Opt_err) {
                        r = match_int(&args[0], &option);
                        if (r < 0) {
-                               P9_DPRINTK(P9_DEBUG_ERROR,
-                               "integer field, but no integer?\n");
+                               p9_debug(P9_DEBUG_ERROR,
+                                        "integer field, but no integer?\n");
                                continue;
                        }
                }
@@ -801,7 +802,8 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket)
        csocket->sk->sk_allocation = GFP_NOIO;
        fd = sock_map_fd(csocket, 0);
        if (fd < 0) {
-               P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
+               pr_err("%s (%d): failed to map fd\n",
+                      __func__, task_pid_nr(current));
                sock_release(csocket);
                kfree(p);
                return fd;
@@ -837,8 +839,8 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket)
 
 static void p9_conn_destroy(struct p9_conn *m)
 {
-       P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m,
-               m->mux_list.prev, m->mux_list.next);
+       p9_debug(P9_DEBUG_TRANS, "mux %p prev %p next %p\n",
+                m, m->mux_list.prev, m->mux_list.next);
 
        p9_mux_poll_stop(m);
        cancel_work_sync(&m->rq);
@@ -919,7 +921,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
        err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_INET,
                            SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
        if (err) {
-               P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
+               pr_err("%s (%d): problem creating socket\n",
+                      __func__, task_pid_nr(current));
                return err;
        }
 
@@ -927,9 +930,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
                                    (struct sockaddr *)&sin_server,
                                    sizeof(struct sockaddr_in), 0);
        if (err < 0) {
-               P9_EPRINTK(KERN_ERR,
-                       "p9_trans_tcp: problem connecting socket to %s\n",
-                       addr);
+               pr_err("%s (%d): problem connecting socket to %s\n",
+                      __func__, task_pid_nr(current), addr);
                sock_release(csocket);
                return err;
        }
@@ -947,8 +949,8 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
        csocket = NULL;
 
        if (strlen(addr) >= UNIX_PATH_MAX) {
-               P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
-                       addr);
+               pr_err("%s (%d): address too long: %s\n",
+                      __func__, task_pid_nr(current), addr);
                return -ENAMETOOLONG;
        }
 
@@ -957,15 +959,16 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
        err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_UNIX,
                            SOCK_STREAM, 0, &csocket, 1);
        if (err < 0) {
-               P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n");
+               pr_err("%s (%d): problem creating socket\n",
+                      __func__, task_pid_nr(current));
+
                return err;
        }
        err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
                        sizeof(struct sockaddr_un) - 1, 0);
        if (err < 0) {
-               P9_EPRINTK(KERN_ERR,
-                       "p9_trans_unix: problem connecting socket: %s: %d\n",
-                       addr, err);
+               pr_err("%s (%d): problem connecting socket: %s: %d\n",
+                      __func__, task_pid_nr(current), addr, err);
                sock_release(csocket);
                return err;
        }
@@ -983,7 +986,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
        parse_opts(args, &opts);
 
        if (opts.rfd == ~0 || opts.wfd == ~0) {
-               printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
+               pr_err("Insufficient options for proto=fd\n");
                return -ENOPROTOOPT;
        }
 
@@ -1050,7 +1053,7 @@ static void p9_poll_workfn(struct work_struct *work)
 {
        unsigned long flags;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current);
+       p9_debug(P9_DEBUG_TRANS, "start %p\n", current);
 
        spin_lock_irqsave(&p9_poll_lock, flags);
        while (!list_empty(&p9_poll_pending_list)) {
@@ -1066,7 +1069,7 @@ static void p9_poll_workfn(struct work_struct *work)
        }
        spin_unlock_irqrestore(&p9_poll_lock, flags);
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "finish\n");
+       p9_debug(P9_DEBUG_TRANS, "finish\n");
 }
 
 int p9_trans_fd_init(void)
index 159c50f1c6bf672c24b0d13f8e4f52dd40a18589..2c69ddd691a16a0056ed071695fb3ebc6293a917 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/net.h>
@@ -178,8 +180,8 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
 
        tmp_options = kstrdup(params, GFP_KERNEL);
        if (!tmp_options) {
-               P9_DPRINTK(P9_DEBUG_ERROR,
-                          "failed to allocate copy of option string\n");
+               p9_debug(P9_DEBUG_ERROR,
+                        "failed to allocate copy of option string\n");
                return -ENOMEM;
        }
        options = tmp_options;
@@ -192,8 +194,8 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
                token = match_token(p, tokens, args);
                r = match_int(&args[0], &option);
                if (r < 0) {
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                  "integer field, but no integer?\n");
+                       p9_debug(P9_DEBUG_ERROR,
+                                "integer field, but no integer?\n");
                        continue;
                }
                switch (token) {
@@ -301,8 +303,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
        return;
 
  err_out:
-       P9_DPRINTK(P9_DEBUG_ERROR, "req %p err %d status %d\n",
-                  req, err, status);
+       p9_debug(P9_DEBUG_ERROR, "req %p err %d status %d\n", req, err, status);
        rdma->state = P9_RDMA_FLUSHING;
        client->status = Disconnected;
 }
@@ -318,8 +319,8 @@ handle_send(struct p9_client *client, struct p9_trans_rdma *rdma,
 
 static void qp_event_handler(struct ib_event *event, void *context)
 {
-       P9_DPRINTK(P9_DEBUG_ERROR, "QP event %d context %p\n", event->event,
-                                                               context);
+       p9_debug(P9_DEBUG_ERROR, "QP event %d context %p\n",
+                event->event, context);
 }
 
 static void cq_comp_handler(struct ib_cq *cq, void *cq_context)
@@ -345,8 +346,7 @@ static void cq_comp_handler(struct ib_cq *cq, void *cq_context)
                        break;
 
                default:
-                       printk(KERN_ERR "9prdma: unexpected completion type, "
-                              "c->wc_op=%d, wc.opcode=%d, status=%d\n",
+                       pr_err("unexpected completion type, c->wc_op=%d, wc.opcode=%d, status=%d\n",
                               c->wc_op, wc.opcode, wc.status);
                        break;
                }
@@ -356,7 +356,7 @@ static void cq_comp_handler(struct ib_cq *cq, void *cq_context)
 
 static void cq_event_handler(struct ib_event *e, void *v)
 {
-       P9_DPRINTK(P9_DEBUG_ERROR, "CQ event %d context %p\n", e->event, v);
+       p9_debug(P9_DEBUG_ERROR, "CQ event %d context %p\n", e->event, v);
 }
 
 static void rdma_destroy_trans(struct p9_trans_rdma *rdma)
@@ -407,7 +407,7 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c)
        return ib_post_recv(rdma->qp, &wr, &bad_wr);
 
  error:
-       P9_DPRINTK(P9_DEBUG_ERROR, "EIO\n");
+       p9_debug(P9_DEBUG_ERROR, "EIO\n");
        return -EIO;
 }
 
@@ -500,7 +500,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
        kfree(c);
        kfree(rpl_context->rc);
        kfree(rpl_context);
-       P9_DPRINTK(P9_DEBUG_ERROR, "EIO\n");
+       p9_debug(P9_DEBUG_ERROR, "EIO\n");
        return -EIO;
  err_free1:
        kfree(rpl_context->rc);
index 32aa9834229cf6a9748fba543c47f5ebb81f5d31..3d432068f627ea9407187a00d37113f5baf39b3c 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/net.h>
@@ -145,7 +147,7 @@ static void req_done(struct virtqueue *vq)
        struct p9_req_t *req;
        unsigned long flags;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
+       p9_debug(P9_DEBUG_TRANS, ": request done\n");
 
        while (1) {
                spin_lock_irqsave(&chan->lock, flags);
@@ -158,8 +160,8 @@ static void req_done(struct virtqueue *vq)
                spin_unlock_irqrestore(&chan->lock, flags);
                /* Wakeup if anyone waiting for VirtIO ring space. */
                wake_up(chan->vc_wq);
-               P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
-               P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
+               p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc);
+               p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
                req = p9_tag_lookup(chan->client, rc->tag);
                req->status = REQ_STATUS_RCVD;
                p9_client_cb(chan->client, req);
@@ -257,7 +259,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
        unsigned long flags;
        struct virtio_chan *chan = client->trans;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
+       p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n");
 
        req->status = REQ_STATUS_SENT;
 req_retry:
@@ -270,7 +272,8 @@ req_retry:
        in = pack_sg_list(chan->sg, out,
                          VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity);
 
-       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc,
+                               GFP_ATOMIC);
        if (err < 0) {
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
@@ -280,20 +283,19 @@ req_retry:
                        if (err  == -ERESTARTSYS)
                                return err;
 
-                       P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
+                       p9_debug(P9_DEBUG_TRANS, "Retry virtio request\n");
                        goto req_retry;
                } else {
                        spin_unlock_irqrestore(&chan->lock, flags);
-                       P9_DPRINTK(P9_DEBUG_TRANS,
-                                       "9p debug: "
-                                       "virtio rpc add_buf returned failure");
+                       p9_debug(P9_DEBUG_TRANS,
+                                "virtio rpc add_buf returned failure\n");
                        return -EIO;
                }
        }
        virtqueue_kick(chan->vq);
        spin_unlock_irqrestore(&chan->lock, flags);
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
+       p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
        return 0;
 }
 
@@ -354,7 +356,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
        struct page **in_pages = NULL, **out_pages = NULL;
        struct virtio_chan *chan = client->trans;
 
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
+       p9_debug(P9_DEBUG_TRANS, "virtio request\n");
 
        if (uodata) {
                out_nr_pages = p9_nr_pages(uodata, outlen);
@@ -413,7 +415,8 @@ req_retry_pinned:
                in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM,
                                     in_pages, in_nr_pages, uidata, inlen);
 
-       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
+       err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc,
+                               GFP_ATOMIC);
        if (err < 0) {
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
@@ -423,20 +426,19 @@ req_retry_pinned:
                        if (err  == -ERESTARTSYS)
                                goto err_out;
 
-                       P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
+                       p9_debug(P9_DEBUG_TRANS, "Retry virtio request\n");
                        goto req_retry_pinned;
                } else {
                        spin_unlock_irqrestore(&chan->lock, flags);
-                       P9_DPRINTK(P9_DEBUG_TRANS,
-                                  "9p debug: "
-                                  "virtio rpc add_buf returned failure");
+                       p9_debug(P9_DEBUG_TRANS,
+                                "virtio rpc add_buf returned failure\n");
                        err = -EIO;
                        goto err_out;
                }
        }
        virtqueue_kick(chan->vq);
        spin_unlock_irqrestore(&chan->lock, flags);
-       P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
+       p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
        err = wait_event_interruptible(*req->wq,
                                       req->status >= REQ_STATUS_RCVD);
        /*
@@ -491,7 +493,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
 
        chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
        if (!chan) {
-               printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
+               pr_err("Failed to allocate virtio 9P channel\n");
                err = -ENOMEM;
                goto fail;
        }
@@ -592,7 +594,7 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
        mutex_unlock(&virtio_9p_lock);
 
        if (!found) {
-               printk(KERN_ERR "9p: no channels available\n");
+               pr_err("no channels available\n");
                return ret;
        }
 
index 9c1c9348ac35d3410ccb255266f9367bbf5d2549..6ceeeb384de73cbd4583b9b22a41c27b8b0885bb 100644 (file)
@@ -106,7 +106,7 @@ retry:
        else if (error)
                return -1;
 
-       P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
+       p9_debug(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
        return i;
 }
 EXPORT_SYMBOL(p9_idpool_get);
@@ -124,7 +124,7 @@ void p9_idpool_put(int id, struct p9_idpool *p)
 {
        unsigned long flags;
 
-       P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", id, p);
+       p9_debug(P9_DEBUG_MUX, " id %d pool %p\n", id, p);
 
        spin_lock_irqsave(&p->lock, flags);
        idr_remove(&p->pool, id);
index cdcfcabb34ab8daf5b2275f52084c055926dac73..ef92864ac6258b32ec600ad5791e19d399d0965b 100644 (file)
@@ -156,17 +156,17 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto,
 
 void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
 {
-       write_lock_bh(&l->lock);
+       write_lock(&l->lock);
        sk_add_node(sk, &l->head);
-       write_unlock_bh(&l->lock);
+       write_unlock(&l->lock);
 }
 EXPORT_SYMBOL(bt_sock_link);
 
 void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
 {
-       write_lock_bh(&l->lock);
+       write_lock(&l->lock);
        sk_del_node_init(sk);
-       write_unlock_bh(&l->lock);
+       write_unlock(&l->lock);
 }
 EXPORT_SYMBOL(bt_sock_unlink);
 
index 4221bd256bddfd89e147f1605f0dd334aa042ea6..001307f810577111d0bbeea9265e0da37574cb5e 100644 (file)
@@ -711,7 +711,14 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
        if (rp->status)
                return;
 
-       memcpy(hdev->extfeatures, rp->features, 8);
+       switch (rp->page) {
+       case 0:
+               memcpy(hdev->features, rp->features, 8);
+               break;
+       case 1:
+               memcpy(hdev->host_features, rp->features, 8);
+               break;
+       }
 
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
 }
@@ -1047,9 +1054,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        case LE_SCANNING_DISABLED:
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
 
-               cancel_delayed_work_sync(&hdev->adv_work);
-               queue_delayed_work(hdev->workqueue, &hdev->adv_work,
-                                                jiffies + ADV_CLEAR_TIMEOUT);
+               schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
                break;
 
        default:
@@ -2266,20 +2271,19 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
        struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
        int i;
 
-       skb_pull(skb, sizeof(*ev));
-
-       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
-
        if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
                BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
                return;
        }
 
-       if (skb->len < ev->num_hndl * 4) {
+       if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) +
+                       ev->num_hndl * sizeof(struct hci_comp_pkts_info)) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
 
+       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_pkts_info *info = &ev->handles[i];
                struct hci_conn *conn;
index 6d94616af3129b3519c914c3458eb30cad40de05..0dcc9626677973d23708b53c7716a126adea107f 100644 (file)
@@ -767,7 +767,6 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                /* Detach sockets from device */
                read_lock(&hci_sk_list.lock);
                sk_for_each(sk, node, &hci_sk_list.head) {
-                       local_bh_disable();
                        bh_lock_sock_nested(sk);
                        if (hci_pi(sk)->hdev == hdev) {
                                hci_pi(sk)->hdev = NULL;
@@ -778,7 +777,6 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
                                hci_dev_put(hdev);
                        }
                        bh_unlock_sock(sk);
-                       local_bh_enable();
                }
                read_unlock(&hci_sk_list.lock);
        }
index aa78d8c4b93be75f630e1389b4886ffdd4ab3623..faf0b11ac1d3610805e6d049f4a2e2221c35053a 100644 (file)
@@ -165,7 +165,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
 {
        int err;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        if (psm && __l2cap_global_chan_by_addr(psm, src)) {
                err = -EADDRINUSE;
@@ -190,17 +190,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
        }
 
 done:
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
        return err;
 }
 
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
 
        chan->scid = scid;
 
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        return 0;
 }
@@ -289,9 +289,9 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
        chan->sk = sk;
 
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_add(&chan->global_l, &chan_list);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
 
@@ -306,9 +306,9 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
 void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
-       write_lock_bh(&chan_list_lock);
+       write_lock(&chan_list_lock);
        list_del(&chan->global_l);
-       write_unlock_bh(&chan_list_lock);
+       write_unlock(&chan_list_lock);
 
        l2cap_chan_put(chan);
 }
@@ -543,14 +543,14 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn)
         *  200 - 254 are used by utilities like l2ping, etc.
         */
 
-       spin_lock_bh(&conn->lock);
+       spin_lock(&conn->lock);
 
        if (++conn->tx_ident > 128)
                conn->tx_ident = 1;
 
        id = conn->tx_ident;
 
-       spin_unlock_bh(&conn->lock);
+       spin_unlock(&conn->lock);
 
        return id;
 }
@@ -1190,7 +1190,7 @@ inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdad
        }
 
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, src);
+       bacpy(&bt_sk(sk)->dst, dst);
        chan->psm = psm;
        chan->dcid = cid;
 
@@ -4702,7 +4702,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
        struct l2cap_chan *c;
 
-       read_lock_bh(&chan_list_lock);
+       read_lock(&chan_list_lock);
 
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
@@ -4715,7 +4715,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
                                        c->sec_level, c->mode);
 }
 
-       read_unlock_bh(&chan_list_lock);
+       read_unlock(&chan_list_lock);
 
        return 0;
 }
index 9ca5616166f7ad911204044b4a0dec80d6b1e099..c61d967012b2008547767dd69cec91be0f97d30d 100644 (file)
@@ -587,6 +587,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        if (smp_conn_security(conn, sec.level))
                                break;
                        sk->sk_state = BT_CONFIG;
+                       chan->state = BT_CONFIG;
 
                /* or for ACL link, under defer_setup time */
                } else if (sk->sk_state == BT_CONNECT2 &&
@@ -731,6 +732,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
 
        if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
                sk->sk_state = BT_CONFIG;
+               pi->chan->state = BT_CONFIG;
 
                __l2cap_connect_rsp_defer(pi->chan);
                release_sock(sk);
index 2540944d871ffa0946565d78b6d23a9503a7f1c2..bc8e59dda78e2bf72f81c3eeacea748d5cbd78ae 100644 (file)
@@ -291,7 +291,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (!(hdev->features[4] & LMP_NO_BREDR))
                settings |= MGMT_SETTING_BREDR;
 
-       if (hdev->extfeatures[0] & LMP_HOST_LE)
+       if (hdev->host_features[0] & LMP_HOST_LE)
                settings |= MGMT_SETTING_LE;
 
        if (test_bit(HCI_AUTH, &hdev->flags))
@@ -2756,7 +2756,7 @@ int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
+       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
        mgmt_pending_remove(cmd);
 
        return err;
index aea2bdd1510f2b4f083a4581105228b927cde858..f066678faeee838efae16243111a1bb51f47c8f3 100644 (file)
@@ -370,7 +370,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
                goto done;
        }
 
-       write_lock_bh(&rfcomm_sk_list.lock);
+       write_lock(&rfcomm_sk_list.lock);
 
        if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
                err = -EADDRINUSE;
@@ -381,7 +381,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
                sk->sk_state = BT_BOUND;
        }
 
-       write_unlock_bh(&rfcomm_sk_list.lock);
+       write_unlock(&rfcomm_sk_list.lock);
 
 done:
        release_sock(sk);
@@ -455,7 +455,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
 
                err = -EINVAL;
 
-               write_lock_bh(&rfcomm_sk_list.lock);
+               write_lock(&rfcomm_sk_list.lock);
 
                for (channel = 1; channel < 31; channel++)
                        if (!__rfcomm_get_sock_by_addr(channel, src)) {
@@ -464,7 +464,7 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog)
                                break;
                        }
 
-               write_unlock_bh(&rfcomm_sk_list.lock);
+               write_unlock(&rfcomm_sk_list.lock);
 
                if (err < 0)
                        goto done;
@@ -982,7 +982,7 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
        struct sock *sk;
        struct hlist_node *node;
 
-       read_lock_bh(&rfcomm_sk_list.lock);
+       read_lock(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
                seq_printf(f, "%s %s %d %d\n",
@@ -991,7 +991,7 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
                                sk->sk_state, rfcomm_pi(sk)->channel);
        }
 
-       read_unlock_bh(&rfcomm_sk_list.lock);
+       read_unlock(&rfcomm_sk_list.lock);
 
        return 0;
 }
index fa8f4de53b997213b05a528434bf5ef14374651d..a2d4f5122a6a2030913814a8ebdc0cf6a381e29d 100644 (file)
@@ -76,7 +76,7 @@ struct rfcomm_dev {
 };
 
 static LIST_HEAD(rfcomm_dev_list);
-static DEFINE_RWLOCK(rfcomm_dev_lock);
+static DEFINE_SPINLOCK(rfcomm_dev_lock);
 
 static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
@@ -146,7 +146,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
 
-       read_lock(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        dev = __rfcomm_dev_get(id);
 
@@ -157,7 +157,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
                        rfcomm_dev_hold(dev);
        }
 
-       read_unlock(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        return dev;
 }
@@ -205,7 +205,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        if (!dev)
                return -ENOMEM;
 
-       write_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        if (req->dev_id < 0) {
                dev->id = 0;
@@ -290,7 +290,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        __module_get(THIS_MODULE);
 
 out:
-       write_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        if (err < 0)
                goto free;
@@ -327,9 +327,9 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
        if (atomic_read(&dev->opened) > 0)
                return;
 
-       write_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
        list_del_init(&dev->list);
-       write_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        rfcomm_dev_put(dev);
 }
@@ -473,7 +473,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        di = dl->dev_info;
 
-       read_lock_bh(&rfcomm_dev_lock);
+       spin_lock(&rfcomm_dev_lock);
 
        list_for_each_entry(dev, &rfcomm_dev_list, list) {
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
@@ -488,7 +488,7 @@ static int rfcomm_get_dev_list(void __user *arg)
                        break;
        }
 
-       read_unlock_bh(&rfcomm_dev_lock);
+       spin_unlock(&rfcomm_dev_lock);
 
        dl->dev_num = n;
        size = sizeof(*dl) + n * sizeof(*di);
@@ -766,9 +766,9 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                rfcomm_dlc_unlock(dev->dlc);
 
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
-                       write_lock_bh(&rfcomm_dev_lock);
+                       spin_lock(&rfcomm_dev_lock);
                        list_del_init(&dev->list);
-                       write_unlock_bh(&rfcomm_dev_lock);
+                       spin_unlock(&rfcomm_dev_lock);
 
                        rfcomm_dev_put(dev);
                }
index 5dc2f2126fac669a2f1b961efb8ce665768da2f2..8bf26d1bc5c181e25641622d980c0f812a6780e0 100644 (file)
@@ -482,7 +482,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                goto done;
        }
 
-       write_lock_bh(&sco_sk_list.lock);
+       write_lock(&sco_sk_list.lock);
 
        if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
                err = -EADDRINUSE;
@@ -492,7 +492,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                sk->sk_state = BT_BOUND;
        }
 
-       write_unlock_bh(&sco_sk_list.lock);
+       write_unlock(&sco_sk_list.lock);
 
 done:
        release_sock(sk);
@@ -965,14 +965,14 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
        struct sock *sk;
        struct hlist_node *node;
 
-       read_lock_bh(&sco_sk_list.lock);
+       read_lock(&sco_sk_list.lock);
 
        sk_for_each(sk, node, &sco_sk_list.head) {
                seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
                                batostr(&bt_sk(sk)->dst), sk->sk_state);
        }
 
-       read_unlock_bh(&sco_sk_list.lock);
+       read_unlock(&sco_sk_list.lock);
 
        return 0;
 }
index 3a94eae7abe924d8d73d454b5a9330ab50bda968..b79747c4b64584cf9674920640ff0cf355efa45b 100644 (file)
@@ -510,10 +510,15 @@ int crush_do_rule(struct crush_map *map,
                switch (rule->steps[step].op) {
                case CRUSH_RULE_TAKE:
                        w[0] = rule->steps[step].arg1;
-                       if (force_pos >= 0) {
-                               BUG_ON(force_context[force_pos] != w[0]);
+
+                       /* find position in force_context/hierarchy */
+                       while (force_pos >= 0 &&
+                              force_context[force_pos] != w[0])
                                force_pos--;
-                       }
+                       /* and move past it */
+                       if (force_pos >= 0)
+                               force_pos--;
+
                        wsize = 1;
                        break;
 
index 85f3bc0a7062ae2d87e3f40bfb8b8f515fb09a66..b780cb7947ddd29f6ae23b11f3b030d22686beda 100644 (file)
@@ -15,10 +15,9 @@ int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
                          const struct ceph_crypto_key *src)
 {
        memcpy(dst, src, sizeof(struct ceph_crypto_key));
-       dst->key = kmalloc(src->len, GFP_NOFS);
+       dst->key = kmemdup(src->key, src->len, GFP_NOFS);
        if (!dst->key)
                return -ENOMEM;
-       memcpy(dst->key, src->key, src->len);
        return 0;
 }
 
index f4f3f58f5234c1a5ce5eb4b54638c730f571ffb9..5e254055c91086287cd0d96091cb2eac50fecc38 100644 (file)
@@ -29,8 +29,8 @@ static void __register_request(struct ceph_osd_client *osdc,
                               struct ceph_osd_request *req);
 static void __unregister_linger_request(struct ceph_osd_client *osdc,
                                        struct ceph_osd_request *req);
-static int __send_request(struct ceph_osd_client *osdc,
-                         struct ceph_osd_request *req);
+static void __send_request(struct ceph_osd_client *osdc,
+                          struct ceph_osd_request *req);
 
 static int op_needs_trail(int op)
 {
@@ -1022,8 +1022,8 @@ out:
 /*
  * caller should hold map_sem (for read) and request_mutex
  */
-static int __send_request(struct ceph_osd_client *osdc,
-                         struct ceph_osd_request *req)
+static void __send_request(struct ceph_osd_client *osdc,
+                          struct ceph_osd_request *req)
 {
        struct ceph_osd_request_head *reqhead;
 
@@ -1041,7 +1041,6 @@ static int __send_request(struct ceph_osd_client *osdc,
        ceph_msg_get(req->r_request); /* send consumes a ref */
        ceph_con_send(&req->r_osd->o_con, req->r_request);
        req->r_sent = req->r_osd->o_incarnation;
-       return 0;
 }
 
 /*
@@ -1726,17 +1725,9 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
                        dout("send_request %p no up osds in pg\n", req);
                        ceph_monc_request_next_osdmap(&osdc->client->monc);
                } else {
-                       rc = __send_request(osdc, req);
-                       if (rc) {
-                               if (nofail) {
-                                       dout("osdc_start_request failed send, "
-                                            " will retry %lld\n", req->r_tid);
-                                       rc = 0;
-                               } else {
-                                       __unregister_request(osdc, req);
-                               }
-                       }
+                       __send_request(osdc, req);
                }
+               rc = 0;
        }
 
 out_unlock:
index abf4393a77b3b1de706931815a72680bfbd78586..f3dbd4f596a4904a99650d18ae73c9a963126aa8 100644 (file)
@@ -1177,9 +1177,9 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                        nonempty = 1;
        }
 
-       if (nonempty)
-               RCU_INIT_POINTER(dev->xps_maps, new_dev_maps);
-       else {
+       if (nonempty) {
+               rcu_assign_pointer(dev->xps_maps, new_dev_maps);
+       else {
                kfree(new_dev_maps);
                RCU_INIT_POINTER(dev->xps_maps, NULL);
        }
index 0d38808a2305d06c642f7192ece302c9b2a971c2..556b082986696d8b80b09c4f687cff23bc540a45 100644 (file)
@@ -765,7 +765,7 @@ int __netpoll_setup(struct netpoll *np)
        }
 
        /* last thing to do is link it to the net device structure */
-       RCU_INIT_POINTER(ndev->npinfo, npinfo);
+       rcu_assign_pointer(ndev->npinfo, npinfo);
 
        return 0;
 
index 8f16257533779dcda5e5d18c5413d5d35c2d9162..028fc43aacbd3a75e2bd87554aa2f3a582900324 100644 (file)
@@ -49,13 +49,13 @@ static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void dccp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&dccp_hashinfo, skb, cb, r, bc);
 }
 
 static int dccp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&dccp_hashinfo, in_skb, nlh, req);
 }
index 2ab16e12520c525db2a84f0bb80eb4857f55f217..74d321a60e7b5751901c2a2e7d185e54043185ec 100644 (file)
@@ -388,7 +388,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        }
 
        ifa->ifa_next = dn_db->ifa_list;
-       RCU_INIT_POINTER(dn_db->ifa_list, ifa);
+       rcu_assign_pointer(dn_db->ifa_list, ifa);
 
        dn_ifaddr_notify(RTM_NEWADDR, ifa);
        blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
@@ -1093,7 +1093,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 
        memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
 
-       RCU_INIT_POINTER(dev->dn_ptr, dn_db);
+       rcu_assign_pointer(dev->dn_ptr, dn_db);
        dn_db->dev = dev;
        init_timer(&dn_db->timer);
 
index 65f01dc47565bcc26282d4472bbd9c3fb2d3712c..e41c40f48cfe053f28baa3fe9dcf4179ce5a1f37 100644 (file)
@@ -258,7 +258,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
                ip_mc_up(in_dev);
 
        /* we can receive as soon as ip_ptr is set -- do this last */
-       RCU_INIT_POINTER(dev->ip_ptr, in_dev);
+       rcu_assign_pointer(dev->ip_ptr, in_dev);
 out:
        return in_dev;
 out_kfree:
index d04b13ae18fecc3b641ecf5a45279a620307f15f..2b555a5521e0b60f8b373b4c72e70d896da15ff0 100644 (file)
@@ -205,7 +205,7 @@ static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node)
        return (struct tnode *)(parent & ~NODE_TYPE_MASK);
 }
 
-/* Same as RCU_INIT_POINTER
+/* Same as rcu_assign_pointer
  * but that macro() assumes that value is a pointer.
  */
 static inline void node_set_parent(struct rt_trie_node *node, struct tnode *ptr)
@@ -529,7 +529,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *
        if (n)
                node_set_parent(n, tn);
 
-       RCU_INIT_POINTER(tn->child[i], n);
+       rcu_assign_pointer(tn->child[i], n);
 }
 
 #define MAX_WORK 10
@@ -1015,7 +1015,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
 
                tp = node_parent((struct rt_trie_node *) tn);
                if (!tp)
-                       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
 
                tnode_free_flush();
                if (!tp)
@@ -1027,7 +1027,7 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
        if (IS_TNODE(tn))
                tn = (struct tnode *)resize(t, (struct tnode *)tn);
 
-       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
        tnode_free_flush();
 }
 
@@ -1164,7 +1164,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
                        put_child(t, (struct tnode *)tp, cindex,
                                  (struct rt_trie_node *)tn);
                } else {
-                       RCU_INIT_POINTER(t->trie, (struct rt_trie_node *)tn);
+                       rcu_assign_pointer(t->trie, (struct rt_trie_node *)tn);
                        tp = tn;
                }
        }
index 5104bc0bbdbe73d43f0b92e659e7fb2dda24928f..450e5d21ed2af271574874479bd0c0d341bf6b38 100644 (file)
@@ -1249,7 +1249,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 
        im->next_rcu = in_dev->mc_list;
        in_dev->mc_count++;
-       RCU_INIT_POINTER(in_dev->mc_list, im);
+       rcu_assign_pointer(in_dev->mc_list, im);
 
 #ifdef CONFIG_IP_MULTICAST
        igmpv3_del_delrec(in_dev, im->multiaddr);
@@ -1821,7 +1821,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
        iml->next_rcu = inet->mc_list;
        iml->sflist = NULL;
        iml->sfmode = MCAST_EXCLUDE;
-       RCU_INIT_POINTER(inet->mc_list, iml);
+       rcu_assign_pointer(inet->mc_list, iml);
        ip_mc_inc_group(in_dev, addr);
        err = 0;
 done:
@@ -2008,7 +2008,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                        atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
                        kfree_rcu(psl, rcu);
                }
-               RCU_INIT_POINTER(pmc->sflist, newpsl);
+               rcu_assign_pointer(pmc->sflist, newpsl);
                psl = newpsl;
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
@@ -2111,7 +2111,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
        } else
                (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
                        0, NULL, 0);
-       RCU_INIT_POINTER(pmc->sflist, newpsl);
+       rcu_assign_pointer(pmc->sflist, newpsl);
        pmc->sfmode = msf->imsf_fmode;
        err = 0;
 done:
index 2240a8e8c44dbefaed2a83aa44b6e058970fc65b..fcf281819cd48f51c824674fbb63673922d5cef0 100644 (file)
@@ -71,7 +71,7 @@ static inline void inet_diag_unlock_handler(
 }
 
 int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh)
 {
@@ -193,7 +193,7 @@ nlmsg_failure:
 EXPORT_SYMBOL_GPL(inet_sk_diag_fill);
 
 static int inet_csk_diag_fill(struct sock *sk,
-                             struct sk_buff *skb, struct inet_diag_req *req,
+                             struct sk_buff *skb, struct inet_diag_req_v2 *req,
                              u32 pid, u32 seq, u16 nlmsg_flags,
                              const struct nlmsghdr *unlh)
 {
@@ -202,7 +202,7 @@ static int inet_csk_diag_fill(struct sock *sk,
 }
 
 static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
-                              struct sk_buff *skb, struct inet_diag_req *req,
+                              struct sk_buff *skb, struct inet_diag_req_v2 *req,
                               u32 pid, u32 seq, u16 nlmsg_flags,
                               const struct nlmsghdr *unlh)
 {
@@ -253,7 +253,7 @@ nlmsg_failure:
 }
 
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
-                       struct inet_diag_req *r, u32 pid, u32 seq, u16 nlmsg_flags,
+                       struct inet_diag_req_v2 *r, u32 pid, u32 seq, u16 nlmsg_flags,
                        const struct nlmsghdr *unlh)
 {
        if (sk->sk_state == TCP_TIME_WAIT)
@@ -264,7 +264,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
 }
 
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb,
-               const struct nlmsghdr *nlh, struct inet_diag_req *req)
+               const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
 {
        int err;
        struct sock *sk;
@@ -333,7 +333,7 @@ EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk);
 
 static int inet_diag_get_exact(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh,
-                              struct inet_diag_req *req)
+                              struct inet_diag_req_v2 *req)
 {
        const struct inet_diag_handler *handler;
        int err;
@@ -540,7 +540,7 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
 static int inet_csk_diag_dump(struct sock *sk,
                              struct sk_buff *skb,
                              struct netlink_callback *cb,
-                             struct inet_diag_req *r,
+                             struct inet_diag_req_v2 *r,
                              const struct nlattr *bc)
 {
        if (!inet_diag_bc_sk(bc, sk))
@@ -554,7 +554,7 @@ static int inet_csk_diag_dump(struct sock *sk,
 static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                               struct sk_buff *skb,
                               struct netlink_callback *cb,
-                              struct inet_diag_req *r,
+                              struct inet_diag_req_v2 *r,
                               const struct nlattr *bc)
 {
        if (bc != NULL) {
@@ -639,7 +639,7 @@ nlmsg_failure:
 
 static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                               struct netlink_callback *cb,
-                              struct inet_diag_req *r,
+                              struct inet_diag_req_v2 *r,
                               const struct nlattr *bc)
 {
        struct inet_diag_entry entry;
@@ -721,7 +721,7 @@ out:
 }
 
 void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *r, struct nlattr *bc)
+               struct netlink_callback *cb, struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        int i, num;
        int s_i, s_num;
@@ -872,7 +872,7 @@ out:
 EXPORT_SYMBOL_GPL(inet_diag_dump_icsk);
 
 static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        const struct inet_diag_handler *handler;
 
@@ -887,12 +887,12 @@ static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct nlattr *bc = NULL;
-       int hdrlen = sizeof(struct inet_diag_req);
+       int hdrlen = sizeof(struct inet_diag_req_v2);
 
        if (nlmsg_attrlen(cb->nlh, hdrlen))
                bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);
 
-       return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc);
+       return __inet_diag_dump(skb, cb, (struct inet_diag_req_v2 *)NLMSG_DATA(cb->nlh), bc);
 }
 
 static inline int inet_diag_type2proto(int type)
@@ -909,10 +909,10 @@ static inline int inet_diag_type2proto(int type)
 
 static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh);
-       struct inet_diag_req req;
+       struct inet_diag_req *rc = NLMSG_DATA(cb->nlh);
+       struct inet_diag_req_v2 req;
        struct nlattr *bc = NULL;
-       int hdrlen = sizeof(struct inet_diag_req_compat);
+       int hdrlen = sizeof(struct inet_diag_req);
 
        req.sdiag_family = AF_UNSPEC; /* compatibility */
        req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type);
@@ -929,8 +929,8 @@ static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *c
 static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh)
 {
-       struct inet_diag_req_compat *rc = NLMSG_DATA(nlh);
-       struct inet_diag_req req;
+       struct inet_diag_req *rc = NLMSG_DATA(nlh);
+       struct inet_diag_req_v2 req;
 
        req.sdiag_family = rc->idiag_family;
        req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type);
@@ -943,7 +943,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
 
 static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-       int hdrlen = sizeof(struct inet_diag_req_compat);
+       int hdrlen = sizeof(struct inet_diag_req);
 
        if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
            nlmsg_len(nlh) < hdrlen)
@@ -970,7 +970,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
 
 static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 {
-       int hdrlen = sizeof(struct inet_diag_req);
+       int hdrlen = sizeof(struct inet_diag_req_v2);
 
        if (nlmsg_len(h) < hdrlen)
                return -EINVAL;
@@ -990,7 +990,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
                                          inet_diag_dump, NULL, 0);
        }
 
-       return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h));
+       return inet_diag_get_exact(skb, h, (struct inet_diag_req_v2 *)NLMSG_DATA(h));
 }
 
 static struct sock_diag_handler inet_diag_handler = {
index 413ed1ba7a5a16976d80ca39fadad9ec719dd6e5..22a19931530910a4f6eae62fb28889f019b2dc68 100644 (file)
@@ -231,7 +231,7 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -241,8 +241,8 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
 {
        struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
 
-       RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
@@ -792,7 +792,7 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
                return -ENOMEM;
 
        dev_hold(dev);
-       RCU_INIT_POINTER(ipn->tunnels_wc[0], tunnel);
+       rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
        return 0;
 }
 
index 8e54490ee3f490d6c07c99e87481b3a1dd395744..7bc2db6db8d407987bbd06f59a25cf1b0f488989 100644 (file)
@@ -1225,7 +1225,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
 
                ret = ip_ra_control(sk, 1, mrtsock_destruct);
                if (ret == 0) {
-                       RCU_INIT_POINTER(mrt->mroute_sk, sk);
+                       rcu_assign_pointer(mrt->mroute_sk, sk);
                        IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
                }
                rtnl_unlock();
index 8cd357a8be7990b5212253d95fa72a1f740a3edf..ed3f2ad42e0f0ea881e507d8c91e7962d336d824 100644 (file)
@@ -35,13 +35,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc);
 }
 
 static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 }
index 7fed04f875c1acf4448333d18276c928c3a0180a..49978788a9dc31e13cec48b472c45234343be13a 100644 (file)
@@ -108,7 +108,7 @@ void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
        tcp = tcp_from_cgproto(cg_proto);
        percpu_counter_destroy(&tcp->tcp_sockets_allocated);
 
-       val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
+       val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
 
        if (val != RESOURCE_MAX)
                jump_label_dec(&memcg_socket_limit_enabled);
index 69f8a7ca63dd8c65ed6357e28af036d002eb65c5..e5e18cb8a58686a2331480c53edac2a77b901e8c 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/sock_diag.h>
 
 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
-               struct netlink_callback *cb, struct inet_diag_req *req,
+               struct netlink_callback *cb, struct inet_diag_req_v2 *req,
                struct nlattr *bc)
 {
        if (!inet_diag_bc_sk(bc, sk))
@@ -30,7 +30,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
 }
 
 static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
-               const struct nlmsghdr *nlh, struct inet_diag_req *req)
+               const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
 {
        int err = -EINVAL;
        struct sock *sk;
@@ -88,7 +88,7 @@ out_nosk:
 }
 
 static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        int num, s_num, slot, s_slot;
 
@@ -136,13 +136,13 @@ done:
 }
 
 static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        udp_dump(&udp_table, skb, cb, r, bc);
 }
 
 static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return udp_dump_one(&udp_table, in_skb, nlh, req);
 }
@@ -154,13 +154,13 @@ static const struct inet_diag_handler udp_diag_handler = {
 };
 
 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req *r, struct nlattr *bc)
+               struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        udp_dump(&udplite_table, skb, cb, r, bc);
 }
 
 static int udplite_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req *req)
+               struct inet_diag_req_v2 *req)
 {
        return udp_dump_one(&udplite_table, in_skb, nlh, req);
 }
index 0ba0866230c99367db4f3706b15cb2ed0ff91dbf..a225d5ee3c2fc877f25e7af417c58de124fe8cb9 100644 (file)
@@ -429,7 +429,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        ndev->tstamp = jiffies;
        addrconf_sysctl_register(ndev);
        /* protected by rtnl_lock */
-       RCU_INIT_POINTER(dev->ip6_ptr, ndev);
+       rcu_assign_pointer(dev->ip6_ptr, ndev);
 
        /* Join all-node multicast group */
        ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
index e1f7761815f36903687dd45f0da702c86ec4f159..aa21da6a09cd66bc2cad80cb227d8514e5466658 100644 (file)
@@ -218,8 +218,8 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
 {
        struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms);
 
-       RCU_INIT_POINTER(t->next , rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next , rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 /**
@@ -237,7 +237,7 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -1450,7 +1450,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 
        t->parms.proto = IPPROTO_IPV6;
        dev_hold(dev);
-       RCU_INIT_POINTER(ip6n->tnls_wc[0], t);
+       rcu_assign_pointer(ip6n->tnls_wc[0], t);
        return 0;
 }
 
index a4894f4f1944e600d93a1f2a9cde719cfe528bb0..d02f7e4dd6113c8c23cb8a3f7ee9be9cbae37685 100644 (file)
@@ -131,7 +131,7 @@ static mh_filter_t __rcu *mh_filter __read_mostly;
 
 int rawv6_mh_filter_register(mh_filter_t filter)
 {
-       RCU_INIT_POINTER(mh_filter, filter);
+       rcu_assign_pointer(mh_filter, filter);
        return 0;
 }
 EXPORT_SYMBOL(rawv6_mh_filter_register);
index 3b6dac956bb09e74cd9119b7763b786b02789743..133768e52912bd561930736f36c0085c594000b4 100644 (file)
@@ -182,7 +182,7 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
             (iter = rtnl_dereference(*tp)) != NULL;
             tp = &iter->next) {
                if (t == iter) {
-                       RCU_INIT_POINTER(*tp, t->next);
+                       rcu_assign_pointer(*tp, t->next);
                        break;
                }
        }
@@ -192,8 +192,8 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
 {
        struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t);
 
-       RCU_INIT_POINTER(t->next, rtnl_dereference(*tp));
-       RCU_INIT_POINTER(*tp, t);
+       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
 }
 
 static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
@@ -393,7 +393,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
        p->addr = a->addr;
        p->flags = a->flags;
        t->prl_count++;
-       RCU_INIT_POINTER(t->prl, p);
+       rcu_assign_pointer(t->prl, p);
 out:
        return err;
 }
@@ -1177,7 +1177,7 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
        dev_hold(dev);
-       RCU_INIT_POINTER(sitn->tunnels_wc[0], tunnel);
+       rcu_assign_pointer(sitn->tunnels_wc[0], tunnel);
        return 0;
 }
 
index 96debba2c407bfeeb91d95ce1524521a07745958..1068f668ac4ec3434b1524624df98c5bf08e5074 100644 (file)
@@ -332,7 +332,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        status = WLAN_STATUS_SUCCESS;
 
        /* activate it for RX */
-       RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
+       rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
 
        if (timeout)
                mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
index 850bb96bd6805204685083dde687b8097bd19b0f..e60df48fa4d4d235016398706bf3b32e5633c1e0 100644 (file)
@@ -616,7 +616,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.bss_conf.dtim_period = new->dtim_period;
 
-       RCU_INIT_POINTER(sdata->u.ap.beacon, new);
+       rcu_assign_pointer(sdata->u.ap.beacon, new);
 
        synchronize_rcu();
 
@@ -1033,7 +1033,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                return -EBUSY;
                        }
 
-                       RCU_INIT_POINTER(vlansdata->u.vlan.sta, sta);
+                       rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
                }
 
                sta->sdata = vlansdata;
index f8a32bf98216c1bb40dadf82bfa67153a349ec9f..b3d76b756cd55e4c8e513bfa506c336ab77e667b 100644 (file)
@@ -207,7 +207,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                *pos++ = 0; /* U-APSD no in use */
        }
 
-       RCU_INIT_POINTER(ifibss->presp, skb);
+       rcu_assign_pointer(ifibss->presp, skb);
 
        sdata->vif.bss_conf.beacon_int = beacon_int;
        sdata->vif.bss_conf.basic_rates = basic_rates;
index b197136aea2c1d67d5223d58d248e6de7fbccb3f..3c428d4839c7c5cca61ba535197068f3b5c10dbd 100644 (file)
@@ -73,7 +73,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
        if (!s)
                return -ENOENT;
        if (s == sta) {
-               RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)],
+               rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)],
                                   s->hnext);
                return 0;
        }
@@ -83,7 +83,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
                s = rcu_dereference_protected(s->hnext,
                                        lockdep_is_held(&local->sta_mtx));
        if (rcu_access_pointer(s->hnext)) {
-               RCU_INIT_POINTER(s->hnext, sta->hnext);
+               rcu_assign_pointer(s->hnext, sta->hnext);
                return 0;
        }
 
@@ -226,7 +226,7 @@ static void sta_info_hash_add(struct ieee80211_local *local,
 {
        lockdep_assert_held(&local->sta_mtx);
        sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
-       RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+       rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
 }
 
 static void sta_unblock(struct work_struct *wk)
index 93aab0715e8ab6f63f4b4f35dde067c0caa023cd..422b79851ec510ef4272f9f2565bb56a0e002aef 100644 (file)
@@ -106,7 +106,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
                if (status->flag & RX_FLAG_MMIC_ERROR)
                        goto mic_fail;
 
-               if (!(status->flag & RX_FLAG_IV_STRIPPED))
+               if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key)
                        goto update_iv;
 
                return RX_CONTINUE;
index e875f8902db3e7224b566e88e7bb82a73646a24f..76613f5a55c0c557920c1f52f2d67a20c0934eda 100644 (file)
@@ -777,7 +777,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                if (exp->helper) {
                        help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
                        if (help)
-                               RCU_INIT_POINTER(help->helper, exp->helper);
+                               rcu_assign_pointer(help->helper, exp->helper);
                }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
index b62c4148b92131444f6e132cb55a058991d68379..14af6329bdda21843ada4be624093e1ac6f980fb 100644 (file)
@@ -91,7 +91,7 @@ int nf_conntrack_register_notifier(struct net *net,
                ret = -EBUSY;
                goto out_unlock;
        }
-       RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, new);
+       rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
        mutex_unlock(&nf_ct_ecache_mutex);
        return ret;
 
@@ -128,7 +128,7 @@ int nf_ct_expect_register_notifier(struct net *net,
                ret = -EBUSY;
                goto out_unlock;
        }
-       RCU_INIT_POINTER(net->ct.nf_expect_event_cb, new);
+       rcu_assign_pointer(net->ct.nf_expect_event_cb, new);
        mutex_unlock(&nf_ct_ecache_mutex);
        return ret;
 
index 4605c947dcc49e751478aaffb816e17470998185..641ff5f967186676a0f99f14b70cb68201038fb9 100644 (file)
@@ -169,7 +169,7 @@ int nf_ct_extend_register(struct nf_ct_ext_type *type)
           before updating alloc_size */
        type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
                           + type->len;
-       RCU_INIT_POINTER(nf_ct_ext_types[type->id], type);
+       rcu_assign_pointer(nf_ct_ext_types[type->id], type);
        update_alloc_size(type);
 out:
        mutex_unlock(&nf_ct_ext_type_mutex);
index c9e0de08aa872bcbd61a4bf0b8171669a632a914..299fec91f74189a562f7fcb0d47914d9b279c286 100644 (file)
@@ -157,7 +157,7 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
                memset(&help->help, 0, sizeof(help->help));
        }
 
-       RCU_INIT_POINTER(help->helper, helper);
+       rcu_assign_pointer(help->helper, helper);
 out:
        return ret;
 }
index e07dc3ae930ea3a2aa3947eb841e47a3cb23173f..2a4834b83332afa2ebf87b37102cd2a9d6dcd8d1 100644 (file)
@@ -1172,7 +1172,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
                return -EOPNOTSUPP;
        }
 
-       RCU_INIT_POINTER(help->helper, helper);
+       rcu_assign_pointer(help->helper, helper);
 
        return 0;
 }
index ce0c406f58a8b645cc4500c85dfad2008d0db70d..957374a234d410bbf87bee24f3fee4428a5ff678 100644 (file)
@@ -55,7 +55,7 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
                llog = rcu_dereference_protected(nf_loggers[pf],
                                                 lockdep_is_held(&nf_log_mutex));
                if (llog == NULL)
-                       RCU_INIT_POINTER(nf_loggers[pf], logger);
+                       rcu_assign_pointer(nf_loggers[pf], logger);
        }
 
        mutex_unlock(&nf_log_mutex);
@@ -92,7 +92,7 @@ int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
                mutex_unlock(&nf_log_mutex);
                return -ENOENT;
        }
-       RCU_INIT_POINTER(nf_loggers[pf], logger);
+       rcu_assign_pointer(nf_loggers[pf], logger);
        mutex_unlock(&nf_log_mutex);
        return 0;
 }
@@ -250,7 +250,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
                        mutex_unlock(&nf_log_mutex);
                        return -ENOENT;
                }
-               RCU_INIT_POINTER(nf_loggers[tindex], logger);
+               rcu_assign_pointer(nf_loggers[tindex], logger);
                mutex_unlock(&nf_log_mutex);
        } else {
                mutex_lock(&nf_log_mutex);
index 99ffd2885088fc3606270984386713b959b75285..b3a7db678b8dddf12e9495630e0e051a0b78cfe9 100644 (file)
@@ -40,7 +40,7 @@ int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh)
        else if (old)
                ret = -EBUSY;
        else {
-               RCU_INIT_POINTER(queue_handler[pf], qh);
+               rcu_assign_pointer(queue_handler[pf], qh);
                ret = 0;
        }
        mutex_unlock(&queue_handler_mutex);
index c879c1a2370e46829c442095b98a58ce705d78b3..b4f8d849480cfb9a6cffa57063a54b5152dfce75 100644 (file)
@@ -59,7 +59,7 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
                nfnl_unlock();
                return -EBUSY;
        }
-       RCU_INIT_POINTER(subsys_table[n->subsys_id], n);
+       rcu_assign_pointer(subsys_table[n->subsys_id], n);
        nfnl_unlock();
 
        return 0;
@@ -210,7 +210,7 @@ static int __net_init nfnetlink_net_init(struct net *net)
        if (!nfnl)
                return -ENOMEM;
        net->nfnl_stash = nfnl;
-       RCU_INIT_POINTER(net->nfnl, nfnl);
+       rcu_assign_pointer(net->nfnl, nfnl);
        return 0;
 }
 
index 38204112b9f4a0faec6e629e3431359c17033b38..d8d42433755051023320299f919f69db9e58ec29 100644 (file)
@@ -282,7 +282,7 @@ int __init netlbl_domhsh_init(u32 size)
                INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
 
        spin_lock(&netlbl_domhsh_lock);
-       RCU_INIT_POINTER(netlbl_domhsh, hsh_tbl);
+       rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
        spin_unlock(&netlbl_domhsh_lock);
 
        return 0;
@@ -330,7 +330,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                    &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
                } else {
                        INIT_LIST_HEAD(&entry->list);
-                       RCU_INIT_POINTER(netlbl_domhsh_def, entry);
+                       rcu_assign_pointer(netlbl_domhsh_def, entry);
                }
 
                if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
index 4b5fa0fe78fd36a3e4055328535ffa3283eae642..e7ff694f1049be48b3193d4a0b3ffded63aecbcd 100644 (file)
@@ -354,7 +354,7 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
                INIT_LIST_HEAD(&iface->list);
                if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)
                        goto add_iface_failure;
-               RCU_INIT_POINTER(netlbl_unlhsh_def, iface);
+               rcu_assign_pointer(netlbl_unlhsh_def, iface);
        }
        spin_unlock(&netlbl_unlhsh_lock);
 
@@ -1447,11 +1447,9 @@ int __init netlbl_unlabel_init(u32 size)
        for (iter = 0; iter < hsh_tbl->size; iter++)
                INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
 
-       rcu_read_lock();
        spin_lock(&netlbl_unlhsh_lock);
-       RCU_INIT_POINTER(netlbl_unlhsh, hsh_tbl);
+       rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);
        spin_unlock(&netlbl_unlhsh_lock);
-       rcu_read_unlock();
 
        register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);
 
index bf10ea8fbbf95bd349d0f69f18527a524d5d3a9c..d65f699fbf343a98d788a8f49286c71dc4f7887f 100644 (file)
@@ -480,7 +480,7 @@ int __init_or_module phonet_proto_register(unsigned int protocol,
        if (proto_tab[protocol])
                err = -EBUSY;
        else
-               RCU_INIT_POINTER(proto_tab[protocol], pp);
+               rcu_assign_pointer(proto_tab[protocol], pp);
        mutex_unlock(&proto_tab_lock);
 
        return err;
index c5827614376bd18c668a99d76b1b61f4b9f57011..9b9a85ecc4c79d70c88db78a12e5d54309e28d43 100644 (file)
@@ -390,7 +390,7 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
        daddr = daddr >> 2;
        mutex_lock(&routes->lock);
        if (routes->table[daddr] == NULL) {
-               RCU_INIT_POINTER(routes->table[daddr], dev);
+               rcu_assign_pointer(routes->table[daddr], dev);
                dev_hold(dev);
                err = 0;
        }
index 3f8d0b1603b98f5c1c2ad5105b6a3226c27df1f3..4c7eff30dfa9e4cc3bb54418e4dda44841b4d9be 100644 (file)
@@ -680,7 +680,7 @@ int pn_sock_bind_res(struct sock *sk, u8 res)
        mutex_lock(&resource_mutex);
        if (pnres.sk[res] == NULL) {
                sock_hold(sk);
-               RCU_INIT_POINTER(pnres.sk[res], sk);
+               rcu_assign_pointer(pnres.sk[res], sk);
                ret = 0;
        }
        mutex_unlock(&resource_mutex);
index 4e1de171866c7ab170297f1fcdf0878c2d8a5f62..a817705ce2d0e9246388c2c65d77b4c486a8feba 100644 (file)
@@ -477,17 +477,6 @@ void rds_iw_sync_mr(void *trans_private, int direction)
        }
 }
 
-static inline unsigned int rds_iw_flush_goal(struct rds_iw_mr_pool *pool, int free_all)
-{
-       unsigned int item_count;
-
-       item_count = atomic_read(&pool->item_count);
-       if (free_all)
-               return item_count;
-
-       return 0;
-}
-
 /*
  * Flush our pool of MRs.
  * At a minimum, all currently unused MRs are unmapped.
@@ -500,7 +489,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
        LIST_HEAD(unmap_list);
        LIST_HEAD(kill_list);
        unsigned long flags;
-       unsigned int nfreed = 0, ncleaned = 0, unpinned = 0, free_goal;
+       unsigned int nfreed = 0, ncleaned = 0, unpinned = 0;
        int ret = 0;
 
        rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
@@ -514,8 +503,6 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
                list_splice_init(&pool->clean_list, &kill_list);
        spin_unlock_irqrestore(&pool->list_lock, flags);
 
-       free_goal = rds_iw_flush_goal(pool, free_all);
-
        /* Batched invalidate of dirty MRs.
         * For FMR based MRs, the mappings on the unmap list are
         * actually members of an ibmr (ibmr->mapping). They either
index 0a7964009e8c99af197fb9454cf11e217fdf28bc..67494aef9acf3c230aa80dd4d70d1369a5318c04 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/flow_keys.h>
+#include <net/red.h>
 
 
 /*     Stochastic Fairness Queuing algorithm.
@@ -108,24 +109,30 @@ struct sfq_slot {
        struct sfq_head dep; /* anchor in dep[] chains */
        unsigned short  hash; /* hash value (index in ht[]) */
        short           allot; /* credit for this slot */
+
+       unsigned int    backlog;
+       struct red_vars vars;
 };
 
 struct sfq_sched_data {
 /* frequently used fields */
        int             limit;          /* limit of total number of packets in this qdisc */
        unsigned int    divisor;        /* number of slots in hash table */
-       unsigned int    maxflows;       /* number of flows in flows array */
-       int             headdrop;
-       int             maxdepth;       /* limit of packets per flow */
+       u8              headdrop;
+       u8              maxdepth;       /* limit of packets per flow */
 
        u32             perturbation;
-       struct tcf_proto *filter_list;
-       sfq_index       cur_depth;      /* depth of longest slot */
+       u8              cur_depth;      /* depth of longest slot */
+       u8              flags;
        unsigned short  scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
-       struct sfq_slot *tail;          /* current slot in round */
+       struct tcf_proto *filter_list;
        sfq_index       *ht;            /* Hash table ('divisor' slots) */
        struct sfq_slot *slots;         /* Flows table ('maxflows' entries) */
 
+       struct red_parms *red_parms;
+       struct tc_sfqred_stats stats;
+       struct sfq_slot *tail;          /* current slot in round */
+
        struct sfq_head dep[SFQ_MAX_DEPTH + 1];
                                        /* Linked lists of slots, indexed by depth
                                         * dep[0] : list of unused flows
@@ -133,6 +140,7 @@ struct sfq_sched_data {
                                         * dep[X] : list of flows with X packets
                                         */
 
+       unsigned int    maxflows;       /* number of flows in flows array */
        int             perturb_period;
        unsigned int    quantum;        /* Allotment per round: MUST BE >= MTU */
        struct timer_list perturb_timer;
@@ -321,6 +329,7 @@ static unsigned int sfq_drop(struct Qdisc *sch)
 drop:
                skb = q->headdrop ? slot_dequeue_head(slot) : slot_dequeue_tail(slot);
                len = qdisc_pkt_len(skb);
+               slot->backlog -= len;
                sfq_dec(q, x);
                kfree_skb(skb);
                sch->q.qlen--;
@@ -341,6 +350,23 @@ drop:
        return 0;
 }
 
+/* Is ECN parameter configured */
+static int sfq_prob_mark(const struct sfq_sched_data *q)
+{
+       return q->flags & TC_RED_ECN;
+}
+
+/* Should packets over max threshold just be marked */
+static int sfq_hard_mark(const struct sfq_sched_data *q)
+{
+       return (q->flags & (TC_RED_ECN | TC_RED_HARDDROP)) == TC_RED_ECN;
+}
+
+static int sfq_headdrop(const struct sfq_sched_data *q)
+{
+       return q->headdrop;
+}
+
 static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
@@ -349,6 +375,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
+       struct sk_buff *head;
+       int delta;
 
        hash = sfq_classify(skb, sch, &ret);
        if (hash == 0) {
@@ -368,24 +396,75 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                q->ht[hash] = x;
                slot = &q->slots[x];
                slot->hash = hash;
+               slot->backlog = 0; /* should already be 0 anyway... */
+               red_set_vars(&slot->vars);
+               goto enqueue;
        }
+       if (q->red_parms) {
+               slot->vars.qavg = red_calc_qavg_no_idle_time(q->red_parms,
+                                                       &slot->vars,
+                                                       slot->backlog);
+               switch (red_action(q->red_parms,
+                                  &slot->vars,
+                                  slot->vars.qavg)) {
+               case RED_DONT_MARK:
+                       break;
 
-       if (slot->qlen >= q->maxdepth) {
-               struct sk_buff *head;
+               case RED_PROB_MARK:
+                       sch->qstats.overlimits++;
+                       if (sfq_prob_mark(q)) {
+                               /* We know we have at least one packet in queue */
+                               if (sfq_headdrop(q) &&
+                                   INET_ECN_set_ce(slot->skblist_next)) {
+                                       q->stats.prob_mark_head++;
+                                       break;
+                               }
+                               if (INET_ECN_set_ce(skb)) {
+                                       q->stats.prob_mark++;
+                                       break;
+                               }
+                       }
+                       q->stats.prob_drop++;
+                       goto congestion_drop;
+
+               case RED_HARD_MARK:
+                       sch->qstats.overlimits++;
+                       if (sfq_hard_mark(q)) {
+                               /* We know we have at least one packet in queue */
+                               if (sfq_headdrop(q) &&
+                                   INET_ECN_set_ce(slot->skblist_next)) {
+                                       q->stats.forced_mark_head++;
+                                       break;
+                               }
+                               if (INET_ECN_set_ce(skb)) {
+                                       q->stats.forced_mark++;
+                                       break;
+                               }
+                       }
+                       q->stats.forced_drop++;
+                       goto congestion_drop;
+               }
+       }
 
-               if (!q->headdrop)
+       if (slot->qlen >= q->maxdepth) {
+congestion_drop:
+               if (!sfq_headdrop(q))
                        return qdisc_drop(skb, sch);
 
+               /* We know we have at least one packet in queue */
                head = slot_dequeue_head(slot);
-               sch->qstats.backlog -= qdisc_pkt_len(head);
+               delta = qdisc_pkt_len(head) - qdisc_pkt_len(skb);
+               sch->qstats.backlog -= delta;
+               slot->backlog -= delta;
                qdisc_drop(head, sch);
 
-               sch->qstats.backlog += qdisc_pkt_len(skb);
                slot_queue_add(slot, skb);
                return NET_XMIT_CN;
        }
 
+enqueue:
        sch->qstats.backlog += qdisc_pkt_len(skb);
+       slot->backlog += qdisc_pkt_len(skb);
        slot_queue_add(slot, skb);
        sfq_inc(q, x);
        if (slot->qlen == 1) {          /* The flow is new */
@@ -396,6 +475,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                        slot->next = q->tail->next;
                        q->tail->next = x;
                }
+               /* We could use a bigger initial quantum for new flows */
                slot->allot = q->scaled_quantum;
        }
        if (++sch->q.qlen <= q->limit)
@@ -439,7 +519,7 @@ next_slot:
        qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
        sch->qstats.backlog -= qdisc_pkt_len(skb);
-
+       slot->backlog -= qdisc_pkt_len(skb);
        /* Is the slot empty? */
        if (slot->qlen == 0) {
                q->ht[slot->hash] = SFQ_EMPTY_SLOT;
@@ -490,6 +570,8 @@ static void sfq_rehash(struct Qdisc *sch)
                        sfq_dec(q, i);
                        __skb_queue_tail(&list, skb);
                }
+               slot->backlog = 0;
+               red_set_vars(&slot->vars);
                q->ht[slot->hash] = SFQ_EMPTY_SLOT;
        }
        q->tail = NULL;
@@ -514,6 +596,11 @@ drop:                              sch->qstats.backlog -= qdisc_pkt_len(skb);
                if (slot->qlen >= q->maxdepth)
                        goto drop;
                slot_queue_add(slot, skb);
+               if (q->red_parms)
+                       slot->vars.qavg = red_calc_qavg(q->red_parms,
+                                                       &slot->vars,
+                                                       slot->backlog);
+               slot->backlog += qdisc_pkt_len(skb);
                sfq_inc(q, x);
                if (slot->qlen == 1) {          /* The flow is new */
                        if (q->tail == NULL) {  /* It is the first flow */
@@ -552,6 +639,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        struct tc_sfq_qopt *ctl = nla_data(opt);
        struct tc_sfq_qopt_v1 *ctl_v1 = NULL;
        unsigned int qlen;
+       struct red_parms *p = NULL;
 
        if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
                return -EINVAL;
@@ -560,7 +648,11 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        if (ctl->divisor &&
            (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
                return -EINVAL;
-
+       if (ctl_v1 && ctl_v1->qth_min) {
+               p = kmalloc(sizeof(*p), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+       }
        sch_tree_lock(sch);
        if (ctl->quantum) {
                q->quantum = ctl->quantum;
@@ -576,6 +668,16 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        if (ctl_v1) {
                if (ctl_v1->depth)
                        q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
+               if (p) {
+                       swap(q->red_parms, p);
+                       red_set_parms(q->red_parms,
+                                     ctl_v1->qth_min, ctl_v1->qth_max,
+                                     ctl_v1->Wlog,
+                                     ctl_v1->Plog, ctl_v1->Scell_log,
+                                     NULL,
+                                     ctl_v1->max_P);
+               }
+               q->flags = ctl_v1->flags;
                q->headdrop = ctl_v1->headdrop;
        }
        if (ctl->limit) {
@@ -594,6 +696,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
                q->perturbation = net_random();
        }
        sch_tree_unlock(sch);
+       kfree(p);
        return 0;
 }
 
@@ -625,6 +728,7 @@ static void sfq_destroy(struct Qdisc *sch)
        del_timer_sync(&q->perturb_timer);
        sfq_free(q->ht);
        sfq_free(q->slots);
+       kfree(q->red_parms);
 }
 
 static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
@@ -683,6 +787,7 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
        struct sfq_sched_data *q = qdisc_priv(sch);
        unsigned char *b = skb_tail_pointer(skb);
        struct tc_sfq_qopt_v1 opt;
+       struct red_parms *p = q->red_parms;
 
        memset(&opt, 0, sizeof(opt));
        opt.v0.quantum  = q->quantum;
@@ -693,6 +798,17 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
        opt.depth       = q->maxdepth;
        opt.headdrop    = q->headdrop;
 
+       if (p) {
+               opt.qth_min     = p->qth_min >> p->Wlog;
+               opt.qth_max     = p->qth_max >> p->Wlog;
+               opt.Wlog        = p->Wlog;
+               opt.Plog        = p->Plog;
+               opt.Scell_log   = p->Scell_log;
+               opt.max_P       = p->max_P;
+       }
+       memcpy(&opt.stats, &q->stats, sizeof(opt.stats));
+       opt.flags       = q->flags;
+
        NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
        return skb->len;
@@ -747,15 +863,13 @@ static int sfq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
        sfq_index idx = q->ht[cl - 1];
        struct gnet_stats_queue qs = { 0 };
        struct tc_sfq_xstats xstats = { 0 };
-       struct sk_buff *skb;
 
        if (idx != SFQ_EMPTY_SLOT) {
                const struct sfq_slot *slot = &q->slots[idx];
 
                xstats.allot = slot->allot << SFQ_ALLOT_SHIFT;
                qs.qlen = slot->qlen;
-               slot_queue_walk(slot, skb)
-                       qs.backlog += qdisc_pkt_len(skb);
+               qs.backlog = slot->backlog;
        }
        if (gnet_stats_copy_queue(d, &qs) < 0)
                return -1;
index e56162cd65b053b7a86119737dd7ca91329573d7..28a96af484b421ee06fffbe87358c1811693c97f 100644 (file)
@@ -2492,7 +2492,7 @@ int sock_register(const struct net_proto_family *ops)
                                      lockdep_is_held(&net_family_lock)))
                err = -EEXIST;
        else {
-               RCU_INIT_POINTER(net_families[ops->family], ops);
+               rcu_assign_pointer(net_families[ops->family], ops);
                err = 0;
        }
        spin_unlock(&net_family_lock);
index e010a015d99671f27a22573a31eae75ae6cda955..1426ec3d0a531ecd4ec0b227c5f7aa22843a1750 100644 (file)
@@ -41,15 +41,17 @@ EXPORT_SYMBOL_GPL(rpc_lookup_cred);
 /*
  * Public call interface for looking up machine creds.
  */
-struct rpc_cred *rpc_lookup_machine_cred(void)
+struct rpc_cred *rpc_lookup_machine_cred(const char *service_name)
 {
        struct auth_cred acred = {
                .uid = RPC_MACHINE_CRED_USERID,
                .gid = RPC_MACHINE_CRED_GROUPID,
+               .principal = service_name,
                .machine_cred = 1,
        };
 
-       dprintk("RPC:       looking up machine cred\n");
+       dprintk("RPC:       looking up machine cred for service %s\n",
+                       service_name);
        return generic_auth.au_ops->lookup_cred(&generic_auth, &acred, 0);
 }
 EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred);
index afb56553dfe72d630aea0737020ff973a815f34f..affa631ac1abe3d42f75635a30e1f066dccbfb44 100644 (file)
@@ -122,7 +122,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
        if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
                return;
        gss_get_ctx(ctx);
-       RCU_INIT_POINTER(gss_cred->gc_ctx, ctx);
+       rcu_assign_pointer(gss_cred->gc_ctx, ctx);
        set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
        smp_mb__before_clear_bit();
        clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
@@ -392,7 +392,8 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
 }
 
 static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
-                               struct rpc_clnt *clnt, int machine_cred)
+                               struct rpc_clnt *clnt,
+                               const char *service_name)
 {
        struct gss_api_mech *mech = gss_msg->auth->mech;
        char *p = gss_msg->databuf;
@@ -407,12 +408,8 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
                p += len;
                gss_msg->msg.len += len;
        }
-       if (machine_cred) {
-               len = sprintf(p, "service=* ");
-               p += len;
-               gss_msg->msg.len += len;
-       } else if (!strcmp(clnt->cl_program->name, "nfs4_cb")) {
-               len = sprintf(p, "service=nfs ");
+       if (service_name != NULL) {
+               len = sprintf(p, "service=%s ", service_name);
                p += len;
                gss_msg->msg.len += len;
        }
@@ -429,17 +426,18 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
 }
 
 static void gss_encode_msg(struct gss_upcall_msg *gss_msg,
-                               struct rpc_clnt *clnt, int machine_cred)
+                               struct rpc_clnt *clnt,
+                               const char *service_name)
 {
        if (pipe_version == 0)
                gss_encode_v0_msg(gss_msg);
        else /* pipe_version == 1 */
-               gss_encode_v1_msg(gss_msg, clnt, machine_cred);
+               gss_encode_v1_msg(gss_msg, clnt, service_name);
 }
 
-static inline struct gss_upcall_msg *
-gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid, struct rpc_clnt *clnt,
-               int machine_cred)
+static struct gss_upcall_msg *
+gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
+               uid_t uid, const char *service_name)
 {
        struct gss_upcall_msg *gss_msg;
        int vers;
@@ -459,7 +457,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid, struct rpc_clnt *clnt,
        atomic_set(&gss_msg->count, 1);
        gss_msg->uid = uid;
        gss_msg->auth = gss_auth;
-       gss_encode_msg(gss_msg, clnt, machine_cred);
+       gss_encode_msg(gss_msg, clnt, service_name);
        return gss_msg;
 }
 
@@ -471,7 +469,7 @@ gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cr
        struct gss_upcall_msg *gss_new, *gss_msg;
        uid_t uid = cred->cr_uid;
 
-       gss_new = gss_alloc_msg(gss_auth, uid, clnt, gss_cred->gc_machine_cred);
+       gss_new = gss_alloc_msg(gss_auth, clnt, uid, gss_cred->gc_principal);
        if (IS_ERR(gss_new))
                return gss_new;
        gss_msg = gss_add_msg(gss_new);
@@ -995,7 +993,9 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
         */
        cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
        cred->gc_service = gss_auth->service;
-       cred->gc_machine_cred = acred->machine_cred;
+       cred->gc_principal = NULL;
+       if (acred->machine_cred)
+               cred->gc_principal = acred->principal;
        kref_get(&gss_auth->kref);
        return &cred->gc_base;
 
@@ -1030,7 +1030,12 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
        if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
                return 0;
 out:
-       if (acred->machine_cred != gss_cred->gc_machine_cred)
+       if (acred->principal != NULL) {
+               if (gss_cred->gc_principal == NULL)
+                       return 0;
+               return strcmp(acred->principal, gss_cred->gc_principal) == 0;
+       }
+       if (gss_cred->gc_principal != NULL)
                return 0;
        return rc->cr_uid == acred->uid;
 }
@@ -1104,7 +1109,8 @@ static int gss_renew_cred(struct rpc_task *task)
        struct rpc_auth *auth = oldcred->cr_auth;
        struct auth_cred acred = {
                .uid = oldcred->cr_uid,
-               .machine_cred = gss_cred->gc_machine_cred,
+               .principal = gss_cred->gc_principal,
+               .machine_cred = (gss_cred->gc_principal != NULL ? 1 : 0),
        };
        struct rpc_cred *new;
 
index 277ebd4bf095fd973af455363a2bf0fc476511bd..593f4c605305d7b0a51465ae42b09a7eaa6fcadd 100644 (file)
@@ -296,7 +296,7 @@ _copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len)
  * Copies data into an arbitrary memory location from an array of pages
  * The copy is assumed to be non-overlapping.
  */
-static void
+void
 _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
 {
        struct page **pgfrom;
@@ -324,6 +324,7 @@ _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
 
        } while ((len -= copy) != 0);
 }
+EXPORT_SYMBOL_GPL(_copy_from_pages);
 
 /*
  * xdr_shrink_bufhead
index b3d3cf8931cb9a3c055df2e497943ec2500cfc51..afeea32e04ad9ea1a0caa1adeabe83b940bc0c42 100644 (file)
@@ -2250,6 +2250,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
 };
 
 static int parse_station_flags(struct genl_info *info,
+                              enum nl80211_iftype iftype,
                               struct station_parameters *params)
 {
        struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
@@ -2283,8 +2284,33 @@ static int parse_station_flags(struct genl_info *info,
                             nla, sta_flags_policy))
                return -EINVAL;
 
-       params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
-       params->sta_flags_mask &= ~1;
+       /*
+        * Only allow certain flags for interface types so that
+        * other attributes are silently ignored. Remember that
+        * this is backward compatibility code with old userspace
+        * and shouldn't be hit in other cases anyway.
+        */
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                        BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+                                        BIT(NL80211_STA_FLAG_WME) |
+                                        BIT(NL80211_STA_FLAG_MFP);
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHORIZED) |
+                                        BIT(NL80211_STA_FLAG_TDLS_PEER);
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               params->sta_flags_mask = BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                        BIT(NL80211_STA_FLAG_MFP) |
+                                        BIT(NL80211_STA_FLAG_AUTHORIZED);
+       default:
+               return -EINVAL;
+       }
 
        for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
                if (flags[flag])
@@ -2585,7 +2611,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->change_station)
                return -EOPNOTSUPP;
 
-       if (parse_station_flags(info, &params))
+       if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
@@ -2731,7 +2757,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->add_station)
                return -EOPNOTSUPP;
 
-       if (parse_station_flags(info, &params))
+       if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
 
        switch (dev->ieee80211_ptr->iftype) {
index e0d747a2e80341eb736c4348212770c3db41c4ad..637f11a1e4df931e772baca8a9a68f1c9bcde2cb 100644 (file)
@@ -2927,7 +2927,7 @@ static int __net_init xfrm_user_net_init(struct net *net)
        if (nlsk == NULL)
                return -ENOMEM;
        net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
-       RCU_INIT_POINTER(net->xfrm.nlsk, nlsk);
+       rcu_assign_pointer(net->xfrm.nlsk, nlsk);
        return 0;
 }
 
index 8fda3b3f7be87c01958c80823aea23cc22c790bf..e3bfcbe8a520b63639b04115bf148fb4ddd144eb 100755 (executable)
@@ -227,7 +227,7 @@ our $Inline = qr{inline|__always_inline|noinline};
 our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
 our $Lval      = qr{$Ident(?:$Member)*};
 
-our $Constant  = qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};
+our $Constant  = qr{(?i:(?:[0-9]+|0x[0-9a-f]+)[ul]*)};
 our $Assignment        = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
 our $Compare    = qr{<=|>=|==|!=|<|>};
 our $Operators = qr{
@@ -315,7 +315,7 @@ sub build_types {
        $NonptrType     = qr{
                        (?:$Modifier\s+|const\s+)*
                        (?:
-                               (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+                               (?:typeof|__typeof__)\s*\([^\)]*\)|
                                (?:$typeTypedefs\b)|
                                (?:${all}\b)
                        )
@@ -334,6 +334,7 @@ our $match_balanced_parentheses = qr/(\((?:[^\(\)]+|(-1))*\))/;
 
 our $Typecast  = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
 our $LvalOrFunc        = qr{($Lval)\s*($match_balanced_parentheses{0,1})\s*};
+our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
 
 sub deparenthesize {
        my ($string) = @_;
@@ -676,6 +677,10 @@ sub ctx_statement_block {
                        if ($off >= $len) {
                                last;
                        }
+                       if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) {
+                               $level++;
+                               $type = '#';
+                       }
                }
                $p = $c;
                $c = substr($blk, $off, 1);
@@ -738,6 +743,13 @@ sub ctx_statement_block {
                                last;
                        }
                }
+               # Preprocessor commands end at the newline unless escaped.
+               if ($type eq '#' && $c eq "\n" && $p ne "\\") {
+                       $level--;
+                       $type = '';
+                       $off++;
+                       last;
+               }
                $off++;
        }
        # We are truly at the end, so shuffle to the next line.
@@ -1020,7 +1032,7 @@ sub annotate_values {
                } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
                        print "CAST($1)\n" if ($dbg_values > 1);
                        push(@av_paren_type, $type);
-                       $type = 'C';
+                       $type = 'c';
 
                } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
                        print "DECLARE($1)\n" if ($dbg_values > 1);
@@ -1212,7 +1224,9 @@ sub possible {
                        case|
                        else|
                        asm|__asm__|
-                       do
+                       do|
+                       \#|
+                       \#\#|
                )(?:\s|$)|
                ^(?:typedef|struct|enum)\b
            )}x;
@@ -1359,6 +1373,7 @@ sub process {
        my %suppress_ifbraces;
        my %suppress_whiletrailers;
        my %suppress_export;
+       my $suppress_statement = 0;
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -1468,6 +1483,7 @@ sub process {
                        %suppress_ifbraces = ();
                        %suppress_whiletrailers = ();
                        %suppress_export = ();
+                       $suppress_statement = 0;
                        next;
 
 # track the line number as we move through the hunk, note that
@@ -1504,9 +1520,11 @@ sub process {
                if ($line =~ /^diff --git.*?(\S+)$/) {
                        $realfile = $1;
                        $realfile =~ s@^([^/]*)/@@;
+                       $in_commit_log = 0;
                } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
                        $realfile = $1;
                        $realfile =~ s@^([^/]*)/@@;
+                       $in_commit_log = 0;
 
                        $p1_prefix = $1;
                        if (!$file && $tree && $p1_prefix ne '' &&
@@ -1546,7 +1564,8 @@ sub process {
                }
 
 # Check signature styles
-               if ($line =~ /^(\s*)($signature_tags)(\s*)(.*)/) {
+               if (!$in_header_lines &&
+                   $line =~ /^(\s*)($signature_tags)(\s*)(.*)/) {
                        my $space_before = $1;
                        my $sign_off = $2;
                        my $space_after = $3;
@@ -1623,7 +1642,7 @@ sub process {
 # Check if it's the start of a commit log
 # (not a header line and we haven't seen the patch filename)
                if ($in_header_lines && $realfile =~ /^$/ &&
-                   $rawline !~ /^(commit\b|from\b|\w+:).+$/i) {
+                   $rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i) {
                        $in_header_lines = 0;
                        $in_commit_log = 1;
                }
@@ -1655,19 +1674,26 @@ sub process {
 # Only applies when adding the entry originally, after that we do not have
 # sufficient context to determine whether it is indeed long enough.
                if ($realfile =~ /Kconfig/ &&
-                   $line =~ /\+\s*(?:---)?help(?:---)?$/) {
+                   $line =~ /.\s*config\s+/) {
                        my $length = 0;
                        my $cnt = $realcnt;
                        my $ln = $linenr + 1;
                        my $f;
+                       my $is_start = 0;
                        my $is_end = 0;
-                       while ($cnt > 0 && defined $lines[$ln - 1]) {
+                       for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) {
                                $f = $lines[$ln - 1];
                                $cnt-- if ($lines[$ln - 1] !~ /^-/);
                                $is_end = $lines[$ln - 1] =~ /^\+/;
-                               $ln++;
 
                                next if ($f =~ /^-/);
+
+                               if ($lines[$ln - 1] =~ /.\s*(?:bool|tristate)\s*\"/) {
+                                       $is_start = 1;
+                               } elsif ($lines[$ln - 1] =~ /.\s*(?:---)?help(?:---)?$/) {
+                                       $length = -1;
+                               }
+
                                $f =~ s/^.//;
                                $f =~ s/#.*//;
                                $f =~ s/^\s+//;
@@ -1679,8 +1705,8 @@ sub process {
                                $length++;
                        }
                        WARN("CONFIG_DESCRIPTION",
-                            "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_end && $length < 4);
-                       #print "is_end<$is_end> length<$length>\n";
+                            "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4);
+                       #print "is_start<$is_start> is_end<$is_end> length<$length>\n";
                }
 
                if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
@@ -1792,12 +1818,24 @@ sub process {
 # Check for potential 'bare' types
                my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
                    $realline_next);
-               if ($realcnt && $line =~ /.\s*\S/) {
+#print "LINE<$line>\n";
+               if ($linenr >= $suppress_statement &&
+                   $realcnt && $line =~ /.\s*\S/) {
                        ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
                                ctx_statement_block($linenr, $realcnt, 0);
                        $stat =~ s/\n./\n /g;
                        $cond =~ s/\n./\n /g;
 
+#print "linenr<$linenr> <$stat>\n";
+                       # If this statement has no statement boundaries within
+                       # it there is no point in retrying a statement scan
+                       # until we hit end of it.
+                       my $frag = $stat; $frag =~ s/;+\s*$//;
+                       if ($frag !~ /(?:{|;)/) {
+#print "skip<$line_nr_next>\n";
+                               $suppress_statement = $line_nr_next;
+                       }
+
                        # Find the real next line.
                        $realline_next = $line_nr_next;
                        if (defined $realline_next &&
@@ -1923,6 +1961,9 @@ sub process {
 
 # Check relative indent for conditionals and blocks.
                if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0)
+                                       if (!defined $stat);
                        my ($s, $c) = ($stat, $cond);
 
                        substr($s, 0, length($c), '');
@@ -2090,7 +2131,7 @@ sub process {
                        #   XXX(foo);
                        #   EXPORT_SYMBOL(something_foo);
                        my $name = $1;
-                       if ($stat =~ /^.([A-Z_]+)\s*\(\s*($Ident)/ &&
+                       if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
                            $name =~ /^${Ident}_$2/) {
 #print "FOO C name<$name>\n";
                                $suppress_export{$realline_next} = 1;
@@ -2168,8 +2209,9 @@ sub process {
 
 # * goes on variable not on type
                # (char*[ const])
-               if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
-                       my ($from, $to) = ($1, $1);
+               while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
+                       #print "AA<$1>\n";
+                       my ($from, $to) = ($2, $2);
 
                        # Should start with a space.
                        $to =~ s/^(\S)/ $1/;
@@ -2184,8 +2226,10 @@ sub process {
                                ERROR("POINTER_LOCATION",
                                      "\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
                        }
-               } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
-                       my ($from, $to, $ident) = ($1, $1, $2);
+               }
+               while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
+                       #print "BB<$1>\n";
+                       my ($from, $to, $ident) = ($2, $2, $3);
 
                        # Should start with a space.
                        $to =~ s/^(\S)/ $1/;
@@ -2568,7 +2612,7 @@ sub process {
                        # Flatten any parentheses
                        $value =~ s/\(/ \(/g;
                        $value =~ s/\)/\) /g;
-                       while ($value =~ s/\[[^\{\}]*\]/1/ ||
+                       while ($value =~ s/\[[^\[\]]*\]/1/ ||
                               $value !~ /(?:$Ident|-?$Constant)\s*
                                             $Compare\s*
                                             (?:$Ident|-?$Constant)/x &&
@@ -2593,28 +2637,6 @@ sub process {
                        }
                }
 
-# typecasts on min/max could be min_t/max_t
-               if ($line =~ /^\+(?:.*?)\b(min|max)\s*\($Typecast{0,1}($LvalOrFunc)\s*,\s*$Typecast{0,1}($LvalOrFunc)\s*\)/) {
-                       if (defined $2 || defined $8) {
-                               my $call = $1;
-                               my $cast1 = deparenthesize($2);
-                               my $arg1 = $3;
-                               my $cast2 = deparenthesize($8);
-                               my $arg2 = $9;
-                               my $cast;
-
-                               if ($cast1 ne "" && $cast2 ne "") {
-                                       $cast = "$cast1 or $cast2";
-                               } elsif ($cast1 ne "") {
-                                       $cast = $cast1;
-                               } else {
-                                       $cast = $cast2;
-                               }
-                               WARN("MINMAX",
-                                    "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr);
-                       }
-               }
-
 # Need a space before open parenthesis after if, while etc
                if ($line=~/\b(if|while|for|switch)\(/) {
                        ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr);
@@ -2623,6 +2645,9 @@ sub process {
 # Check for illegal assignment in if conditional -- and check for trailing
 # statements after the conditional.
                if ($line =~ /do\s*(?!{)/) {
+                       ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+                               ctx_statement_block($linenr, $realcnt, 0)
+                                       if (!defined $stat);
                        my ($stat_next) = ctx_statement_block($line_nr_next,
                                                $remain_next, $off_next);
                        $stat_next =~ s/\n./\n /g;
@@ -2778,47 +2803,13 @@ sub process {
                        my $cnt = $realcnt;
                        my ($off, $dstat, $dcond, $rest);
                        my $ctx = '';
-
-                       my $args = defined($1);
-
-                       # Find the end of the macro and limit our statement
-                       # search to that.
-                       while ($cnt > 0 && defined $lines[$ln - 1] &&
-                               $lines[$ln - 1] =~ /^(?:-|..*\\$)/)
-                       {
-                               $ctx .= $rawlines[$ln - 1] . "\n";
-                               $cnt-- if ($lines[$ln - 1] !~ /^-/);
-                               $ln++;
-                       }
-                       $ctx .= $rawlines[$ln - 1];
-
                        ($dstat, $dcond, $ln, $cnt, $off) =
-                               ctx_statement_block($linenr, $ln - $linenr + 1, 0);
+                               ctx_statement_block($linenr, $realcnt, 0);
+                       $ctx = $dstat;
                        #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
                        #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
 
-                       # Extract the remainder of the define (if any) and
-                       # rip off surrounding spaces, and trailing \'s.
-                       $rest = '';
-                       while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
-                               #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
-                               if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
-                                       $rest .= substr($lines[$ln - 1], $off) . "\n";
-                                       $cnt--;
-                               }
-                               $ln++;
-                               $off = 0;
-                       }
-                       $rest =~ s/\\\n.//g;
-                       $rest =~ s/^\s*//s;
-                       $rest =~ s/\s*$//s;
-
-                       # Clean up the original statement.
-                       if ($args) {
-                               substr($dstat, 0, length($dcond), '');
-                       } else {
-                               $dstat =~ s/^.\s*\#\s*define\s+$Ident\s*//;
-                       }
+                       $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
                        $dstat =~ s/$;//g;
                        $dstat =~ s/\\\n.//g;
                        $dstat =~ s/^\s*//s;
@@ -2827,7 +2818,7 @@ sub process {
                        # Flatten any parentheses and braces
                        while ($dstat =~ s/\([^\(\)]*\)/1/ ||
                               $dstat =~ s/\{[^\{\}]*\}/1/ ||
-                              $dstat =~ s/\[[^\{\}]*\]/1/)
+                              $dstat =~ s/\[[^\[\]]*\]/1/)
                        {
                        }
 
@@ -2844,23 +2835,32 @@ sub process {
                                ^\"|\"$
                        }x;
                        #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
-                       if ($rest ne '' && $rest ne ',') {
-                               if ($rest !~ /while\s*\(/ &&
-                                   $dstat !~ /$exceptions/)
-                               {
-                                       ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
-                                             "Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
+                       if ($dstat ne '' &&
+                           $dstat !~ /^(?:$Ident|-?$Constant),$/ &&                    # 10, // foo(),
+                           $dstat !~ /^(?:$Ident|-?$Constant);$/ &&                    # foo();
+                           $dstat !~ /^(?:$Ident|-?$Constant)$/ &&                     # 10 // foo()
+                           $dstat !~ /$exceptions/ &&
+                           $dstat !~ /^\.$Ident\s*=/ &&                                # .foo =
+                           $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ &&       # do {...} while (...); // do {...} while (...)
+                           $dstat !~ /^for\s*$Constant$/ &&                            # for (...)
+                           $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ &&   # for (...) bar()
+                           $dstat !~ /^do\s*{/ &&                                      # do {...
+                           $dstat !~ /^\({/)                                           # ({...
+                       {
+                               $ctx =~ s/\n*$//;
+                               my $herectx = $here . "\n";
+                               my $cnt = statement_rawlines($ctx);
+
+                               for (my $n = 0; $n < $cnt; $n++) {
+                                       $herectx .= raw_line($linenr, $n) . "\n";
                                }
 
-                       } elsif ($ctx !~ /;/) {
-                               if ($dstat ne '' &&
-                                   $dstat !~ /^(?:$Ident|-?$Constant)$/ &&
-                                   $dstat !~ /$exceptions/ &&
-                                   $dstat !~ /^\.$Ident\s*=/ &&
-                                   $dstat =~ /$Operators/)
-                               {
+                               if ($dstat =~ /;/) {
+                                       ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
+                                             "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
+                               } else {
                                        ERROR("COMPLEX_MACRO",
-                                             "Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+                                             "Macros with complex values should be enclosed in parenthesis\n" . "$herectx");
                                }
                        }
                }
@@ -3111,6 +3111,12 @@ sub process {
                             "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr);
                }
 
+# Check for __attribute__ format(printf, prefer __printf
+               if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
+                       WARN("PREFER_PRINTF",
+                            "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
+               }
+
 # check for sizeof(&)
                if ($line =~ /\bsizeof\s*\(\s*\&/) {
                        WARN("SIZEOF_ADDRESS",
@@ -3123,6 +3129,46 @@ sub process {
                             "Avoid line continuations in quoted strings\n" . $herecurr);
                }
 
+# Check for misused memsets
+               if (defined $stat &&
+                   $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
+
+                       my $ms_addr = $2;
+                       my $ms_val = $8;
+                       my $ms_size = $14;
+
+                       if ($ms_size =~ /^(0x|)0$/i) {
+                               ERROR("MEMSET",
+                                     "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n");
+                       } elsif ($ms_size =~ /^(0x|)1$/i) {
+                               WARN("MEMSET",
+                                    "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n");
+                       }
+               }
+
+# typecasts on min/max could be min_t/max_t
+               if (defined $stat &&
+                   $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
+                       if (defined $2 || defined $8) {
+                               my $call = $1;
+                               my $cast1 = deparenthesize($2);
+                               my $arg1 = $3;
+                               my $cast2 = deparenthesize($8);
+                               my $arg2 = $9;
+                               my $cast;
+
+                               if ($cast1 ne "" && $cast2 ne "") {
+                                       $cast = "$cast1 or $cast2";
+                               } elsif ($cast1 ne "") {
+                                       $cast = $cast1;
+                               } else {
+                                       $cast = $cast2;
+                               }
+                               WARN("MINMAX",
+                                    "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n");
+                       }
+               }
+
 # check for new externs in .c files.
                if ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
@@ -3294,12 +3340,6 @@ sub process {
                        WARN("EXPORTED_WORLD_WRITABLE",
                             "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
                }
-
-               # Check for memset with swapped arguments
-               if ($line =~ /memset.*\,(\ |)(0x|)0(\ |0|)\);/) {
-                       ERROR("MEMSET",
-                             "memset size is 3rd argument, not the second.\n" . $herecurr);
-               }
        }
 
        # If we have no input at all, then there is nothing to report on
index 4594f334105110fefba64883186a2cd546641a82..f32a04c4c5bc1c56a88e0f7fba3cb521aa997e52 100755 (executable)
@@ -95,7 +95,7 @@ my %VCS_cmds_git = (
     "execute_cmd" => \&git_execute_cmd,
     "available" => '(which("git") ne "") && (-d ".git")',
     "find_signers_cmd" =>
-       "git log --no-color --since=\$email_git_since " .
+       "git log --no-color --follow --since=\$email_git_since " .
            '--format="GitCommit: %H%n' .
                      'GitAuthor: %an <%ae>%n' .
                      'GitDate: %aD%n' .
index 363ab4666b173bbb79f31fbd5e634a6fff342703..296f17ff751b58173e22518a1829dcc28ad2a687 100644 (file)
@@ -774,6 +774,15 @@ static int do_spi_entry(const char *filename, struct spi_device_id *id,
        return 1;
 }
 
+/* Looks like: mcp:S */
+static int do_mcp_entry(const char *filename, struct mcp_device_id *id,
+                       char *alias)
+{
+       sprintf(alias, MCP_MODULE_PREFIX "%s", id->name);
+
+       return 1;
+}
+
 static const struct dmifield {
        const char *prefix;
        int field;
@@ -1095,6 +1104,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct spi_device_id), "spi",
                         do_spi_entry, mod);
+       else if (sym_is(symname, "__mod_mcp_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct mcp_device_id), "mcp",
+                        do_mcp_entry, mod);
        else if (sym_is(symname, "__mod_dmi_device_table"))
                do_table(symval, sym->st_size,
                         sizeof(struct dmi_system_id), "dmi",
index 96502b22b268626ee1496057dba45f16c5c2d2ed..f3fafedd798a9abc9734b1e80379b05fe3892daa 100644 (file)
@@ -133,7 +133,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
                struct aa_profile *profile = sa->aad.profile;
                pid_t pid;
                rcu_read_lock();
-               pid = tsk->real_parent->pid;
+               pid = rcu_dereference(tsk->real_parent)->pid;
                rcu_read_unlock();
                audit_log_format(ab, " parent=%d", pid);
                if (profile->ns != root_ns) {
index 2c0a0ff413991f2ab73480017db4d28e84eab3f2..d7f06f8b283721df6f450bff880aa6d87a40bb50 100644 (file)
@@ -670,7 +670,7 @@ static struct security_operations apparmor_ops = {
 
 static int param_set_aabool(const char *val, const struct kernel_param *kp);
 static int param_get_aabool(char *buffer, const struct kernel_param *kp);
-#define param_check_aabool(name, p) __param_check(name, p, int)
+#define param_check_aabool param_check_bool
 static struct kernel_param_ops param_ops_aabool = {
        .set = param_set_aabool,
        .get = param_get_aabool
@@ -678,7 +678,7 @@ static struct kernel_param_ops param_ops_aabool = {
 
 static int param_set_aauint(const char *val, const struct kernel_param *kp);
 static int param_get_aauint(char *buffer, const struct kernel_param *kp);
-#define param_check_aauint(name, p) __param_check(name, p, int)
+#define param_check_aauint param_check_uint
 static struct kernel_param_ops param_ops_aauint = {
        .set = param_set_aauint,
        .get = param_get_aauint
@@ -686,7 +686,7 @@ static struct kernel_param_ops param_ops_aauint = {
 
 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
-#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+#define param_check_aalockpolicy param_check_bool
 static struct kernel_param_ops param_ops_aalockpolicy = {
        .set = param_set_aalockpolicy,
        .get = param_get_aalockpolicy
index 90a70a67d8352aff1bc91e7f817a82bdcee3f5ce..43ce6e19015fc81e80786c26a07e2ac47e71109b 100644 (file)
 static struct vfsmount *mount;
 static int mount_count;
 
-/*
- * TODO:
- *   I think I can get rid of these default_file_ops, but not quite sure...
- */
-static ssize_t default_read_file(struct file *file, char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t default_write_file(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       return count;
-}
-
-static int default_open(struct inode *inode, struct file *file)
-{
-       if (inode->i_private)
-               file->private_data = inode->i_private;
-
-       return 0;
-}
-
-static const struct file_operations default_file_ops = {
-       .read =         default_read_file,
-       .write =        default_write_file,
-       .open =         default_open,
-       .llseek =       noop_llseek,
-};
-
-static struct inode *get_inode(struct super_block *sb, umode_t mode, dev_t dev)
-{
-       struct inode *inode = new_inode(sb);
-
-       if (inode) {
-               inode->i_ino = get_next_ino();
-               inode->i_mode = mode;
-               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-               switch (mode & S_IFMT) {
-               default:
-                       init_special_inode(inode, mode, dev);
-                       break;
-               case S_IFREG:
-                       inode->i_fop = &default_file_ops;
-                       break;
-               case S_IFDIR:
-                       inode->i_op = &simple_dir_inode_operations;
-                       inode->i_fop = &simple_dir_operations;
-
-                       /* directory inodes start off with i_nlink == 2 (for "." entry) */
-                       inc_nlink(inode);
-                       break;
-               }
-       }
-       return inode;
-}
-
-/* SMP-safe */
-static int mknod(struct inode *dir, struct dentry *dentry,
-                        umode_t mode, dev_t dev)
-{
-       struct inode *inode;
-       int error = -ENOMEM;
-
-       if (dentry->d_inode)
-               return -EEXIST;
-
-       inode = get_inode(dir->i_sb, mode, dev);
-       if (inode) {
-               d_instantiate(dentry, inode);
-               dget(dentry);
-               error = 0;
-       }
-       return error;
-}
-
-static int mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-       int res;
-
-       mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
-       res = mknod(dir, dentry, mode, 0);
-       if (!res)
-               inc_nlink(dir);
-       return res;
-}
-
-static int create(struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-       mode = (mode & S_IALLUGO) | S_IFREG;
-       return mknod(dir, dentry, mode, 0);
-}
-
 static inline int positive(struct dentry *dentry)
 {
        return dentry->d_inode && !d_unhashed(dentry);
@@ -145,38 +51,6 @@ static struct file_system_type fs_type = {
        .kill_sb =      kill_litter_super,
 };
 
-static int create_by_name(const char *name, umode_t mode,
-                         struct dentry *parent,
-                         struct dentry **dentry)
-{
-       int error = 0;
-
-       *dentry = NULL;
-
-       /* If the parent is not specified, we create it in the root.
-        * We need the root dentry to do this, which is in the super
-        * block. A pointer to that is in the struct vfsmount that we
-        * have around.
-        */
-       if (!parent)
-               parent = mount->mnt_root;
-
-       mutex_lock(&parent->d_inode->i_mutex);
-       *dentry = lookup_one_len(name, parent, strlen(name));
-       if (!IS_ERR(*dentry)) {
-               if (S_ISDIR(mode))
-                       error = mkdir(parent->d_inode, *dentry, mode);
-               else
-                       error = create(parent->d_inode, *dentry, mode);
-               if (error)
-                       dput(*dentry);
-       } else
-               error = PTR_ERR(*dentry);
-       mutex_unlock(&parent->d_inode->i_mutex);
-
-       return error;
-}
-
 /**
  * securityfs_create_file - create a file in the securityfs filesystem
  *
@@ -209,31 +83,66 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops)
 {
-       struct dentry *dentry = NULL;
+       struct dentry *dentry;
+       int is_dir = S_ISDIR(mode);
+       struct inode *dir, *inode;
        int error;
 
+       if (!is_dir) {
+               BUG_ON(!fops);
+               mode = (mode & S_IALLUGO) | S_IFREG;
+       }
+
        pr_debug("securityfs: creating file '%s'\n",name);
 
        error = simple_pin_fs(&fs_type, &mount, &mount_count);
-       if (error) {
-               dentry = ERR_PTR(error);
-               goto exit;
+       if (error)
+               return ERR_PTR(error);
+
+       if (!parent)
+               parent = mount->mnt_root;
+
+       dir = parent->d_inode;
+
+       mutex_lock(&dir->i_mutex);
+       dentry = lookup_one_len(name, parent, strlen(name));
+       if (IS_ERR(dentry))
+               goto out;
+
+       if (dentry->d_inode) {
+               error = -EEXIST;
+               goto out1;
        }
 
-       error = create_by_name(name, mode, parent, &dentry);
-       if (error) {
-               dentry = ERR_PTR(error);
-               simple_release_fs(&mount, &mount_count);
-               goto exit;
+       inode = new_inode(dir->i_sb);
+       if (!inode) {
+               error = -ENOMEM;
+               goto out1;
        }
 
-       if (dentry->d_inode) {
-               if (fops)
-                       dentry->d_inode->i_fop = fops;
-               if (data)
-                       dentry->d_inode->i_private = data;
+       inode->i_ino = get_next_ino();
+       inode->i_mode = mode;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_private = data;
+       if (is_dir) {
+               inode->i_op = &simple_dir_inode_operations;
+               inode->i_fop = &simple_dir_operations;
+               inc_nlink(inode);
+               inc_nlink(dir);
+       } else {
+               inode->i_fop = fops;
        }
-exit:
+       d_instantiate(dentry, inode);
+       dget(dentry);
+       mutex_unlock(&dir->i_mutex);
+       return dentry;
+
+out1:
+       dput(dentry);
+       dentry = ERR_PTR(error);
+out:
+       mutex_unlock(&dir->i_mutex);
+       simple_release_fs(&mount, &mount_count);
        return dentry;
 }
 EXPORT_SYMBOL_GPL(securityfs_create_file);
index 4bf00acf7937cf35afba531709841038b961b7c5..d384ea921482088dea0c7c13f54e2d3c57c18f26 100644 (file)
@@ -3,5 +3,19 @@ config INTEGRITY
        def_bool y
        depends on IMA || EVM
 
+config INTEGRITY_DIGSIG
+       boolean "Digital signature verification using multiple keyrings"
+       depends on INTEGRITY && KEYS
+       default n
+       select DIGSIG
+       help
+         This option enables digital signature verification support
+         using multiple keyrings. It defines separate keyrings for each
+         of the different use cases - evm, ima, and modules.
+         Different keyrings improves search performance, but also allow
+         to "lock" certain keyring to prevent adding new keys.
+         This is useful for evm and module keyrings, when keys are
+         usually only added from initramfs.
+
 source security/integrity/ima/Kconfig
 source security/integrity/evm/Kconfig
index 0ae44aea6516680f20bd1e513ab4c8d3a73f0b8d..bece0563ee5e019bc9fa56bd2dff4e426cf262b7 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_INTEGRITY) += integrity.o
+obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o
 
 integrity-y := iint.o
 
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
new file mode 100644 (file)
index 0000000..2dc167d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Intel Corporation
+ *
+ * Author:
+ * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/rbtree.h>
+#include <linux/key-type.h>
+#include <linux/digsig.h>
+
+#include "integrity.h"
+
+static struct key *keyring[INTEGRITY_KEYRING_MAX];
+
+static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
+       "_evm",
+       "_module",
+       "_ima",
+};
+
+int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
+                                       const char *digest, int digestlen)
+{
+       if (id >= INTEGRITY_KEYRING_MAX)
+               return -EINVAL;
+
+       if (!keyring[id]) {
+               keyring[id] =
+                       request_key(&key_type_keyring, keyring_name[id], NULL);
+               if (IS_ERR(keyring[id])) {
+                       int err = PTR_ERR(keyring[id]);
+                       pr_err("no %s keyring: %d\n", keyring_name[id], err);
+                       keyring[id] = NULL;
+                       return err;
+               }
+       }
+
+       return digsig_verify(keyring[id], sig, siglen, digest, digestlen);
+}
index d320f51974376219250efa3262a23488eacb76a0..c885247ebcf7d7b64c5f97ac0449e75488de317b 100644 (file)
  * File: evm.h
  *
  */
+
+#ifndef __INTEGRITY_EVM_H
+#define __INTEGRITY_EVM_H
+
 #include <linux/xattr.h>
 #include <linux/security.h>
+
 #include "../integrity.h"
 
 extern int evm_initialized;
 extern char *evm_hmac;
+extern char *evm_hash;
 
 extern struct crypto_shash *hmac_tfm;
+extern struct crypto_shash *hash_tfm;
 
 /* List of EVM protected security xattrs */
 extern char *evm_config_xattrnames[];
@@ -32,7 +39,12 @@ extern int evm_update_evmxattr(struct dentry *dentry,
 extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
                         const char *req_xattr_value,
                         size_t req_xattr_value_len, char *digest);
+extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+                        const char *req_xattr_value,
+                        size_t req_xattr_value_len, char *digest);
 extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
                         char *hmac_val);
 extern int evm_init_secfs(void);
 extern void evm_cleanup_secfs(void);
+
+#endif
index 8738deff26fadde6a6bf200972d0422193e4fdc9..49a464f5595b99f46a52da35bb331f546082b31f 100644 (file)
@@ -26,44 +26,56 @@ static unsigned char evmkey[MAX_KEY_SIZE];
 static int evmkey_len = MAX_KEY_SIZE;
 
 struct crypto_shash *hmac_tfm;
+struct crypto_shash *hash_tfm;
 
 static DEFINE_MUTEX(mutex);
 
-static struct shash_desc *init_desc(void)
+static struct shash_desc *init_desc(char type)
 {
-       int rc;
+       long rc;
+       char *algo;
+       struct crypto_shash **tfm;
        struct shash_desc *desc;
 
-       if (hmac_tfm == NULL) {
+       if (type == EVM_XATTR_HMAC) {
+               tfm = &hmac_tfm;
+               algo = evm_hmac;
+       } else {
+               tfm = &hash_tfm;
+               algo = evm_hash;
+       }
+
+       if (*tfm == NULL) {
                mutex_lock(&mutex);
-               if (hmac_tfm)
+               if (*tfm)
                        goto out;
-               hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
-               if (IS_ERR(hmac_tfm)) {
-                       pr_err("Can not allocate %s (reason: %ld)\n",
-                              evm_hmac, PTR_ERR(hmac_tfm));
-                       rc = PTR_ERR(hmac_tfm);
-                       hmac_tfm = NULL;
+               *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(*tfm)) {
+                       rc = PTR_ERR(*tfm);
+                       pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
+                       *tfm = NULL;
                        mutex_unlock(&mutex);
                        return ERR_PTR(rc);
                }
-               rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
-               if (rc) {
-                       crypto_free_shash(hmac_tfm);
-                       hmac_tfm = NULL;
-                       mutex_unlock(&mutex);
-                       return ERR_PTR(rc);
+               if (type == EVM_XATTR_HMAC) {
+                       rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
+                       if (rc) {
+                               crypto_free_shash(*tfm);
+                               *tfm = NULL;
+                               mutex_unlock(&mutex);
+                               return ERR_PTR(rc);
+                       }
                }
 out:
                mutex_unlock(&mutex);
        }
 
-       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+       desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
                        GFP_KERNEL);
        if (!desc)
                return ERR_PTR(-ENOMEM);
 
-       desc->tfm = hmac_tfm;
+       desc->tfm = *tfm;
        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
        rc = crypto_shash_init(desc);
@@ -108,9 +120,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
  * the hmac using the requested xattr value. Don't alloc/free memory for
  * each xattr, but attempt to re-use the previously allocated memory.
  */
-int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
-                 const char *req_xattr_value, size_t req_xattr_value_len,
-                 char *digest)
+static int evm_calc_hmac_or_hash(struct dentry *dentry,
+                               const char *req_xattr_name,
+                               const char *req_xattr_value,
+                               size_t req_xattr_value_len,
+                               char type, char *digest)
 {
        struct inode *inode = dentry->d_inode;
        struct shash_desc *desc;
@@ -122,7 +136,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
 
        if (!inode->i_op || !inode->i_op->getxattr)
                return -EOPNOTSUPP;
-       desc = init_desc();
+       desc = init_desc(type);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
@@ -156,6 +170,22 @@ out:
        return error;
 }
 
+int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+                 const char *req_xattr_value, size_t req_xattr_value_len,
+                 char *digest)
+{
+       return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+                               req_xattr_value_len, EVM_XATTR_HMAC, digest);
+}
+
+int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+                 const char *req_xattr_value, size_t req_xattr_value_len,
+                 char *digest)
+{
+       return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+                               req_xattr_value_len, IMA_XATTR_DIGEST, digest);
+}
+
 /*
  * Calculate the hmac and update security.evm xattr
  *
@@ -186,7 +216,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
 {
        struct shash_desc *desc;
 
-       desc = init_desc();
+       desc = init_desc(EVM_XATTR_HMAC);
        if (IS_ERR(desc)) {
                printk(KERN_INFO "init_desc failed\n");
                return PTR_ERR(desc);
index 92d3d99a9f7b8efd96a1659c5dbb170376c28908..8901501425f42beb8a0e23dade6b4e4200019bf1 100644 (file)
@@ -25,6 +25,7 @@
 int evm_initialized;
 
 char *evm_hmac = "hmac(sha1)";
+char *evm_hash = "sha1";
 
 char *evm_config_xattrnames[] = {
 #ifdef CONFIG_SECURITY_SELINUX
@@ -46,6 +47,29 @@ static int __init evm_set_fixmode(char *str)
 }
 __setup("evm=", evm_set_fixmode);
 
+static int evm_find_protected_xattrs(struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       char **xattr;
+       int error;
+       int count = 0;
+
+       if (!inode->i_op || !inode->i_op->getxattr)
+               return -EOPNOTSUPP;
+
+       for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
+               error = inode->i_op->getxattr(dentry, *xattr, NULL, 0);
+               if (error < 0) {
+                       if (error == -ENODATA)
+                               continue;
+                       return error;
+               }
+               count++;
+       }
+
+       return count;
+}
+
 /*
  * evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
  *
@@ -65,32 +89,72 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                                             size_t xattr_value_len,
                                             struct integrity_iint_cache *iint)
 {
-       struct evm_ima_xattr_data xattr_data;
+       struct evm_ima_xattr_data *xattr_data = NULL;
+       struct evm_ima_xattr_data calc;
        enum integrity_status evm_status = INTEGRITY_PASS;
-       int rc;
+       int rc, xattr_len;
 
        if (iint && iint->evm_status == INTEGRITY_PASS)
                return iint->evm_status;
 
        /* if status is not PASS, try to check again - against -ENOMEM */
 
-       rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
-                          xattr_value_len, xattr_data.digest);
-       if (rc < 0) {
-               evm_status = (rc == -ENODATA)
-                   ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+       /* first need to know the sig type */
+       rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
+                               GFP_NOFS);
+       if (rc <= 0) {
+               if (rc == 0)
+                       evm_status = INTEGRITY_FAIL; /* empty */
+               else if (rc == -ENODATA) {
+                       rc = evm_find_protected_xattrs(dentry);
+                       if (rc > 0)
+                               evm_status = INTEGRITY_NOLABEL;
+                       else if (rc == 0)
+                               evm_status = INTEGRITY_NOXATTRS; /* new file */
+               }
                goto out;
        }
 
-       xattr_data.type = EVM_XATTR_HMAC;
-       rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
-                          sizeof xattr_data, GFP_NOFS);
-       if (rc < 0)
-               evm_status = (rc == -ENODATA)
-                   ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
+       xattr_len = rc - 1;
+
+       /* check value type */
+       switch (xattr_data->type) {
+       case EVM_XATTR_HMAC:
+               rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+                                  xattr_value_len, calc.digest);
+               if (rc)
+                       break;
+               rc = memcmp(xattr_data->digest, calc.digest,
+                           sizeof(calc.digest));
+               if (rc)
+                       rc = -EINVAL;
+               break;
+       case EVM_IMA_XATTR_DIGSIG:
+               rc = evm_calc_hash(dentry, xattr_name, xattr_value,
+                               xattr_value_len, calc.digest);
+               if (rc)
+                       break;
+               rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
+                                       xattr_data->digest, xattr_len,
+                                       calc.digest, sizeof(calc.digest));
+               if (!rc) {
+                       /* we probably want to replace rsa with hmac here */
+                       evm_update_evmxattr(dentry, xattr_name, xattr_value,
+                                  xattr_value_len);
+               }
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       if (rc)
+               evm_status = (rc == -ENODATA) ?
+                               INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
 out:
        if (iint)
                iint->evm_status = evm_status;
+       kfree(xattr_data);
        return evm_status;
 }
 
@@ -354,6 +418,8 @@ static int __init init_evm(void)
                printk(KERN_INFO "EVM: Error registering secfs\n");
                goto err;
        }
+
+       return 0;
 err:
        return error;
 }
@@ -363,6 +429,8 @@ static void __exit cleanup_evm(void)
        evm_cleanup_secfs();
        if (hmac_tfm)
                crypto_free_shash(hmac_tfm);
+       if (hash_tfm)
+               crypto_free_shash(hash_tfm);
 }
 
 /*
index 0d50df04ccc469f6cab0e68323b7de9d915ca09e..88a2788b981d96ab543ac982c8935b09e56b26e3 100644 (file)
@@ -178,8 +178,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
        strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
 
        result = ima_store_template(entry, violation, inode);
-       if (!result)
+       if (!result || result == -EEXIST)
                iint->flags |= IMA_MEASURED;
-       else
+       if (result < 0)
                kfree(entry);
 }
index 8e28f04a5e2e8282d2bdd940393fda3a889e77cc..55a6271bce7ab7e0b87cd0ac250dd47ea68f9e23 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/slab.h>
 #include "ima.h"
 
+#define AUDIT_CAUSE_LEN_MAX 32
+
 LIST_HEAD(ima_measurements);   /* list of all measurements */
 
 /* key: inode (before secure-hashing a file) */
@@ -94,7 +96,8 @@ static int ima_pcr_extend(const u8 *hash)
 
        result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
        if (result != 0)
-               pr_err("IMA: Error Communicating to TPM chip\n");
+               pr_err("IMA: Error Communicating to TPM chip, result: %d\n",
+                      result);
        return result;
 }
 
@@ -106,14 +109,16 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 {
        u8 digest[IMA_DIGEST_SIZE];
        const char *audit_cause = "hash_added";
+       char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
        int audit_info = 1;
-       int result = 0;
+       int result = 0, tpmresult = 0;
 
        mutex_lock(&ima_extend_list_mutex);
        if (!violation) {
                memcpy(digest, entry->digest, sizeof digest);
                if (ima_lookup_digest_entry(digest)) {
                        audit_cause = "hash_exists";
+                       result = -EEXIST;
                        goto out;
                }
        }
@@ -128,9 +133,11 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
        if (violation)          /* invalidate pcr */
                memset(digest, 0xff, sizeof digest);
 
-       result = ima_pcr_extend(digest);
-       if (result != 0) {
-               audit_cause = "TPM error";
+       tpmresult = ima_pcr_extend(digest);
+       if (tpmresult != 0) {
+               snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
+                        tpmresult);
+               audit_cause = tpm_audit_cause;
                audit_info = 0;
        }
 out:
index 3143a3c39868061ef7ea0d94713f8b88df792498..4da6ba81d1532aa4690cc95b99ba682ddb0254b1 100644 (file)
@@ -46,5 +46,26 @@ struct integrity_iint_cache {
 struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
+#define INTEGRITY_KEYRING_EVM          0
+#define INTEGRITY_KEYRING_MODULE       1
+#define INTEGRITY_KEYRING_IMA          2
+#define INTEGRITY_KEYRING_MAX          3
+
+#ifdef CONFIG_INTEGRITY_DIGSIG
+
+int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
+                                       const char *digest, int digestlen);
+
+#else
+
+static inline int integrity_digsig_verify(const unsigned int id,
+                                         const char *sig, int siglen,
+                                         const char *digest, int digestlen)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_INTEGRITY_DIGSIG */
+
 /* set during initialization */
 extern int iint_initialized;
index 4414abddcb5bfd6951d168018990c6df2567b901..4f64c7267afb64332db0e6218754a8d17190c870 100644 (file)
@@ -291,6 +291,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 
        atomic_set(&key->usage, 1);
        init_rwsem(&key->sem);
+       lockdep_set_class(&key->sem, &type->lock_class);
        key->type = type;
        key->user = user;
        key->quotalen = quotalen;
@@ -946,6 +947,8 @@ int register_key_type(struct key_type *ktype)
        struct key_type *p;
        int ret;
 
+       memset(&ktype->lock_class, 0, sizeof(ktype->lock_class));
+
        ret = -EEXIST;
        down_write(&key_types_sem);
 
index f46658722c78d2b798a2d77634a08df968b2d0da..48a7d0014b4f4f5c4f40d92de9cb029bdf149d45 100644 (file)
@@ -749,14 +749,6 @@ out:
        return length;
 }
 
-static inline int hexcode_to_int(int code) {
-       if (code == '\0' || !isxdigit(code))
-               return -1;
-       if (isdigit(code))
-               return code - '0';
-       return tolower(code) - 'a' + 10;
-}
-
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
        char *scon = NULL, *tcon = NULL;
@@ -808,9 +800,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
                        if (c1 == '+')
                                c1 = ' ';
                        else if (c1 == '%') {
-                               if ((c1 = hexcode_to_int(*r++)) < 0)
+                               c1 = hex_to_bin(*r++);
+                               if (c1 < 0)
                                        goto out;
-                               if ((c2 = hexcode_to_int(*r++)) < 0)
+                               c2 = hex_to_bin(*r++);
+                               if (c2 < 0)
                                        goto out;
                                c1 = (c1 << 4) | c2;
                        }
index 2ec904177fe0bb65a522b110f642fd2f4ea0a5dd..377d148e715743250c9836b7a5ca6c1a05fa98e0 100644 (file)
@@ -175,7 +175,7 @@ void cond_policydb_destroy(struct policydb *p)
 int cond_init_bool_indexes(struct policydb *p)
 {
        kfree(p->bool_val_to_struct);
-       p->bool_val_to_struct = (struct cond_bool_datum **)
+       p->bool_val_to_struct =
                kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
        if (!p->bool_val_to_struct)
                return -ENOMEM;
diff --git a/security/tomoyo/.gitignore b/security/tomoyo/.gitignore
new file mode 100644 (file)
index 0000000..5caf1a6
--- /dev/null
@@ -0,0 +1,2 @@
+builtin-policy.h
+policy/
index deeab7be5b9747a93f57ac1024bf4c48792ccacc..9512222d558181d5b14be1c6716d9be5d42015f4 100644 (file)
@@ -1122,7 +1122,7 @@ static inline pid_t tomoyo_sys_getppid(void)
 {
        pid_t pid;
        rcu_read_lock();
-       pid = task_tgid_vnr(current->real_parent);
+       pid = task_tgid_vnr(rcu_dereference(current->real_parent));
        rcu_read_unlock();
        return pid;
 }
index 5d9411839cd7494c54586380ebf6262ebb633227..3a39626a82d627943d0cec0f891fe130e1d5b60e 100644 (file)
@@ -251,18 +251,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
        },
 };
 
-static int __init pxa2xx_ac97_init(void)
-{
-       return platform_driver_register(&pxa2xx_ac97_driver);
-}
-
-static void __exit pxa2xx_ac97_exit(void)
-{
-       platform_driver_unregister(&pxa2xx_ac97_driver);
-}
-
-module_init(pxa2xx_ac97_init);
-module_exit(pxa2xx_ac97_exit);
+module_platform_driver(pxa2xx_ac97_driver);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
index c15682a2f9dbd743db935ca682be3ba1a669bb63..ad409381f8cca21370f4802b1a5044af2f946b71 100644 (file)
@@ -154,6 +154,16 @@ config SND_DYNAMIC_MINORS
 
          If you are unsure about this, say N here.
 
+config SND_COMPRESS_OFFLOAD
+       tristate "ALSA Compressed audio offload support"
+       default n
+       help
+         If you want support for offloading compressed audio and have such
+         a hardware, then you should say Y here and also to the DSP driver
+         of your platform.
+
+         If you are unsure about this, say N here.
+
 config SND_SUPPORT_OLD_API
        bool "Support old ALSA API"
        default y
@@ -206,6 +216,9 @@ config SND_PCM_XRUN_DEBUG
 config SND_VMASTER
        bool
 
+config SND_KCTL_JACK
+       bool
+
 config SND_DMA_SGBUF
        def_bool y
        depends on X86
index 350a08d277f42ba41fd4c96ead6c7900c1ec9824..43d4117428ac9d551391f0f89d1edfd3b2665c6b 100644 (file)
@@ -7,6 +7,7 @@ snd-y     := sound.o init.o memory.o info.o control.o misc.o device.o
 snd-$(CONFIG_ISA_DMA_API) += isadma.o
 snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
 snd-$(CONFIG_SND_VMASTER) += vmaster.o
+snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o
 snd-$(CONFIG_SND_JACK)   += jack.o
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
@@ -21,6 +22,8 @@ snd-hrtimer-objs  := hrtimer.o
 snd-rtctimer-objs := rtctimer.o
 snd-hwdep-objs    := hwdep.o
 
+snd-compress-objs := compress_offload.o
+
 obj-$(CONFIG_SND)              += snd.o
 obj-$(CONFIG_SND_HWDEP)                += snd-hwdep.o
 obj-$(CONFIG_SND_TIMER)                += snd-timer.o
@@ -31,3 +34,5 @@ obj-$(CONFIG_SND_RAWMIDI)     += snd-rawmidi.o
 
 obj-$(CONFIG_SND_OSSEMUL)      += oss/
 obj-$(CONFIG_SND_SEQUENCER)    += seq/
+
+obj-$(CONFIG_SND_COMPRESS_OFFLOAD)     += snd-compress.o
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
new file mode 100644 (file)
index 0000000..dac3633
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ *  compress_core.c - compress offload core
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *             Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
+#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/uio.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+
+/* TODO:
+ * - add substream support for multiple devices in case of
+ *     SND_DYNAMIC_MINORS is not used
+ * - Multiple node representation
+ *     driver should be able to register multiple nodes
+ */
+
+static DEFINE_MUTEX(device_mutex);
+
+struct snd_compr_file {
+       unsigned long caps;
+       struct snd_compr_stream stream;
+};
+
+/*
+ * a note on stream states used:
+ * we use follwing states in the compressed core
+ * SNDRV_PCM_STATE_OPEN: When stream has been opened.
+ * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
+ *     calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
+ *     state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
+ * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
+ *     decoding/encoding and rendering/capturing data.
+ * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
+ *     by calling SNDRV_COMPRESS_DRAIN.
+ * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
+ *     SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
+ *     SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
+ */
+static int snd_compr_open(struct inode *inode, struct file *f)
+{
+       struct snd_compr *compr;
+       struct snd_compr_file *data;
+       struct snd_compr_runtime *runtime;
+       enum snd_compr_direction dirn;
+       int maj = imajor(inode);
+       int ret;
+
+       if (f->f_flags & O_WRONLY)
+               dirn = SND_COMPRESS_PLAYBACK;
+       else if (f->f_flags & O_RDONLY)
+               dirn = SND_COMPRESS_CAPTURE;
+       else {
+               pr_err("invalid direction\n");
+               return -EINVAL;
+       }
+
+       if (maj == snd_major)
+               compr = snd_lookup_minor_data(iminor(inode),
+                                       SNDRV_DEVICE_TYPE_COMPRESS);
+       else
+               return -EBADFD;
+
+       if (compr == NULL) {
+               pr_err("no device data!!!\n");
+               return -ENODEV;
+       }
+
+       if (dirn != compr->direction) {
+               pr_err("this device doesn't support this direction\n");
+               return -EINVAL;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       data->stream.ops = compr->ops;
+       data->stream.direction = dirn;
+       data->stream.private_data = compr->private_data;
+       data->stream.device = compr;
+       runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+       if (!runtime) {
+               kfree(data);
+               return -ENOMEM;
+       }
+       runtime->state = SNDRV_PCM_STATE_OPEN;
+       init_waitqueue_head(&runtime->sleep);
+       data->stream.runtime = runtime;
+       f->private_data = (void *)data;
+       mutex_lock(&compr->lock);
+       ret = compr->ops->open(&data->stream);
+       mutex_unlock(&compr->lock);
+       if (ret) {
+               kfree(runtime);
+               kfree(data);
+       }
+       return ret;
+}
+
+static int snd_compr_free(struct inode *inode, struct file *f)
+{
+       struct snd_compr_file *data = f->private_data;
+       data->stream.ops->free(&data->stream);
+       kfree(data->stream.runtime->buffer);
+       kfree(data->stream.runtime);
+       kfree(data);
+       return 0;
+}
+
+static void snd_compr_update_tstamp(struct snd_compr_stream *stream,
+               struct snd_compr_tstamp *tstamp)
+{
+       if (!stream->ops->pointer)
+               return;
+       stream->ops->pointer(stream, tstamp);
+       pr_debug("dsp consumed till %d total %d bytes\n",
+               tstamp->byte_offset, tstamp->copied_total);
+       stream->runtime->hw_pointer = tstamp->byte_offset;
+       stream->runtime->total_bytes_transferred = tstamp->copied_total;
+}
+
+static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
+               struct snd_compr_avail *avail)
+{
+       long avail_calc; /*this needs to be signed variable */
+
+       snd_compr_update_tstamp(stream, &avail->tstamp);
+
+       /* FIXME: This needs to be different for capture stream,
+          available is # of compressed data, for playback it's
+          remainder of buffer */
+
+       if (stream->runtime->total_bytes_available == 0 &&
+                       stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
+               pr_debug("detected init and someone forgot to do a write\n");
+               return stream->runtime->buffer_size;
+       }
+       pr_debug("app wrote %lld, DSP consumed %lld\n",
+                       stream->runtime->total_bytes_available,
+                       stream->runtime->total_bytes_transferred);
+       if (stream->runtime->total_bytes_available ==
+                               stream->runtime->total_bytes_transferred) {
+               pr_debug("both pointers are same, returning full avail\n");
+               return stream->runtime->buffer_size;
+       }
+
+       /* FIXME: this routine isn't consistent, in one test we use
+        * cumulative values and in the other byte offsets. Do we
+        * really need the byte offsets if the cumulative values have
+        * been updated? In the PCM interface app_ptr and hw_ptr are
+        * already cumulative */
+
+       avail_calc = stream->runtime->buffer_size -
+               (stream->runtime->app_pointer - stream->runtime->hw_pointer);
+       pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc,
+                       stream->runtime->app_pointer,
+                       stream->runtime->hw_pointer);
+       if (avail_calc >= stream->runtime->buffer_size)
+               avail_calc -= stream->runtime->buffer_size;
+       pr_debug("ret avail as %ld\n", avail_calc);
+       avail->avail = avail_calc;
+       return avail_calc;
+}
+
+static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
+{
+       struct snd_compr_avail avail;
+
+       return snd_compr_calc_avail(stream, &avail);
+}
+
+static int
+snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_compr_avail ioctl_avail;
+       size_t avail;
+
+       avail = snd_compr_calc_avail(stream, &ioctl_avail);
+       ioctl_avail.avail = avail;
+
+       if (copy_to_user((__u64 __user *)arg,
+                               &ioctl_avail, sizeof(ioctl_avail)))
+               return -EFAULT;
+       return 0;
+}
+
+static int snd_compr_write_data(struct snd_compr_stream *stream,
+              const char __user *buf, size_t count)
+{
+       void *dstn;
+       size_t copy;
+       struct snd_compr_runtime *runtime = stream->runtime;
+
+       dstn = runtime->buffer + runtime->app_pointer;
+       pr_debug("copying %ld at %lld\n",
+                       (unsigned long)count, runtime->app_pointer);
+       if (count < runtime->buffer_size - runtime->app_pointer) {
+               if (copy_from_user(dstn, buf, count))
+                       return -EFAULT;
+               runtime->app_pointer += count;
+       } else {
+               copy = runtime->buffer_size - runtime->app_pointer;
+               if (copy_from_user(dstn, buf, copy))
+                       return -EFAULT;
+               if (copy_from_user(runtime->buffer, buf + copy, count - copy))
+                       return -EFAULT;
+               runtime->app_pointer = count - copy;
+       }
+       /* if DSP cares, let it know data has been written */
+       if (stream->ops->ack)
+               stream->ops->ack(stream, count);
+       return count;
+}
+
+static ssize_t snd_compr_write(struct file *f, const char __user *buf,
+               size_t count, loff_t *offset)
+{
+       struct snd_compr_file *data = f->private_data;
+       struct snd_compr_stream *stream;
+       size_t avail;
+       int retval;
+
+       if (snd_BUG_ON(!data))
+               return -EFAULT;
+
+       stream = &data->stream;
+       mutex_lock(&stream->device->lock);
+       /* write is allowed when stream is running or has been steup */
+       if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
+                       stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
+               mutex_unlock(&stream->device->lock);
+               return -EBADFD;
+       }
+
+       avail = snd_compr_get_avail(stream);
+       pr_debug("avail returned %ld\n", (unsigned long)avail);
+       /* calculate how much we can write to buffer */
+       if (avail > count)
+               avail = count;
+
+       if (stream->ops->copy)
+               retval = stream->ops->copy(stream, buf, avail);
+       else
+               retval = snd_compr_write_data(stream, buf, avail);
+       if (retval > 0)
+               stream->runtime->total_bytes_available += retval;
+
+       /* while initiating the stream, write should be called before START
+        * call, so in setup move state */
+       if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
+               stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+               pr_debug("stream prepared, Houston we are good to go\n");
+       }
+
+       mutex_unlock(&stream->device->lock);
+       return retval;
+}
+
+
+static ssize_t snd_compr_read(struct file *f, char __user *buf,
+               size_t count, loff_t *offset)
+{
+       return -ENXIO;
+}
+
+static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
+{
+       return -ENXIO;
+}
+
+static inline int snd_compr_get_poll(struct snd_compr_stream *stream)
+{
+       if (stream->direction == SND_COMPRESS_PLAYBACK)
+               return POLLOUT | POLLWRNORM;
+       else
+               return POLLIN | POLLRDNORM;
+}
+
+static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
+{
+       struct snd_compr_file *data = f->private_data;
+       struct snd_compr_stream *stream;
+       size_t avail;
+       int retval = 0;
+
+       if (snd_BUG_ON(!data))
+               return -EFAULT;
+       stream = &data->stream;
+       if (snd_BUG_ON(!stream))
+               return -EFAULT;
+
+       mutex_lock(&stream->device->lock);
+       if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED ||
+                       stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+               retval = -EBADFD;
+               goto out;
+       }
+       poll_wait(f, &stream->runtime->sleep, wait);
+
+       avail = snd_compr_get_avail(stream);
+       pr_debug("avail is %ld\n", (unsigned long)avail);
+       /* check if we have at least one fragment to fill */
+       switch (stream->runtime->state) {
+       case SNDRV_PCM_STATE_DRAINING:
+               /* stream has been woken up after drain is complete
+                * draining done so set stream state to stopped
+                */
+               retval = snd_compr_get_poll(stream);
+               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+               break;
+       case SNDRV_PCM_STATE_RUNNING:
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_PAUSED:
+               if (avail >= stream->runtime->fragment_size)
+                       retval = snd_compr_get_poll(stream);
+               break;
+       default:
+               if (stream->direction == SND_COMPRESS_PLAYBACK)
+                       retval = POLLOUT | POLLWRNORM | POLLERR;
+               else
+                       retval = POLLIN | POLLRDNORM | POLLERR;
+               break;
+       }
+out:
+       mutex_unlock(&stream->device->lock);
+       return retval;
+}
+
+static int
+snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+       int retval;
+       struct snd_compr_caps caps;
+
+       if (!stream->ops->get_caps)
+               return -ENXIO;
+
+       retval = stream->ops->get_caps(stream, &caps);
+       if (retval)
+               goto out;
+       if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
+               retval = -EFAULT;
+out:
+       return retval;
+}
+
+static int
+snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+{
+       int retval;
+       struct snd_compr_codec_caps *caps;
+
+       if (!stream->ops->get_codec_caps)
+               return -ENXIO;
+
+       caps = kmalloc(sizeof(*caps), GFP_KERNEL);
+       if (!caps)
+               return -ENOMEM;
+
+       retval = stream->ops->get_codec_caps(stream, caps);
+       if (retval)
+               goto out;
+       if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
+               retval = -EFAULT;
+
+out:
+       kfree(caps);
+       return retval;
+}
+
+/* revisit this with snd_pcm_preallocate_xxx */
+static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
+               struct snd_compr_params *params)
+{
+       unsigned int buffer_size;
+       void *buffer;
+
+       buffer_size = params->buffer.fragment_size * params->buffer.fragments;
+       if (stream->ops->copy) {
+               buffer = NULL;
+               /* if copy is defined the driver will be required to copy
+                * the data from core
+                */
+       } else {
+               buffer = kmalloc(buffer_size, GFP_KERNEL);
+               if (!buffer)
+                       return -ENOMEM;
+       }
+       stream->runtime->fragment_size = params->buffer.fragment_size;
+       stream->runtime->fragments = params->buffer.fragments;
+       stream->runtime->buffer = buffer;
+       stream->runtime->buffer_size = buffer_size;
+       return 0;
+}
+
+static int
+snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_compr_params *params;
+       int retval;
+
+       if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+               /*
+                * we should allow parameter change only when stream has been
+                * opened not in other cases
+                */
+               params = kmalloc(sizeof(*params), GFP_KERNEL);
+               if (!params)
+                       return -ENOMEM;
+               if (copy_from_user(params, (void __user *)arg, sizeof(*params)))
+                       return -EFAULT;
+               retval = snd_compr_allocate_buffer(stream, params);
+               if (retval) {
+                       kfree(params);
+                       return -ENOMEM;
+               }
+               retval = stream->ops->set_params(stream, params);
+               if (retval)
+                       goto out;
+               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+       } else
+               return -EPERM;
+out:
+       kfree(params);
+       return retval;
+}
+
+static int
+snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_codec *params;
+       int retval;
+
+       if (!stream->ops->get_params)
+               return -EBADFD;
+
+       params = kmalloc(sizeof(*params), GFP_KERNEL);
+       if (!params)
+               return -ENOMEM;
+       retval = stream->ops->get_params(stream, params);
+       if (retval)
+               goto out;
+       if (copy_to_user((char __user *)arg, params, sizeof(*params)))
+               retval = -EFAULT;
+
+out:
+       kfree(params);
+       return retval;
+}
+
+static inline int
+snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
+{
+       struct snd_compr_tstamp tstamp;
+
+       snd_compr_update_tstamp(stream, &tstamp);
+       return copy_to_user((struct snd_compr_tstamp __user *)arg,
+               &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
+}
+
+static int snd_compr_pause(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+               return -EPERM;
+       retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+       if (!retval) {
+               stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+               wake_up(&stream->runtime->sleep);
+       }
+       return retval;
+}
+
+static int snd_compr_resume(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+               return -EPERM;
+       retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+       if (!retval)
+               stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+       return retval;
+}
+
+static int snd_compr_start(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
+               return -EPERM;
+       retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
+       if (!retval)
+               stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+       return retval;
+}
+
+static int snd_compr_stop(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+               return -EPERM;
+       retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
+       if (!retval) {
+               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+               wake_up(&stream->runtime->sleep);
+       }
+       return retval;
+}
+
+static int snd_compr_drain(struct snd_compr_stream *stream)
+{
+       int retval;
+
+       if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
+                       stream->runtime->state == SNDRV_PCM_STATE_SETUP)
+               return -EPERM;
+       retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
+       if (!retval) {
+               stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+               wake_up(&stream->runtime->sleep);
+       }
+       return retval;
+}
+
+static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+       struct snd_compr_file *data = f->private_data;
+       struct snd_compr_stream *stream;
+       int retval = -ENOTTY;
+
+       if (snd_BUG_ON(!data))
+               return -EFAULT;
+       stream = &data->stream;
+       if (snd_BUG_ON(!stream))
+               return -EFAULT;
+       mutex_lock(&stream->device->lock);
+       switch (_IOC_NR(cmd)) {
+       case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
+               put_user(SNDRV_COMPRESS_VERSION,
+                               (int __user *)arg) ? -EFAULT : 0;
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
+               retval = snd_compr_get_caps(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
+               retval = snd_compr_get_codec_caps(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
+               retval = snd_compr_set_params(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
+               retval = snd_compr_get_params(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
+               retval = snd_compr_tstamp(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_AVAIL):
+               retval = snd_compr_ioctl_avail(stream, arg);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_PAUSE):
+               retval = snd_compr_pause(stream);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_RESUME):
+               retval = snd_compr_resume(stream);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_START):
+               retval = snd_compr_start(stream);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_STOP):
+               retval = snd_compr_stop(stream);
+               break;
+       case _IOC_NR(SNDRV_COMPRESS_DRAIN):
+               retval = snd_compr_drain(stream);
+               break;
+       }
+       mutex_unlock(&stream->device->lock);
+       return retval;
+}
+
+static const struct file_operations snd_compr_file_ops = {
+               .owner =        THIS_MODULE,
+               .open =         snd_compr_open,
+               .release =      snd_compr_free,
+               .write =        snd_compr_write,
+               .read =         snd_compr_read,
+               .unlocked_ioctl = snd_compr_ioctl,
+               .mmap =         snd_compr_mmap,
+               .poll =         snd_compr_poll,
+};
+
+static int snd_compress_dev_register(struct snd_device *device)
+{
+       int ret = -EINVAL;
+       char str[16];
+       struct snd_compr *compr;
+
+       if (snd_BUG_ON(!device || !device->device_data))
+               return -EBADFD;
+       compr = device->device_data;
+
+       sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
+       pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
+                       compr->direction);
+       /* register compressed device */
+       ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+                       compr->device, &snd_compr_file_ops, compr, str);
+       if (ret < 0) {
+               pr_err("snd_register_device failed\n %d", ret);
+               return ret;
+       }
+       return ret;
+
+}
+
+static int snd_compress_dev_disconnect(struct snd_device *device)
+{
+       struct snd_compr *compr;
+
+       compr = device->device_data;
+       snd_unregister_device(compr->direction, compr->card, compr->device);
+       return 0;
+}
+
+/*
+ * snd_compress_new: create new compress device
+ * @card: sound card pointer
+ * @device: device number
+ * @dirn: device direction, should be of type enum snd_compr_direction
+ * @compr: compress device pointer
+ */
+int snd_compress_new(struct snd_card *card, int device,
+                       int dirn, struct snd_compr *compr)
+{
+       static struct snd_device_ops ops = {
+               .dev_free = NULL,
+               .dev_register = snd_compress_dev_register,
+               .dev_disconnect = snd_compress_dev_disconnect,
+       };
+
+       compr->card = card;
+       compr->device = device;
+       compr->direction = dirn;
+       return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
+}
+EXPORT_SYMBOL_GPL(snd_compress_new);
+
+static int snd_compress_add_device(struct snd_compr *device)
+{
+       int ret;
+
+       if (!device->card)
+               return -EINVAL;
+
+       /* register the card */
+       ret = snd_card_register(device->card);
+       if (ret)
+               goto out;
+       return 0;
+
+out:
+       pr_err("failed with %d\n", ret);
+       return ret;
+
+}
+
+static int snd_compress_remove_device(struct snd_compr *device)
+{
+       return snd_card_free(device->card);
+}
+
+/**
+ * snd_compress_register - register compressed device
+ *
+ * @device: compressed device to register
+ */
+int snd_compress_register(struct snd_compr *device)
+{
+       int retval;
+
+       if (device->name == NULL || device->dev == NULL || device->ops == NULL)
+               return -EINVAL;
+
+       pr_debug("Registering compressed device %s\n", device->name);
+       if (snd_BUG_ON(!device->ops->open))
+               return -EINVAL;
+       if (snd_BUG_ON(!device->ops->free))
+               return -EINVAL;
+       if (snd_BUG_ON(!device->ops->set_params))
+               return -EINVAL;
+       if (snd_BUG_ON(!device->ops->trigger))
+               return -EINVAL;
+
+       mutex_init(&device->lock);
+
+       /* register a compressed card */
+       mutex_lock(&device_mutex);
+       retval = snd_compress_add_device(device);
+       mutex_unlock(&device_mutex);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(snd_compress_register);
+
+int snd_compress_deregister(struct snd_compr *device)
+{
+       pr_debug("Removing compressed device %s\n", device->name);
+       mutex_lock(&device_mutex);
+       snd_compress_remove_device(device);
+       mutex_unlock(&device_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_compress_deregister);
+
+static int __init snd_compress_init(void)
+{
+       return 0;
+}
+
+static void __exit snd_compress_exit(void)
+{
+}
+
+module_init(snd_compress_init);
+module_exit(snd_compress_exit);
+
+MODULE_DESCRIPTION("ALSA Compressed offload framework");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c
new file mode 100644 (file)
index 0000000..e4b38fb
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Helper functions for jack-detection kcontrols
+ *
+ * Copyright (c) 2011 Takashi Iwai <tiwai@suse.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/kernel.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#define jack_detect_kctl_info  snd_ctl_boolean_mono_info
+
+static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = kcontrol->private_value;
+       return 0;
+}
+
+static struct snd_kcontrol_new jack_detect_kctl = {
+       /* name is filled later */
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .access = SNDRV_CTL_ELEM_ACCESS_READ,
+       .info = jack_detect_kctl_info,
+       .get = jack_detect_kctl_get,
+};
+
+struct snd_kcontrol *
+snd_kctl_jack_new(const char *name, int idx, void *private_data)
+{
+       struct snd_kcontrol *kctl;
+       kctl = snd_ctl_new1(&jack_detect_kctl, private_data);
+       if (!kctl)
+               return NULL;
+       snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name);
+       kctl->id.index = idx;
+       kctl->private_value = 0;
+       return kctl;
+}
+EXPORT_SYMBOL_GPL(snd_kctl_jack_new);
+
+void snd_kctl_jack_report(struct snd_card *card,
+                         struct snd_kcontrol *kctl, bool status)
+{
+       if (kctl->private_value == status)
+               return;
+       kctl->private_value = status;
+       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+}
+EXPORT_SYMBOL_GPL(snd_kctl_jack_report);
index 3cc4b86dfb7ebb97799e861bfd8db3bfd57b581e..08fde0060fd9377ee9f5e12dc1113858c73b3d20 100644 (file)
@@ -47,7 +47,7 @@
 
 static int dsp_map[SNDRV_CARDS];
 static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-static int nonblock_open = 1;
+static bool nonblock_open = 1;
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
index b9b2235d9ab1075115cd01dbce8abcbd266dcb2c..bbe32d2177d972f21bc25f8bc1784b6e886556c8 100644 (file)
@@ -65,7 +65,7 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
 
 static int ports = 1;
-static int duplex;
+static bool duplex;
 
 module_param(ports, int, 0444);
 MODULE_PARM_DESC(ports, "number of ports to be created");
index 828af353ea9f17f652d2c7ae154ed550c3c25845..28f35593a750464b87306a5c4355d98333856e36 100644 (file)
@@ -229,6 +229,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
        case SNDRV_DEVICE_TYPE_RAWMIDI:
        case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
        case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
+       case SNDRV_DEVICE_TYPE_COMPRESS:
                if (snd_BUG_ON(!card))
                        return -EINVAL;
                minor = SNDRV_MINOR(card->number, type + dev);
index d83bafc5d8b5c6b8395676c9eb5eaf9538ae7f0b..ad079b63b8bab170f6481112c568cfc7989b0294 100644 (file)
@@ -51,7 +51,7 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
 
 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 bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
 static int pcm_notify[SNDRV_CARDS];
 
index 97f1f93ed275d632344a7c9a9e47e57c6687e0c6..ad9434fd6370d87afef124954b6a0adb56736354 100644 (file)
@@ -60,15 +60,15 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
 
 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 bool 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};
 #ifdef CONFIG_HIGH_RES_TIMERS
-static int hrtimer = 1;
+static bool hrtimer = 1;
 #endif
-static int fake_buffer = 1;
+static bool fake_buffer = 1;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
index 2ee82c5d9ee54b609aec2bd1ff09cc7836b92a57..6c83b1aed288a8d8a7bb08bf142adf954218efe6 100644 (file)
@@ -73,7 +73,7 @@ MODULE_SUPPORTED_DEVICE("{{Xilinx,ML403 AC97 Controller Reference}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ML403 AC97 Controller Reference.");
@@ -1341,15 +1341,4 @@ static struct platform_driver snd_ml403_ac97cr_driver = {
        },
 };
 
-static int __init alsa_card_ml403_ac97cr_init(void)
-{
-       return platform_driver_register(&snd_ml403_ac97cr_driver);
-}
-
-static void __exit alsa_card_ml403_ac97cr_exit(void)
-{
-       platform_driver_unregister(&snd_ml403_ac97cr_driver);
-}
-
-module_init(alsa_card_ml403_ac97cr_init)
-module_exit(alsa_card_ml403_ac97cr_exit)
+module_platform_driver(snd_ml403_ac97cr_driver);
index 257569014f237162bfe605efd0c4ff208c6a6ea6..86f5fbc2da727fc08f5e4fe1c8b17a349b3f5dd7 100644 (file)
@@ -35,13 +35,13 @@ MODULE_LICENSE("GPL");
 
 static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 #ifdef CONFIG_PNP
-static int pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool pnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* MPU-401 port number */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* MPU-401 IRQ */
-static int uart_enter[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool uart_enter[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for MPU-401 device.");
index f24bf9a06cff385e7a8643817dd214582ad6c0a2..621e60e2029fe1a30a37ef2a576d7e5b4291272b 100644 (file)
@@ -36,7 +36,7 @@
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 static struct platform_device *platform_devices[SNDRV_CARDS]; 
 static int device_count;
index 7d722a025d0d7783d775c824a0076b8160b11304..2bfe4bcb7a7dd8b4b667895e9a96012197207230 100644 (file)
@@ -27,7 +27,7 @@
 
 extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
 
-extern int use_internal_drums;
+extern bool use_internal_drums;
 
 static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
                                     struct snd_midi_channel *chan);
index 723562e34fcc7414ab4b6ca7d918bca1015768b2..68399538e435ffbbd324175258bde0f3949827a2 100644 (file)
@@ -32,7 +32,7 @@ MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ALSA driver for OPL3 FM synth");
 
-int use_internal_drums = 0;
+bool use_internal_drums = 0;
 module_param(use_internal_drums, bool, 0444);
 MODULE_PARM_DESC(use_internal_drums, "Enable internal OPL2/3 drums.");
 
index 946a0cb996a9a09a1b71315fbbd17f1aa8b90602..99704e6a2e26eb634c4b3f776f54c7ec4bdc704c 100644 (file)
@@ -25,8 +25,8 @@ MODULE_ALIAS("platform:pcspkr");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int enable = SNDRV_DEFAULT_ENABLE1;     /* Enable this card */
-static int nopcm;      /* Disable PCM capability of the driver */
+static bool enable = SNDRV_DEFAULT_ENABLE1;    /* Enable this card */
+static bool nopcm;     /* Disable PCM capability of the driver */
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
index ce9e7d170c0dc09b6f1274ff9e91cd7ab5ea2826..434981dd4a611966b9c6f9d4e695ca23c58fb7a7 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/io.h>
 #include "pcsp.h"
 
-static int nforce_wa;
+static bool nforce_wa;
 module_param(nforce_wa, bool, 0444);
 MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
                "(expect bad sound)");
index f664823a9635873e8d5a4c268c47313a9457adea..3e32bd3d95d94afac88742c5d4168adbb3c5bee4 100644 (file)
@@ -55,7 +55,7 @@
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 static struct platform_device *platform_devices[SNDRV_CARDS]; 
 static int device_count;
index 85aad43f0b1efd04717b9cfa8b14971abdc199fd..b2d0e8e49bedd46852431ddea9caf7813c2c2e38 100644 (file)
@@ -69,7 +69,7 @@ static char *adaptor_names[] = {
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x3f8,0x2f8,0x3e8,0x2e8 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 3,4,5,7,9,10,11,14,15 */
 static int speed[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 38400}; /* 9600,19200,38400,57600,115200 */
@@ -77,7 +77,7 @@ static int base[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 115200}; /* baud bas
 static int outs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};         /* 1 to 16 */
 static int ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */
 static int adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS};
-static int droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF };
+static bool droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Serial MIDI.");
index d79d6edc0f52b50689d9d7cf21ead9353414d9b4..9d97478a18b32205ec5501326d15e8c09d16b58b 100644 (file)
@@ -63,7 +63,7 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual rawmidi device}}");
 
 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 bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
 static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
 
 module_param_array(index, int, NULL, 0444);
index cd44c74207d8e294f2d235dd398835be9fc5bb0e..94b83b6e46a3a97bef06e38be481159afe9b3c4e 100644 (file)
@@ -44,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{Highscreen,Sound-Boostar 16 3D},"
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 1-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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* 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 */
index 34ab69bdffc0cf2ea674875f9a1ec8083c4c7e84..2af77faefbb1734fc5822b3753fbf1c8b046eee3 100644 (file)
@@ -43,11 +43,11 @@ MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* PnP setup */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 5,7,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 0,1,3,5,6,7 */
-static int thinkpad[SNDRV_CARDS];                      /* Thinkpad special case */
+static bool thinkpad[SNDRV_CARDS];                     /* Thinkpad special case */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
index 7465ae036e0bd9e871ef632e03207e2347bf7b73..4d50c69f3290969f416333754a7798a91d9df1aa 100644 (file)
@@ -18,7 +18,7 @@ MODULE_LICENSE("GPL");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 
 module_param_array(index, int, NULL, 0444);
index fc5b38fd2652d402678692fb02be2e73d250fccc..d1f4351fb6ee31674b895cb1baa1869e1becd2b4 100644 (file)
@@ -54,7 +54,7 @@ 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 bool 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 */
index e55f3ebe87b9298fcec4b0dd0d04c2052b441141..6a2c78ef1d8fdf46d41bd90aed88d7b688f32a2e 100644 (file)
@@ -55,7 +55,7 @@ MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* PnP setup */
 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* PnP setup */
 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* PnP setup */
index c94578d40b1aa66d431fc7eb0eaae93f62dfe4c4..7bd5e337ee93b6b205fc9202c8ee94f03abb2fab 100644 (file)
@@ -69,9 +69,9 @@ MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8330,isapnp:{CMI0001,@@@0001,@X@0001}}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 static int sbirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
index 6d81fa75c33d4f23f98d5596a3685a03759906cc..99dda45e82f5a33c0130db4ca36dc1c7bfdecb1a 100644 (file)
@@ -41,7 +41,7 @@ MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4231}}");
 
 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 bool 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 int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 5,7,9,11,12,15 */
index f5a94b6e6245cc9e9d89c6d0e7ac7cb2d21586df..740c51a1ed7bfbd5a508147990e67dcd30b46c15 100644 (file)
@@ -74,9 +74,9 @@ MODULE_ALIAS("snd_cs4232");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* PnP setup */
 static long cport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;   /* PnP setup */
index 9a1a6f2c44842c114c770fae0473fd9d763bbbd8..b036e60f62d14b02ec672aaa43f37e866fc1098b 100644 (file)
@@ -51,9 +51,9 @@ MODULE_ALIAS("snd_es968");
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
 #endif
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260 */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
 static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
index 98e3ac1cfa08b64edfe3ecc0f7ab08ce1586f127..c20baafd9b7cfc0acfb02a943078da333ef294da 100644 (file)
@@ -1964,9 +1964,9 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1868 PnP AudioDrive},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260,0x280 */
 #ifndef CONFIG_PNP
index e51d3244742af23dc673496dd822f20e7d5cfa73..55e20782858d75baec9b48cf119e7740ed99134f 100644 (file)
@@ -35,7 +35,7 @@ MODULE_LICENSE("GPL");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
index d7296500bce8c18ac2a64c8a354a20be73879334..bf63336716130a438c1c61e4020b8714dfe15c06 100644 (file)
@@ -42,7 +42,7 @@ MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x230,0x240,0x250,0x260 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 3,5,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 1,3,5,6,7 */
index 597accdb15d2e9f45bd6dfc0287eb2d83f1f1219..bc10cc26e5f94361594f76aaa8856b6347ccb133 100644 (file)
@@ -46,7 +46,7 @@ MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260 */
 static long gf1_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x210,0x220,0x230,0x240,0x250,0x260,0x270 */
 static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x300,0x310,0x320 */
index 933cb0f4c549b5a9333757c6ac07aefa4c24da1c..41c3f448745ff14f197b1c5715fed49b12ebb386 100644 (file)
@@ -40,7 +40,7 @@ MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x230,0x240,0x250,0x260 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 2,3,5,9,11,12,15 */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 1,3,5,6,7 */
index 8e7e19484dacb75a86888bdcb3e94a7e29d839cf..a76bc8d27c1d914a2dd36262ef2f1f8f1a9307bf 100644 (file)
@@ -55,9 +55,9 @@ MODULE_SUPPORTED_DEVICE("{{AMD,InterWave STB with TEA6330T}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x210,0x220,0x230,0x240,0x250,0x260 */
 #ifdef SNDRV_STB
index 0961e2cf20caa8c0697f4775e0621ad0540af242..29cc8e162b0276bc380132ca78c2fae07293b798 100644 (file)
@@ -785,7 +785,7 @@ static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
 static int calibrate_signal;
 
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 module_param_array(isapnp, bool, NULL, 0444);
 MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
 #define has_isapnp(x) isapnp[x]
index 64a9a2177f4b375f14d1857eed8240a13984864b..f6cc0b917ef03bfe5d38f619e1b3341a42cacf39 100644 (file)
@@ -46,9 +46,9 @@ MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0xf86,0x370,0x100 */
 static long sb_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
index 3785b7a784c98ae3b0e9107f78b706139f0a4f06..c24594c866f458adbcdd155e025d4f2ba9c78ebf 100644 (file)
@@ -61,7 +61,7 @@ static int dma2 = SNDRV_DEFAULT_DMA1;         /* 0,1,3 */
 static int wss;
 static int ide;
 #ifdef CONFIG_PNP
-static int isapnp = 1;                         /* Enable ISA PnP detection */
+static bool isapnp = 1;                                /* Enable ISA PnP detection */
 #endif
 
 module_param(index, int, 0444);
index 97871bebea90304d49084716675f3cc7edd5446e..babaedd242f70b0fafb71dbcbdd8071c19c3f892 100644 (file)
@@ -63,7 +63,7 @@ MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)},"
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;          /* ID for this card */
-//static int enable = SNDRV_DEFAULT_ENABLE1;   /* Enable this card */
+//static bool enable = SNDRV_DEFAULT_ENABLE1;  /* Enable this card */
 #ifdef CONFIG_PNP
 static int isapnp = 1;                 /* Enable ISA PnP detection */
 #endif
index 54e3c2c1806075689609c9ab9076e799504a24ee..410758c68090397d2747af150f5b2f8cbc07c9e2 100644 (file)
@@ -36,7 +36,7 @@ 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 bool 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;
index 115c7748204ff30efeecf53e863d4bf882209100..39b8eca152137434e32cba0b0e60bf6ecba444b2 100644 (file)
@@ -68,9 +68,9 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260,0x280 */
 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* 0x330,0x300 */
index 453ef283491df1248889916ba53126aaa4438ea9..ab5cebea52e17156f542d5e87006dd490adbdd20 100644 (file)
@@ -36,7 +36,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220,0x240,0x260 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 5,7,9,10 */
 static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 1,3 */
index 207c161f100c5bd06f416fe5c11bfaa08757a2db..d97d0f381817f633364e5041a6b3fb41e1828c9d 100644 (file)
@@ -48,7 +48,7 @@ MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000},"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;        /* Enable this card */
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;    /* 0x220, 0x240 */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 5, 7, 9, 10, 11 */
 static long mss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;        /* 0x530, 0xe80 */
index 150b96b3ea106bfc0d6a42b8216a26c8f7379111..e0a73271cb91aff3191d4e32753ac17d91715ca1 100644 (file)
@@ -38,9 +38,9 @@ MODULE_SUPPORTED_DEVICE("{{Turtle Beach,Maui/Tropez/Tropez+}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;            /* Enable this card */
 #ifdef CONFIG_PNP
-static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 #endif
 static long cs4232_pcm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
 static int cs4232_pcm_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */
@@ -51,7 +51,7 @@ static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* 2,9,11,12,15 */
 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;          /* 0,1,3,5,6,7 */
 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;          /* 0,1,3,5,6,7 */
-static int use_cs4232_midi[SNDRV_CARDS];
+static bool use_cs4232_midi[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for WaveFront soundcard.");
index 2e6c85894e0be4481bf4d37994f4abfb5e21f780..5f88d1f09ffeef01f3fd9d0cc1a5746972ec1e90 100644 (file)
@@ -935,15 +935,4 @@ static struct platform_driver hal2_driver = {
        }
 };
 
-static int __init alsa_card_hal2_init(void)
-{
-       return platform_driver_register(&hal2_driver);
-}
-
-static void __exit alsa_card_hal2_exit(void)
-{
-       platform_driver_unregister(&hal2_driver);
-}
-
-module_init(alsa_card_hal2_init);
-module_exit(alsa_card_hal2_exit);
+module_platform_driver(hal2_driver);
index 69425d4c91fd1522e517afeb4a7524c70c2a8eb3..ceaa593ea4ef632d9f8ad4a6333ded19c0602684 100644 (file)
@@ -976,15 +976,4 @@ static struct platform_driver sgio2audio_driver = {
        }
 };
 
-static int __init alsa_card_sgio2audio_init(void)
-{
-       return platform_driver_register(&sgio2audio_driver);
-}
-
-static void __exit alsa_card_sgio2audio_exit(void)
-{
-       platform_driver_unregister(&sgio2audio_driver);
-}
-
-module_init(alsa_card_sgio2audio_init)
-module_exit(alsa_card_sgio2audio_exit)
+module_platform_driver(sgio2audio_driver);
index 8a197fd3c57e07602156d11f3acd1debe33e504c..98d23bdcaf21bd0208e82bc82d53ee569b56600e 100644 (file)
@@ -119,9 +119,9 @@ ad1848_port_info;
 static struct address_info cfg;
 static int nr_ad1848_devs;
 
-static int deskpro_xl;
-static int deskpro_m;
-static int soundpro;
+static bool deskpro_xl;
+static bool deskpro_m;
+static bool soundpro;
 
 static volatile signed char irq2dev[17] = {
        -1, -1, -1, -1, -1, -1, -1, -1,
@@ -177,7 +177,7 @@ static struct {
 #ifdef CONFIG_PNP
 static int isapnp      = 1;
 static int isapnpjump;
-static int reverse;
+static bool reverse;
 
 static int audio_activated;
 #else
index 7b5c77b32a90b9a5d4c967dcb58f2cb8e335fd24..eba734560f6f799896b4ab7b59edd0a57a44c901 100644 (file)
@@ -1701,7 +1701,7 @@ static int joystick_io __initdata =       CONFIG_MSNDPIN_JOYSTICK_IO;
 #ifndef CONFIG_MSNDPIN_DIGITAL
 #  define CONFIG_MSNDPIN_DIGITAL       0
 #endif
-static int digital __initdata =                CONFIG_MSNDPIN_DIGITAL;
+static bool digital __initdata =       CONFIG_MSNDPIN_DIGITAL;
 
 #endif /* MSND_CLASSIC */
 
index 7f377ec3486d9f822c14fe2c77fb35d85f49cfd2..dabf8a871dcc26b75166712e3ee109136f7babd6 100644 (file)
@@ -41,19 +41,19 @@ static int      pas_irq;
 static int      pas_sb_base;
 DEFINE_SPINLOCK(pas_lock);
 #ifndef CONFIG_PAS_JOYSTICK
-static int     joystick;
+static bool    joystick;
 #else
-static int     joystick = 1;
+static bool    joystick = 1;
 #endif
 #ifdef SYMPHONY_PAS
-static int     symphony = 1;
+static bool    symphony = 1;
 #else
-static int     symphony;
+static bool    symphony;
 #endif
 #ifdef BROKEN_BUS_CLOCK
-static int     broken_bus_clock = 1;
+static bool    broken_bus_clock = 1;
 #else
-static int     broken_bus_clock;
+static bool    broken_bus_clock;
 #endif
 
 static struct address_info cfg;
index 2fc0624024b5c44e84f60c9e4e20926239b9319a..0f32a561f15f6a6575d75888abc733b3ceebd377 100644 (file)
 
 /* If compiled into kernel, it enable or disable pss mixer */
 #ifdef CONFIG_PSS_MIXER
-static int pss_mixer = 1;
+static bool pss_mixer = 1;
 #else
-static int pss_mixer;
+static bool pss_mixer;
 #endif
 
 
@@ -147,7 +147,7 @@ static DEFINE_SPINLOCK(lock);
 static int      pss_initialized;
 static int      nonstandard_microcode;
 static int     pss_cdrom_port = -1;    /* Parameter for the PSS cdrom port */
-static int     pss_enable_joystick;    /* Parameter for enabling the joystick */
+static bool    pss_enable_joystick;    /* Parameter for enabling the joystick */
 static coproc_operations pss_coproc_operations;
 
 static void pss_write(pss_confdata *devc, int data)
@@ -1133,8 +1133,8 @@ static int mss_irq __initdata     = -1;
 static int mss_dma __initdata  = -1;
 static int mpu_io __initdata   = -1;
 static int mpu_irq __initdata  = -1;
-static int pss_no_sound = 0;   /* Just configure non-sound components */
-static int pss_keep_settings  = 1;     /* Keep hardware settings at module exit */
+static bool pss_no_sound = 0;  /* Just configure non-sound components */
+static bool pss_keep_settings  = 1;    /* Keep hardware settings at module exit */
 static char *pss_firmware = "/etc/sound/pss_synth";
 
 module_param(pss_io, int, 0);
index e04169e8e3f86be4a9460cd53589b2a49c241c70..944e0c0154853d8fb31fe4cfa3fbf1b963a3137e 100644 (file)
@@ -31,7 +31,7 @@
 
 static int mpu;
 
-static int joystick;
+static bool joystick;
 
 static unsigned char trix_read(int addr)
 {
index fac51eef2725d9ad7e64727a6dcb6f02e20019f9..9473fca9681dd7e291595501a6270c47793aa3bc 100644 (file)
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Universal interface for Audio Codec '97");
 MODULE_LICENSE("GPL");
 
-static int enable_loopback;
+static bool enable_loopback;
 
 module_param(enable_loopback, bool, 0444);
 MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
index 6e311184bb10213106439c2dc006d64677d5ce9f..9d91d61902b47edb7b7c8af381015653dc158d1f 100644 (file)
@@ -66,7 +66,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
 module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard.");
 
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable AD1889 soundcard.");
 
index ef85ac5d9007aefb8ec27191ed7ec2a3158ab6bb..bdd6164e9c7eca267115564ad30e05e4860b18f8 100644 (file)
@@ -48,7 +48,7 @@ MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");
 static int index = SNDRV_DEFAULT_IDX1; /* Index */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int pcm_channels = 32;
-static int spdif;
+static bool spdif;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");
@@ -60,7 +60,7 @@ module_param(spdif, bool, 0444);
 MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index 8dc77a0a5d8b992ba91c6b9107cecb110b002849..8196e229b2dfbeb4801413b9f87bc7f3e06177aa 100644 (file)
@@ -115,7 +115,14 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS300},{Avance Logic,ALS300+}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for ALS300 sound card.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for ALS300 sound card.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable ALS300 sound card.");
 
 struct snd_als300 {
        unsigned long port;
index 28ef40e01cc2e0f478aa9231678a93cdcea9cd06..3269b8011ea9692daa0068df3be024d7848fc96c 100644 (file)
@@ -90,7 +90,7 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 #ifdef SUPPORT_JOYSTICK
 static int joystick_port[SNDRV_CARDS];
 #endif
index f4b9e2b7ae87ae1df0b5dfa374c1e2528b2232b7..e8de831f98bc510c6cde42159bce817dad45408b 100644 (file)
  */
 
 #include "hpi_internal.h"
+#include "hpi_version.h"
 #include "hpimsginit.h"
 #include "hpioctl.h"
+#include "hpicmn.h"
+
 
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -44,7 +47,8 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
-MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
+MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx "
+                       HPI_VER_STRING);
 
 #if defined CONFIG_SND_DEBUG_VERBOSE
 /**
@@ -63,8 +67,8 @@ MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 
 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_PNP;
-static int enable_hpi_hwdep = 1;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable_hpi_hwdep = 1;
 
 module_param_array(index, int, NULL, S_IRUGO);
 MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard.");
@@ -119,12 +123,7 @@ struct clk_cache {
 struct snd_card_asihpi {
        struct snd_card *card;
        struct pci_dev *pci;
-       u16 adapter_index;
-       u32 serial_number;
-       u16 type;
-       u16 version;
-       u16 num_outstreams;
-       u16 num_instreams;
+       struct hpi_adapter *hpi;
 
        u32 h_mixer;
        struct clk_cache cc;
@@ -135,6 +134,8 @@ struct snd_card_asihpi {
        u16 update_interval_frames;
        u16 in_max_chans;
        u16 out_max_chans;
+       u16 in_min_chans;
+       u16 out_min_chans;
 };
 
 /* Per stream data */
@@ -495,6 +496,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
 
                snd_printdd("stream_host_buffer_attach status 0x%x\n",
                                dpcm->hpi_buffer_attached);
+
        }
        bytes_per_sec = params_rate(params) * params_channels(params);
        width = snd_pcm_format_width(params_format(params));
@@ -757,8 +759,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
                        if (state == HPI_STATE_STOPPED) {
-                               if ((bytes_avail == 0) &&
-                                   (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
+                               if (bytes_avail == 0) {
                                        hpi_handle_error(hpi_stream_start(ds->h_stream));
                                        snd_printdd("P%d start\n", s->number);
                                        ds->drained_count = 0;
@@ -767,7 +768,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                                snd_printd(KERN_WARNING "P%d drained\n",
                                                s->number);
                                ds->drained_count++;
-                               if (ds->drained_count > 2) {
+                               if (ds->drained_count > 20) {
                                        snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
                                        continue;
                                }
@@ -888,8 +889,8 @@ static void snd_card_asihpi_timer_function(unsigned long data)
                                                        pd, xfer2));
                                }
                        }
-                       ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
-                       ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
+                       ds->pcm_buf_host_rw_ofs += xfercount;
+                       ds->pcm_buf_elapsed_dma_ofs += xfercount;
                        snd_pcm_period_elapsed(s);
                }
        }
@@ -902,7 +903,9 @@ static void snd_card_asihpi_timer_function(unsigned long data)
 static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
                                          unsigned int cmd, void *arg)
 {
-       snd_printddd(KERN_INFO "P%d ioctl %d\n", substream->number, cmd);
+       char name[16];
+       snd_pcm_debug_name(substream, name, sizeof(name));
+       snd_printddd(KERN_INFO "%s ioctl %d\n", name, cmd);
        return snd_pcm_lib_ioctl(substream, cmd, arg);
 }
 
@@ -927,21 +930,23 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
        snd_pcm_uframes_t ptr;
+       char name[16];
+       snd_pcm_debug_name(substream, name, sizeof(name));
 
        ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs  % dpcm->buffer_bytes);
-       snd_printddd("P%d pointer = 0x%04lx\n", substream->number, (unsigned long)ptr);
+       snd_printddd("%s pointer = 0x%04lx\n", name, (unsigned long)ptr);
        return ptr;
 }
 
-static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
-                                               u32 h_stream,
-                                               struct snd_pcm_hardware *pcmhw)
+static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi,
+                                               u32 h_stream)
 {
        struct hpi_format hpi_format;
        u16 format;
        u16 err;
        u32 h_control;
        u32 sample_rate = 48000;
+       u64 formats = 0;
 
        /* on cards without SRC, must query at valid rate,
        * maybe set by external sync
@@ -956,41 +961,29 @@ static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
 
        for (format = HPI_FORMAT_PCM8_UNSIGNED;
             format <= HPI_FORMAT_PCM24_SIGNED; format++) {
-               err = hpi_format_create(&hpi_format,
-                                       2, format, sample_rate, 128000, 0);
+               err = hpi_format_create(&hpi_format, asihpi->out_max_chans,
+                                       format, sample_rate, 128000, 0);
                if (!err)
-                       err = hpi_outstream_query_format(h_stream,
-                                                       &hpi_format);
+                       err = hpi_outstream_query_format(h_stream, &hpi_format);
                if (!err && (hpi_to_alsa_formats[format] != -1))
-                       pcmhw->formats |=
-                               (1ULL << hpi_to_alsa_formats[format]);
+                       formats |= (1ULL << hpi_to_alsa_formats[format]);
        }
+       return formats;
 }
 
-static struct snd_pcm_hardware snd_card_asihpi_playback = {
-       .channels_min = 1,
-       .channels_max = 2,
-       .buffer_bytes_max = BUFFER_BYTES_MAX,
-       .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
-       .periods_min = PERIODS_MIN,
-       .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
-       .fifo_size = 0,
-};
-
 static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_card_asihpi_pcm *dpcm;
        struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
+       struct snd_pcm_hardware snd_card_asihpi_playback;
        int err;
 
        dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
        if (dpcm == NULL)
                return -ENOMEM;
 
-       err =
-           hpi_outstream_open(card->adapter_index,
+       err = hpi_outstream_open(card->hpi->adapter->index,
                              substream->number, &dpcm->h_stream);
        hpi_handle_error(err);
        if (err)
@@ -1012,12 +1005,19 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
        runtime->private_data = dpcm;
        runtime->private_free = snd_card_asihpi_runtime_free;
 
-       snd_card_asihpi_playback.channels_max = card->out_max_chans;
+       memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback));
+       snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
+       snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
        /*?snd_card_asihpi_playback.period_bytes_min =
        card->out_max_chans * 4096; */
-
-       snd_card_asihpi_playback_format(card, dpcm->h_stream,
-                                       &snd_card_asihpi_playback);
+       snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+       snd_card_asihpi_playback.periods_min = PERIODS_MIN;
+       snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+       /* snd_card_asihpi_playback.fifo_size = 0; */
+       snd_card_asihpi_playback.channels_max = card->out_max_chans;
+       snd_card_asihpi_playback.channels_min = card->out_min_chans;
+       snd_card_asihpi_playback.formats =
+                       snd_card_asihpi_playback_formats(card, dpcm->h_stream);
 
        snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_playback);
 
@@ -1029,8 +1029,10 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
                                        SNDRV_PCM_INFO_MMAP |
                                        SNDRV_PCM_INFO_MMAP_VALID;
 
-       if (card->support_grouping)
+       if (card->support_grouping) {
                snd_card_asihpi_playback.info |= SNDRV_PCM_INFO_SYNC_START;
+               snd_pcm_set_sync(substream);
+       }
 
        /* struct is copied, so can create initializer dynamically */
        runtime->hw = snd_card_asihpi_playback;
@@ -1047,8 +1049,6 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
                card->update_interval_frames * 2, UINT_MAX);
 
-       snd_pcm_set_sync(substream);
-
        snd_printdd("playback open\n");
 
        return 0;
@@ -1114,15 +1114,15 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
 
 
 
-static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
-                                       u32 h_stream,
-                                        struct snd_pcm_hardware *pcmhw)
+static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
+                                       u32 h_stream)
 {
   struct hpi_format hpi_format;
        u16 format;
        u16 err;
        u32 h_control;
        u32 sample_rate = 48000;
+       u64 formats = 0;
 
        /* on cards without SRC, must query at valid rate,
                maybe set by external sync */
@@ -1137,34 +1137,22 @@ static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
        for (format = HPI_FORMAT_PCM8_UNSIGNED;
                format <= HPI_FORMAT_PCM24_SIGNED; format++) {
 
-               err = hpi_format_create(&hpi_format, 2, format,
-                               sample_rate, 128000, 0);
+               err = hpi_format_create(&hpi_format, asihpi->in_max_chans,
+                                       format, sample_rate, 128000, 0);
                if (!err)
-                       err = hpi_instream_query_format(h_stream,
-                                           &hpi_format);
+                       err = hpi_instream_query_format(h_stream, &hpi_format);
                if (!err)
-                       pcmhw->formats |=
-                               (1ULL << hpi_to_alsa_formats[format]);
+                       formats |= (1ULL << hpi_to_alsa_formats[format]);
        }
+       return formats;
 }
 
-
-static struct snd_pcm_hardware snd_card_asihpi_capture = {
-       .channels_min = 1,
-       .channels_max = 2,
-       .buffer_bytes_max = BUFFER_BYTES_MAX,
-       .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN,
-       .periods_min = PERIODS_MIN,
-       .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
-       .fifo_size = 0,
-};
-
 static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
        struct snd_card_asihpi_pcm *dpcm;
+       struct snd_pcm_hardware snd_card_asihpi_capture;
        int err;
 
        dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
@@ -1172,10 +1160,10 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
                return -ENOMEM;
 
        snd_printdd("capture open adapter %d stream %d\n",
-                  card->adapter_index, substream->number);
+                       card->hpi->adapter->index, substream->number);
 
        err = hpi_handle_error(
-           hpi_instream_open(card->adapter_index,
+           hpi_instream_open(card->hpi->adapter->index,
                             substream->number, &dpcm->h_stream));
        if (err)
                kfree(dpcm);
@@ -1184,7 +1172,6 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
        if (err)
                return -EIO;
 
-
        init_timer(&dpcm->timer);
        dpcm->timer.data = (unsigned long) dpcm;
        dpcm->timer.function = snd_card_asihpi_timer_function;
@@ -1192,9 +1179,17 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
        runtime->private_data = dpcm;
        runtime->private_free = snd_card_asihpi_runtime_free;
 
+       memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture));
+       snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
+       snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
+       snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+       snd_card_asihpi_capture.periods_min = PERIODS_MIN;
+       snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+       /* snd_card_asihpi_capture.fifo_size = 0; */
        snd_card_asihpi_capture.channels_max = card->in_max_chans;
-       snd_card_asihpi_capture_format(card, dpcm->h_stream,
-                                      &snd_card_asihpi_capture);
+       snd_card_asihpi_capture.channels_min = card->in_min_chans;
+       snd_card_asihpi_capture.formats =
+               snd_card_asihpi_capture_formats(card, dpcm->h_stream);
        snd_card_asihpi_pcm_samplerates(card,  &snd_card_asihpi_capture);
        snd_card_asihpi_capture.info = SNDRV_PCM_INFO_INTERLEAVED |
                                        SNDRV_PCM_INFO_MMAP |
@@ -1240,15 +1235,20 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = {
        .pointer = snd_card_asihpi_capture_pointer,
 };
 
-static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
-                                     int device, int substreams)
+static int __devinit snd_card_asihpi_pcm_new(
+               struct snd_card_asihpi *asihpi, int device)
 {
        struct snd_pcm *pcm;
        int err;
+       u16 num_instreams, num_outstreams, x16;
+       u32 x32;
+
+       err = hpi_adapter_get_info(asihpi->hpi->adapter->index,
+                       &num_outstreams, &num_instreams,
+                       &x16, &x32, &x16);
 
        err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
-                        asihpi->num_outstreams, asihpi->num_instreams,
-                        &pcm);
+                       num_outstreams, num_instreams, &pcm);
        if (err < 0)
                return err;
        /* pointer to ops struct is stored, dont change ops afterwards! */
@@ -1314,7 +1314,7 @@ static const char * const asihpi_src_names[] = {
        "Analog",
        "Adapter",
        "RTP",
-       "GPI",
+       "Internal"
 };
 
 compile_time_assert(
@@ -1332,7 +1332,6 @@ static const char * const asihpi_dst_names[] = {
        "Net",
        "Analog",
        "RTP",
-       "GPO",
 };
 
 compile_time_assert(
@@ -1410,6 +1409,7 @@ static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
        u32 h_control = kcontrol->private_value;
+       u32 count;
        u16 err;
        /* native gains are in millibels */
        short min_gain_mB;
@@ -1424,8 +1424,12 @@ static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
                step_gain_mB = VOL_STEP_mB;
        }
 
+       err = hpi_meter_query_channels(h_control, &count);
+       if (err)
+               count = HPI_MAX_CHANNELS;
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
+       uinfo->count = count;
        uinfo->value.integer.min = min_gain_mB / VOL_STEP_mB;
        uinfo->value.integer.max = max_gain_mB / VOL_STEP_mB;
        uinfo->value.integer.step = step_gain_mB / VOL_STEP_mB;
@@ -2033,8 +2037,15 @@ static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
 static int snd_asihpi_meter_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
 {
+       u32 h_control = kcontrol->private_value;
+       u32 count;
+       u16 err;
+       err = hpi_meter_query_channels(h_control, &count);
+       if (err)
+               count = HPI_MAX_CHANNELS;
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = HPI_MAX_CHANNELS;
+       uinfo->count = count;
        uinfo->value.integer.min = 0;
        uinfo->value.integer.max = 0x7FFFFFFF;
        return 0;
@@ -2248,6 +2259,9 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
                        valid_modes++;
                        }
 
+       if (!valid_modes)
+               return -EINVAL;
+
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = valid_modes;
@@ -2547,7 +2561,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
        strcpy(card->mixername, "Asihpi Mixer");
 
        err =
-           hpi_mixer_open(asihpi->adapter_index,
+           hpi_mixer_open(asihpi->hpi->adapter->index,
                          &asihpi->h_mixer);
        hpi_handle_error(err);
        if (err)
@@ -2665,24 +2679,33 @@ snd_asihpi_proc_read(struct snd_info_entry *entry,
                        struct snd_info_buffer *buffer)
 {
        struct snd_card_asihpi *asihpi = entry->private_data;
-       u16 version;
        u32 h_control;
        u32 rate = 0;
        u16 source = 0;
+
+       u16 num_outstreams;
+       u16 num_instreams;
+       u16 version;
+       u32 serial_number;
+       u16 type;
+
        int err;
 
        snd_iprintf(buffer, "ASIHPI driver proc file\n");
+
+       hpi_handle_error(hpi_adapter_get_info(asihpi->hpi->adapter->index,
+                       &num_outstreams, &num_instreams,
+                       &version, &serial_number, &type));
+
        snd_iprintf(buffer,
-               "adapter ID=%4X\n_index=%d\n"
-               "num_outstreams=%d\n_num_instreams=%d\n",
-               asihpi->type, asihpi->adapter_index,
-               asihpi->num_outstreams, asihpi->num_instreams);
+                       "Adapter type ASI%4X\nHardware Index %d\n"
+                       "%d outstreams\n%d instreams\n",
+                       type, asihpi->hpi->adapter->index,
+                       num_outstreams, num_instreams);
 
-       version = asihpi->version;
        snd_iprintf(buffer,
-               "serial#=%d\n_hw version %c%d\nDSP code version %03d\n",
-               asihpi->serial_number, ((version >> 3) & 0xf) + 'A',
-               version & 0x7,
+               "Serial#%d\nHardware version %c%d\nDSP code version %03d\n",
+               serial_number, ((version >> 3) & 0xf) + 'A', version & 0x7,
                ((version >> 13) * 100) + ((version >> 7) & 0x3f));
 
        err = hpi_mixer_get_control(asihpi->h_mixer,
@@ -2690,18 +2713,15 @@ snd_asihpi_proc_read(struct snd_info_entry *entry,
                                  HPI_CONTROL_SAMPLECLOCK, &h_control);
 
        if (!err) {
-               err = hpi_sample_clock_get_sample_rate(
-                                       h_control, &rate);
+               err = hpi_sample_clock_get_sample_rate(h_control, &rate);
                err += hpi_sample_clock_get_source(h_control, &source);
 
                if (!err)
-                       snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
+                       snd_iprintf(buffer, "Sample Clock %dHz, source %s\n",
                        rate, sampleclock_sources[source]);
        }
-
 }
 
-
 static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi)
 {
        struct snd_info_entry *entry;
@@ -2773,35 +2793,34 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
                                       const struct pci_device_id *pci_id)
 {
        int err;
-
-       u16 version;
-       int pcm_substreams;
-
-       struct hpi_adapter *hpi_card;
+       struct hpi_adapter *hpi;
        struct snd_card *card;
        struct snd_card_asihpi *asihpi;
 
        u32 h_control;
        u32 h_stream;
+       u32 adapter_index;
 
        static int dev;
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
 
-       /* Should this be enable[hpi_card->index] ? */
+       /* Should this be enable[hpi->index] ? */
        if (!enable[dev]) {
                dev++;
                return -ENOENT;
        }
 
+       /* Initialise low-level HPI driver */
        err = asihpi_adapter_probe(pci_dev, pci_id);
        if (err < 0)
                return err;
 
-       hpi_card = pci_get_drvdata(pci_dev);
+       hpi = pci_get_drvdata(pci_dev);
+       adapter_index = hpi->adapter->index;
        /* first try to give the card the same index as its hardware index */
-       err = snd_card_create(hpi_card->index,
-                             id[hpi_card->index], THIS_MODULE,
+       err = snd_card_create(adapter_index,
+                             id[adapter_index], THIS_MODULE,
                              sizeof(struct snd_card_asihpi),
                              &card);
        if (err < 0) {
@@ -2815,50 +2834,32 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
                        return err;
                snd_printk(KERN_WARNING
                        "**** WARNING **** Adapter index %d->ALSA index %d\n",
-                       hpi_card->index, card->number);
+                       adapter_index, card->number);
        }
 
        snd_card_set_dev(card, &pci_dev->dev);
 
-       asihpi = (struct snd_card_asihpi *) card->private_data;
+       asihpi = card->private_data;
        asihpi->card = card;
        asihpi->pci = pci_dev;
-       asihpi->adapter_index = hpi_card->index;
-       hpi_handle_error(hpi_adapter_get_info(
-                                asihpi->adapter_index,
-                                &asihpi->num_outstreams,
-                                &asihpi->num_instreams,
-                                &asihpi->version,
-                                &asihpi->serial_number, &asihpi->type));
-
-       version = asihpi->version;
-       snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
-                       "num_instreams=%d S/N=%d\n"
-                       "Hw Version %c%d DSP code version %03d\n",
-                       asihpi->type, asihpi->adapter_index,
-                       asihpi->num_outstreams,
-                       asihpi->num_instreams, asihpi->serial_number,
-                       ((version >> 3) & 0xf) + 'A',
-                       version & 0x7,
-                       ((version >> 13) * 100) + ((version >> 7) & 0x3f));
-
-       pcm_substreams = asihpi->num_outstreams;
-       if (pcm_substreams < asihpi->num_instreams)
-               pcm_substreams = asihpi->num_instreams;
-
-       err = hpi_adapter_get_property(asihpi->adapter_index,
+       asihpi->hpi = hpi;
+
+       snd_printk(KERN_INFO "adapter ID=%4X index=%d\n",
+                       asihpi->hpi->adapter->type, adapter_index);
+
+       err = hpi_adapter_get_property(adapter_index,
                HPI_ADAPTER_PROPERTY_CAPS1,
                NULL, &asihpi->support_grouping);
        if (err)
                asihpi->support_grouping = 0;
 
-       err = hpi_adapter_get_property(asihpi->adapter_index,
+       err = hpi_adapter_get_property(adapter_index,
                HPI_ADAPTER_PROPERTY_CAPS2,
                &asihpi->support_mrx, NULL);
        if (err)
                asihpi->support_mrx = 0;
 
-       err = hpi_adapter_get_property(asihpi->adapter_index,
+       err = hpi_adapter_get_property(adapter_index,
                HPI_ADAPTER_PROPERTY_INTERVAL,
                NULL, &asihpi->update_interval_frames);
        if (err)
@@ -2867,7 +2868,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
        if (!asihpi->can_dma)
                asihpi->update_interval_frames *= 2;
 
-       hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
+       hpi_handle_error(hpi_instream_open(adapter_index,
                             0, &h_stream));
 
        err = hpi_instream_host_buffer_free(h_stream);
@@ -2875,7 +2876,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 
        hpi_handle_error(hpi_instream_close(h_stream));
 
-       err = hpi_adapter_get_property(asihpi->adapter_index,
+       err = hpi_adapter_get_property(adapter_index,
                HPI_ADAPTER_PROPERTY_CURCHANNELS,
                &asihpi->in_max_chans, &asihpi->out_max_chans);
        if (err) {
@@ -2883,13 +2884,22 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
                asihpi->out_max_chans = 2;
        }
 
-       snd_printk(KERN_INFO "has dma:%d, grouping:%d, mrx:%d\n",
+       if (asihpi->out_max_chans > 2) { /* assume LL mode */
+               asihpi->out_min_chans = asihpi->out_max_chans;
+               asihpi->in_min_chans = asihpi->in_max_chans;
+               asihpi->support_grouping = 0;
+       } else {
+               asihpi->out_min_chans = 1;
+               asihpi->in_min_chans = 1;
+       }
+
+       snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n",
                        asihpi->can_dma,
                        asihpi->support_grouping,
                        asihpi->support_mrx
              );
 
-       err = snd_card_asihpi_pcm_new(asihpi, 0, pcm_substreams);
+       err = snd_card_asihpi_pcm_new(asihpi, 0);
        if (err < 0) {
                snd_printk(KERN_ERR "pcm_new failed\n");
                goto __nodev;
@@ -2916,13 +2926,14 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
 
        strcpy(card->driver, "ASIHPI");
 
-       sprintf(card->shortname, "AudioScience ASI%4X", asihpi->type);
+       sprintf(card->shortname, "AudioScience ASI%4X",
+                       asihpi->hpi->adapter->type);
        sprintf(card->longname, "%s %i",
-                       card->shortname, asihpi->adapter_index);
+                       card->shortname, adapter_index);
        err = snd_card_register(card);
 
        if (!err) {
-               hpi_card->snd_card_asihpi = card;
+               hpi->snd_card = card;
                dev++;
                return 0;
        }
@@ -2935,10 +2946,9 @@ __nodev:
 
 static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev)
 {
-       struct hpi_adapter *hpi_card = pci_get_drvdata(pci_dev);
-
-       snd_card_free(hpi_card->snd_card_asihpi);
-       hpi_card->snd_card_asihpi = NULL;
+       struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);
+       snd_card_free(hpi->snd_card);
+       hpi->snd_card = NULL;
        asihpi_adapter_remove(pci_dev);
 }
 
index f20727288994932c4d64bb1c3c8c2a0de3b6cc88..20887241a3ae0e1d686c9851baa2dafd29e028f0 100644 (file)
 
 #ifndef _HPI_H_
 #define _HPI_H_
-/* HPI Version
-If HPI_VER_MINOR is odd then its a development release not intended for the
-public. If HPI_VER_MINOR is even then is a release version
-i.e 3.05.02 is a development version
-*/
-#define HPI_VERSION_CONSTRUCTOR(maj, min, rel) \
-       ((maj << 16) + (min << 8) + rel)
-
-#define HPI_VER_MAJOR(v) ((int)(v >> 16))
-#define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
-#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
-
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 8, 0)
-#define HPI_VER_STRING "4.08.00"
-
-/* Library version as documented in hpi-api-versions.txt */
-#define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(10, 0, 0)
 
 #include <linux/types.h>
-#define HPI_BUILD_EXCLUDE_DEPRECATED
 #define HPI_BUILD_KERNEL_MODE
 
 /******************************************************************************/
@@ -213,7 +195,7 @@ enum HPI_SOURCENODES {
        /** RTP stream input node - This node is a destination for
            packets of RTP audio samples from other devices. */
        HPI_SOURCENODE_RTP_DESTINATION = 112,
-       HPI_SOURCENODE_GP_IN = 113,          /**< general purpose input. */
+       HPI_SOURCENODE_INTERNAL = 113,       /**< node internal to the device. */
        /* !!!Update this  AND hpidebug.h if you add a new sourcenode type!!! */
        HPI_SOURCENODE_LAST_INDEX = 113      /**< largest ID */
                /* AX6 max sourcenode types = 15 */
@@ -242,9 +224,8 @@ enum HPI_DESTNODES {
        /** RTP stream output node - This node is a source for
            packets of RTP audio samples that are sent to other devices. */
        HPI_DESTNODE_RTP_SOURCE = 208,
-       HPI_DESTNODE_GP_OUT = 209,           /**< general purpose output node. */
        /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
-       HPI_DESTNODE_LAST_INDEX = 209        /**< largest ID */
+       HPI_DESTNODE_LAST_INDEX = 208        /**< largest ID */
                /* AX6 max destnode types = 15 */
 };
 
@@ -450,7 +431,19 @@ Indicates that the adapter in it's current mode supports interrupts
 across the host bus. Note, this does not imply that interrupts are
 enabled. Instead it indicates that they can be enabled.
 */
-       HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ = 272
+       HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ = 272,
+/** Readonly supports firmware updating.
+Indicates that the adapter implements an interface to update firmware
+on the adapter.
+*/
+       HPI_ADAPTER_PROPERTY_SUPPORTS_FW_UPDATE = 273,
+/** Readonly Firmware IDs
+Identifiy firmware independent of individual adapter type.
+May be used as a filter for firmware update images.
+Property 1 = Bootloader ID
+Property 2 = Main program ID
+*/
+       HPI_ADAPTER_PROPERTY_FIRMWARE_ID = 274
 };
 
 /** Adapter mode commands
@@ -638,7 +631,7 @@ enum HPI_MIXER_STORE_COMMAND {
        HPI_MIXER_STORE_ENABLE = 4,
 /** Disable auto storage of some control settings. */
        HPI_MIXER_STORE_DISABLE = 5,
-/** Save the attributes of a single control. */
+/** Unimplemented - save the attributes of a single control. */
        HPI_MIXER_STORE_SAVE_SINGLE = 6
 };
 
@@ -941,7 +934,7 @@ enum HPI_ERROR_CODES {
        HPI_ERROR_BAD_ADAPTER_NUMBER = 202,
        /** 2 adapters with the same adapter number. */
        HPI_ERROR_DUPLICATE_ADAPTER_NUMBER = 203,
-       /** DSP code failed to bootload. (unused?) */
+       /** DSP code failed to bootload. Usually a DSP memory test failure. */
        HPI_ERROR_DSP_BOOTLOAD = 204,
        /** Couldn't find or open the DSP code file. */
        HPI_ERROR_DSP_FILE_NOT_FOUND = 206,
@@ -978,6 +971,9 @@ enum HPI_ERROR_CODES {
        HPI_ERROR_FLASH_VERIFY = 225,
        HPI_ERROR_FLASH_TYPE = 226,
        HPI_ERROR_FLASH_START = 227,
+       HPI_ERROR_FLASH_READ = 228,
+       HPI_ERROR_FLASH_READ_NO_FILE = 229,
+       HPI_ERROR_FLASH_SIZE = 230,
 
        /** Reserved for OEMs. */
        HPI_ERROR_RESERVED_1 = 290,
@@ -1020,6 +1016,8 @@ enum HPI_ERROR_CODES {
        HPI_ERROR_NO_INTERDSP_GROUPS = 315,
        /** Stream wait cancelled before threshold reached. */
        HPI_ERROR_WAIT_CANCELLED = 316,
+       /** A character string is invalid. */
+       HPI_ERROR_INVALID_STRING = 317,
 
        /** Invalid mixer node for this adapter. */
        HPI_ERROR_INVALID_NODE = 400,
@@ -1046,11 +1044,15 @@ enum HPI_ERROR_CODES {
        /** I2C */
        HPI_ERROR_I2C_BAD_ADR = 460,
 
-       /** Entity errors */
+       /** Entity type did not match requested type */
        HPI_ERROR_ENTITY_TYPE_MISMATCH = 470,
+       /** Entity item count did not match requested count */
        HPI_ERROR_ENTITY_ITEM_COUNT = 471,
+       /** Entity type is not one of the valid types */
        HPI_ERROR_ENTITY_TYPE_INVALID = 472,
+       /** Entity role is not one of the valid roles */
        HPI_ERROR_ENTITY_ROLE_INVALID = 473,
+       /** Entity size doesn't match target size */
        HPI_ERROR_ENTITY_SIZE_MISMATCH = 474,
 
        /* AES18 specific errors were 500..507 */
@@ -1078,8 +1080,7 @@ enum HPI_ERROR_CODES {
 /** \defgroup maximums HPI maximum values
 \{
 */
-/** Maximum number of adapters per HPI sub-system
-   WARNING: modifying this value changes the response structure size.*/
+/** Maximum number of PCI HPI adapters */
 #define HPI_MAX_ADAPTERS                20
 /** Maximum number of in or out streams per adapter */
 #define HPI_MAX_STREAMS                 16
@@ -1090,6 +1091,9 @@ enum HPI_ERROR_CODES {
 #define HPI_MAX_ANC_BYTES_PER_FRAME     (64)
 #define HPI_STRING_LEN                  16
 
+/** Networked adapters have index >= 100 */
+#define HPI_MIN_NETWORK_ADAPTER_IDX 100
+
 /** Velocity units */
 #define HPI_OSTREAM_VELOCITY_UNITS      4096
 /** OutStream timescale units */
@@ -1111,14 +1115,14 @@ enum HPI_ERROR_CODES {
 struct hpi_format {
        u32 sample_rate;
                                /**< 11025, 32000, 44100 ... */
-       u32 bit_rate;         /**< for MPEG */
+       u32 bit_rate;             /**< for MPEG */
        u32 attributes;
                                /**< Stereo/JointStereo/Mono */
        u16 mode_legacy;
                                /**< Legacy ancillary mode or idle bit  */
-       u16 unused;           /**< Unused */
-       u16 channels; /**< 1,2..., (or ancillary mode or idle bit */
-       u16 format;   /**< HPI_FORMAT_PCM16, _MPEG etc. see #HPI_FORMATS. */
+       u16 unused;               /**< Unused */
+       u16 channels;     /**< 1,2..., (or ancillary mode or idle bit */
+       u16 format;       /**< HPI_FORMAT_PCM16, _MPEG etc. see #HPI_FORMATS. */
 };
 
 struct hpi_anc_frame {
@@ -1144,9 +1148,6 @@ struct hpi_async_event {
        } u;
 };
 
-/* skip host side function declarations for
-   DSP compile and documentation extraction */
-
 #ifndef DISABLE_PRAGMA_PACK1
 #pragma pack(pop)
 #endif
@@ -1357,7 +1358,7 @@ u16 hpi_volume_get_mute(u32 h_control, u32 *mute);
 u16 hpi_volume_query_range(u32 h_control, short *min_gain_01dB,
        short *max_gain_01dB, short *step_gain_01dB);
 
-u16 hpi_volume_query_channels(const u32 h_volume, u32 *p_channels);
+u16 hpi_volume_query_channels(const u32 h_control, u32 *p_channels);
 
 u16 hpi_volume_auto_fade(u32 h_control,
        short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms);
@@ -1366,6 +1367,9 @@ u16 hpi_volume_auto_fade_profile(u32 h_control,
        short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms,
        u16 profile);
 
+u16 hpi_volume_query_auto_fade_profile(const u32 h_control, const u32 i,
+       u16 *profile);
+
 /*****************/
 /* Level control */
 /*****************/
index 3cc6f11c20aac007057c4cf8b8b6661ce7e083c2..2414d7a2239d325b95cf08077654fad970343f22 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -231,6 +231,8 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
 static void control_message(struct hpi_adapter_obj *pao,
        struct hpi_message *phm, struct hpi_response *phr)
 {
+       struct hpi_hw_obj *phw = pao->priv;
+
        switch (phm->function) {
        case HPI_CONTROL_GET_STATE:
                if (pao->has_control_cache) {
@@ -248,17 +250,14 @@ static void control_message(struct hpi_adapter_obj *pao,
                                break;
                        }
 
-                       if (hpi_check_control_cache(((struct hpi_hw_obj *)
-                                               pao->priv)->p_cache, phm,
-                                       phr))
+                       if (hpi_check_control_cache(phw->p_cache, phm, phr))
                                break;
                }
                hw_message(pao, phm, phr);
                break;
        case HPI_CONTROL_SET_STATE:
                hw_message(pao, phm, phr);
-               hpi_cmn_control_cache_sync_to_msg(((struct hpi_hw_obj *)pao->
-                               priv)->p_cache, phm, phr);
+               hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm, phr);
                break;
 
        case HPI_CONTROL_GET_INFO:
@@ -451,11 +450,11 @@ static void subsys_create_adapter(struct hpi_message *phm,
        }
 
        for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {
-               struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+               struct hpi_hw_obj *phw = pao->priv;
                phw->ado[dsp_index].pa_parent_adapter = pao;
        }
 
-       phr->u.s.adapter_type = ao.adapter_type;
+       phr->u.s.adapter_type = ao.type;
        phr->u.s.adapter_index = ao.index;
        phr->error = 0;
 }
@@ -476,7 +475,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
        u32 dsp_index = 0;
        u32 control_cache_size = 0;
        u32 control_cache_count = 0;
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
 
        /* The PCI2040 has the following address map */
        /* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */
@@ -559,7 +558,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
                        if (error)
                                return error;
                }
-               pao->adapter_type = hr0.u.ax.info.adapter_type;
+               pao->type = hr0.u.ax.info.adapter_type;
                pao->index = hr0.u.ax.info.adapter_index;
        }
 
@@ -584,9 +583,8 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
                        pao->has_control_cache = 1;
        }
 
-       HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n",
-               pao->adapter_type, pao->index);
-       pao->open = 0;  /* upon creation the adapter is closed */
+       HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n", pao->type,
+               pao->index);
 
        if (phw->p_cache)
                phw->p_cache->adap_idx = pao->index;
@@ -596,7 +594,7 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
 
 static void delete_adapter_obj(struct hpi_adapter_obj *pao)
 {
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
 
        if (pao->has_control_cache)
                hpi_free_control_cache(phw->p_cache);
@@ -639,7 +637,7 @@ static void adapter_get_asserts(struct hpi_adapter_obj *pao,
 static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
        u32 *pos_error_code)
 {
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
        short error;
        u32 timeout;
        u32 read = 0;
@@ -1220,8 +1218,8 @@ static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,
 static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
        u16 dsp_index, u32 hpi_address, u32 *source, u32 count)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 time_out = PCI_TIMEOUT;
        int c6711_burst_size = 128;
        u32 local_hpi_address = hpi_address;
@@ -1258,8 +1256,8 @@ static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,
 static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
        u16 dsp_index, u32 hpi_address, u32 *dest, u32 count)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 time_out = PCI_TIMEOUT;
        int c6711_burst_size = 16;
        u32 local_hpi_address = hpi_address;
@@ -1298,7 +1296,7 @@ static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,
 static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
        u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr)
 {
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
        struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 timeout;
        u16 ack;
@@ -1414,8 +1412,8 @@ static short hpi6000_send_data_check_adr(u32 address, u32 length_in_dwords)
 static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
        struct hpi_message *phm, struct hpi_response *phr)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 data_sent = 0;
        u16 ack;
        u32 length, address;
@@ -1487,8 +1485,8 @@ static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,
 static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,
        struct hpi_message *phm, struct hpi_response *phr)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 data_got = 0;
        u16 ack;
        u32 length, address;
@@ -1551,8 +1549,8 @@ static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo)
 static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,
        u16 dsp_index, u32 host_cmd)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 timeout = TIMEOUT;
 
        /* set command */
@@ -1577,7 +1575,7 @@ static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
 {
        u32 hPI_error;
 
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
 
        /* read the error bits from the PCI2040 */
        hPI_error = ioread32(phw->dw2040_HPICSR + HPI_ERROR_REPORT);
@@ -1597,8 +1595,8 @@ static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,
 static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,
        u32 ack_value)
 {
-       struct dsp_obj *pdo =
-               &(*(struct hpi_hw_obj *)pao->priv).ado[dsp_index];
+       struct hpi_hw_obj *phw = pao->priv;
+       struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 ack = 0L;
        u32 timeout;
        u32 hPIC = 0L;
@@ -1640,7 +1638,7 @@ static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,
        struct hpi_message *phm)
 {
        const u16 dsp_index = 0;
-       struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+       struct hpi_hw_obj *phw = pao->priv;
        struct dsp_obj *pdo = &phw->ado[dsp_index];
        u32 timeout;
        u32 cache_dirty_flag;
@@ -1740,7 +1738,8 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
 {
        u16 error = 0;
        u16 dsp_index = 0;
-       u16 num_dsp = ((struct hpi_hw_obj *)pao->priv)->num_dsp;
+       struct hpi_hw_obj *phw = pao->priv;
+       u16 num_dsp = phw->num_dsp;
 
        if (num_dsp < 2)
                dsp_index = 0;
index 4c7d507c0ecdb52a1fd0a03b87391e14bbe599e2..7e0deeff5e7c5cbabec3d8309a1b2dbe28448266 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index e041a6ae1c5a44bc48f76dcffa08622f35e14d29..4f2873880b1675fffcaea14cb876d8a8601a69bc 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
 #define HPI6205_ERROR_MSG_RESP_TIMEOUT          1016
 
 /* initialization/bootload errors */
-#define HPI6205_ERROR_6205_NO_IRQ               1002
-#define HPI6205_ERROR_6205_INIT_FAILED          1003
-#define HPI6205_ERROR_6205_REG                  1006
-#define HPI6205_ERROR_6205_DSPPAGE              1007
-#define HPI6205_ERROR_C6713_HPIC                1009
-#define HPI6205_ERROR_C6713_HPIA                1010
-#define HPI6205_ERROR_C6713_PLL                 1011
-#define HPI6205_ERROR_DSP_INTMEM                1012
-#define HPI6205_ERROR_DSP_EXTMEM                1013
-#define HPI6205_ERROR_DSP_PLD                   1014
-#define HPI6205_ERROR_6205_EEPROM               1017
-#define HPI6205_ERROR_DSP_EMIF                  1018
+#define HPI6205_ERROR_6205_NO_IRQ       1002
+#define HPI6205_ERROR_6205_INIT_FAILED  1003
+#define HPI6205_ERROR_6205_REG          1006
+#define HPI6205_ERROR_6205_DSPPAGE      1007
+#define HPI6205_ERROR_C6713_HPIC        1009
+#define HPI6205_ERROR_C6713_HPIA        1010
+#define HPI6205_ERROR_C6713_PLL         1011
+#define HPI6205_ERROR_DSP_INTMEM        1012
+#define HPI6205_ERROR_DSP_EXTMEM        1013
+#define HPI6205_ERROR_DSP_PLD           1014
+#define HPI6205_ERROR_6205_EEPROM       1017
+#define HPI6205_ERROR_DSP_EMIF1         1018
+#define HPI6205_ERROR_DSP_EMIF2         1019
+#define HPI6205_ERROR_DSP_EMIF3         1020
+#define HPI6205_ERROR_DSP_EMIF4         1021
 
 /*****************************************************************************/
 /* for C6205 PCI i/f */
@@ -488,7 +491,7 @@ static void subsys_create_adapter(struct hpi_message *phm,
                return;
        }
 
-       phr->u.s.adapter_type = ao.adapter_type;
+       phr->u.s.adapter_type = ao.type;
        phr->u.s.adapter_index = ao.index;
        phr->error = 0;
 }
@@ -503,7 +506,7 @@ static void adapter_delete(struct hpi_adapter_obj *pao,
                phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
                return;
        }
-       phw = (struct hpi_hw_obj *)pao->priv;
+       phw = pao->priv;
        /* reset adapter h/w */
        /* Reset C6713 #1 */
        boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
@@ -652,7 +655,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                if (hr.error)
                        return hr.error;
 
-               pao->adapter_type = hr.u.ax.info.adapter_type;
+               pao->type = hr.u.ax.info.adapter_type;
                pao->index = hr.u.ax.info.adapter_index;
 
                max_streams =
@@ -665,8 +668,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                        hr.u.ax.info.serial_number);
        }
 
-       pao->open = 0;  /* upon creation the adapter is closed */
-
        if (phw->p_cache)
                phw->p_cache->adap_idx = pao->index;
 
@@ -803,8 +804,8 @@ static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
                        obj_index];
                status->samples_processed = 0;
                status->stream_state = HPI_STATE_STOPPED;
-               status->dSP_index = 0;
-               status->host_index = status->dSP_index;
+               status->dsp_index = 0;
+               status->host_index = status->dsp_index;
                status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
                status->auxiliary_data_available = 0;
 
@@ -878,7 +879,7 @@ static void outstream_host_buffer_free(struct hpi_adapter_obj *pao,
 static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status)
 {
        return status->size_in_bytes - (status->host_index -
-               status->dSP_index);
+               status->dsp_index);
 }
 
 static void outstream_write(struct hpi_adapter_obj *pao,
@@ -1080,8 +1081,8 @@ static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
                        obj_index];
                status->samples_processed = 0;
                status->stream_state = HPI_STATE_STOPPED;
-               status->dSP_index = 0;
-               status->host_index = status->dSP_index;
+               status->dsp_index = 0;
+               status->host_index = status->dsp_index;
                status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
                status->auxiliary_data_available = 0;
 
@@ -1162,7 +1163,7 @@ static void instream_start(struct hpi_adapter_obj *pao,
 
 static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status)
 {
-       return status->dSP_index - status->host_index;
+       return status->dsp_index - status->host_index;
 }
 
 static void instream_read(struct hpi_adapter_obj *pao,
@@ -1614,7 +1615,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
                boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
                if (setting != boot_loader_read_mem32(pao, dsp_index,
                                0x01800008))
-                       return HPI6205_ERROR_DSP_EMIF;
+                       return HPI6205_ERROR_DSP_EMIF1;
 
                /* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
                /* which occupies D15..0. 6713 starts at 27MHz, so need */
@@ -1627,7 +1628,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
                boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
                if (setting != boot_loader_read_mem32(pao, dsp_index,
                                0x01800004))
-                       return HPI6205_ERROR_DSP_EMIF;
+                       return HPI6205_ERROR_DSP_EMIF2;
 
                /* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
                /* which occupies D15..0. 6713 starts at 27MHz, so need */
@@ -1639,7 +1640,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
                boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
                if (setting != boot_loader_read_mem32(pao, dsp_index,
                                0x01800010))
-                       return HPI6205_ERROR_DSP_EMIF;
+                       return HPI6205_ERROR_DSP_EMIF3;
 
                /* EMIF CE3 setup - 32 bit async. */
                /* This is the PLD on the ASI5000 cards only */
@@ -1650,7 +1651,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
                boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
                if (setting != boot_loader_read_mem32(pao, dsp_index,
                                0x01800014))
-                       return HPI6205_ERROR_DSP_EMIF;
+                       return HPI6205_ERROR_DSP_EMIF4;
 
                /* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
                /*  need to use this else DSP code crashes? */
index d497030c160fb951bd5148bd067d1b77bda2b6a6..4cc315daeda0dcfcbd04d976aa6b7b02f13a1656 100644 (file)
@@ -25,6 +25,7 @@ HPI internal definitions
 #define _HPI_INTERNAL_H_
 
 #include "hpi.h"
+
 /** maximum number of memory regions mapped to an adapter */
 #define HPI_MAX_ADAPTER_MEM_SPACES (2)
 
@@ -220,8 +221,6 @@ enum HPI_CONTROL_ATTRIBUTES {
 
        HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1),
        HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2),
-       /*HPI_COBRANET_SET_DATA         = HPI_CTL_ATTR(COBRANET, 3), */
-       /*HPI_COBRANET_GET_DATA         = HPI_CTL_ATTR(COBRANET, 4), */
        HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5),
        HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6),
        HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7),
@@ -241,7 +240,9 @@ enum HPI_CONTROL_ATTRIBUTES {
        HPI_PAD_PROGRAM_TYPE = HPI_CTL_ATTR(PAD, 5),
        HPI_PAD_PROGRAM_ID = HPI_CTL_ATTR(PAD, 6),
        HPI_PAD_TA_SUPPORT = HPI_CTL_ATTR(PAD, 7),
-       HPI_PAD_TA_ACTIVE = HPI_CTL_ATTR(PAD, 8)
+       HPI_PAD_TA_ACTIVE = HPI_CTL_ATTR(PAD, 8),
+
+       HPI_UNIVERSAL_ENTITY = HPI_CTL_ATTR(UNIVERSAL, 1)
 };
 
 #define HPI_POLARITY_POSITIVE           0
@@ -393,14 +394,10 @@ enum HPI_FUNCTION_IDS {
        HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
        HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
        HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
-       /* HPI_SUBSYS_FIND_ADAPTERS     = HPI_FUNC_ID(SUBSYSTEM, 4), */
        HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
        HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
-       /* HPI_SUBSYS_DELETE_ADAPTER    = HPI_FUNC_ID(SUBSYSTEM, 7), */
        HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
        HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
-       /* HPI_SUBSYS_READ_PORT_8               = HPI_FUNC_ID(SUBSYSTEM, 10), */
-       /* HPI_SUBSYS_WRITE_PORT_8              = HPI_FUNC_ID(SUBSYSTEM, 11), */
        HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
        HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
        HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
@@ -430,7 +427,10 @@ enum HPI_FUNCTION_IDS {
        HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
        HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
        HPI_ADAPTER_DELETE = HPI_FUNC_ID(ADAPTER, 21),
-#define HPI_ADAPTER_FUNCTION_COUNT 21
+       HPI_ADAPTER_READ_FLASH = HPI_FUNC_ID(ADAPTER, 22),
+       HPI_ADAPTER_END_FLASH = HPI_FUNC_ID(ADAPTER, 23),
+       HPI_ADAPTER_FILESTORE_DELETE_ALL = HPI_FUNC_ID(ADAPTER, 24),
+#define HPI_ADAPTER_FUNCTION_COUNT 24
 
        HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
        HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
@@ -495,7 +495,9 @@ enum HPI_FUNCTION_IDS {
        HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES = HPI_FUNC_ID(MIXER, 10),
        HPI_MIXER_STORE = HPI_FUNC_ID(MIXER, 11),
        HPI_MIXER_GET_CACHE_INFO = HPI_FUNC_ID(MIXER, 12),
-#define HPI_MIXER_FUNCTION_COUNT 12
+       HPI_MIXER_GET_BLOCK_HANDLE = HPI_FUNC_ID(MIXER, 13),
+       HPI_MIXER_GET_PARAMETER_HANDLE = HPI_FUNC_ID(MIXER, 14),
+#define HPI_MIXER_FUNCTION_COUNT 14
 
        HPI_CONTROL_GET_INFO = HPI_FUNC_ID(CONTROL, 1),
        HPI_CONTROL_GET_STATE = HPI_FUNC_ID(CONTROL, 2),
@@ -618,7 +620,7 @@ struct hpi_hostbuffer_status {
        u32 auxiliary_data_available;
        u32 stream_state;
        /* DSP index in to the host bus master buffer. */
-       u32 dSP_index;
+       u32 dsp_index;
        /* Host index in to the host bus master buffer. */
        u32 host_index;
        u32 size_in_bytes;
@@ -660,13 +662,6 @@ union hpi_adapterx_msg {
        struct {
                u16 index;
        } module_info;
-       struct {
-               u32 checksum;
-               u16 sequence;
-               u16 length;
-               u16 offset; /**< offset from start of msg to data */
-               u16 unused;
-       } program_flash;
        struct {
                u16 index;
                u16 what;
@@ -677,19 +672,11 @@ union hpi_adapterx_msg {
                u16 parameter1;
                u16 parameter2;
        } property_set;
-       struct {
-               u32 offset;
-       } query_flash;
        struct {
                u32 pad32;
                u16 key1;
                u16 key2;
        } restart;
-       struct {
-               u32 offset;
-               u32 length;
-               u32 key;
-       } start_flash;
        struct {
                u32 pad32;
                u16 value;
@@ -697,6 +684,7 @@ union hpi_adapterx_msg {
        struct {
                u32 yes;
        } irq_query;
+       u32 pad[3];
 };
 
 struct hpi_adapter_res {
@@ -723,18 +711,10 @@ union hpi_adapterx_res {
        struct {
                u32 adapter_mode;
        } mode;
-       struct {
-               u16 sequence;
-       } program_flash;
        struct {
                u16 parameter1;
                u16 parameter2;
        } property_get;
-       struct {
-               u32 checksum;
-               u32 length;
-               u32 version;
-       } query_flash;
        struct {
                u32 yes;
        } irq_query;
@@ -1150,74 +1130,9 @@ struct hpi_res_adapter_get_info {
        struct hpi_adapter_res p;
 };
 
-/* padding is so these are same size as v0 hpi_message */
-struct hpi_msg_adapter_query_flash {
-       struct hpi_message_header h;
-       u32 offset;
-       u8 pad_to_version0_size[sizeof(struct hpi_message) -    /* V0 res */
-               sizeof(struct hpi_message_header) - 1 * sizeof(u32)];
-};
-
-/* padding is so these are same size as v0 hpi_response */
-struct hpi_res_adapter_query_flash {
-       struct hpi_response_header h;
-       u32 checksum;
-       u32 length;
-       u32 version;
-       u8 pad_to_version0_size[sizeof(struct hpi_response) -   /* V0 res */
-               sizeof(struct hpi_response_header) - 3 * sizeof(u32)];
-};
-
-struct hpi_msg_adapter_start_flash {
-       struct hpi_message_header h;
-       u32 offset;
-       u32 length;
-       u32 key;
-       u8 pad_to_version0_size[sizeof(struct hpi_message) -    /* V0 res */
-               sizeof(struct hpi_message_header) - 3 * sizeof(u32)];
-};
-
-struct hpi_res_adapter_start_flash {
-       struct hpi_response_header h;
-       u8 pad_to_version0_size[sizeof(struct hpi_response) -   /* V0 res */
-               sizeof(struct hpi_response_header)];
-};
-
-struct hpi_msg_adapter_program_flash_payload {
-       u32 checksum;
-       u16 sequence;
-       u16 length;
-       u16 offset; /**< offset from start of msg to data */
-       u16 unused;
-       /* ensure sizeof(header + payload) == sizeof(hpi_message_V0)
-          because old firmware expects data after message of this size */
-       u8 pad_to_version0_size[sizeof(struct hpi_message) -    /* V0 message */
-               sizeof(struct hpi_message_header) - sizeof(u32) -
-               4 * sizeof(u16)];
-};
-
-struct hpi_msg_adapter_program_flash {
-       struct hpi_message_header h;
-       struct hpi_msg_adapter_program_flash_payload p;
-       u32 data[256];
-};
-
-struct hpi_res_adapter_program_flash {
-       struct hpi_response_header h;
-       u16 sequence;
-       u8 pad_to_version0_size[sizeof(struct hpi_response) -   /* V0 res */
-               sizeof(struct hpi_response_header) - sizeof(u16)];
-};
-
-struct hpi_msg_adapter_debug_read {
-       struct hpi_message_header h;
-       u32 dsp_address;
-       u32 count_bytes;
-};
-
 struct hpi_res_adapter_debug_read {
        struct hpi_response_header h;
-       u8 bytes[256];
+       u8 bytes[1024];
 };
 
 struct hpi_msg_cobranet_hmi {
@@ -1461,7 +1376,7 @@ struct hpi_control_cache_pad {
 /* 2^N sized FIFO buffer (internal to HPI<->DSP interaction) */
 struct hpi_fifo_buffer {
        u32 size;
-       u32 dSP_index;
+       u32 dsp_index;
        u32 host_index;
 };
 
diff --git a/sound/pci/asihpi/hpi_version.h b/sound/pci/asihpi/hpi_version.h
new file mode 100644 (file)
index 0000000..e9146e5
--- /dev/null
@@ -0,0 +1,32 @@
+/** HPI Version Definitions
+Development releases have odd minor version.
+Production releases have even minor version.
+
+\file hpi_version.h
+*/
+
+#ifndef _HPI_VERSION_H
+#define _HPI_VERSION_H
+
+/* Use single digits for versions less that 10 to avoid octal. */
+/* *** HPI_VER is the only edit required to update version *** */
+/** HPI version */
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4, 10, 1)
+
+/** HPI version string in dotted decimal format */
+#define HPI_VER_STRING "4.10.01"
+
+/** Library version as documented in hpi-api-versions.txt */
+#define HPI_LIB_VER  HPI_VERSION_CONSTRUCTOR(10, 2, 0)
+
+/** Construct hpi version number from major, minor, release numbers */
+#define HPI_VERSION_CONSTRUCTOR(maj, min, r) ((maj << 16) + (min << 8) + r)
+
+/** Extract major version from hpi version number */
+#define HPI_VER_MAJOR(v) ((int)(v >> 16))
+/** Extract minor version from hpi version number */
+#define HPI_VER_MINOR(v) ((int)((v >> 8) & 0xFF))
+/** Extract release from hpi version number */
+#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
+
+#endif
index bd47521b24ec1fa336f0b0a952d2b41c39cc5dd6..7ed5c26c3737f11fd2eb98a5c4da858ac23f3731 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -68,7 +68,7 @@ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
 u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
 {
        u16 retval = 0;
-       /*HPI_ASSERT(pao->wAdapterType); */
+       /*HPI_ASSERT(pao->type); */
 
        hpios_alistlock_lock(&adapters);
 
@@ -77,13 +77,13 @@ u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
                goto unlock;
        }
 
-       if (adapters.adapter[pao->index].adapter_type) {
+       if (adapters.adapter[pao->index].type) {
                int a;
                for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
-                       if (!adapters.adapter[a].adapter_type) {
+                       if (!adapters.adapter[a].type) {
                                HPI_DEBUG_LOG(WARNING,
                                        "ASI%X duplicate index %d moved to %d\n",
-                                       pao->adapter_type, pao->index, a);
+                                       pao->type, pao->index, a);
                                pao->index = a;
                                break;
                        }
@@ -104,13 +104,13 @@ unlock:
 
 void hpi_delete_adapter(struct hpi_adapter_obj *pao)
 {
-       if (!pao->adapter_type) {
+       if (!pao->type) {
                HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
                return;
        }
 
        hpios_alistlock_lock(&adapters);
-       if (adapters.adapter[pao->index].adapter_type)
+       if (adapters.adapter[pao->index].type)
                adapters.gw_num_adapters--;
        memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
        hpios_alistlock_unlock(&adapters);
@@ -132,7 +132,7 @@ struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
        }
 
        pao = &adapters.adapter[adapter_index];
-       if (pao->adapter_type != 0) {
+       if (pao->type != 0) {
                /*
                   HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n",
                   wAdapterIndex);
@@ -165,7 +165,7 @@ static void subsys_get_adapter(struct hpi_message *phm,
 
        /* find the nCount'th nonzero adapter in array */
        for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
-               if (adapters.adapter[index].adapter_type) {
+               if (adapters.adapter[index].type) {
                        if (!count)
                                break;
                        count--;
@@ -174,11 +174,11 @@ static void subsys_get_adapter(struct hpi_message *phm,
 
        if (index < HPI_MAX_ADAPTERS) {
                phr->u.s.adapter_index = adapters.adapter[index].index;
-               phr->u.s.adapter_type = adapters.adapter[index].adapter_type;
+               phr->u.s.adapter_type = adapters.adapter[index].type;
        } else {
                phr->u.s.adapter_index = 0;
                phr->u.s.adapter_type = 0;
-               phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
+               phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
        }
 }
 
@@ -324,6 +324,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
        }
 
        phr->error = 0;
+       phr->specific_error = 0;
+       phr->version = 0;
 
        /* set the default response size */
        response_size =
@@ -531,8 +533,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
                found ? "Cached" : "Uncached", phm->adapter_index,
                pI->control_index, pI->control_type, phm->u.c.attribute);
 
-       if (found)
+       if (found) {
                phr->size = (u16)response_size;
+               phr->type = HPI_TYPE_RESPONSE;
+               phr->object = phm->object;
+               phr->function = phm->function;
+       }
 
        return found;
 }
@@ -631,7 +637,7 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
        if (!p_cache)
                return NULL;
 
-       p_cache->p_info = kzalloc(sizeof(*p_cache->p_info) * control_count,
+       p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info),
                                  GFP_KERNEL);
        if (!p_cache->p_info) {
                kfree(p_cache);
index d53cdf6e535f51d877bee38925d26a6c7e9c99e1..e44121283047f964338c89a93e9d39cb110540ce 100644 (file)
@@ -1,7 +1,7 @@
 /**
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
 
 */
 
+struct hpi_adapter_obj;
+
+/* a function that takes an adapter obj and returns an int */
+typedef int adapter_int_func(struct hpi_adapter_obj *pao);
+
 struct hpi_adapter_obj {
        struct hpi_pci pci;     /* PCI info - bus#,dev#,address etc */
-       u16 adapter_type;       /* ASI6701 etc */
-       u16 index;              /* */
-       u16 open;               /* =1 when adapter open */
-       u16 mixer_open;
+       u16 type;               /* 0x6644 == ASI6644 etc */
+       u16 index;
 
        struct hpios_spinlock dsp_lock;
 
index b52baf62791ed3bf96bab2515bfaaf62383e3597..ac86a1f1d3bfba36d33adb52ef6349421aa16329 100644 (file)
@@ -1,7 +1,7 @@
 /************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index 940f54c3c5383e377a77dbf3f794818f06147085..2c9af2329d36bf2b6541f875b2aa332fde5b7e45 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index 71d32c868c9244e19160687922fb7c7fa86ca97c..456a758f04f6112ee7c75bf2a9c842cc711b70c3 100644 (file)
@@ -25,6 +25,7 @@ hotplug firmware loader from individual dsp code files
 #define SOURCEFILE_NAME "hpidspcd.c"
 #include "hpidspcd.h"
 #include "hpidebug.h"
+#include "hpi_version.h"
 
 struct dsp_code_private {
        /**  Firmware descriptor */
@@ -32,9 +33,6 @@ struct dsp_code_private {
        struct pci_dev *dev;
 };
 
-#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
-           HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
-
 /*-------------------------------------------------------------------*/
 short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
        u32 *os_error_code)
@@ -66,22 +64,25 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
        if ((header.type != 0x45444F43) ||      /* "CODE" */
                (header.adapter != adapter)
                || (header.size != firmware->size)) {
-               dev_printk(KERN_ERR, &dev->dev, "Invalid firmware file\n");
+               dev_printk(KERN_ERR, &dev->dev,
+                       "Invalid firmware header size %d != file %zd\n",
+                       header.size, firmware->size);
                goto error2;
        }
 
-       if ((header.version / 100 & ~1) != (HPI_VER_DECIMAL / 100 & ~1)) {
+       if ((header.version >> 9) != (HPI_VER >> 9)) {
+               /* Consider even and subsequent odd minor versions to be compatible */
                dev_printk(KERN_ERR, &dev->dev,
                        "Incompatible firmware version "
-                       "DSP image %d != Driver %d\n", header.version,
-                       HPI_VER_DECIMAL);
+                       "DSP image %X != Driver %X\n", header.version,
+                       HPI_VER);
                goto error2;
        }
 
-       if (header.version != HPI_VER_DECIMAL) {
-               dev_printk(KERN_WARNING, &dev->dev,
-                       "Firmware: release version mismatch  DSP image %d != Driver %d\n",
-                       header.version, HPI_VER_DECIMAL);
+       if (header.version != HPI_VER) {
+               dev_printk(KERN_INFO, &dev->dev,
+                       "Firmware: release version mismatch  DSP image %X != Driver %X\n",
+                       header.version, HPI_VER);
        }
 
        HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
@@ -108,11 +109,8 @@ error1:
 /*-------------------------------------------------------------------*/
 void hpi_dsp_code_close(struct dsp_code *dsp_code)
 {
-       if (dsp_code->pvt->firmware) {
-               HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
-               release_firmware(dsp_code->pvt->firmware);
-               dsp_code->pvt->firmware = NULL;
-       }
+       HPI_DEBUG_LOG(DEBUG, "dsp code closed\n");
+       release_firmware(dsp_code->pvt->firmware);
        kfree(dsp_code->pvt);
 }
 
index b22881122f196c4e4f84fecccfd20838cd842558..659d19ca6d42ce58df5ecf7f7f45302a497318a2 100644 (file)
@@ -27,10 +27,6 @@ Functions for reading DSP code to load into DSP
 
 #include "hpi_internal.h"
 
-/** Code header version is decimal encoded e.g. 4.06.10 is 40601 */
-#define HPI_VER_DECIMAL ((int)(HPI_VER_MAJOR(HPI_VER) * 10000 + \
-HPI_VER_MINOR(HPI_VER) * 100 + HPI_VER_RELEASE(HPI_VER)))
-
 /** Header structure for dsp firmware file
  This structure must match that used in s2bin.c for generation of asidsp.bin
  */
index ebb568d695f150c75c364472067664f401692361..510e56cffd31b6b71664c2b381b424e15b93888b 100644 (file)
@@ -2826,6 +2826,16 @@ u16 hpi_volume_auto_fade(u32 h_control,
                duration_ms, HPI_VOLUME_AUTOFADE_LOG);
 }
 
+u16 hpi_volume_query_auto_fade_profile(const u32 h_volume, const u32 i,
+       u16 *profile)
+{
+       u16 e;
+       u32 u;
+       e = hpi_control_query(h_volume, HPI_VOLUME_AUTOFADE, i, 0, &u);
+       *profile = (u16)u;
+       return e;
+}
+
 u16 hpi_vox_set_threshold(u32 h_control, short an_gain0_01dB)
 {
        struct hpi_message hm;
index 52400a6b5f15abf1f3e757a81a3f8f438a4cf712..032d563e37089b58556a4f7a870f948008dbdd1c 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index bfd330d78b580c2747368c990d895c898d64d3aa..5b48708c7d1e559724f2c3232dfdc772b85b2b18 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index 2e779421a6188374fe2b0d0cccb50da0257f90fd..d4790ddc225c1cbdfb7d8c5348f48ca717db8856 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -22,6 +22,7 @@ Extended Message Function With Response Caching
 *****************************************************************************/
 #define SOURCEFILE_NAME "hpimsgx.c"
 #include "hpi_internal.h"
+#include "hpi_version.h"
 #include "hpimsginit.h"
 #include "hpicmn.h"
 #include "hpimsgx.h"
index fd49e7542a885bd323c0385c07896a578714ab2c..37f3efd95a701427ce250e4bfcbac32bad680858 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index f6b9517b4696e1070ccdc9ef3aee9773dfd628f0..60915620556289dd4701ea6434b797e485d1f7b4 100644 (file)
@@ -21,6 +21,7 @@ Common Linux HPI ioctl and module probe/remove functions
 #define SOURCEFILE_NAME "hpioctl.c"
 
 #include "hpi_internal.h"
+#include "hpi_version.h"
 #include "hpimsginit.h"
 #include "hpidebug.h"
 #include "hpimsgx.h"
@@ -65,9 +66,7 @@ static struct hpi_adapter adapters[HPI_MAX_ADAPTERS];
 static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr,
        struct file *file)
 {
-       int adapter = phm->adapter_index;
-
-       if ((adapter >= HPI_MAX_ADAPTERS || adapter < 0)
+       if ((phm->adapter_index >= HPI_MAX_ADAPTERS)
                && (phm->object != HPI_OBJ_SUBSYSTEM))
                phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
        else
@@ -178,19 +177,14 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        } else {
                u16 __user *ptr = NULL;
                u32 size = 0;
-               u32 adapter_present;
                /* -1=no data 0=read from user mem, 1=write to user mem */
                int wrflag = -1;
-               struct hpi_adapter *pa;
+               struct hpi_adapter *pa = NULL;
 
-               if (hm->h.adapter_index < HPI_MAX_ADAPTERS) {
+               if (hm->h.adapter_index < ARRAY_SIZE(adapters))
                        pa = &adapters[hm->h.adapter_index];
-                       adapter_present = pa->type;
-               } else {
-                       adapter_present = 0;
-               }
 
-               if (!adapter_present) {
+               if (!pa || !pa->adapter || !pa->adapter->type) {
                        hpi_init_response(&hr->r0, hm->h.object,
                                hm->h.function, HPI_ERROR_BAD_ADAPTER_NUMBER);
 
@@ -317,6 +311,7 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
        const struct pci_device_id *pci_id)
 {
        int idx, nm;
+       int adapter_index;
        unsigned int memlen;
        struct hpi_message hm;
        struct hpi_response hr;
@@ -345,8 +340,6 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 
        hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
 
-       adapter.pci = pci_dev;
-
        nm = HPI_MAX_ADAPTER_MEM_SPACES;
 
        for (idx = 0; idx < nm; idx++) {
@@ -355,18 +348,16 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 
                if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
                        memlen = pci_resource_len(pci_dev, idx);
-                       adapter.ap_remapped_mem_base[idx] =
+                       pci.ap_mem_base[idx] =
                                ioremap(pci_resource_start(pci_dev, idx),
                                memlen);
-                       if (!adapter.ap_remapped_mem_base[idx]) {
+                       if (!pci.ap_mem_base[idx]) {
                                HPI_DEBUG_LOG(ERROR,
                                        "ioremap failed, aborting\n");
                                /* unmap previously mapped pci mem space */
                                goto err;
                        }
                }
-
-               pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx];
        }
 
        pci.pci_dev = pci_dev;
@@ -378,6 +369,9 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
        if (hr.error)
                goto err;
 
+       adapter_index = hr.u.s.adapter_index;
+       adapter.adapter = hpi_find_adapter(adapter_index);
+
        if (prealloc_stream_buf) {
                adapter.p_buffer = vmalloc(prealloc_stream_buf);
                if (!adapter.p_buffer) {
@@ -389,36 +383,32 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
                }
        }
 
-       adapter.index = hr.u.s.adapter_index;
-       adapter.type = hr.u.s.adapter_type;
-
        hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
                HPI_ADAPTER_OPEN);
-       hm.adapter_index = adapter.index;
+       hm.adapter_index = adapter.adapter->index;
        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
        if (hr.error)
                goto err;
 
-       adapter.snd_card_asihpi = NULL;
        /* WARNING can't init mutex in 'adapter'
         * and then copy it to adapters[] ?!?!
         */
-       adapters[adapter.index] = adapter;
-       mutex_init(&adapters[adapter.index].mutex);
-       pci_set_drvdata(pci_dev, &adapters[adapter.index]);
+       adapters[adapter_index] = adapter;
+       mutex_init(&adapters[adapter_index].mutex);
+       pci_set_drvdata(pci_dev, &adapters[adapter_index]);
 
        dev_printk(KERN_INFO, &pci_dev->dev,
-               "probe succeeded for ASI%04X HPI index %d\n", adapter.type,
-               adapter.index);
+               "probe succeeded for ASI%04X HPI index %d\n",
+               adapter.adapter->type, adapter_index);
 
        return 0;
 
 err:
        for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
-               if (adapter.ap_remapped_mem_base[idx]) {
-                       iounmap(adapter.ap_remapped_mem_base[idx]);
-                       adapter.ap_remapped_mem_base[idx] = NULL;
+               if (pci.ap_mem_base[idx]) {
+                       iounmap(pci.ap_mem_base[idx]);
+                       pci.ap_mem_base[idx] = NULL;
                }
        }
 
@@ -437,19 +427,20 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
        struct hpi_message hm;
        struct hpi_response hr;
        struct hpi_adapter *pa;
+       struct hpi_pci pci;
+
        pa = pci_get_drvdata(pci_dev);
+       pci = pa->adapter->pci;
 
        hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
                HPI_ADAPTER_DELETE);
-       hm.adapter_index = pa->index;
+       hm.adapter_index = pa->adapter->index;
        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
        /* unmap PCI memory space, mapped during device init. */
        for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
-               if (pa->ap_remapped_mem_base[idx]) {
-                       iounmap(pa->ap_remapped_mem_base[idx]);
-                       pa->ap_remapped_mem_base[idx] = NULL;
-               }
+               if (pci.ap_mem_base[idx])
+                       iounmap(pci.ap_mem_base[idx]);
        }
 
        if (pa->p_buffer)
@@ -461,7 +452,7 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
                        "remove %04x:%04x,%04x:%04x,%04x," " HPI index %d.\n",
                        pci_dev->vendor, pci_dev->device,
                        pci_dev->subsystem_vendor, pci_dev->subsystem_device,
-                       pci_dev->devfn, pa->index);
+                       pci_dev->devfn, pa->adapter->index);
 
        memset(pa, 0, sizeof(*pa));
 }
index 847f72f03fe193df707e0807902b5d8e2372a41a..2614aff672e2c8ccea387a96bbe7e97604b2ebb4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index ff2a19b544fa7643c55342259edbe6e71984260c..2d7d1c2e1d0d2553e8fbe180b7a41a66a9c4b2af 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index 2f605e34bad099cabd5e87cbb6411c5be339421b..c5cef113c2090cec68732398384ee8b1fd6d592f 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
@@ -149,20 +149,18 @@ static inline void cond_unlock(struct hpios_spinlock *l)
 #define hpios_alistlock_lock(obj) spin_lock(&((obj)->list_lock.lock))
 #define hpios_alistlock_unlock(obj) spin_unlock(&((obj)->list_lock.lock))
 
+struct snd_card;
+
+/** pci drvdata points to an instance of this struct */
 struct hpi_adapter {
+       struct hpi_adapter_obj *adapter;
+       struct snd_card *snd_card;
+
        /* mutex prevents contention for one card
           between multiple user programs (via ioctl) */
        struct mutex mutex;
-       u16 index;
-       u16 type;
-
-       /* ALSA card structure */
-       void *snd_card_asihpi;
-
        char *p_buffer;
        size_t buffer_size;
-       struct pci_dev *pci;
-       void __iomem *ap_remapped_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
 };
 
 #endif
index bb30868ce1a345abd8f2cbd36f7da5f4a66ad035..db570ddf64b3df63bbb0653fcafafcd03598c9ed 100644 (file)
@@ -1,7 +1,7 @@
 /******************************************************************************
 
     AudioScience HPI driver
-    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
+    Copyright (C) 1997-2011  AudioScience Inc. <support@audioscience.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of version 2 of the GNU General Public License as
index 15e4e5ee3881859d2910674256525e6da65496e6..590682f115ef20f6ecf9e52423049fd28de6f06c 100644 (file)
@@ -43,7 +43,7 @@ static int index = SNDRV_DEFAULT_IDX1;        /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int ac97_clock = 48000;
 static char *ac97_quirk;
-static int spdif_aclink = 1;
+static bool spdif_aclink = 1;
 static int ac97_codec = -1;
 
 module_param(index, int, 0444);
@@ -60,7 +60,7 @@ module_param(spdif_aclink, bool, 0444);
 MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index 57bf8f4bc7a8dd3e5feb2d3a39274b2313bbbbd0..524d35f312321145cc08461d78d9b498e4907d9f 100644 (file)
@@ -51,7 +51,7 @@ module_param(ac97_clock, int, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index dc326be58c4b59d7f19060bde057b2e2e3d0d14b..762bb108c51c139b71e93cf8d627ebae858a25d2 100644 (file)
@@ -26,7 +26,7 @@
 // module parameters (see "Module Parameters")
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 };
 
 module_param_array(index, int, NULL, 0444);
index 489150380eac0d11ac9c0531fa37f1d59b7cb410..6933a27a5d76279e1c98b59953200dbd52b84e08 100644 (file)
@@ -805,7 +805,7 @@ static void vortex_fifo_setadbvalid(vortex_t * vortex, int fifo, int en)
 }
 
 static void
-vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int b, int priority,
+vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority,
                       int empty, int valid, int f)
 {
        int temp, lifeboat = 0;
@@ -837,7 +837,7 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int b, int priority,
 #else
                        temp = (this_4 & 0x3f) << 0xc;
 #endif
-                       temp = (temp & 0xfffffffd) | ((b & 1) << 1);
+                       temp = (temp & 0xfffffffd) | ((stereo & 1) << 1);
                        temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
                        temp = (temp & 0xffffffef) | ((valid & 1) << 4);
                        temp |= FIFO_U1;
@@ -1148,11 +1148,11 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
 
 static void
 vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir,
-                     int fmt, int d, u32 offset)
+                     int fmt, int stereo, u32 offset)
 {
        stream_t *dma = &vortex->dma_adb[adbdma];
 
-       dma->dma_unknown = d;
+       dma->dma_unknown = stereo;
        dma->dma_ctrl =
            ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK));
        /* Enable PCMOUT interrupts. */
@@ -1336,7 +1336,6 @@ static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma)
        dma->fifo_status = FIFO_PAUSE;
 }
 
-#if 0                          // Using pause instead
 static void vortex_adbdma_stopfifo(vortex_t * vortex, int adbdma)
 {
        stream_t *dma = &vortex->dma_adb[adbdma];
@@ -1351,7 +1350,6 @@ static void vortex_adbdma_stopfifo(vortex_t * vortex, int adbdma)
        dma->fifo_enabled = 0;
 }
 
-#endif
 /* WTDMA */
 
 #ifndef CHIP_AU8810
index c5f7ae46afefca324b1e31b8100fb0cd80afdf2b..0488633ea87474c608591601201030a65a1c91f5 100644 (file)
@@ -307,8 +307,8 @@ static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
        fmt = vortex_alsafmt_aspfmt(runtime->format);
        spin_lock_irq(&chip->lock);
        if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
-               vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ ,
-                                     0);
+               vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
+                               runtime->channels == 1 ? 0 : 1, 0);
                vortex_adbdma_setstartbuffer(chip, dma, 0);
                if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
                        vortex_adb_setsrc(chip, dma, runtime->rate, dir);
@@ -353,8 +353,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                //printk(KERN_INFO "vortex: stop %d\n", dma);
                stream->fifo_enabled = 0;
                if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
-                       vortex_adbdma_pausefifo(chip, dma);
-               //vortex_adbdma_stopfifo(chip, dma);
+                       vortex_adbdma_stopfifo(chip, dma);
 #ifndef CHIP_AU8810
                else {
                        printk(KERN_INFO "vortex: wt stop %d\n", dma);
index b4151e208b719d60d3b55ec209c1e00a927fae9c..b278e285fd401103efdae0d9e24d67bb50f5ad84 100644 (file)
@@ -48,43 +48,61 @@ static unsigned short const wXtalkNarrowLeftDelay = 0x7;
 static unsigned short const wXtalkNarrowRightDelay = 0x7;
 
 static xtalk_gains_t const asXtalkGainsDefault = {
-       0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000,
-       0x4000
+       0x4000, 0x4000, 0x4000, 0x4000, 0x4000,
+       0x4000, 0x4000, 0x4000, 0x4000, 0x4000
 };
 
 static xtalk_gains_t const asXtalkGainsTest = {
-       0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002,
-       0
+       0x7fff, 0x8000, 0x0000, 0x0000, 0x0001,
+       0xffff, 0x4000, 0xc000, 0x0002, 0xfffe
 };
+
 static xtalk_gains_t const asXtalkGains1Chan = {
-       0x7FFF, 0, 0, 0, 0x7FFF, 0, 0, 0, 0, 0
+       0x7FFF, 0, 0, 0, 0,
+       0x7FFF, 0, 0, 0, 0,
 };
 
 // Input gain for 4 A3D slices. One possible input pair is left zero.
 static xtalk_gains_t const asXtalkGainsAllChan = {
-       0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
-       0
-           //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
+       0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0,
+       0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0
+};
+
+static xtalk_gains_t const asXtalkGainsZeros = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
-static xtalk_gains_t const asXtalkGainsZeros;
 
-static xtalk_dline_t const alXtalkDlineZeros;
+static xtalk_dline_t const alXtalkDlineZeros = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
 static xtalk_dline_t const alXtalkDlineTest = {
-       0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0x0000fc18, 0xfff03e8, 0x000186a0, 0xfffe7960, 1, 0xffffffff, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static xtalk_instate_t const asXtalkInStateZeros = {
        0, 0, 0, 0
 };
 
-static xtalk_instate_t const asXtalkInStateZeros;
-static xtalk_instate_t const asXtalkInStateTest =
-    { 0xFF80, 0x0080, 0xFFFF, 0x0001 };
-static xtalk_state_t const asXtalkOutStateZeros;
+static xtalk_instate_t const asXtalkInStateTest = {
+       0x0080, 0xff80, 0x0001, 0xffff
+};
+
+static xtalk_state_t const asXtalkOutStateZeros = {
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0},
+       {0, 0, 0, 0}
+};
 
 static short const sDiamondKLeftEq = 0x401d;
 static short const sDiamondKRightEq = 0x401d;
 static short const sDiamondKLeftXt = 0xF90E;
 static short const sDiamondKRightXt = 0xF90E;
-static short const sDiamondShiftLeftEq = 1;    /* 0xF90E Is this a bug ??? */
+static short const sDiamondShiftLeftEq = 1;
 static short const sDiamondShiftRightEq = 1;
 static short const sDiamondShiftLeftXt = 0;
 static short const sDiamondShiftRightXt = 0;
@@ -94,29 +112,29 @@ static unsigned short const wDiamondRightDelay = 0xb;
 static xtalk_coefs_t const asXtalkWideCoefsLeftEq = {
        {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
        {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
-       {0x340B, 0xf504, 0x6CE8, 0x0D23, 0x00E4},
-       {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
+       {0x340B, 0xe8f5, 0x236c, 0xe40d, 0},
+       {0x76d5, 0xc78d, 0x05ac, 0xfa5b, 0},
        {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
 };
 static xtalk_coefs_t const asXtalkWideCoefsRightEq = {
        {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
        {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
-       {0x340B, 0xF504, 0x6CE8, 0x0D23, 0x00E4},
-       {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
+       {0x340B, 0xe8f5, 0x236c, 0xe40d, 0},
+       {0x76d5, 0xc78d, 0x05ac, 0xfa5b, 0},
        {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
 };
 static xtalk_coefs_t const asXtalkWideCoefsLeftXt = {
-       {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
-       {0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
-       {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
-       {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
+       {0x55c6, 0xc97b, 0x005b, 0x0047, 0},
+       {0x6a60, 0xca20, 0xffc6, 0x0040, 0},
+       {0x6411, 0xd711, 0xfca1, 0x0190, 0},
+       {0x77dc, 0xc79e, 0xffb8, 0x000a, 0},
        {0, 0, 0, 0, 0}
 };
 static xtalk_coefs_t const asXtalkWideCoefsRightXt = {
-       {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
-       {0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
-       {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
-       {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
+       {0x55c6, 0xc97b, 0x005b, 0x0047, 0},
+       {0x6a60, 0xca20, 0xffc6, 0x0040, 0},
+       {0x6411, 0xd711, 0xfca1, 0x0190, 0},
+       {0x77dc, 0xc79e, 0xffb8, 0x000a, 0},
        {0, 0, 0, 0, 0}
 };
 static xtalk_coefs_t const asXtalkNarrowCoefsLeftEq = {
@@ -151,7 +169,14 @@ static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
        {0, 0, 0, 0, 0}
 };
 
-static xtalk_coefs_t const asXtalkCoefsZeros;
+static xtalk_coefs_t const asXtalkCoefsZeros = {
+       {0, 0, 0, 0, 0},
+       {0, 0, 0, 0, 0},
+       {0, 0, 0, 0, 0},
+       {0, 0, 0, 0, 0},
+       {0, 0, 0, 0, 0}
+};
+
 static xtalk_coefs_t const asXtalkCoefsPipe = {
        {0, 0, 0x0FA0, 0, 0},
        {0, 0, 0x0FA0, 0, 0},
@@ -186,7 +211,7 @@ static xtalk_coefs_t const asXtalkCoefsDenTest = {
 static xtalk_state_t const asXtalkOutStateTest = {
        {0x7FFF, 0x0004, 0xFFFC, 0},
        {0xFE00, 0x0008, 0xFFF8, 0x4000},
-       {0x200, 0x0010, 0xFFF0, 0xC000},
+       {0x0200, 0x0010, 0xFFF0, 0xC000},
        {0x8000, 0x0020, 0xFFE0, 0},
        {0, 0, 0, 0}
 };
@@ -306,10 +331,10 @@ vortex_XtalkHw_SetLeftEQStates(vortex_t * vortex,
                hwwrite(vortex->mmio, 0x2421C + i * 0x24, coefs[i][2]);
                hwwrite(vortex->mmio, 0x24220 + i * 0x24, coefs[i][3]);
        }
-       hwwrite(vortex->mmio, 0x244F8 + i * 0x24, arg_0[0]);
-       hwwrite(vortex->mmio, 0x244FC + i * 0x24, arg_0[1]);
-       hwwrite(vortex->mmio, 0x24500 + i * 0x24, arg_0[2]);
-       hwwrite(vortex->mmio, 0x24504 + i * 0x24, arg_0[3]);
+       hwwrite(vortex->mmio, 0x244F8, arg_0[0]);
+       hwwrite(vortex->mmio, 0x244FC, arg_0[1]);
+       hwwrite(vortex->mmio, 0x24500, arg_0[2]);
+       hwwrite(vortex->mmio, 0x24504, arg_0[3]);
 }
 
 static void
@@ -325,10 +350,10 @@ vortex_XtalkHw_SetRightEQStates(vortex_t * vortex,
                hwwrite(vortex->mmio, 0x242D0 + i * 0x24, coefs[i][2]);
                hwwrite(vortex->mmio, 0x244D4 + i * 0x24, coefs[i][3]);
        }
-       hwwrite(vortex->mmio, 0x24508 + i * 0x24, arg_0[0]);
-       hwwrite(vortex->mmio, 0x2450C + i * 0x24, arg_0[1]);
-       hwwrite(vortex->mmio, 0x24510 + i * 0x24, arg_0[2]);
-       hwwrite(vortex->mmio, 0x24514 + i * 0x24, arg_0[3]);
+       hwwrite(vortex->mmio, 0x24508, arg_0[0]);
+       hwwrite(vortex->mmio, 0x2450C, arg_0[1]);
+       hwwrite(vortex->mmio, 0x24510, arg_0[2]);
+       hwwrite(vortex->mmio, 0x24514, arg_0[3]);
 }
 
 static void
@@ -344,10 +369,10 @@ vortex_XtalkHw_SetLeftXTStates(vortex_t * vortex,
                hwwrite(vortex->mmio, 0x24384 + i * 0x24, coefs[i][2]);
                hwwrite(vortex->mmio, 0x24388 + i * 0x24, coefs[i][3]);
        }
-       hwwrite(vortex->mmio, 0x24518 + i * 0x24, arg_0[0]);
-       hwwrite(vortex->mmio, 0x2451C + i * 0x24, arg_0[1]);
-       hwwrite(vortex->mmio, 0x24520 + i * 0x24, arg_0[2]);
-       hwwrite(vortex->mmio, 0x24524 + i * 0x24, arg_0[3]);
+       hwwrite(vortex->mmio, 0x24518, arg_0[0]);
+       hwwrite(vortex->mmio, 0x2451C, arg_0[1]);
+       hwwrite(vortex->mmio, 0x24520, arg_0[2]);
+       hwwrite(vortex->mmio, 0x24524, arg_0[3]);
 }
 
 static void
@@ -363,10 +388,10 @@ vortex_XtalkHw_SetRightXTStates(vortex_t * vortex,
                hwwrite(vortex->mmio, 0x24438 + i * 0x24, coefs[i][2]);
                hwwrite(vortex->mmio, 0x2443C + i * 0x24, coefs[i][3]);
        }
-       hwwrite(vortex->mmio, 0x24528 + i * 0x24, arg_0[0]);
-       hwwrite(vortex->mmio, 0x2452C + i * 0x24, arg_0[1]);
-       hwwrite(vortex->mmio, 0x24530 + i * 0x24, arg_0[2]);
-       hwwrite(vortex->mmio, 0x24534 + i * 0x24, arg_0[3]);
+       hwwrite(vortex->mmio, 0x24528, arg_0[0]);
+       hwwrite(vortex->mmio, 0x2452C, arg_0[1]);
+       hwwrite(vortex->mmio, 0x24530, arg_0[2]);
+       hwwrite(vortex->mmio, 0x24534, arg_0[3]);
 }
 
 #if 0
@@ -450,10 +475,10 @@ vortex_XtalkHw_GetLeftEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
                coefs[i][2] = hwread(vortex->mmio, 0x2421C + i * 0x24);
                coefs[i][3] = hwread(vortex->mmio, 0x24220 + i * 0x24);
        }
-       arg_0[0] = hwread(vortex->mmio, 0x244F8 + i * 0x24);
-       arg_0[1] = hwread(vortex->mmio, 0x244FC + i * 0x24);
-       arg_0[2] = hwread(vortex->mmio, 0x24500 + i * 0x24);
-       arg_0[3] = hwread(vortex->mmio, 0x24504 + i * 0x24);
+       arg_0[0] = hwread(vortex->mmio, 0x244F8);
+       arg_0[1] = hwread(vortex->mmio, 0x244FC);
+       arg_0[2] = hwread(vortex->mmio, 0x24500);
+       arg_0[3] = hwread(vortex->mmio, 0x24504);
 }
 
 static void
@@ -468,10 +493,10 @@ vortex_XtalkHw_GetRightEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
                coefs[i][2] = hwread(vortex->mmio, 0x242D0 + i * 0x24);
                coefs[i][3] = hwread(vortex->mmio, 0x242D4 + i * 0x24);
        }
-       arg_0[0] = hwread(vortex->mmio, 0x24508 + i * 0x24);
-       arg_0[1] = hwread(vortex->mmio, 0x2450C + i * 0x24);
-       arg_0[2] = hwread(vortex->mmio, 0x24510 + i * 0x24);
-       arg_0[3] = hwread(vortex->mmio, 0x24514 + i * 0x24);
+       arg_0[0] = hwread(vortex->mmio, 0x24508);
+       arg_0[1] = hwread(vortex->mmio, 0x2450C);
+       arg_0[2] = hwread(vortex->mmio, 0x24510);
+       arg_0[3] = hwread(vortex->mmio, 0x24514);
 }
 
 static void
@@ -486,10 +511,10 @@ vortex_XtalkHw_GetLeftXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
                coefs[i][2] = hwread(vortex->mmio, 0x24384 + i * 0x24);
                coefs[i][3] = hwread(vortex->mmio, 0x24388 + i * 0x24);
        }
-       arg_0[0] = hwread(vortex->mmio, 0x24518 + i * 0x24);
-       arg_0[1] = hwread(vortex->mmio, 0x2451C + i * 0x24);
-       arg_0[2] = hwread(vortex->mmio, 0x24520 + i * 0x24);
-       arg_0[3] = hwread(vortex->mmio, 0x24524 + i * 0x24);
+       arg_0[0] = hwread(vortex->mmio, 0x24518);
+       arg_0[1] = hwread(vortex->mmio, 0x2451C);
+       arg_0[2] = hwread(vortex->mmio, 0x24520);
+       arg_0[3] = hwread(vortex->mmio, 0x24524);
 }
 
 static void
@@ -504,10 +529,10 @@ vortex_XtalkHw_GetRightXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
                coefs[i][2] = hwread(vortex->mmio, 0x24438 + i * 0x24);
                coefs[i][3] = hwread(vortex->mmio, 0x2443C + i * 0x24);
        }
-       arg_0[0] = hwread(vortex->mmio, 0x24528 + i * 0x24);
-       arg_0[1] = hwread(vortex->mmio, 0x2452C + i * 0x24);
-       arg_0[2] = hwread(vortex->mmio, 0x24530 + i * 0x24);
-       arg_0[3] = hwread(vortex->mmio, 0x24534 + i * 0x24);
+       arg_0[0] = hwread(vortex->mmio, 0x24528);
+       arg_0[1] = hwread(vortex->mmio, 0x2452C);
+       arg_0[2] = hwread(vortex->mmio, 0x24530);
+       arg_0[3] = hwread(vortex->mmio, 0x24534);
 }
 
 #endif
index 7a581151db0d6d2848e556f5092d0f6296d9316b..1c5231931462926f5919c57814b034f8474951d7 100644 (file)
@@ -153,7 +153,7 @@ static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
  ********************************/
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Audiowerk2 soundcard.");
index bc1e6830b50db25c620a8660d925e93995a1e01d..95ffa6a9db6e7412e3cca49ab6eb175d55b0983d 100644 (file)
@@ -301,7 +301,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;   /* ID for this card */
 module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard.");
 
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard.");
 
index c1c2d0c1c7f08a499e9bc97a44c7a3e6c8572b02..62d6163fc9d9c0bdfa2ef49ffbb230c2ea82386a 100644 (file)
@@ -42,9 +42,9 @@ MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878},"
 
 static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 static int digital_rate[SNDRV_CARDS];  /* digital input rate */
-static int load_all;   /* allow to load the non-whitelisted cards */
+static bool load_all;  /* allow to load the non-whitelisted cards */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Bt87x soundcard");
index fe99fdeaf15fcac90c7024d0c0ada7917fa096ac..08d6ebfe5a610d6b3c7a1951d43d9f44ca219838 100644 (file)
@@ -156,7 +156,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}");
 // module parameters (see "Module Parameters")
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
 
 module_param_array(index, int, NULL, 0444);
index 954c9934748a666026aac171726d5f29d9dce6d3..19b06269adc22df7b54bd1ad941e4a4796745423 100644 (file)
@@ -54,10 +54,10 @@ MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8738},"
 
 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_PNP;     /* Enable switches */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable switches */
 static long mpu_port[SNDRV_CARDS];
 static long fm_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1};
-static int soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1};
+static bool soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1};
 #ifdef SUPPORT_JOYSTICK
 static int joystick_port[SNDRV_CARDS];
 #endif
index a6c6c5c53af905a04159da4b43dc32ad034d9c2a..a9f368f60df6f3b7b271ce6f8e08f6a80259da35 100644 (file)
@@ -44,8 +44,8 @@ MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}");
 
 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_PNP;     /* Enable switches */
-static int dual_codec[SNDRV_CARDS];    /* dual codec */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable switches */
+static bool dual_codec[SNDRV_CARDS];   /* dual codec */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for CS4281 soundcard.");
index a4ecb40f8507dc70d47f2f839a9e2200f7a9ec61..819d79d0586de2909f308fe1094047a7b0830820 100644 (file)
@@ -46,10 +46,10 @@ MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)},"
 
 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_PNP;     /* Enable this card */
-static int external_amp[SNDRV_CARDS];
-static int thinkpad[SNDRV_CARDS];
-static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
+static bool external_amp[SNDRV_CARDS];
+static bool thinkpad[SNDRV_CARDS];
+static bool mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard.");
index 958f4949e973323d3fd9ed7cb2b9907b3d615683..c47cabff2bfa2b6cbfd92755a8f5658f43ba90b5 100644 (file)
@@ -50,7 +50,14 @@ MODULE_LICENSE("GPL");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
 
 struct snd_cs5530 {
        struct snd_card *card;
index b8959d2c804b766196c55d748528a5531c60806a..a2fb2173e980ea3697341446867d7d52a2a8350f 100644 (file)
@@ -57,7 +57,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME);
index e134b3a5780da709d9ccbf3fce4c9f99f7f82fc5..6e77e86307c2c90fd8ca8d3dde53dceebd0499af 100644 (file)
@@ -437,7 +437,7 @@ get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc)
 
        /* Allocate mem for master src resource */
        if (MEMRD == desc->mode)
-               src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL);
+               src = kcalloc(desc->multi, sizeof(*src), GFP_KERNEL);
        else
                src = kzalloc(sizeof(*src), GFP_KERNEL);
 
index 93b0aedc36d448be8ae902c6f1e2e5213934a84c..03fb909085af375322d53f653496e5f56d94d162 100644 (file)
@@ -15,8 +15,8 @@
 #include "cthardware.h"
 #include "cttimer.h"
 
-static int use_system_timer;
-MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
+static bool use_system_timer;
+MODULE_PARM_DESC(use_system_timer, "Force to use system-timer");
 module_param(use_system_timer, bool, S_IRUGO);
 
 struct ct_timer_ops {
index 33931ef5e129b046b5bb9e5c76c3e0070deef04c..15d95d2bacee67ff9c1c17c86a01e7aee6a44b75 100644 (file)
@@ -32,7 +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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static unsigned int subsystem[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
index 9fd694c61866feec00f6f018148c1297db42dbc7..595c11f904bbf72e5cded83a807f8e8c7f9c3acd 100644 (file)
@@ -26,7 +26,7 @@ MODULE_DEVICE_TABLE(pci, snd_echo_ids);
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard.");
index eaa198e122c089415418c9104b76a5fbd4106bb1..790c65d980c8550c828dde2baa0be1c40be40adf 100644 (file)
@@ -44,13 +44,13 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 static int extin[SNDRV_CARDS];
 static int extout[SNDRV_CARDS];
 static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
 static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
 static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
-static int enable_ir[SNDRV_CARDS];
+static bool enable_ir[SNDRV_CARDS];
 static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
 static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 
index 6a3e5677f5916ddcf0ab40561ca74e2c3f0bcad9..754924081d0ac99a4434c0e887faa1b69dc9f417 100644 (file)
@@ -1480,6 +1480,18 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .spdif_bug = 1,
         .invert_shared_spdif = 1,      /* digital/analog switch swapped */
         .ac97_chip = 1} ,
+       /* 0x20051102 also has SB0350 written on it, treated as Audigy 2 ZS by
+          Creative's Windows driver */
+       {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20051102,
+        .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350a]",
+        .id = "Audigy2",
+        .emu10k2_chip = 1,
+        .ca0102_chip = 1,
+        .ca0151_chip = 1,
+        .spk71 = 1,
+        .spdif_bug = 1,
+        .invert_shared_spdif = 1,      /* digital/analog switch swapped */
+        .ac97_chip = 1} ,
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
         .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]",
         .id = "Audigy2",
index 2228be9f30e6a1e4184bbe8033d9256c7cb7f9f7..47a651cb6e842d78c3cdc42bc3884de129a36baa 100644 (file)
@@ -50,7 +50,7 @@ MODULE_SUPPORTED_DEVICE("{{Dell Creative Labs,SB Live!}");
 // module parameters (see "Module Parameters")
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the EMU10K1X soundcard.");
index d085ad03efe823de724fa18be0d846988172f9b1..47a245e84190c08279075b5f14433fa1906a48a7 100644 (file)
@@ -83,12 +83,12 @@ MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI ES1371/73},"
 
 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_PNP;     /* Enable switches */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable switches */
 #ifdef SUPPORT_JOYSTICK
 #ifdef CHIP1371
 static int joystick_port[SNDRV_CARDS];
 #else
-static int joystick[SNDRV_CARDS];
+static bool joystick[SNDRV_CARDS];
 #endif
 #endif
 #ifdef CHIP1371
index 04cc21f5d014125597370ccf3a01b96ccfa9a396..53eb76b41108a07da237bf33af48f2cfe1da0d92 100644 (file)
@@ -79,7 +79,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ESS Solo-1 soundcard.");
index 297a151bdba99e5eba6caef1b44f9a962be237fd..cb557c603a80e2044673fa2209c4c9ae90127ca6 100644 (file)
@@ -132,7 +132,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e},"
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 1-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 };
 static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 };
 static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 };
@@ -140,7 +140,7 @@ static int clock[SNDRV_CARDS];
 static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
 #ifdef SUPPORT_JOYSTICK
-static int joystick[SNDRV_CARDS];
+static bool joystick[SNDRV_CARDS];
 #endif
 
 module_param_array(index, int, NULL, 0444);
index ec05ef5a5abf0c5aae21c1a18ed72403efb74094..9597ef1eccca39ff5a776c6f5259767ca459ecce 100644 (file)
@@ -48,7 +48,7 @@ MODULE_SUPPORTED_DEVICE("{{ForteMedia,FM801},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 /*
  *  Enable TEA575x tuner
  *    1 = MediaForte 256-PCS
index bb7e102d6726284e4a50808a7f887d7128fcffed..163b6b5de3eb535fe972e145b6ed35f0182590fa 100644 (file)
@@ -2,6 +2,7 @@ menuconfig SND_HDA_INTEL
        tristate "Intel HD Audio"
        select SND_PCM
        select SND_VMASTER
+       select SND_KCTL_JACK
        help
          Say Y here to include support for Intel "High Definition
          Audio" (Azalia) and its compatible devices.
index f928d663472322f00d0f7fdb835e6bf589bd65f7..ace157cc3d15c7e5b560910ca1adcfb2162d093a 100644 (file)
@@ -1,6 +1,6 @@
 snd-hda-intel-objs := hda_intel.o
 
-snd-hda-codec-y := hda_codec.o
+snd-hda-codec-y := hda_codec.o hda_jack.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
diff --git a/sound/pci/hda/alc262_quirks.c b/sound/pci/hda/alc262_quirks.c
deleted file mode 100644 (file)
index 7894b2b..0000000
+++ /dev/null
@@ -1,875 +0,0 @@
-/*
- * ALC262 quirk models
- * included by patch_realtek.c
- */
-
-/* ALC262 models */
-enum {
-       ALC262_AUTO,
-       ALC262_BASIC,
-       ALC262_HIPPO,
-       ALC262_HIPPO_1,
-       ALC262_FUJITSU,
-       ALC262_BENQ_ED8,
-       ALC262_BENQ_T31,
-       ALC262_ULTRA,
-       ALC262_LENOVO_3000,
-       ALC262_NEC,
-       ALC262_TOSHIBA_S06,
-       ALC262_TOSHIBA_RX1,
-       ALC262_TYAN,
-       ALC262_MODEL_LAST /* last tag */
-};
-
-#define ALC262_DIGOUT_NID      ALC880_DIGOUT_NID
-#define ALC262_DIGIN_NID       ALC880_DIGIN_NID
-
-#define alc262_dac_nids                alc260_dac_nids
-#define alc262_adc_nids                alc882_adc_nids
-#define alc262_adc_nids_alt    alc882_adc_nids_alt
-#define alc262_capsrc_nids     alc882_capsrc_nids
-#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
-
-#define alc262_modes           alc260_modes
-#define alc262_capture_source  alc882_capture_source
-
-static const hda_nid_t alc262_dmic_adc_nids[1] = {
-       /* ADC0 */
-       0x09
-};
-
-static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
-
-static const struct snd_kcontrol_new alc262_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-/* bind hp and internal speaker mute (with plug check) as master switch */
-
-static int alc262_hippo_master_sw_get(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       *ucontrol->value.integer.value = !spec->master_mute;
-       return 0;
-}
-
-static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int val = !*ucontrol->value.integer.value;
-
-       if (val == spec->master_mute)
-               return 0;
-       spec->master_mute = val;
-       update_outputs(codec);
-       return 1;
-}
-
-#define ALC262_HIPPO_MASTER_SWITCH                             \
-       {                                                       \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,            \
-               .name = "Master Playback Switch",               \
-               .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), \
-       }
-
-#define alc262_hp_master_sw_get                alc262_hippo_master_sw_get
-#define alc262_hp_master_sw_put                alc262_hippo_master_sw_put
-
-static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_hippo_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc262_hippo1_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-
-static const struct snd_kcontrol_new alc262_sony_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_tyan_verbs[] = {
-       /* Headphone automute */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* P11 AUX_IN, white 4-pin connector */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
-       {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
-
-       {}
-};
-
-/* unsolicited event for HP jack sensing */
-static void alc262_tyan_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-
-#define alc262_capture_mixer           alc882_capture_mixer
-#define alc262_capture_alt_mixer       alc882_capture_alt_mixer
-
-/*
- * generic initialization of ADC, input mixers and output mixers
- */
-static const struct hda_verb alc262_init_verbs[] = {
-       /*
-        * Unmute ADC0-2 and set the default input to mic-in
-        */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {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 - 0x0e)
-        */
-       /* set vol=0 to output mixers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0e, 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)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
-
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
-       /* 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))},
-       /* 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))},
-
-       { }
-};
-
-static const struct hda_verb alc262_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
-
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_sony_unsol_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},   // Front Mic
-
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_toshiba_s06_verbs[] = {
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_MIC_EVENT},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {}
-};
-
-static void alc262_toshiba_s06_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->ext_mic_pin = 0x18;
-       spec->int_mic_pin = 0x12;
-       spec->auto_mic = 1;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_PIN);
-}
-
-/*
- * nec model
- *  0x15 = headphone
- *  0x16 = internal speaker
- *  0x18 = external mic
- */
-
-static const struct snd_kcontrol_new alc262_nec_mixer[] = {
-       HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
-
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_nec_verbs[] = {
-       /* Unmute Speaker */
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Headphone */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* External mic to headphone */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* External mic to speaker */
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {}
-};
-
-/*
- * fujitsu model
- *  0x14 = headphone/spdif-out, 0x15 = internal speaker,
- *  0x1b = port replicator headphone out
- */
-
-static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
-       /* Front Mic pin: input vref at 50% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {}
-};
-
-static const struct hda_input_mux alc262_fujitsu_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "CD", 0x4 },
-       },
-};
-
-static void alc262_fujitsu_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.hp_pins[1] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/* bind volumes of both NID 0x0c and 0x0d */
-static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
-               HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
-               .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 = 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 Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static void alc262_lenovo_3000_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Master Playback Switch",
-               .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-               .info = snd_ctl_boolean_mono_info,
-               .get = alc262_hp_master_sw_get,
-               .put = alc262_hp_master_sw_put,
-       },
-       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 Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
-       HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
-       ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* additional init verbs for Benq laptops */
-static const struct hda_verb alc262_EAPD_verbs[] = {
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3070},
-       {}
-};
-
-static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3050},
-       {}
-};
-
-/* Samsung Q1 Ultra Vista model setup */
-static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc262_ultra_verbs[] = {
-       /* output mixer */
-       {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_OUT_ZERO},
-       /* speaker */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       /* internal mic */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* ADC, choose mic */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {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)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
-       {}
-};
-
-/* mute/unmute internal speaker according to the hp jack and mute state */
-static void alc262_ultra_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int mute;
-
-       mute = 0;
-       /* auto-mute only when HP is used as HP */
-       if (!spec->cur_mux[0]) {
-               spec->hp_jack_present = snd_hda_jack_detect(codec, 0x15);
-               if (spec->hp_jack_present)
-                       mute = HDA_AMP_MUTE;
-       }
-       /* mute/unmute internal speaker */
-       snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute);
-       /* mute/unmute HP */
-       snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
-                                HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
-}
-
-/* unsolicited event for HP jack sensing */
-static void alc262_ultra_unsol_event(struct hda_codec *codec,
-                                      unsigned int res)
-{
-       if ((res >> 26) != ALC_HP_EVENT)
-               return;
-       alc262_ultra_automute(codec);
-}
-
-static const struct hda_input_mux alc262_ultra_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "Headphone", 0x7 },
-       },
-};
-
-static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct alc_spec *spec = codec->spec;
-       int ret;
-
-       ret = alc_mux_enum_put(kcontrol, ucontrol);
-       if (!ret)
-               return 0;
-       /* reprogram the HP pin as mic or HP according to the input source */
-       snd_hda_codec_write_cache(codec, 0x15, 0,
-                                 AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
-       alc262_ultra_automute(codec); /* mute/unmute HP */
-       return ret;
-}
-
-static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
-       HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc262_ultra_mux_enum_put,
-       },
-       {
-               .iface = NID_MAPPING,
-               .name = "Capture Source",
-               .private_value = 0x15,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },       /* Front Speaker */
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* MIC jack */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },    /* Front MIC */
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },        /* HP  jack */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {}
-};
-
-/*
- * configuration and preset
- */
-static const char * const alc262_models[ALC262_MODEL_LAST] = {
-       [ALC262_BASIC]          = "basic",
-       [ALC262_HIPPO]          = "hippo",
-       [ALC262_HIPPO_1]        = "hippo_1",
-       [ALC262_FUJITSU]        = "fujitsu",
-       [ALC262_BENQ_ED8]       = "benq",
-       [ALC262_BENQ_T31]       = "benq-t31",
-       [ALC262_TOSHIBA_S06]    = "toshiba-s06",
-       [ALC262_TOSHIBA_RX1]    = "toshiba-rx1",
-       [ALC262_ULTRA]          = "ultra",
-       [ALC262_LENOVO_3000]    = "lenovo-3000",
-       [ALC262_NEC]            = "nec",
-       [ALC262_TYAN]           = "tyan",
-       [ALC262_AUTO]           = "auto",
-};
-
-static const struct snd_pci_quirk alc262_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
-       SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
-       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
-                     ALC262_TOSHIBA_RX1),
-       SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
-       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
-       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
-       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
-                          ALC262_ULTRA),
-       SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
-       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
-       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
-       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
-       SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
-       {}
-};
-
-static const struct alc_config_preset alc262_presets[] = {
-       [ALC262_BASIC] = {
-               .mixers = { alc262_base_mixer },
-               .init_verbs = { alc262_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_HIPPO] = {
-               .mixers = { alc262_hippo_mixer },
-               .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_HIPPO_1] = {
-               .mixers = { alc262_hippo1_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x02,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo1_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_FUJITSU] = {
-               .mixers = { alc262_fujitsu_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
-                               alc262_fujitsu_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_fujitsu_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_fujitsu_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_BENQ_ED8] = {
-               .mixers = { alc262_base_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_BENQ_T31] = {
-               .mixers = { alc262_benq_t31_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
-                               alc_hp15_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_ULTRA] = {
-               .mixers = { alc262_ultra_mixer },
-               .cap_mixer = alc262_ultra_capture_mixer,
-               .init_verbs = { alc262_ultra_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_ultra_capture_source,
-               .adc_nids = alc262_adc_nids, /* ADC0 */
-               .capsrc_nids = alc262_capsrc_nids,
-               .num_adc_nids = 1, /* single ADC */
-               .unsol_event = alc262_ultra_unsol_event,
-               .init_hook = alc262_ultra_automute,
-       },
-       [ALC262_LENOVO_3000] = {
-               .mixers = { alc262_lenovo_3000_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
-                               alc262_lenovo_3000_unsol_verbs,
-                               alc262_lenovo_3000_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_fujitsu_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_lenovo_3000_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_NEC] = {
-               .mixers = { alc262_nec_mixer },
-               .init_verbs = { alc262_nec_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-       },
-       [ALC262_TOSHIBA_S06] = {
-               .mixers = { alc262_toshiba_s06_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
-                                                       alc262_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .capsrc_nids = alc262_dmic_capsrc_nids,
-               .dac_nids = alc262_dac_nids,
-               .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
-               .num_adc_nids = 1, /* single ADC */
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_toshiba_s06_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_TOSHIBA_RX1] = {
-               .mixers = { alc262_toshiba_rx1_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x03,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_hippo_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC262_TYAN] = {
-               .mixers = { alc262_tyan_mixer },
-               .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
-               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
-               .dac_nids = alc262_dac_nids,
-               .hp_nid = 0x02,
-               .dig_out_nid = ALC262_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc262_modes),
-               .channel_mode = alc262_modes,
-               .input_mux = &alc262_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc262_tyan_setup,
-               .init_hook = alc_hp_automute,
-       },
-};
-
index bea22edcfd8ca2ef79d5f2c71d4ad8614887d85d..5b68435d195ba29d530113dd8471f06ea5d8e64e 100644 (file)
@@ -26,8 +26,6 @@ enum {
        ALC880_CLEVO,
        ALC880_TCL_S700,
        ALC880_LG,
-       ALC880_LG_LW,
-       ALC880_MEDION_RIM,
 #ifdef CONFIG_SND_DEBUG
        ALC880_TEST,
 #endif
@@ -1052,163 +1050,6 @@ static void alc880_lg_setup(struct hda_codec *codec)
        alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
 }
 
-/*
- * LG LW20
- *
- * Pin assignment:
- *   Speaker-out: 0x14
- *   Mic-In: 0x18
- *   Built-in Mic-In: 0x19
- *   Line-In: 0x1b
- *   HP-Out: 0x1a
- *   SPDIF-Out: 0x1e
- */
-
-static const struct hda_input_mux alc880_lg_lw_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-               { "Line In", 0x2 },
-       },
-};
-
-#define alc880_lg_lw_modes alc880_threestack_modes
-
-static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-static const struct hda_verb alc880_lg_lw_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
-
-       /* set capture source to mic-in */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-       /* speaker-out */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* HP-out */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* mic-in to input */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* built-in mic */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* jack sense */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_lg_lw_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_input_mux alc880_medion_rim_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
-       },
-};
-
-static const struct hda_verb alc880_medion_rim_init_verbs[] = {
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       /* Mic1 (rear panel) pin widget for input and vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Mic2 (as headphone out) for HP output */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Internal Speaker */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x3060},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       { }
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc880_medion_rim_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_hp_automute(codec);
-       /* toggle EAPD */
-       if (spec->hp_jack_present)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
-       else
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
-}
-
-static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
-                                         unsigned int res)
-{
-       /* Looks like the unsol event is incompatible with the standard
-        * definition.  4bit tag is placed at 28 bit!
-        */
-       if ((res >> 28) == ALC_HP_EVENT)
-               alc880_medion_rim_automute(codec);
-}
-
-static void alc880_medion_rim_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static const struct hda_amp_list alc880_lg_loopbacks[] = {
        { 0x0b, HDA_INPUT, 1 },
@@ -1505,8 +1346,6 @@ static const char * const alc880_models[ALC880_MODEL_LAST] = {
        [ALC880_FUJITSU]        = "fujitsu",
        [ALC880_F1734]          = "F1734",
        [ALC880_LG]             = "lg",
-       [ALC880_LG_LW]          = "lg-lw",
-       [ALC880_MEDION_RIM]     = "medion",
 #ifdef CONFIG_SND_DEBUG
        [ALC880_TEST]           = "test",
 #endif
@@ -1557,18 +1396,15 @@ static const struct snd_pci_quirk alc880_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
        SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
        SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
-       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
        SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
        SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
        SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
        SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
        SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
-       SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
        SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
        SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
        SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
-       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
        SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
        SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
        SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
@@ -1848,35 +1684,6 @@ static const struct alc_config_preset alc880_presets[] = {
                .loopbacks = alc880_lg_loopbacks,
 #endif
        },
-       [ALC880_LG_LW] = {
-               .mixers = { alc880_lg_lw_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_lg_lw_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
-               .channel_mode = alc880_lg_lw_modes,
-               .input_mux = &alc880_lg_lw_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc880_lg_lw_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC880_MEDION_RIM] = {
-               .mixers = { alc880_medion_rim_mixer },
-               .init_verbs = { alc880_volume_init_verbs,
-                               alc880_medion_rim_init_verbs,
-                               alc_gpio2_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
-               .dac_nids = alc880_dac_nids,
-               .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
-               .input_mux = &alc880_medion_rim_capture_source,
-               .unsol_event = alc880_medion_rim_unsol_event,
-               .setup = alc880_medion_rim_setup,
-               .init_hook = alc880_medion_rim_automute,
-       },
 #ifdef CONFIG_SND_DEBUG
        [ALC880_TEST] = {
                .mixers = { alc880_test_mixer },
index e251514a26a4bddccd95d3acdd2c8e468c3518bc..bdf0ed4ab3e24663284013856ed9f83a95c86acd 100644 (file)
 /* ALC882 models */
 enum {
        ALC882_AUTO,
-       ALC882_3ST_DIG,
-       ALC882_6ST_DIG,
-       ALC882_ARIMA,
-       ALC882_W2JC,
-       ALC882_TARGA,
-       ALC882_ASUS_A7J,
-       ALC882_ASUS_A7M,
-       ALC885_MACPRO,
        ALC885_MBA21,
        ALC885_MBP3,
        ALC885_MB5,
        ALC885_MACMINI3,
-       ALC885_IMAC24,
        ALC885_IMAC91,
-       ALC883_3ST_2ch_DIG,
-       ALC883_3ST_6ch_DIG,
-       ALC883_3ST_6ch,
-       ALC883_6ST_DIG,
-       ALC883_TARGA_DIG,
-       ALC883_TARGA_2ch_DIG,
-       ALC883_TARGA_8ch_DIG,
-       ALC883_ACER,
-       ALC883_ACER_ASPIRE,
-       ALC888_ACER_ASPIRE_4930G,
-       ALC888_ACER_ASPIRE_6530G,
-       ALC888_ACER_ASPIRE_8930G,
-       ALC888_ACER_ASPIRE_7730G,
-       ALC883_MEDION,
-       ALC883_MEDION_WIM2160,
-       ALC883_LAPTOP_EAPD,
-       ALC883_LENOVO_101E_2ch,
-       ALC883_LENOVO_NB0763,
-       ALC888_LENOVO_MS7195_DIG,
-       ALC888_LENOVO_SKY,
-       ALC883_HAIER_W66,
-       ALC888_3ST_HP,
-       ALC888_6ST_DELL,
-       ALC883_MITAC,
-       ALC883_CLEVO_M540R,
-       ALC883_CLEVO_M720,
-       ALC883_FUJITSU_PI2515,
-       ALC888_FUJITSU_XA3530,
-       ALC883_3ST_6ch_INTEL,
-       ALC889A_INTEL,
-       ALC889_INTEL,
-       ALC888_ASUS_M90V,
-       ALC888_ASUS_EEE1601,
        ALC889A_MB31,
-       ALC1200_ASUS_P5Q,
-       ALC883_SONY_VAIO_TT,
        ALC882_MODEL_LAST,
 };
 
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
-/* Mic-in jack as mic in */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Line in */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-Out as Front */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
-/* Mic-in jack as mic in */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Front */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
-/* Mic-in jack as CLFE */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
-/* Mic-in jack as CLFE */
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-in jack as Surround */
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-/* Line-Out as Side */
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
-       { 2, alc888_4ST_ch2_intel_init },
-       { 4, alc888_4ST_ch4_intel_init },
-       { 6, alc888_4ST_ch6_intel_init },
-       { 8, alc888_4ST_ch8_intel_init },
-};
-
-/*
- * ALC888 Fujitsu Siemens Amillo xa3530
- */
-
-static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Connect Internal HP to Front */
-       {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, 0x00},
-/* Connect Bass HP to Front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Connect Line-Out side jack (SPDIF) to Side */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable unsolicited event for HP jack and Line-out jack */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {}
-};
-
-static void alc889_automute_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       spec->autocfg.speaker_pins[3] = 0x19;
-       spec->autocfg.speaker_pins[4] = 0x1a;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc889_intel_init_hook(struct hda_codec *codec)
-{
-       alc889_coef_init(codec);
-       alc_hp_automute(codec);
-}
-
-static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x17; /* line-out */
-       spec->autocfg.hp_pins[1] = 0x1b; /* hp */
-       spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
-       spec->autocfg.speaker_pins[1] = 0x15; /* bass */
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/*
- * ALC888 Acer Aspire 4930G model
- */
-
-static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal HP to front */
-       {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, 0x00},
-/* Connect HP out to front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-/*
- * ALC888 Acer Aspire 6530G model
- */
-
-static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
-/* Route to built-in subwoofer as well as speakers */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, 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)},
-/* Bias voltage on for external mic port */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-/*
- *ALC888 Acer Aspire 7730G model
- */
-
-static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
-/* Bias voltage on for external mic port */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-/* Enable speaker output */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/* Enable headphone output */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-/*Enable internal subwoofer */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-/*
- * ALC889 Acer Aspire 8930G model
- */
-
-static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
-/* Front Mic: set to PIN_IN (empty by default) */
-       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-/* Unselect Front Mic by default in input mixer 3 */
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
-/* Enable unsolicited event for HP jack */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-/* Connect Internal Front to Front */
-       {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, 0x00},
-/* Connect Internal Rear to Rear */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect Internal CLFE to CLFE */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect HP out to Front */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-/* Enable all DACs */
-/*  DAC DISABLE/MUTE 1? */
-/*  setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/*  DAC DISABLE/MUTE 2? */
-/*  some bit here disables the other DACs. Init=0x4900 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
-/* DMIC fix
- * This laptop has a stereo digital microphone. The mics are only 1cm apart
- * which makes the stereo useless. However, either the mic or the ALC889
- * makes the signal become a difference/sum signal instead of standard
- * stereo, which is annoying. So instead we flip this bit which makes the
- * codec replicate the sum signal to both channels, turning it into a
- * normal mono mic.
- */
-/*  DMIC_CONTROL? Init value = 0x0001 */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
-       { }
-};
-
-static const struct hda_input_mux alc888_2_capture_sources[2] = {
-       /* Front mic only available on one ADC */
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Front Mic", 0xb },
-               },
-       },
-       {
-               .num_items = 3,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-               },
-       }
-};
-
-static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
-       /* Interal mic only available on one ADC */
-       {
-               .num_items = 5,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line In", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-                       { "Internal Mic", 0xb },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line In", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       }
-};
-
-static const struct hda_input_mux alc889_capture_sources[3] = {
-       /* Digital mic only available on first "ADC" */
-       {
-               .num_items = 5,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Front Mic", 0xb },
-                       { "Input Mix", 0xa },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       },
-       {
-               .num_items = 4,
-               .items = {
-                       { "Mic", 0x0 },
-                       { "Line", 0x2 },
-                       { "CD", 0x4 },
-                       { "Input Mix", 0xa },
-               },
-       }
-};
-
-static const struct snd_kcontrol_new alc888_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-               HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-
-static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x1b;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
 #define ALC882_DIGOUT_NID      0x06
 #define ALC882_DIGIN_NID       0x0a
 #define ALC883_DIGOUT_NID      ALC882_DIGOUT_NID
@@ -531,15 +37,9 @@ static const hda_nid_t alc882_dac_nids[4] = {
 #define alc882_adc_nids                alc880_adc_nids
 #define alc882_adc_nids_alt    alc880_adc_nids_alt
 #define alc883_adc_nids                alc882_adc_nids_alt
-static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
-static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
-#define alc889_adc_nids                alc880_adc_nids
 
-static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
 static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
 #define alc883_capsrc_nids     alc882_capsrc_nids_alt
-static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
-#define alc889_capsrc_nids     alc882_capsrc_nids
 
 /* input MUX */
 /* FIXME: should be a matrix-type input source selection */
@@ -556,15 +56,6 @@ static const struct hda_input_mux alc882_capture_source = {
 
 #define alc883_capture_source  alc882_capture_source
 
-static const struct hda_input_mux alc889_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Front Mic", 0x0 },
-               { "Mic", 0x3 },
-               { "Line", 0x2 },
-       },
-};
-
 static const struct hda_input_mux mb5_capture_source = {
        .num_items = 3,
        .items = {
@@ -592,197 +83,29 @@ static const struct hda_input_mux alc883_3stack_6ch_intel = {
        },
 };
 
-static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
+static const struct hda_input_mux alc889A_mb31_capture_source = {
        .num_items = 2,
-       .items = {
-               { "Mic", 0x1 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
-       .num_items = 4,
        .items = {
                { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
+               /* Front Mic (0x01) unused */
                { "Line", 0x2 },
-               { "CD", 0x4 },
+               /* Line 2 (0x03) unused */
+               /* CD (0x04) unused? */
        },
 };
 
-static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
+static const struct hda_input_mux alc889A_imac91_capture_source = {
        .num_items = 2,
        .items = {
-               { "Mic", 0x0 },
-               { "Internal Mic", 0x1 },
+               { "Mic", 0x01 },
+               { "Line", 0x2 }, /* Not sure! */
        },
 };
 
-static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
-       .num_items = 3,
-       .items = {
-               { "Mic", 0x0 },
-               { "Front Mic", 0x1 },
-               { "Line", 0x4 },
-       },
-};
-
-static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               { "Line", 0x2 },
-       },
-};
-
-static const struct hda_input_mux alc889A_mb31_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x0 },
-               /* Front Mic (0x01) unused */
-               { "Line", 0x2 },
-               /* Line 2 (0x03) unused */
-               /* CD (0x04) unused? */
-       },
-};
-
-static const struct hda_input_mux alc889A_imac91_capture_source = {
-       .num_items = 2,
-       .items = {
-               { "Mic", 0x01 },
-               { "Line", 0x2 }, /* Not sure! */
-       },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
-       { 2, NULL }
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc882_3ST_ch2_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc882_3ST_ch4_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_3ST_ch6_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
-       { 2, alc882_3ST_ch2_init },
-       { 4, alc882_3ST_ch4_init },
-       { 6, alc882_3ST_ch6_init },
-};
-
-#define alc883_3ST_6ch_modes   alc882_3ST_6ch_modes
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
-       { 2, alc883_3ST_ch2_clevo_init },
-       { 4, alc883_3ST_ch4_clevo_init },
-       { 6, alc883_3ST_ch6_clevo_init },
-};
-
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc882_sixstack_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc882_sixstack_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc882_sixstack_modes[2] = {
-       { 6, alc882_sixstack_ch6_init },
-       { 8, alc882_sixstack_ch8_init },
-};
-
-
-/* Macbook Air 2,1 */
-
-static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
-      { 2, NULL },
+/* Macbook Air 2,1 */
+
+static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
+      { 2, NULL },
 };
 
 /*
@@ -847,216 +170,6 @@ static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
 
 #define alc885_macmini3_6ch_modes      alc885_mb5_6ch_modes
 
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_4ST_ch2_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_4ST_ch4_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_4ST_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_4ST_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
-       { 2, alc883_4ST_ch2_init },
-       { 4, alc883_4ST_ch4_init },
-       { 6, alc883_4ST_ch6_init },
-       { 8, alc883_4ST_ch8_init },
-};
-
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
-       { 2, alc883_3ST_ch2_intel_init },
-       { 4, alc883_3ST_ch4_intel_init },
-       { 6, alc883_3ST_ch6_intel_init },
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc889_ch2_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc889_ch6_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc889_ch8_intel_init[] = {
-       { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
-       { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
-       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
-       { 2, alc889_ch2_intel_init },
-       { 6, alc889_ch6_intel_init },
-       { 8, alc889_ch8_intel_init },
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc883_sixstack_ch6_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-/*
- * 8ch mode
- */
-static const struct hda_verb alc883_sixstack_ch8_init[] = {
-       { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc883_sixstack_modes[2] = {
-       { 6, alc883_sixstack_ch6_init },
-       { 8, alc883_sixstack_ch8_init },
-};
-
-
-/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
- *                 Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
- */
-static const struct snd_kcontrol_new alc882_base_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
 /* Macbook Air 2,1 same control for HP and internal Speaker */
 
 static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
@@ -1121,78 +234,14 @@ static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
 };
 
 
-static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_targa_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       { } /* end */
-};
-
-/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
- *                 Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
- */
-static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
+static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
        { } /* end */
 };
 
@@ -1258,179 +307,8 @@ static const struct hda_verb alc882_base_init_verbs[] = {
        { }
 };
 
-static const struct hda_verb alc882_adc1_init_verbs[] = {
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {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)},
-       /* ADC1: mute amp left and right */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       { }
-};
-
-static const struct hda_verb alc882_eapd_verbs[] = {
-       /* change to EAPD mode */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
-       { }
-};
-
-static const struct hda_verb alc889_eapd_verbs[] = {
-       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
-       { }
-};
-
-static const struct hda_verb alc_hp15_unsol_verbs[] = {
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {}
-};
-
-static const 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_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Rear mixer */
-       {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_IN_UNMUTE(0)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* Side mixer */
-       {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},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Pin: output 0 (0x0c) */
-       {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, 0x00},
-       /* Rear Pin: output 1 (0x0d) */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
-       /* CLFE Pin: output 2 (0x0e) */
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
-       /* Side Pin: output 3 (0x0f) */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Front Mic pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: input */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-
-       /* Mixer elements: 0x18, , 0x1a, 0x1b */
-       /* Input mixer1 */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer2 */
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       /* Input mixer3 */
-       {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 */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-
-       { }
-};
-
-static const struct hda_verb alc885_init_input_verbs[] = {
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
-       { }
-};
-
-
-/* Unmute Selector 24h and set the default input to front mic */
-static const struct hda_verb alc889_init_input_verbs[] = {
-       {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       { }
-};
-
-
 #define alc883_init_verbs      alc882_base_init_verbs
 
-/* Mac Pro test */
-static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       /* FIXME: this looks suspicious...
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       */
-       { } /* end */
-};
-
-static const struct hda_verb alc882_macpro_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)},
-       /* Front Pin: output 0 (0x0c) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Mic pin: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Speaker:  output */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
-       /* Headphone output (output 0 - 0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
-       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {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)},
-       /* 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)},
-       /* ADC1: mute amp left and right */
-       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC2: mute amp left and right */
-       {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
-       {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       { }
-};
-
 /* Macbook 5,1 */
 static const struct hda_verb alc885_mb5_init_verbs[] = {
        /* DACs */
@@ -1669,34 +547,6 @@ static const struct hda_verb alc885_imac91_init_verbs[] = {
        { }
 };
 
-/* iMac 24 mixer. */
-static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
-       { } /* end */
-};
-
-/* iMac 24 init verbs. */
-static const struct hda_verb alc885_imac24_init_verbs[] = {
-       /* Internal speakers: output 0 (0x0c) */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Internal speakers: output 0 (0x0c) */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Headphone: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       /* Front Mic: input vref at 80% */
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       { }
-};
-
 /* Toggle speaker-output according to the hp-jack state */
 static void alc885_imac24_setup(struct hda_codec *codec)
 {
@@ -1742,127 +592,6 @@ static void alc885_imac91_setup(struct hda_codec *codec)
        alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
 }
 
-static const struct hda_verb alc882_targa_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc882_targa_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_hp_automute(codec);
-       snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
-                                 spec->hp_jack_present ? 1 : 3);
-}
-
-static void alc882_targa_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       if ((res >> 26) == ALC_HP_EVENT)
-               alc882_targa_automute(codec);
-}
-
-static const struct hda_verb alc882_asus_a7j_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       { } /* end */
-};
-
-static const struct hda_verb alc882_asus_a7m_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
-
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
-       { } /* end */
-};
-
-static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
-{
-       unsigned int gpiostate, gpiomask, gpiodir;
-
-       gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
-                                      AC_VERB_GET_GPIO_DATA, 0);
-
-       if (!muted)
-               gpiostate |= (1 << pin);
-       else
-               gpiostate &= ~(1 << pin);
-
-       gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
-                                     AC_VERB_GET_GPIO_MASK, 0);
-       gpiomask |= (1 << pin);
-
-       gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
-                                    AC_VERB_GET_GPIO_DIRECTION, 0);
-       gpiodir |= (1 << pin);
-
-
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_MASK, gpiomask);
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
-
-       msleep(1);
-
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, gpiostate);
-}
-
-/* set up GPIO at initialization */
-static void alc885_macpro_init_hook(struct hda_codec *codec)
-{
-       alc882_gpio_mute(codec, 0, 0);
-       alc882_gpio_mute(codec, 1, 0);
-}
-
-/* set up GPIO and update auto-muting at initialization */
-static void alc885_imac24_init_hook(struct hda_codec *codec)
-{
-       alc885_macpro_init_hook(codec);
-       alc_hp_automute(codec);
-}
-
 /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
 static const struct hda_verb alc889A_mb31_ch2_init[] = {
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},             /* HP as front */
@@ -1906,63 +635,15 @@ static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
        { 6, alc889A_mb31_ch6_init },
 };
 
-static const struct hda_verb alc883_medion_eapd_verbs[] = {
-        /* eanable EAPD on medion laptop */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
-       { }
-};
-
-#define alc883_base_mixer      alc882_base_mixer
-
-static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
+static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
        HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
-       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@ -1977,258 +658,6 @@ static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
        { } /* end */
 };
 
-static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
-                             HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_verb alc883_medion_wim2160_verbs[] = {
-       /* Unmute front mixer */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       /* Set speaker pin to front mixer */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       /* Init headphone pin */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_wim2160_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1a;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume",
-                                               0x0d, 1, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
-       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
 static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
        /* Output mixers */
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
@@ -2249,495 +678,23 @@ static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
        HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
        /* Input mixers */
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_vol = {
-       .ops = &snd_hda_bind_vol,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct hda_bind_ctls alc883_bind_cap_switch = {
-       .ops = &snd_hda_bind_sw,
-       .values = {
-               HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
-               HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
-               0
-       },
-};
-
-static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
-       HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
-       HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               /* .name = "Capture Source", */
-               .name = "Input Source",
-               .count = 1,
-               .info = alc_mux_enum_info,
-               .get = alc_mux_enum_get,
-               .put = alc_mux_enum_put,
-       },
-       { } /* end */
-};
-
-static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Channel Mode",
-               .info = alc_ch_mode_info,
-               .get = alc_ch_mode_get,
-               .put = alc_ch_mode_put,
-       },
-       { } /* end */
-};
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_mitac_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct hda_verb alc883_mitac_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Subwoofer */
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN}, */
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m540r_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Int speaker */
-       /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
-
-       /* enable unsolicited event */
-       /*
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
-       */
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_clevo_m720_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Int speaker */
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
-       /* HP */
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       /* Subwoofer */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_targa_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-/* Connect Line-Out side jack (SPDIF) to Side */
-       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
-/* Connect Mic jack to CLFE */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
-/* Connect Line-in jack to Surround */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-/* Connect HP out jack to Front */
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_101e_verbs[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT|AC_USRSP_EN},
-        {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT|AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
-        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-        {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_FRONT_EVENT | AC_USRSP_EN},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT    | AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc883_haier_w66_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-
-       {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_lenovo_sky_verbs[] = {
-       {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)},
-       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-static const struct hda_verb alc888_6st_dell_verbs[] = {
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static const struct hda_verb alc883_vaiott_verbs[] = {
-       /* HP */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       /* enable unsolicited event */
-       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-
-       { } /* end */
-};
-
-static void alc888_3st_hp_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       spec->autocfg.speaker_pins[2] = 0x18;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct hda_verb alc888_3st_hp_verbs[] = {
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
-       {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
-/*
- * 2ch mode
- */
-static const struct hda_verb alc888_3st_hp_2ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { } /* end */
-};
-
-/*
- * 4ch mode
- */
-static const struct hda_verb alc888_3st_hp_4ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-/*
- * 6ch mode
- */
-static const struct hda_verb alc888_3st_hp_6ch_init[] = {
-       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
-       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-       { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
-       { } /* end */
-};
-
-static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
-       { 2, alc888_3st_hp_2ch_init },
-       { 4, alc888_3st_hp_4ch_init },
-       { 6, alc888_3st_hp_6ch_init },
-};
-
-static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.line_out_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-#define alc883_targa_init_hook         alc882_targa_init_hook
-#define alc883_targa_unsol_event       alc882_targa_unsol_event
-
-static void alc883_clevo_m720_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
-{
-       alc_hp_automute(codec);
-       alc88x_simple_mic_automute(codec);
-}
-
-static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
-                                          unsigned int res)
-{
-       switch (res >> 26) {
-       case ALC_MIC_EVENT:
-               alc88x_simple_mic_automute(codec);
-               break;
-       default:
-               alc_sku_unsol_event(codec, res);
-               break;
-       }
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc883_haier_w66_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc883_lenovo_101e_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.line_out_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-/* toggle speaker-output according to the hp-jack state */
-static void alc883_acer_aspire_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[1] = 0x16;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct hda_verb alc883_acer_eapd_verbs[] = {
-       /* HP Pin: output 0 (0x0c) */
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Front Pin: output 0 (0x0c) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
-        /* eanable EAPD on medion laptop */
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
-       {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       { }
-};
-
-static void alc888_6st_dell_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->autocfg.speaker_pins[3] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc888_lenovo_sky_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->autocfg.speaker_pins[3] = 0x17;
-       spec->autocfg.speaker_pins[4] = 0x1a;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static void alc883_vaiott_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x15;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x17;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct hda_verb alc888_asus_m90v_verbs[] = {
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-       /* enable unsolicited event */
-       {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
-       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_MIC_EVENT | AC_USRSP_EN},
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        { } /* end */
 };
 
-static void alc883_mode2_setup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x1b;
-       spec->autocfg.speaker_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.speaker_pins[2] = 0x16;
-       spec->ext_mic_pin = 0x18;
-       spec->int_mic_pin = 0x19;
-       spec->auto_mic = 1;
-       alc_simple_setup_automute(spec, ALC_AUTOMUTE_AMP);
-}
-
-static const struct hda_verb alc888_asus_eee1601_verbs[] = {
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-       {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
-       {0x20, AC_VERB_SET_PROC_COEF,  0x0838},
-       /* enable unsolicited event */
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC_HP_EVENT | AC_USRSP_EN},
+static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
        { } /* end */
 };
 
-static void alc883_eee1601_inithook(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x1b;
-       alc_hp_automute(codec);
-}
-
 static const struct hda_verb alc889A_mb31_verbs[] = {
        /* Init rear pin (used as headphone output) */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},    /* Apple Headphones */
@@ -2773,211 +730,30 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
                alc889A_mb31_automute(codec);
 }
 
-static const hda_nid_t alc883_slave_dig_outs[] = {
-       ALC1200_DIGOUT_NID, 0,
-};
-
-static const hda_nid_t alc1200_slave_dig_outs[] = {
-       ALC883_DIGOUT_NID, 0,
-};
-
 /*
  * configuration and preset
  */
 static const char * const alc882_models[ALC882_MODEL_LAST] = {
-       [ALC882_3ST_DIG]        = "3stack-dig",
-       [ALC882_6ST_DIG]        = "6stack-dig",
-       [ALC882_ARIMA]          = "arima",
-       [ALC882_W2JC]           = "w2jc",
-       [ALC882_TARGA]          = "targa",
-       [ALC882_ASUS_A7J]       = "asus-a7j",
-       [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",
-       [ALC883_3ST_2ch_DIG]    = "3stack-2ch-dig",
-       [ALC883_3ST_6ch_DIG]    = "3stack-6ch-dig",
-       [ALC883_3ST_6ch]        = "3stack-6ch",
-       [ALC883_6ST_DIG]        = "alc883-6stack-dig",
-       [ALC883_TARGA_DIG]      = "targa-dig",
-       [ALC883_TARGA_2ch_DIG]  = "targa-2ch-dig",
-       [ALC883_TARGA_8ch_DIG]  = "targa-8ch-dig",
-       [ALC883_ACER]           = "acer",
-       [ALC883_ACER_ASPIRE]    = "acer-aspire",
-       [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
-       [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
-       [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
-       [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
-       [ALC883_MEDION]         = "medion",
-       [ALC883_MEDION_WIM2160] = "medion-wim2160",
-       [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
-       [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
-       [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
-       [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
-       [ALC888_LENOVO_SKY] = "lenovo-sky",
-       [ALC883_HAIER_W66]      = "haier-w66",
-       [ALC888_3ST_HP]         = "3stack-hp",
-       [ALC888_6ST_DELL]       = "6stack-dell",
-       [ALC883_MITAC]          = "mitac",
-       [ALC883_CLEVO_M540R]    = "clevo-m540r",
-       [ALC883_CLEVO_M720]     = "clevo-m720",
-       [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
-       [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
-       [ALC883_3ST_6ch_INTEL]  = "3stack-6ch-intel",
-       [ALC889A_INTEL]         = "intel-alc889a",
-       [ALC889_INTEL]          = "intel-x58",
-       [ALC1200_ASUS_P5Q]      = "asus-p5q",
        [ALC889A_MB31]          = "mb31",
-       [ALC883_SONY_VAIO_TT]   = "sony-vaio-tt",
        [ALC882_AUTO]           = "auto",
 };
 
-static const struct snd_pci_quirk alc882_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
-
-       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
-               ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
-               ALC888_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
-               ALC888_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
-               ALC888_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-               ALC888_ACER_ASPIRE_6530G),
-       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
-               ALC888_ACER_ASPIRE_6530G),
-       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
-               ALC888_ACER_ASPIRE_7730G),
-       /* default Acer -- disabled as it causes more problems.
-        *    model=auto should work fine now
-        */
-       /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
-
-       SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
-
-       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
-       SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
-
-       SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
-       SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
-       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
-       SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
-       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
-       SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
-       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
-
-       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
-       SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
-       SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
-       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
-       SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
-
-       SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
-       SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
-       SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
-       SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
-
-       SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
-       SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
-       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
-       SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
-       /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
-       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
-       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
-                     ALC883_FUJITSU_PI2515),
-       SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
-               ALC888_FUJITSU_XA3530),
-       SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
-       SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
-       SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
-       SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
-       SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
-       SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
-
-       SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
-       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
-       SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
-       SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
-
-       {}
-};
-
 /* codec SSID table for Intel Mac */
 static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
-       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
-       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
        SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
-       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
        SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
        SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
        SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
        SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
-       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
        SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
        SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
        SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
@@ -2991,53 +767,6 @@ static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
 };
 
 static const struct alc_config_preset alc882_presets[] = {
-       [ALC882_3ST_DIG] = {
-               .mixers = { alc882_base_mixer },
-               .init_verbs = { alc882_base_init_verbs,
-                               alc882_adc1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_6ST_DIG] = {
-               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs,
-                               alc882_adc1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
-               .channel_mode = alc882_sixstack_modes,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_ARIMA] = {
-               .mixers = { alc882_base_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
-               .channel_mode = alc882_sixstack_modes,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_W2JC] = {
-               .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs, alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .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 },
@@ -3096,32 +825,6 @@ static const struct alc_config_preset alc882_presets[] = {
                .setup = alc885_macmini3_setup,
                .init_hook = alc_hp_automute,
        },
-       [ALC885_MACPRO] = {
-               .mixers = { alc882_macpro_mixer },
-               .init_verbs = { alc882_macpro_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .input_mux = &alc882_capture_source,
-               .init_hook = alc885_macpro_init_hook,
-       },
-       [ALC885_IMAC24] = {
-               .mixers = { alc885_imac24_mixer },
-               .init_verbs = { alc885_imac24_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .dig_in_nid = ALC882_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
-               .channel_mode = alc882_ch_modes,
-               .input_mux = &alc882_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc885_imac24_setup,
-               .init_hook = alc885_imac24_init_hook,
-       },
        [ALC885_IMAC91] = {
                .mixers = {alc885_imac91_mixer},
                .init_verbs = { alc885_imac91_init_verbs,
@@ -3137,564 +840,6 @@ static const struct alc_config_preset alc882_presets[] = {
                .setup = alc885_imac91_setup,
                .init_hook = alc_hp_automute,
        },
-       [ALC882_TARGA] = {
-               .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc880_gpio3_init_verbs, alc882_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
-               .capsrc_nids = alc882_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
-               .channel_mode = alc882_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC882_ASUS_A7J] = {
-               .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_asus_a7j_verbs},
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
-               .adc_nids = alc882_adc_nids,
-               .capsrc_nids = alc882_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
-               .channel_mode = alc882_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC882_ASUS_A7M] = {
-               .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
-               .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
-                               alc882_eapd_verbs, alc880_gpio1_init_verbs,
-                               alc882_asus_a7m_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
-               .dac_nids = alc882_dac_nids,
-               .dig_out_nid = ALC882_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
-               .channel_mode = alc880_threestack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc882_capture_source,
-       },
-       [ALC883_3ST_2ch_DIG] = {
-               .mixers = { alc883_3ST_2ch_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch_DIG] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_3ST_6ch_INTEL] = {
-               .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
-               .channel_mode = alc883_3ST_6ch_intel_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_3stack_6ch_intel,
-       },
-       [ALC889A_INTEL] = {
-               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
-                               alc_hp15_unsol_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
-               .channel_mode = alc889_8ch_intel_modes,
-               .capsrc_nids = alc889_capsrc_nids,
-               .input_mux = &alc889_capture_source,
-               .setup = alc889_automute_setup,
-               .init_hook = alc_hp_automute,
-               .unsol_event = alc_sku_unsol_event,
-               .need_dac_fix = 1,
-       },
-       [ALC889_INTEL] = {
-               .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
-                               alc889_eapd_verbs, alc_hp15_unsol_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc883_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
-               .channel_mode = alc889_8ch_intel_modes,
-               .capsrc_nids = alc889_capsrc_nids,
-               .input_mux = &alc889_capture_source,
-               .setup = alc889_automute_setup,
-               .init_hook = alc889_intel_init_hook,
-               .unsol_event = alc_sku_unsol_event,
-               .need_dac_fix = 1,
-       },
-       [ALC883_6ST_DIG] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_TARGA_DIG] = {
-               .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_TARGA_2ch_DIG] = {
-               .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_TARGA_8ch_DIG] = {
-               .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
-                           alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
-                               alc883_targa_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
-               .channel_mode = alc883_4ST_8ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_targa_unsol_event,
-               .setup = alc882_targa_setup,
-               .init_hook = alc882_targa_automute,
-       },
-       [ALC883_ACER] = {
-               .mixers = { alc883_base_mixer },
-               /* On TravelMate laptops, GPIO 0 enables the internal speaker
-                * and the headphone jack.  Turn this on and rely on the
-                * standard mute methods whenever the user wants to turn
-                * these outputs off.
-                */
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_ACER_ASPIRE] = {
-               .mixers = { alc883_acer_aspire_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_acer_aspire_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_4930G] = {
-               .mixers = { alc888_acer_aspire_4930g_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_4930g_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_4930g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_6530G] = {
-               .mixers = { alc888_acer_aspire_6530_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_6530g_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_acer_aspire_6530_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_6530g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ACER_ASPIRE_8930G] = {
-               .mixers = { alc889_acer_aspire_8930g_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc889_acer_aspire_8930g_verbs,
-                               alc889_eapd_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
-               .adc_nids = alc889_adc_nids,
-               .capsrc_nids = alc889_capsrc_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc889_capture_sources),
-               .input_mux = alc889_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc889_acer_aspire_8930g_setup,
-               .init_hook = alc_hp_automute,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               .power_hook = alc_power_eapd,
-#endif
-       },
-       [ALC888_ACER_ASPIRE_7730G] = {
-               .mixers = { alc883_3ST_6ch_mixer,
-                               alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
-                               alc888_acer_aspire_7730G_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .const_channel_count = 6,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_acer_aspire_7730g_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_MEDION] = {
-               .mixers = { alc883_fivestack_mixer,
-                           alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs,
-                               alc883_medion_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_MEDION_WIM2160] = {
-               .mixers = { alc883_medion_wim2160_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
-               .adc_nids = alc883_adc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_medion_wim2160_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_LAPTOP_EAPD] = {
-               .mixers = { alc883_base_mixer },
-               .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-       },
-       [ALC883_CLEVO_M540R] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
-               .channel_mode = alc883_3ST_6ch_clevo_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               /* This machine has the hardware HP auto-muting, thus
-                * we need no software mute via unsol event
-                */
-       },
-       [ALC883_CLEVO_M720] = {
-               .mixers = { alc883_clevo_m720_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc883_clevo_m720_unsol_event,
-               .setup = alc883_clevo_m720_setup,
-               .init_hook = alc883_clevo_m720_init_hook,
-       },
-       [ALC883_LENOVO_101E_2ch] = {
-               .mixers = { alc883_lenovo_101e_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .adc_nids = alc883_adc_nids_alt,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
-               .capsrc_nids = alc883_capsrc_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_lenovo_101e_capture_source,
-               .setup = alc883_lenovo_101e_setup,
-               .unsol_event = alc_sku_unsol_event,
-               .init_hook = alc_inithook,
-       },
-       [ALC883_LENOVO_NB0763] = {
-               .mixers = { alc883_lenovo_nb0763_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_lenovo_nb0763_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_lenovo_nb0763_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_LENOVO_MS7195_DIG] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_lenovo_ms7195_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC883_HAIER_W66] = {
-               .mixers = { alc883_targa_2ch_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_haier_w66_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_3ST_HP] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
-               .channel_mode = alc888_3st_hp_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_3st_hp_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_6ST_DELL] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_6st_dell_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_MITAC] = {
-               .mixers = { alc883_mitac_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_mitac_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC883_FUJITSU_PI2515] = {
-               .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
-               .init_verbs = { alc883_init_verbs,
-                               alc883_2ch_fujitsu_pi2515_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_fujitsu_pi2515_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_2ch_fujitsu_pi2515_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_FUJITSU_XA3530] = {
-               .mixers = { alc888_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs,
-                       alc888_fujitsu_xa3530_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
-               .adc_nids = alc883_adc_nids_rev,
-               .capsrc_nids = alc883_capsrc_nids_rev,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
-               .channel_mode = alc888_4ST_8ch_intel_modes,
-               .num_mux_defs =
-                       ARRAY_SIZE(alc888_2_capture_sources),
-               .input_mux = alc888_2_capture_sources,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_fujitsu_xa3530_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_LENOVO_SKY] = {
-               .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_lenovo_sky_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc888_lenovo_sky_setup,
-               .init_hook = alc_hp_automute,
-       },
-       [ALC888_ASUS_M90V] = {
-               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
-               .channel_mode = alc883_3ST_6ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_fujitsu_pi2515_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_mode2_setup,
-               .init_hook = alc_inithook,
-       },
-       [ALC888_ASUS_EEE1601] = {
-               .mixers = { alc883_asus_eee1601_mixer },
-               .cap_mixer = alc883_asus_eee1601_cap_mixer,
-               .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .need_dac_fix = 1,
-               .input_mux = &alc883_asus_eee1601_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .init_hook = alc883_eee1601_inithook,
-       },
-       [ALC1200_ASUS_P5Q] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
-               .init_verbs = { alc883_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC1200_DIGOUT_NID,
-               .dig_in_nid = ALC883_DIGIN_NID,
-               .slave_dig_outs = alc1200_slave_dig_outs,
-               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
-               .channel_mode = alc883_sixstack_modes,
-               .input_mux = &alc883_capture_source,
-       },
        [ALC889A_MB31] = {
                .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
                .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
@@ -3711,18 +856,6 @@ static const struct alc_config_preset alc882_presets[] = {
                .unsol_event = alc889A_mb31_unsol_event,
                .init_hook = alc889A_mb31_automute,
        },
-       [ALC883_SONY_VAIO_TT] = {
-               .mixers = { alc883_vaiott_mixer },
-               .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_sku_unsol_event,
-               .setup = alc883_vaiott_setup,
-               .init_hook = alc_hp_automute,
-       },
 };
 
 
index 4562e9de6a1ab0dc7015e28d7be14c2eafa5a6b3..4df72c0e8c37c9011cecff85cca8e834d74260de 100644 (file)
@@ -33,6 +33,7 @@
 #include <sound/jack.h>
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 #include <sound/hda_hwdep.h>
 
 #define CREATE_TRACE_POINTS
@@ -1723,43 +1724,6 @@ int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
 
-/**
- * snd_hda_pin_sense - execute pin sense measurement
- * @codec: the CODEC to sense
- * @nid: the pin NID to sense
- *
- * Execute necessary pin sense measurement and return its Presence Detect,
- * Impedance, ELD Valid etc. status bits.
- */
-u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
-{
-       u32 pincap;
-
-       if (!codec->no_trigger_sense) {
-               pincap = snd_hda_query_pin_caps(codec, nid);
-               if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
-                       snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_SET_PIN_SENSE, 0);
-       }
-       return snd_hda_codec_read(codec, nid, 0,
-                                 AC_VERB_GET_PIN_SENSE, 0);
-}
-EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
-
-/**
- * snd_hda_jack_detect - query pin Presence Detect status
- * @codec: the CODEC to sense
- * @nid: the pin NID to sense
- *
- * Query and return the pin's Presence Detect status.
- */
-int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
-{
-       u32 sense = snd_hda_pin_sense(codec, nid);
-       return !!(sense & AC_PINSENSE_PRESENCE);
-}
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
-
 /*
  * read the current volume to info
  * if the cache exists, read the cache value.
@@ -2308,6 +2272,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        }
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
+       snd_hda_jack_tbl_clear(codec);
        codec->proc_widget_hook = NULL;
        codec->spec = NULL;
        free_hda_cache(&codec->amp_cache);
@@ -3364,6 +3329,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
        restore_pincfgs(codec); /* restore all current pin configs */
        restore_shutup_pins(codec);
        hda_exec_init_verbs(codec);
+       snd_hda_jack_set_dirty_all(codec);
        if (codec->patch_ops.resume)
                codec->patch_ops.resume(codec);
        else {
@@ -3850,6 +3816,12 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type)
                if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits))
                        return audio_idx[type][i];
 
+       /* non-fixed slots starting from 10 */
+       for (i = 10; i < 32; i++) {
+               if (!test_and_set_bit(i, bus->pcm_dev_bits))
+                       return i;
+       }
+
        snd_printk(KERN_WARNING "Too many %s devices\n",
                snd_hda_pcm_type_name[type]);
        return -EAGAIN;
@@ -5004,8 +4976,8 @@ EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
  * "Rear", "Internal".
  */
 
-const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
-                                       int check_location)
+static const char *hda_get_input_pin_label(struct hda_codec *codec,
+                                          hda_nid_t pin, bool check_location)
 {
        unsigned int def_conf;
        static const char * const mic_names[] = {
@@ -5044,7 +5016,6 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
                return "Misc";
        }
 }
-EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
 
 /* Check whether the location prefix needs to be added to the label.
  * If all mic-jacks are in the same location (e.g. rear panel), we don't
@@ -5101,6 +5072,149 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
 
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* get a unique suffix or an index number */
+static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
+                                   int num_pins, int *indexp)
+{
+       static const char * const channel_sfx[] = {
+               " Front", " Surround", " CLFE", " Side"
+       };
+       int i;
+
+       i = find_idx_in_nid_list(nid, pins, num_pins);
+       if (i < 0)
+               return NULL;
+       if (num_pins == 1)
+               return "";
+       if (num_pins > ARRAY_SIZE(channel_sfx)) {
+               if (indexp)
+                       *indexp = i;
+               return "";
+       }
+       return channel_sfx[i];
+}
+
+static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
+                              const struct auto_pin_cfg *cfg,
+                              const char *name, char *label, int maxlen,
+                              int *indexp)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int attr = snd_hda_get_input_pin_attr(def_conf);
+       const char *pfx = "", *sfx = "";
+
+       /* handle as a speaker if it's a fixed line-out */
+       if (!strcmp(name, "Line-Out") && attr == INPUT_PIN_ATTR_INT)
+               name = "Speaker";
+       /* check the location */
+       switch (attr) {
+       case INPUT_PIN_ATTR_DOCK:
+               pfx = "Dock ";
+               break;
+       case INPUT_PIN_ATTR_FRONT:
+               pfx = "Front ";
+               break;
+       }
+       if (cfg) {
+               /* try to give a unique suffix if needed */
+               sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
+                                      indexp);
+               if (!sfx)
+                       sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
+                                              indexp);
+               if (!sfx) {
+                       /* don't add channel suffix for Headphone controls */
+                       int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
+                                                      cfg->hp_outs);
+                       if (idx >= 0)
+                               *indexp = idx;
+                       sfx = "";
+               }
+       }
+       snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
+       return 1;
+}
+
+/**
+ * snd_hda_get_pin_label - Get a label for the given I/O pin
+ *
+ * Get a label for the given pin.  This function works for both input and
+ * output pins.  When @cfg is given as non-NULL, the function tries to get
+ * an optimized label using hda_get_autocfg_input_label().
+ *
+ * This function tries to give a unique label string for the pin as much as
+ * possible.  For example, when the multiple line-outs are present, it adds
+ * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
+ * If no unique name with a suffix is available and @indexp is non-NULL, the
+ * index number is stored in the pointer.
+ */
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+                         const struct auto_pin_cfg *cfg,
+                         char *label, int maxlen, int *indexp)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       const char *name = NULL;
+       int i;
+
+       if (indexp)
+               *indexp = 0;
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+               return 0;
+
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_LINE_OUT:
+               return fill_audio_out_name(codec, nid, cfg, "Line-Out",
+                                          label, maxlen, indexp);
+       case AC_JACK_SPEAKER:
+               return fill_audio_out_name(codec, nid, cfg, "Speaker",
+                                          label, maxlen, indexp);
+       case AC_JACK_HP_OUT:
+               return fill_audio_out_name(codec, nid, cfg, "Headphone",
+                                          label, maxlen, indexp);
+       case AC_JACK_SPDIF_OUT:
+       case AC_JACK_DIG_OTHER_OUT:
+               if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
+                       name = "HDMI";
+               else
+                       name = "SPDIF";
+               if (cfg && indexp) {
+                       i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
+                                                cfg->dig_outs);
+                       if (i >= 0)
+                               *indexp = i;
+               }
+               break;
+       default:
+               if (cfg) {
+                       for (i = 0; i < cfg->num_inputs; i++) {
+                               if (cfg->inputs[i].pin != nid)
+                                       continue;
+                               name = hda_get_autocfg_input_label(codec, cfg, i);
+                               if (name)
+                                       break;
+                       }
+               }
+               if (!name)
+                       name = hda_get_input_pin_label(codec, nid, true);
+               break;
+       }
+       if (!name)
+               return 0;
+       strlcpy(label, name, maxlen);
+       return 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+
 /**
  * snd_hda_add_imux_item - Add an item to input_mux
  *
@@ -5252,113 +5366,5 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
 }
 EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
 
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-/*
- * Input-jack notification support
- */
-struct hda_jack_item {
-       hda_nid_t nid;
-       int type;
-       struct snd_jack *jack;
-};
-
-static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
-                                        int type)
-{
-       switch (type) {
-       case SND_JACK_HEADPHONE:
-               return "Headphone";
-       case SND_JACK_MICROPHONE:
-               return "Mic";
-       case SND_JACK_LINEOUT:
-               return "Line-out";
-       case SND_JACK_LINEIN:
-               return "Line-in";
-       case SND_JACK_HEADSET:
-               return "Headset";
-       case SND_JACK_VIDEOOUT:
-               return "HDMI/DP";
-       default:
-               return "Misc";
-       }
-}
-
-static void hda_free_jack_priv(struct snd_jack *jack)
-{
-       struct hda_jack_item *jacks = jack->private_data;
-       jacks->nid = 0;
-       jacks->jack = NULL;
-}
-
-int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
-                          const char *name)
-{
-       struct hda_jack_item *jack;
-       int err;
-
-       snd_array_init(&codec->jacks, sizeof(*jack), 32);
-       jack = snd_array_new(&codec->jacks);
-       if (!jack)
-               return -ENOMEM;
-
-       jack->nid = nid;
-       jack->type = type;
-       if (!name)
-               name = get_jack_default_name(codec, nid, type);
-       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
-       if (err < 0) {
-               jack->nid = 0;
-               return err;
-       }
-       jack->jack->private_data = jack;
-       jack->jack->private_free = hda_free_jack_priv;
-       return 0;
-}
-EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);
-
-void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct hda_jack_item *jacks = codec->jacks.list;
-       int i;
-
-       if (!jacks)
-               return;
-
-       for (i = 0; i < codec->jacks.used; i++, jacks++) {
-               unsigned int pin_ctl;
-               unsigned int present;
-               int type;
-
-               if (jacks->nid != nid)
-                       continue;
-               present = snd_hda_jack_detect(codec, nid);
-               type = jacks->type;
-               if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) {
-                       pin_ctl = snd_hda_codec_read(codec, nid, 0,
-                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                       type = (pin_ctl & AC_PINCTL_HP_EN) ?
-                               SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
-               }
-               snd_jack_report(jacks->jack, present ? type : 0);
-       }
-}
-EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);
-
-/* free jack instances manually when clearing/reconfiguring */
-void snd_hda_input_jack_free(struct hda_codec *codec)
-{
-       if (!codec->bus->shutdown && codec->jacks.list) {
-               struct hda_jack_item *jacks = codec->jacks.list;
-               int i;
-               for (i = 0; i < codec->jacks.used; i++, jacks++) {
-                       if (jacks->jack)
-                               snd_device_free(codec->bus->card, jacks->jack);
-               }
-       }
-       snd_array_free(&codec->jacks);
-}
-EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-
 MODULE_DESCRIPTION("HDA codec core");
 MODULE_LICENSE("GPL");
index 564471169cae72ada50a63e0f2e920964d60d107..e9f71dc0d46415587f7461678d5ae6051aa9b289 100644 (file)
@@ -547,9 +547,6 @@ enum {
 /* max. codec address */
 #define HDA_MAX_CODEC_ADDRESS  0x0f
 
-/* max number of PCM devics per card */
-#define HDA_MAX_PCMS           10
-
 /*
  * generic arrays
  */
@@ -869,6 +866,9 @@ struct hda_codec {
        void (*proc_widget_hook)(struct snd_info_buffer *buffer,
                                 struct hda_codec *codec, hda_nid_t nid);
 
+       /* jack detection */
+       struct snd_array jacktbl;
+
 #ifdef CONFIG_SND_HDA_INPUT_JACK
        /* jack detection */
        struct snd_array jacks;
index c2f79e63124d82cb32ee0a47668f8997bc73e298..0852e204a4c8439e557bd553dcde3aae1f7c173a 100644 (file)
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static char *model[SNDRV_CARDS];
 static int position_fix[SNDRV_CARDS];
 static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_only[SNDRV_CARDS];
-static int single_cmd;
+static bool single_cmd;
 static int enable_msi = -1;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 static char *patch[SNDRV_CARDS];
@@ -116,12 +116,12 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
  * this may give more power-saving, but will take longer time to
  * wake up.
  */
-static int power_save_controller = 1;
+static bool power_save_controller = 1;
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
-static int align_buffer_size = 1;
+static bool align_buffer_size = 1;
 module_param(align_buffer_size, bool, 0644);
 MODULE_PARM_DESC(align_buffer_size,
                "Force buffer and period sizes to be multiple of 128 bytes.");
@@ -407,6 +407,14 @@ struct azx_rb {
        u32 res[AZX_MAX_CODECS];        /* last read value */
 };
 
+struct azx_pcm {
+       struct azx *chip;
+       struct snd_pcm *pcm;
+       struct hda_codec *codec;
+       struct hda_pcm_stream *hinfo[2];
+       struct list_head list;
+};
+
 struct azx {
        struct snd_card *card;
        struct pci_dev *pci;
@@ -434,7 +442,7 @@ struct azx {
        struct azx_dev *azx_dev;
 
        /* PCM */
-       struct snd_pcm *pcm[HDA_MAX_PCMS];
+       struct list_head pcm_list; /* azx_pcm list */
 
        /* HD codec */
        unsigned short codec_mask;
@@ -479,6 +487,7 @@ enum {
        AZX_DRIVER_SCH,
        AZX_DRIVER_ATI,
        AZX_DRIVER_ATIHDMI,
+       AZX_DRIVER_ATIHDMI_NS,
        AZX_DRIVER_VIA,
        AZX_DRIVER_SIS,
        AZX_DRIVER_ULI,
@@ -525,6 +534,7 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_SCH] = "HDA Intel MID",
        [AZX_DRIVER_ATI] = "HDA ATI SB",
        [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
+       [AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI",
        [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
        [AZX_DRIVER_SIS] = "HDA SIS966",
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
@@ -1143,16 +1153,6 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
 
 static void azx_init_pci(struct azx *chip)
 {
-       /* force to non-snoop mode for a new VIA controller when BIOS is set */
-       if (chip->snoop && chip->driver_type == AZX_DRIVER_VIA) {
-               u8 snoop;
-               pci_read_config_byte(chip->pci, 0x42, &snoop);
-               if (!(snoop & 0x80) && chip->pci->revision == 0x30) {
-                       chip->snoop = 0;
-                       snd_printdd(SFX "Force to non-snoop mode\n");
-               }
-       }
-
        /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
         * TCSEL == Traffic Class Select Register, which sets PCI express QOS
         * Ensuring these bits are 0 clears playback static on some HD Audio
@@ -1486,10 +1486,9 @@ static void azx_bus_reset(struct hda_bus *bus)
        azx_init_chip(chip, 1);
 #ifdef CONFIG_PM
        if (chip->initialized) {
-               int i;
-
-               for (i = 0; i < HDA_MAX_PCMS; i++)
-                       snd_pcm_suspend_all(chip->pcm[i]);
+               struct azx_pcm *p;
+               list_for_each_entry(p, &chip->pcm_list, list)
+                       snd_pcm_suspend_all(p->pcm);
                snd_hda_suspend(chip->bus);
                snd_hda_resume(chip->bus);
        }
@@ -1667,12 +1666,6 @@ static struct snd_pcm_hardware azx_pcm_hw = {
        .fifo_size =            0,
 };
 
-struct azx_pcm {
-       struct azx *chip;
-       struct hda_codec *codec;
-       struct hda_pcm_stream *hinfo[2];
-};
-
 static int azx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
@@ -2197,7 +2190,7 @@ static void azx_pcm_free(struct snd_pcm *pcm)
 {
        struct azx_pcm *apcm = pcm->private_data;
        if (apcm) {
-               apcm->chip->pcm[pcm->device] = NULL;
+               list_del(&apcm->list);
                kfree(apcm);
        }
 }
@@ -2215,14 +2208,11 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        unsigned int size;
        int s, err;
 
-       if (pcm_dev >= HDA_MAX_PCMS) {
-               snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
-                          pcm_dev);
-               return -EINVAL;
-       }
-       if (chip->pcm[pcm_dev]) {
-               snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
-               return -EBUSY;
+       list_for_each_entry(apcm, &chip->pcm_list, list) {
+               if (apcm->pcm->device == pcm_dev) {
+                       snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
+                       return -EBUSY;
+               }
        }
        err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
                          cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
@@ -2235,12 +2225,13 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
        if (apcm == NULL)
                return -ENOMEM;
        apcm->chip = chip;
+       apcm->pcm = pcm;
        apcm->codec = codec;
        pcm->private_data = apcm;
        pcm->private_free = azx_pcm_free;
        if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
                pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
-       chip->pcm[pcm_dev] = pcm;
+       list_add_tail(&apcm->list, &chip->pcm_list);
        cpcm->pcm = pcm;
        for (s = 0; s < 2; s++) {
                apcm->hinfo[s] = &cpcm->stream[s];
@@ -2370,12 +2361,12 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct azx *chip = card->private_data;
-       int i;
+       struct azx_pcm *p;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        azx_clear_irq_pending(chip);
-       for (i = 0; i < HDA_MAX_PCMS; i++)
-               snd_pcm_suspend_all(chip->pcm[i]);
+       list_for_each_entry(p, &chip->pcm_list, list)
+               snd_pcm_suspend_all(p->pcm);
        if (chip->initialized)
                snd_hda_suspend(chip->bus);
        azx_stop_chip(chip);
@@ -2502,12 +2493,10 @@ static int azx_dev_free(struct snd_device *device)
 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(0x1028, 0x02c6, "Dell Inspiron 1010", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS 1101HA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
@@ -2634,6 +2623,35 @@ static void __devinit check_msi(struct azx *chip)
        }
 }
 
+/* check the snoop mode availability */
+static void __devinit azx_check_snoop_available(struct azx *chip)
+{
+       bool snoop = chip->snoop;
+
+       switch (chip->driver_type) {
+       case AZX_DRIVER_VIA:
+               /* force to non-snoop mode for a new VIA controller
+                * when BIOS is set
+                */
+               if (snoop) {
+                       u8 val;
+                       pci_read_config_byte(chip->pci, 0x42, &val);
+                       if (!(val & 0x80) && chip->pci->revision == 0x30)
+                               snoop = false;
+               }
+               break;
+       case AZX_DRIVER_ATIHDMI_NS:
+               /* new ATI HDMI requires non-snoop */
+               snoop = false;
+               break;
+       }
+
+       if (snoop != chip->snoop) {
+               snd_printk(KERN_INFO SFX "Force to %s mode\n",
+                          snoop ? "snoop" : "non-snoop");
+               chip->snoop = snoop;
+       }
+}
 
 /*
  * constructor
@@ -2672,6 +2690,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        check_msi(chip);
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
+       INIT_LIST_HEAD(&chip->pcm_list);
 
        chip->position_fix[0] = chip->position_fix[1] =
                check_position_fix(chip, position_fix[dev]);
@@ -2679,6 +2698,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 
        chip->single_cmd = single_cmd;
        chip->snoop = hda_snoop;
+       azx_check_snoop_available(chip);
 
        if (bdl_pos_adj[dev] < 0) {
                switch (chip->driver_type) {
@@ -2777,6 +2797,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
                        chip->capture_streams = ULI_NUM_CAPTURE;
                        break;
                case AZX_DRIVER_ATIHDMI:
+               case AZX_DRIVER_ATIHDMI_NS:
                        chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
                        chip->capture_streams = ATIHDMI_NUM_CAPTURE;
                        break;
@@ -2972,6 +2993,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(0x8086, 0x811b),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
          AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */
+       { PCI_DEVICE(0x8086, 0x080a),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */
        /* ICH */
        { PCI_DEVICE(0x8086, 0x2668),
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
@@ -3039,6 +3063,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
        { PCI_DEVICE(0x1002, 0xaa48),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0x9902),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaaa0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaaa8),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+       { PCI_DEVICE(0x1002, 0xaab0),
+         .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
        /* VIA VT8251/VT8237A */
        { PCI_DEVICE(0x1106, 0x3288),
          .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
new file mode 100644 (file)
index 0000000..d8a35da
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Jack-detection handling for HD-audio
+ *
+ * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/jack.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_jack.h"
+
+/* execute pin sense measurement */
+static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+       u32 pincap;
+
+       if (!codec->no_trigger_sense) {
+               pincap = snd_hda_query_pin_caps(codec, nid);
+               if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
+                       snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_SET_PIN_SENSE, 0);
+       }
+       return snd_hda_codec_read(codec, nid, 0,
+                                 AC_VERB_GET_PIN_SENSE, 0);
+}
+
+/**
+ * snd_hda_jack_tbl_get - query the jack-table entry for the given NID
+ */
+struct hda_jack_tbl *
+snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       int i;
+
+       if (!nid || !jack)
+               return NULL;
+       for (i = 0; i < codec->jacktbl.used; i++, jack++)
+               if (jack->nid == nid)
+                       return jack;
+       return NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);
+
+/**
+ * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
+ */
+struct hda_jack_tbl *
+snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
+{
+       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       int i;
+
+       if (!tag || !jack)
+               return NULL;
+       for (i = 0; i < codec->jacktbl.used; i++, jack++)
+               if (jack->tag == tag)
+                       return jack;
+       return NULL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag);
+
+/**
+ * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
+ */
+struct hda_jack_tbl *
+snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+       if (jack)
+               return jack;
+       snd_array_init(&codec->jacktbl, sizeof(*jack), 16);
+       jack = snd_array_new(&codec->jacktbl);
+       if (!jack)
+               return NULL;
+       jack->nid = nid;
+       jack->jack_dirty = 1;
+       jack->tag = codec->jacktbl.used;
+       return jack;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_new);
+
+void snd_hda_jack_tbl_clear(struct hda_codec *codec)
+{
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+       /* free jack instances manually when clearing/reconfiguring */
+       if (!codec->bus->shutdown && codec->jacktbl.list) {
+               struct hda_jack_tbl *jack = codec->jacktbl.list;
+               int i;
+               for (i = 0; i < codec->jacktbl.used; i++, jack++) {
+                       if (jack->jack)
+                               snd_device_free(codec->bus->card, jack->jack);
+               }
+       }
+#endif
+       snd_array_free(&codec->jacktbl);
+}
+
+/* update the cached value and notification flag if needed */
+static void jack_detect_update(struct hda_codec *codec,
+                              struct hda_jack_tbl *jack)
+{
+       if (jack->jack_dirty || !jack->jack_detect) {
+               jack->pin_sense = read_pin_sense(codec, jack->nid);
+               jack->jack_dirty = 0;
+       }
+}
+
+/**
+ * snd_hda_set_dirty_all - Mark all the cached as dirty
+ *
+ * This function sets the dirty flag to all entries of jack table.
+ * It's called from the resume path in hda_codec.c.
+ */
+void snd_hda_jack_set_dirty_all(struct hda_codec *codec)
+{
+       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       int i;
+
+       for (i = 0; i < codec->jacktbl.used; i++, jack++)
+               if (jack->nid)
+                       jack->jack_dirty = 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all);
+
+/**
+ * snd_hda_pin_sense - execute pin sense measurement
+ * @codec: the CODEC to sense
+ * @nid: the pin NID to sense
+ *
+ * Execute necessary pin sense measurement and return its Presence Detect,
+ * Impedance, ELD Valid etc. status bits.
+ */
+u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+       if (jack) {
+               jack_detect_update(codec, jack);
+               return jack->pin_sense;
+       }
+       return read_pin_sense(codec, nid);
+}
+EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
+
+#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
+
+/**
+ * snd_hda_jack_detect - query pin Presence Detect status
+ * @codec: the CODEC to sense
+ * @nid: the pin NID to sense
+ *
+ * Query and return the pin's Presence Detect status.
+ */
+int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+{
+       u32 sense = snd_hda_pin_sense(codec, nid);
+       return get_jack_plug_state(sense);
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
+
+/**
+ * snd_hda_jack_detect_enable - enable the jack-detection
+ */
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned char action)
+{
+       struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
+       if (!jack)
+               return -ENOMEM;
+       if (jack->jack_detect)
+               return 0; /* already registered */
+       jack->jack_detect = 1;
+       if (action)
+               jack->action = action;
+       return snd_hda_codec_write_cache(codec, nid, 0,
+                                        AC_VERB_SET_UNSOLICITED_ENABLE,
+                                        AC_USRSP_EN | jack->tag);
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
+
+/**
+ * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
+ */
+void snd_hda_jack_report_sync(struct hda_codec *codec)
+{
+       struct hda_jack_tbl *jack = codec->jacktbl.list;
+       int i, state;
+
+       for (i = 0; i < codec->jacktbl.used; i++, jack++)
+               if (jack->nid) {
+                       jack_detect_update(codec, jack);
+                       if (!jack->kctl)
+                               continue;
+                       state = get_jack_plug_state(jack->pin_sense);
+                       snd_kctl_jack_report(codec->bus->card, jack->kctl, state);
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+                       if (jack->jack)
+                               snd_jack_report(jack->jack,
+                                               state ? jack->type : 0);
+#endif
+               }
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
+
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+/* guess the jack type from the pin-config */
+static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_LINE_OUT:
+       case AC_JACK_SPEAKER:
+               return SND_JACK_LINEOUT;
+       case AC_JACK_HP_OUT:
+               return SND_JACK_HEADPHONE;
+       case AC_JACK_SPDIF_OUT:
+       case AC_JACK_DIG_OTHER_OUT:
+               return SND_JACK_AVOUT;
+       case AC_JACK_MIC_IN:
+               return SND_JACK_MICROPHONE;
+       default:
+               return SND_JACK_LINEIN;
+       }
+}
+
+static void hda_free_jack_priv(struct snd_jack *jack)
+{
+       struct hda_jack_tbl *jacks = jack->private_data;
+       jacks->nid = 0;
+       jacks->jack = NULL;
+}
+#endif
+
+/**
+ * snd_hda_jack_add_kctl - Add a kctl for the given pin
+ *
+ * This assigns a jack-detection kctl to the given pin.  The kcontrol
+ * will have the given name and index.
+ */
+int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+                         const char *name, int idx)
+{
+       struct hda_jack_tbl *jack;
+       struct snd_kcontrol *kctl;
+       int err, state;
+
+       jack = snd_hda_jack_tbl_new(codec, nid);
+       if (!jack)
+               return 0;
+       if (jack->kctl)
+               return 0; /* already created */
+       kctl = snd_kctl_jack_new(name, idx, codec);
+       if (!kctl)
+               return -ENOMEM;
+       err = snd_hda_ctl_add(codec, nid, kctl);
+       if (err < 0)
+               return err;
+       jack->kctl = kctl;
+       state = snd_hda_jack_detect(codec, nid);
+       snd_kctl_jack_report(codec->bus->card, kctl, state);
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+       jack->type = get_input_jack_type(codec, nid);
+       err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack);
+       if (err < 0)
+               return err;
+       jack->jack->private_data = jack;
+       jack->jack->private_free = hda_free_jack_priv;
+       snd_jack_report(jack->jack, state ? jack->type : 0);
+#endif
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl);
+
+static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
+                        const struct auto_pin_cfg *cfg)
+{
+       unsigned int def_conf, conn;
+       char name[44];
+       int idx, err;
+
+       if (!nid)
+               return 0;
+       if (!is_jack_detectable(codec, nid))
+               return 0;
+       def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       conn = get_defcfg_connect(def_conf);
+       if (conn != AC_JACK_PORT_COMPLEX)
+               return 0;
+
+       snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx);
+       err = snd_hda_jack_add_kctl(codec, nid, name, idx);
+       if (err < 0)
+               return err;
+       return snd_hda_jack_detect_enable(codec, nid, 0);
+}
+
+/**
+ * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
+ */
+int snd_hda_jack_add_kctls(struct hda_codec *codec,
+                          const struct auto_pin_cfg *cfg)
+{
+       const hda_nid_t *p;
+       int i, err;
+
+       for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
+               err = add_jack_kctl(codec, *p, cfg);
+               if (err < 0)
+                       return err;
+       }
+       for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
+               if (*p == *cfg->line_out_pins) /* might be duplicated */
+                       break;
+               err = add_jack_kctl(codec, *p, cfg);
+               if (err < 0)
+                       return err;
+       }
+       for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
+               if (*p == *cfg->line_out_pins) /* might be duplicated */
+                       break;
+               err = add_jack_kctl(codec, *p, cfg);
+               if (err < 0)
+                       return err;
+       }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg);
+               if (err < 0)
+                       return err;
+       }
+       for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
+               err = add_jack_kctl(codec, *p, cfg);
+               if (err < 0)
+                       return err;
+       }
+       err = add_jack_kctl(codec, cfg->dig_in_pin, cfg);
+       if (err < 0)
+               return err;
+       err = add_jack_kctl(codec, cfg->mono_out_pin, cfg);
+       if (err < 0)
+               return err;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
new file mode 100644 (file)
index 0000000..f8f97c7
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Jack-detection handling for HD-audio
+ *
+ * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __SOUND_HDA_JACK_H
+#define __SOUND_HDA_JACK_H
+
+struct hda_jack_tbl {
+       hda_nid_t nid;
+       unsigned char action;           /* event action (0 = none) */
+       unsigned char tag;              /* unsol event tag */
+       unsigned int private_data;      /* arbitrary data */
+       /* jack-detection stuff */
+       unsigned int pin_sense;         /* cached pin-sense value */
+       unsigned int jack_detect:1;     /* capable of jack-detection? */
+       unsigned int jack_dirty:1;      /* needs to update? */
+       struct snd_kcontrol *kctl;      /* assigned kctl for jack-detection */
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+       int type;
+       struct snd_jack *jack;
+#endif
+};
+
+struct hda_jack_tbl *
+snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
+struct hda_jack_tbl *
+snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);
+
+struct hda_jack_tbl *
+snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid);
+void snd_hda_jack_tbl_clear(struct hda_codec *codec);
+
+/**
+ * snd_hda_jack_get_action - get jack-tbl entry for the tag
+ *
+ * Call this from the unsol event handler to get the assigned action for the
+ * event.  This will mark the dirty flag for the later reporting, too.
+ */
+static inline unsigned char
+snd_hda_jack_get_action(struct hda_codec *codec, unsigned int tag)
+{
+       struct hda_jack_tbl *jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (jack) {
+               jack->jack_dirty = 1;
+               return jack->action;
+       }
+       return 0;
+}
+
+void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
+
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned char action);
+
+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);
+
+static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
+               return false;
+       if (!codec->ignore_misc_bit &&
+           (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+            AC_DEFCFG_MISC_NO_PRESENCE))
+               return false;
+       if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+               return false;
+       return true;
+}
+
+int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+                         const char *name, int idx);
+int snd_hda_jack_add_kctls(struct hda_codec *codec,
+                          const struct auto_pin_cfg *cfg);
+
+void snd_hda_jack_report_sync(struct hda_codec *codec);
+
+
+#endif /* __SOUND_HDA_JACK_H */
index 618ddad172369b22062ad97114dd783841ccde43..aca8d3193b9507f55080b13811936fca3a301a28 100644 (file)
@@ -394,11 +394,12 @@ struct auto_pin_cfg_item {
 };
 
 struct auto_pin_cfg;
-const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
-                                   int check_location);
 const char *hda_get_autocfg_input_label(struct hda_codec *codec,
                                        const struct auto_pin_cfg *cfg,
                                        int input);
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+                         const struct auto_pin_cfg *cfg,
+                         char *label, int maxlen, int *indexp);
 int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
                          int index, int *type_index_ret);
 
@@ -487,7 +488,12 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
 }
 
 /* get the widget type from widget capability bits */
-#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT)
+static inline int get_wcaps_type(unsigned int wcaps)
+{
+       if (!wcaps)
+               return -1; /* invalid type */
+       return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
 
 static inline unsigned int get_wcaps_channels(u32 wcaps)
 {
@@ -505,21 +511,6 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
 u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
                              unsigned int caps);
-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);
-
-static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
-{
-       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
-               return false;
-       if (!codec->ignore_misc_bit &&
-           (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-            AC_DEFCFG_MISC_NO_PRESENCE))
-               return false;
-       if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
-               return false;
-       return true;
-}
 
 /* flags for hda_nid_item */
 #define HDA_NID_ITEM_AMP       (1<<0)
@@ -688,28 +679,4 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
 #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
 
-/*
- * Input-jack notification support
- */
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
-                          const char *name);
-void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
-void snd_hda_input_jack_free(struct hda_codec *codec);
-#else /* CONFIG_SND_HDA_INPUT_JACK */
-static inline int snd_hda_input_jack_add(struct hda_codec *codec,
-                                        hda_nid_t nid, int type,
-                                        const char *name)
-{
-       return 0;
-}
-static inline void snd_hda_input_jack_report(struct hda_codec *codec,
-                                            hda_nid_t nid)
-{
-}
-static inline void snd_hda_input_jack_free(struct hda_codec *codec)
-{
-}
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-
 #endif /* __SOUND_HDA_LOCAL_H */
index 2c981b55940b1d170971ea703fe13d21d563cb49..254ab5204603767c54f44f25b5d94df624bb89d3 100644 (file)
@@ -54,6 +54,8 @@ static const char *get_wid_type_name(unsigned int wid_value)
                [AC_WID_BEEP] = "Beep Generator Widget",
                [AC_WID_VENDOR] = "Vendor Defined Widget",
        };
+       if (wid_value == -1)
+               return "UNKNOWN Widget";
        wid_value &= 0xf;
        if (names[wid_value])
                return names[wid_value];
index bcb3310c394ff808a83d531cb49bdf2defcac056..9cb14b42dfff48f890ee10871dea7fffb14b7054 100644 (file)
@@ -29,6 +29,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 struct ad198x_spec {
        const struct snd_kcontrol_new *mixers[6];
index 993757b65736a01687c571ce3003e18507e861f4..09ccfabb4a17c38a608d04d05b4a5979e6dc7ed7 100644 (file)
@@ -41,7 +41,7 @@ struct ca0110_spec {
        hda_nid_t dig_out;
        hda_nid_t dig_in;
        unsigned int num_inputs;
-       const char *input_labels[AUTO_PIN_LAST];
+       char input_labels[AUTO_PIN_LAST][32];
        struct hda_pcm pcm_rec[2];      /* PCM information */
 };
 
@@ -476,7 +476,9 @@ static void parse_input(struct hda_codec *codec)
                if (j >= cfg->num_inputs)
                        continue;
                spec->input_pins[n] = pin;
-               spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
+               snd_hda_get_pin_label(codec, pin, cfg,
+                                     spec->input_labels[n],
+                                     sizeof(spec->input_labels[n]), NULL);
                spec->adcs[n] = nid;
                n++;
        }
index 70a7abda7e225744bf93d90f795c86bfcd95dac6..0e99357e822c201a03ffeadf451e9cc29e2001c0 100644 (file)
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_jack.h"
 #include <sound/tlv.h>
 
 /*
@@ -78,6 +79,7 @@ enum {
        CS420X_MBP53,
        CS420X_MBP55,
        CS420X_IMAC27,
+       CS420X_IMAC27_122,
        CS420X_APPLE,
        CS420X_AUTO,
        CS420X_MODELS
@@ -137,7 +139,7 @@ enum {
 */
 #define CS4210_DAC_NID         0x02
 #define CS4210_ADC_NID         0x03
-#define CS421X_VENDOR_NID      0x0B
+#define CS4210_VENDOR_NID      0x0B
 #define CS421X_DMIC_PIN_NID    0x09 /* Port E */
 #define CS421X_SPDIF_PIN_NID   0x0A /* Port H */
 
@@ -148,6 +150,10 @@ enum {
 
 #define SPDIF_EVENT            0x04
 
+/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
+#define CS4213_VENDOR_NID      0x09
+
+
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
        struct cs_spec *spec = codec->spec;
@@ -721,8 +727,9 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
        if (uinfo->value.enumerated.item >= spec->num_inputs)
                uinfo->value.enumerated.item = spec->num_inputs - 1;
        idx = spec->input_idx[uinfo->value.enumerated.item];
-       strcpy(uinfo->value.enumerated.name,
-              hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
+       snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg,
+                             uinfo->value.enumerated.name,
+                             sizeof(uinfo->value.enumerated.name), NULL);
        return 0;
 }
 
@@ -920,16 +927,14 @@ static void cs_automute(struct hda_codec *codec)
 
        /* mute speakers if spdif or hp jack is plugged in */
        for (i = 0; i < cfg->speaker_outs; i++) {
+               int pin_ctl = hp_present ? 0 : PIN_OUT;
+               /* detect on spdif is specific to CS4210 */
+               if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID))
+                       pin_ctl = 0;
+
                nid = cfg->speaker_pins[i];
                snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   hp_present ? 0 : PIN_OUT);
-               /* detect on spdif is specific to CS421x */
-               if (spec->vendor_nid == CS421X_VENDOR_NID) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                       spdif_present ? 0 : PIN_OUT);
-               }
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
        }
        if (spec->gpio_eapd_hp) {
                unsigned int gpio = hp_present ?
@@ -938,8 +943,8 @@ static void cs_automute(struct hda_codec *codec)
                                    AC_VERB_SET_GPIO_DATA, gpio);
        }
 
-       /* specific to CS421x */
-       if (spec->vendor_nid == CS421X_VENDOR_NID) {
+       /* specific to CS4210 */
+       if (spec->vendor_nid == CS4210_VENDOR_NID) {
                /* mute HPs if spdif jack (SENSE_B) is present */
                for (i = 0; i < cfg->hp_outs; i++) {
                        nid = cfg->hp_pins[i];
@@ -976,7 +981,12 @@ static void cs_automic(struct hda_codec *codec)
        present = snd_hda_jack_detect(codec, nid);
 
        /* specific to CS421x, single ADC */
-       if (spec->vendor_nid == CS421X_VENDOR_NID) {
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               if (present)
+                       change_cur_input(codec, spec->automic_idx, 0);
+               else
+                       change_cur_input(codec, !spec->automic_idx, 0);
+       } else {
                if (present) {
                        spec->last_input = spec->cur_input;
                        spec->cur_input = spec->automic_idx;
@@ -984,11 +994,6 @@ static void cs_automic(struct hda_codec *codec)
                        spec->cur_input = spec->last_input;
                }
                cs_update_input_select(codec);
-       } else {
-               if (present)
-                       change_cur_input(codec, spec->automic_idx, 0);
-               else
-                       change_cur_input(codec, !spec->automic_idx, 0);
        }
 }
 
@@ -1027,9 +1032,7 @@ static void init_output(struct hda_codec *codec)
                if (!cfg->speaker_outs)
                        continue;
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | HP_EVENT);
+                       snd_hda_jack_detect_enable(codec, nid, HP_EVENT);
                        spec->hp_detect = 1;
                }
        }
@@ -1070,19 +1073,10 @@ static void init_input(struct hda_codec *codec)
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_MUTE(spec->adc_idx[i]));
                if (spec->mic_detect && spec->automic_idx == i)
-                       snd_hda_codec_write(codec, pin, 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | MIC_EVENT);
+                       snd_hda_jack_detect_enable(codec, pin, MIC_EVENT);
        }
-       /* specific to CS421x */
-       if (spec->vendor_nid == CS421X_VENDOR_NID) {
-               if (spec->mic_detect)
-                       cs_automic(codec);
-               else  {
-                       spec->cur_adc = spec->adc_nid[spec->cur_input];
-                       cs_update_input_select(codec);
-               }
-       } else {
+       /* CS420x has multiple ADC, CS421x has single ADC */
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
                change_cur_input(codec, spec->cur_input, 1);
                if (spec->mic_detect)
                        cs_automic(codec);
@@ -1096,6 +1090,13 @@ static void init_input(struct hda_codec *codec)
                                         * selected in IDX_SPDIF_CTL.
                                        */
                cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+       } else {
+               if (spec->mic_detect)
+                       cs_automic(codec);
+               else  {
+                       spec->cur_adc = spec->adc_nid[spec->cur_input];
+                       cs_update_input_select(codec);
+               }
        }
 }
 
@@ -1200,11 +1201,14 @@ static int cs_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_digital(codec);
+       snd_hda_jack_report_sync(codec);
+
        return 0;
 }
 
 static int cs_build_controls(struct hda_codec *codec)
 {
+       struct cs_spec *spec = codec->spec;
        int err;
 
        err = build_output(codec);
@@ -1219,7 +1223,15 @@ static int cs_build_controls(struct hda_codec *codec)
        err = build_digital_input(codec);
        if (err < 0)
                return err;
-       return cs_init(codec);
+       err = cs_init(codec);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 static void cs_free(struct hda_codec *codec)
@@ -1232,7 +1244,7 @@ static void cs_free(struct hda_codec *codec)
 
 static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       switch ((res >> 26) & 0x7f) {
+       switch (snd_hda_jack_get_action(codec, res >> 26)) {
        case HP_EVENT:
                cs_automute(codec);
                break;
@@ -1240,6 +1252,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
                cs_automic(codec);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 static const struct hda_codec_ops cs_patch_ops = {
@@ -1278,6 +1291,7 @@ static const char * const cs420x_models[CS420X_MODELS] = {
        [CS420X_MBP53] = "mbp53",
        [CS420X_MBP55] = "mbp55",
        [CS420X_IMAC27] = "imac27",
+       [CS420X_IMAC27_122] = "imac27_122",
        [CS420X_APPLE] = "apple",
        [CS420X_AUTO] = "auto",
 };
@@ -1294,6 +1308,7 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
 };
 
 static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
        SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
 };
@@ -1393,6 +1408,12 @@ static int patch_cs420x(struct hda_codec *codec)
                spec->gpio_mask = spec->gpio_dir =
                        spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
                break;
+       case CS420X_IMAC27_122:
+               spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+               break;
        }
 
        err = cs_parse_auto_config(codec);
@@ -1557,7 +1578,7 @@ static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = {
        .tlv = { .p = cs421x_speaker_boost_db_scale },
 };
 
-static void cs421x_pinmux_init(struct hda_codec *codec)
+static void cs4210_pinmux_init(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
        unsigned int def_conf, coef;
@@ -1602,10 +1623,7 @@ static void init_cs421x_digital(struct hda_codec *codec)
                if (!cfg->speaker_outs)
                        continue;
                if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-
-                       snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | SPDIF_EVENT);
+                       snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT);
                        spec->spdif_detect = 1;
                }
        }
@@ -1615,10 +1633,11 @@ static int cs421x_init(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
 
-       snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
-       snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
-
-       cs421x_pinmux_init(codec);
+       if (spec->vendor_nid == CS4210_VENDOR_NID) {
+               snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+               snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+               cs4210_pinmux_init(codec);
+       }
 
        if (spec->gpio_mask) {
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
@@ -1632,6 +1651,7 @@ static int cs421x_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_cs421x_digital(codec);
+       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -1771,32 +1791,21 @@ static int build_cs421x_output(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        struct snd_kcontrol *kctl;
        int err;
-       char *name = "HP/Speakers";
+       char *name = "Master";
 
        fix_volume_caps(codec, dac);
-       if (!spec->vmaster_sw) {
-               err = add_vmaster(codec, dac);
-               if (err < 0)
-                       return err;
-       }
 
        err = add_mute(codec, name, 0,
                        HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
        if (err < 0)
                return err;
-       err = snd_ctl_add_slave(spec->vmaster_sw, kctl);
-       if (err < 0)
-               return err;
 
        err = add_volume(codec, name, 0,
                        HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
        if (err < 0)
                return err;
-       err = snd_ctl_add_slave(spec->vmaster_vol, kctl);
-       if (err < 0)
-               return err;
 
-       if (cfg->speaker_outs) {
+       if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) {
                err = snd_hda_ctl_add(codec, 0,
                        snd_ctl_new1(&cs421x_speaker_bost_ctl, codec));
                if (err < 0)
@@ -1807,6 +1816,7 @@ static int build_cs421x_output(struct hda_codec *codec)
 
 static int cs421x_build_controls(struct hda_codec *codec)
 {
+       struct cs_spec *spec = codec->spec;
        int err;
 
        err = build_cs421x_output(codec);
@@ -1818,12 +1828,20 @@ static int cs421x_build_controls(struct hda_codec *codec)
        err = build_digital_output(codec);
        if (err < 0)
                return err;
-       return cs421x_init(codec);
+       err =  cs421x_init(codec);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
 }
 
 static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       switch ((res >> 26) & 0x3f) {
+       switch (snd_hda_jack_get_action(codec, res >> 26)) {
        case HP_EVENT:
        case SPDIF_EVENT:
                cs_automute(codec);
@@ -1833,6 +1851,7 @@ static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
                cs_automic(codec);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 static int parse_cs421x_input(struct hda_codec *codec)
@@ -1883,6 +1902,7 @@ static int cs421x_parse_auto_config(struct hda_codec *codec)
 */
 static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
 {
+       struct cs_spec *spec = codec->spec;
        unsigned int coef;
 
        snd_hda_shutup_pins(codec);
@@ -1892,15 +1912,17 @@ static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
        snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
                            AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
 
-       coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-       coef |= 0x0004; /* PDREF */
-       cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+       if (spec->vendor_nid == CS4210_VENDOR_NID) {
+               coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+               coef |= 0x0004; /* PDREF */
+               cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+       }
 
        return 0;
 }
 #endif
 
-static struct hda_codec_ops cs4210_patch_ops = {
+static struct hda_codec_ops cs421x_patch_ops = {
        .build_controls = cs421x_build_controls,
        .build_pcms = cs_build_pcms,
        .init = cs421x_init,
@@ -1911,7 +1933,7 @@ static struct hda_codec_ops cs4210_patch_ops = {
 #endif
 };
 
-static int patch_cs421x(struct hda_codec *codec)
+static int patch_cs4210(struct hda_codec *codec)
 {
        struct cs_spec *spec;
        int err;
@@ -1921,7 +1943,7 @@ static int patch_cs421x(struct hda_codec *codec)
                return -ENOMEM;
        codec->spec = spec;
 
-       spec->vendor_nid = CS421X_VENDOR_NID;
+       spec->vendor_nid = CS4210_VENDOR_NID;
 
        spec->board_config =
                snd_hda_check_board_config(codec, CS421X_MODELS,
@@ -1949,14 +1971,39 @@ static int patch_cs421x(struct hda_codec *codec)
            is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
            is disabled.
        */
-       cs421x_pinmux_init(codec);
+       cs4210_pinmux_init(codec);
 
        err = cs421x_parse_auto_config(codec);
        if (err < 0)
                goto error;
 
-       codec->patch_ops = cs4210_patch_ops;
+       codec->patch_ops = cs421x_patch_ops;
+
+       return 0;
+
+ error:
+       kfree(codec->spec);
+       codec->spec = NULL;
+       return err;
+}
+
+static int patch_cs4213(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+
+       spec->vendor_nid = CS4213_VENDOR_NID;
+
+       err = cs421x_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
 
+       codec->patch_ops = cs421x_patch_ops;
        return 0;
 
  error:
@@ -1972,13 +2019,15 @@ static int patch_cs421x(struct hda_codec *codec)
 static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
        { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
        { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
-       { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x },
+       { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 },
+       { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 },
        {} /* terminator */
 };
 
 MODULE_ALIAS("snd-hda-codec-id:10134206");
 MODULE_ALIAS("snd-hda-codec-id:10134207");
 MODULE_ALIAS("snd-hda-codec-id:10134210");
+MODULE_ALIAS("snd-hda-codec-id:10134213");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
index 0de21193a2b025ba58363c0e2a509ec4545b495d..8a32a69c83c330939b18f10f2cd3a6c9cfc10ebe 100644 (file)
@@ -31,6 +31,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 #define CXT_PIN_DIR_IN              0x00
 #define CXT_PIN_DIR_OUT             0x01
@@ -415,40 +416,6 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
                                     &spec->cur_mux[adc_idx]);
 }
 
-static int conexant_init_jacks(struct hda_codec *codec)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       struct conexant_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_init_verbs; i++) {
-               const struct hda_verb *hv;
-
-               hv = spec->init_verbs[i];
-               while (hv->nid) {
-                       int err = 0;
-                       switch (hv->param ^ AC_USRSP_EN) {
-                       case CONEXANT_HP_EVENT:
-                               err = snd_hda_input_jack_add(codec, hv->nid,
-                                               SND_JACK_HEADPHONE, NULL);
-                               snd_hda_input_jack_report(codec, hv->nid);
-                               break;
-                       case CXT5051_PORTC_EVENT:
-                       case CONEXANT_MIC_EVENT:
-                               err = snd_hda_input_jack_add(codec, hv->nid,
-                                               SND_JACK_MICROPHONE, NULL);
-                               snd_hda_input_jack_report(codec, hv->nid);
-                               break;
-                       }
-                       if (err < 0)
-                               return err;
-                       ++hv;
-               }
-       }
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-       return 0;
-}
-
 static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
                               unsigned int power_state)
 {
@@ -474,7 +441,6 @@ static int conexant_init(struct hda_codec *codec)
 
 static void conexant_free(struct hda_codec *codec)
 {
-       snd_hda_input_jack_free(codec);
        snd_hda_detach_beep_device(codec);
        kfree(codec->spec);
 }
@@ -1120,8 +1086,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = {
 
 static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
-       SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
-                          CXT5045_LAPTOP_HPSENSE),
        SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
        SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
@@ -1750,7 +1714,6 @@ static void cxt5051_hp_automute(struct hda_codec *codec)
 static void cxt5051_hp_unsol_event(struct hda_codec *codec,
                                   unsigned int res)
 {
-       int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5051_hp_automute(codec);
@@ -1762,7 +1725,6 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
                cxt5051_portc_automic(codec);
                break;
        }
-       snd_hda_input_jack_report(codec, nid);
 }
 
 static const struct snd_kcontrol_new cxt5051_playback_mixers[] = {
@@ -1901,8 +1863,6 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0,
                            AC_VERB_SET_UNSOLICITED_ENABLE,
                            AC_USRSP_EN | event);
-       snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
-       snd_hda_input_jack_report(codec, nid);
 }
 
 static const struct hda_verb cxt5051_ideapad_init_verbs[] = {
@@ -1918,7 +1878,6 @@ 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);
@@ -3450,7 +3409,6 @@ static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
                hda_nid_t nid = pins[i];
                if (!nid || !is_jack_detectable(codec, nid))
                        break;
-               snd_hda_input_jack_report(codec, nid);
                present |= snd_hda_jack_detect(codec, nid);
        }
        return present;
@@ -3755,8 +3713,7 @@ static void cx_auto_automic(struct hda_codec *codec)
 
 static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
-       switch (res >> 26) {
+       switch (snd_hda_jack_get_action(codec, res >> 26)) {
        case CONEXANT_HP_EVENT:
                cx_auto_hp_automute(codec);
                break;
@@ -3765,9 +3722,9 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
                break;
        case CONEXANT_MIC_EVENT:
                cx_auto_automic(codec);
-               snd_hda_input_jack_report(codec, nid);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 /* check whether the pin config is suitable for auto-mic switching;
@@ -3979,13 +3936,11 @@ static void mute_outputs(struct hda_codec *codec, int num_nids,
 }
 
 static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
-                             hda_nid_t *pins, unsigned int tag)
+                             hda_nid_t *pins, unsigned int action)
 {
        int i;
        for (i = 0; i < num_pins; i++)
-               snd_hda_codec_write(codec, pins[i], 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | tag);
+               snd_hda_jack_detect_enable(codec, pins[i], action);
 }
 
 static void cx_auto_init_output(struct hda_codec *codec)
@@ -4060,16 +4015,14 @@ static void cx_auto_init_input(struct hda_codec *codec)
 
        if (spec->auto_mic) {
                if (spec->auto_mic_ext >= 0) {
-                       snd_hda_codec_write(codec,
-                               cfg->inputs[spec->auto_mic_ext].pin, 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | CONEXANT_MIC_EVENT);
+                       snd_hda_jack_detect_enable(codec,
+                               cfg->inputs[spec->auto_mic_ext].pin,
+                               CONEXANT_MIC_EVENT);
                }
                if (spec->auto_mic_dock >= 0) {
-                       snd_hda_codec_write(codec,
-                               cfg->inputs[spec->auto_mic_dock].pin, 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | CONEXANT_MIC_EVENT);
+                       snd_hda_jack_detect_enable(codec,
+                               cfg->inputs[spec->auto_mic_dock].pin,
+                               CONEXANT_MIC_EVENT);
                }
                cx_auto_automic(codec);
        } else {
@@ -4097,6 +4050,7 @@ static int cx_auto_init(struct hda_codec *codec)
        cx_auto_init_output(codec);
        cx_auto_init_input(codec);
        cx_auto_init_digital(codec);
+       snd_hda_jack_report_sync(codec);
        return 0;
 }
 
@@ -4326,6 +4280,7 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
 
 static int cx_auto_build_controls(struct hda_codec *codec)
 {
+       struct conexant_spec *spec = codec->spec;
        int err;
 
        err = cx_auto_build_output_controls(codec);
@@ -4334,7 +4289,13 @@ static int cx_auto_build_controls(struct hda_codec *codec)
        err = cx_auto_build_input_controls(codec);
        if (err < 0)
                return err;
-       return conexant_build_controls(codec);
+       err = conexant_build_controls(codec);
+       if (err < 0)
+               return err;
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 static int cx_auto_search_adcs(struct hda_codec *codec)
index c505fd5d338cc91d1de2199143c8141f24890355..1168ebd3fb5c9cfe3bc964b9e223f45f3513c471 100644 (file)
@@ -36,6 +36,7 @@
 #include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_jack.h"
 
 static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
  *
  * The HDA correspondence of pipes/ports are converter/pin nodes.
  */
-#define MAX_HDMI_CVTS  4
-#define MAX_HDMI_PINS  4
+#define MAX_HDMI_CVTS  8
+#define MAX_HDMI_PINS  8
 
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
@@ -754,10 +755,18 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
 {
        struct hdmi_spec *spec = codec->spec;
-       int pin_nid = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int pin_nid;
        int pd = !!(res & AC_UNSOL_RES_PD);
        int eldv = !!(res & AC_UNSOL_RES_ELDV);
        int pin_idx;
+       struct hda_jack_tbl *jack;
+
+       jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (!jack)
+               return;
+       pin_nid = jack->nid;
+       jack->jack_dirty = 1;
 
        printk(KERN_INFO
                "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
@@ -768,6 +777,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
                return;
 
        hdmi_present_sense(&spec->pins[pin_idx], 1);
+       snd_hda_jack_report_sync(codec);
 }
 
 static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -795,11 +805,10 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
 
 static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       struct hdmi_spec *spec = codec->spec;
        int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
        int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
 
-       if (pin_nid_to_pin_index(spec, tag) < 0) {
+       if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) {
                snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag);
                return;
        }
@@ -996,8 +1005,6 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
                                           msecs_to_jiffies(300));
                }
        }
-
-       snd_hda_input_jack_report(codec, pin_nid);
 }
 
 static void hdmi_repoll_eld(struct work_struct *work)
@@ -1126,12 +1133,12 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
 /*
  */
-static char *generic_hdmi_pcm_names[MAX_HDMI_PINS] = {
-       "HDMI 0",
-       "HDMI 1",
-       "HDMI 2",
-       "HDMI 3",
-};
+static char *get_hdmi_pcm_name(int idx)
+{
+       static char names[MAX_HDMI_PINS][8];
+       sprintf(&names[idx][0], "HDMI %d", idx);
+       return &names[idx][0];
+}
 
 /*
  * HDMI callbacks
@@ -1209,7 +1216,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                struct hda_pcm_stream *pstr;
 
                info = &spec->pcm_rec[pin_idx];
-               info->name = generic_hdmi_pcm_names[pin_idx];
+               info->name = get_hdmi_pcm_name(pin_idx);
                info->pcm_type = HDA_PCM_TYPE_HDMI;
 
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
@@ -1226,21 +1233,15 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
 
 static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
 {
-       int err;
-       char hdmi_str[32];
+       char hdmi_str[32] = "HDMI/DP";
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
        int pcmdev = spec->pcm_rec[pin_idx].device;
 
-       snprintf(hdmi_str, sizeof(hdmi_str), "HDMI/DP,pcm=%d", pcmdev);
-
-       err = snd_hda_input_jack_add(codec, per_pin->pin_nid,
-                            SND_JACK_VIDEOOUT, pcmdev > 0 ? hdmi_str : NULL);
-       if (err < 0)
-               return err;
+       if (pcmdev > 0)
+               sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
 
-       hdmi_present_sense(per_pin, 0);
-       return 0;
+       return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0);
 }
 
 static int generic_hdmi_build_controls(struct hda_codec *codec)
@@ -1270,6 +1271,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
 
                if (err < 0)
                        return err;
+
+               hdmi_present_sense(per_pin, 0);
        }
 
        return 0;
@@ -1286,14 +1289,13 @@ static int generic_hdmi_init(struct hda_codec *codec)
                struct hdmi_eld *eld = &per_pin->sink_eld;
 
                hdmi_init_pin(codec, pin_nid);
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | pin_nid);
+               snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
 
                per_pin->codec = codec;
                INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
                snd_hda_eld_proc_new(codec, eld, pin_idx);
        }
+       snd_hda_jack_report_sync(codec);
        return 0;
 }
 
@@ -1309,7 +1311,6 @@ static void generic_hdmi_free(struct hda_codec *codec)
                cancel_delayed_work(&per_pin->work);
                snd_hda_eld_proc_free(codec, eld);
        }
-       snd_hda_input_jack_free(codec);
 
        flush_workqueue(codec->bus->workq);
        kfree(spec);
@@ -1364,7 +1365,7 @@ static int simple_playback_build_pcms(struct hda_codec *codec)
                chans = get_wcaps(codec, spec->cvts[i].cvt_nid);
                chans = get_wcaps_channels(chans);
 
-               info->name = generic_hdmi_pcm_names[i];
+               info->name = get_hdmi_pcm_name(i);
                info->pcm_type = HDA_PCM_TYPE_HDMI;
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
                snd_BUG_ON(!spec->pcm_playback);
index 1d07e8fa243360d25236a4942ab5e363d69d1558..5e82acf77c5ae84cbd3f77b1d3b8165246a8df22 100644 (file)
@@ -33,6 +33,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 /* unsol event tags */
 #define ALC_FRONT_EVENT                0x01
@@ -183,6 +184,8 @@ struct alc_spec {
        unsigned int single_input_src:1;
        unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
        unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
+       unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
+       unsigned int use_jack_tbl:1; /* 1 for model=auto */
 
        /* auto-mute control */
        int automute_mode;
@@ -283,6 +286,8 @@ static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
                spec->capsrc_nids[idx] : spec->adc_nids[idx];
 }
 
+static void call_update_outputs(struct hda_codec *codec);
+
 /* select the given imux item; either unmute exclusively or select the route */
 static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
                          unsigned int idx, bool force)
@@ -306,6 +311,19 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
                return 0;
        spec->cur_mux[adc_idx] = idx;
 
+       /* for shared I/O, change the pin-control accordingly */
+       if (spec->shared_mic_hp) {
+               /* NOTE: this assumes that there are only two inputs, the
+                * first is the real internal mic and the second is HP jack.
+                */
+               snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   spec->cur_mux[adc_idx] ?
+                                   PIN_VREF80 : PIN_HP);
+               spec->automute_speaker = !spec->cur_mux[adc_idx];
+               call_update_outputs(codec);
+       }
+
        if (spec->dyn_adc_switch) {
                alc_dyn_adc_pcm_resetup(codec, idx);
                adc_idx = spec->dyn_adc_idx[idx];
@@ -449,46 +467,6 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-/*
- * Jack-reporting via input-jack layer
- */
-
-/* initialization of jacks; currently checks only a few known pins */
-static int alc_init_jacks(struct hda_codec *codec)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       struct alc_spec *spec = codec->spec;
-       int err;
-       unsigned int hp_nid = spec->autocfg.hp_pins[0];
-       unsigned int mic_nid = spec->ext_mic_pin;
-       unsigned int dock_nid = spec->dock_mic_pin;
-
-       if (hp_nid) {
-               err = snd_hda_input_jack_add(codec, hp_nid,
-                                            SND_JACK_HEADPHONE, NULL);
-               if (err < 0)
-                       return err;
-               snd_hda_input_jack_report(codec, hp_nid);
-       }
-
-       if (mic_nid) {
-               err = snd_hda_input_jack_add(codec, mic_nid,
-                                            SND_JACK_MICROPHONE, NULL);
-               if (err < 0)
-                       return err;
-               snd_hda_input_jack_report(codec, mic_nid);
-       }
-       if (dock_nid) {
-               err = snd_hda_input_jack_add(codec, dock_nid,
-                                            SND_JACK_MICROPHONE, NULL);
-               if (err < 0)
-                       return err;
-               snd_hda_input_jack_report(codec, dock_nid);
-       }
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-       return 0;
-}
-
 /*
  * Jack detections for HP auto-mute and mic-switch
  */
@@ -502,7 +480,6 @@ static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
                hda_nid_t nid = pins[i];
                if (!nid)
                        break;
-               snd_hda_input_jack_report(codec, nid);
                present |= snd_hda_jack_detect(codec, nid);
        }
        return present;
@@ -554,7 +531,8 @@ static void update_outputs(struct hda_codec *codec)
         * in general, HP pins/amps control should be enabled in all cases,
         * but currently set only for master_mute, just to be safe
         */
-       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+       if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
+               do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
                    spec->autocfg.hp_pins, spec->master_mute, true);
 
        if (!spec->automute_speaker)
@@ -641,19 +619,18 @@ static void alc_mic_automute(struct hda_codec *codec)
                alc_mux_select(codec, 0, spec->dock_mic_idx, false);
        else
                alc_mux_select(codec, 0, spec->int_mic_idx, false);
-
-       snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
-       if (spec->dock_mic_idx >= 0)
-               snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
 }
 
 /* unsolicited event for HP jack sensing */
 static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
 {
+       struct alc_spec *spec = codec->spec;
        if (codec->vendor_id == 0x10ec0880)
                res >>= 28;
        else
                res >>= 26;
+       if (spec->use_jack_tbl)
+               res = snd_hda_jack_get_action(codec, res);
        switch (res) {
        case ALC_HP_EVENT:
                alc_hp_automute(codec);
@@ -665,6 +642,7 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
                alc_mic_automute(codec);
                break;
        }
+       snd_hda_jack_report_sync(codec);
 }
 
 /* call init functions of standard auto-mute helpers */
@@ -954,9 +932,7 @@ static void alc_init_automute(struct hda_codec *codec)
                        continue;
                snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
                            nid);
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | ALC_HP_EVENT);
+               snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT);
                spec->detect_hp = 1;
        }
 
@@ -968,9 +944,8 @@ static void alc_init_automute(struct hda_codec *codec)
                                        continue;
                                snd_printdd("realtek: Enable Line-Out "
                                            "auto-muting on NID 0x%x\n", nid);
-                               snd_hda_codec_write_cache(codec, nid, 0,
-                                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                                               AC_USRSP_EN | ALC_FRONT_EVENT);
+                               snd_hda_jack_detect_enable(codec, nid,
+                                                          ALC_FRONT_EVENT);
                                spec->detect_lo = 1;
                }
                spec->automute_lo_possible = spec->detect_hp;
@@ -1109,13 +1084,10 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec)
                return false; /* no corresponding imux */
        }
 
-       snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | ALC_MIC_EVENT);
+       snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT);
        if (spec->dock_mic_pin)
-               snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | ALC_MIC_EVENT);
+               snd_hda_jack_detect_enable(codec, spec->dock_mic_pin,
+                                          ALC_MIC_EVENT);
 
        spec->auto_mic_valid_imux = 1;
        spec->auto_mic = 1;
@@ -1133,6 +1105,9 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        hda_nid_t fixed, ext, dock;
        int i;
 
+       if (spec->shared_mic_hp)
+               return; /* no auto-mic for the shared I/O */
+
        spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
 
        fixed = ext = dock = 0;
@@ -1524,6 +1499,7 @@ static void alc_pick_fixup(struct hda_codec *codec,
                           const struct alc_fixup *fixlist)
 {
        struct alc_spec *spec = codec->spec;
+       const struct snd_pci_quirk *q;
        int id = -1;
        const char *name = NULL;
 
@@ -1538,12 +1514,25 @@ static void alc_pick_fixup(struct hda_codec *codec,
                }
        }
        if (id < 0) {
-               quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-               if (quirk) {
-                       id = quirk->value;
+               q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+               if (q) {
+                       id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                       name = q->name;
+#endif
+               }
+       }
+       if (id < 0) {
+               for (q = quirk; q->subvendor; q++) {
+                       unsigned int vendorid =
+                               q->subdevice | (q->subvendor << 16);
+                       if (vendorid == codec->subsystem_id) {
+                               id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
-                       name = quirk->name;
+                               name = q->name;
 #endif
+                               break;
+                       }
                }
        }
 
@@ -2040,6 +2029,10 @@ static int alc_build_controls(struct hda_codec *codec)
 
        alc_free_kctls(codec); /* no longer needed */
 
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -2067,6 +2060,8 @@ static int alc_init(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
 
+       snd_hda_jack_report_sync(codec);
+
        hda_call_check_power_status(codec, 0x01);
        return 0;
 }
@@ -2450,7 +2445,6 @@ static void alc_free(struct hda_codec *codec)
                return;
 
        alc_shutup(codec);
-       snd_hda_input_jack_free(codec);
        alc_free_kctls(codec);
        alc_free_bind_ctls(codec);
        kfree(spec);
@@ -2685,6 +2679,9 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
        int max_nums = ARRAY_SIZE(spec->private_adc_nids);
        int i, nums = 0;
 
+       if (spec->shared_mic_hp)
+               max_nums = 1; /* no multi streams with the shared HP/mic */
+
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                hda_nid_t src;
@@ -2747,6 +2744,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec)
                        continue;
 
                label = hda_get_autocfg_input_label(codec, cfg, i);
+               if (spec->shared_mic_hp && !strcmp(label, "Misc"))
+                       label = "Headphone Mic";
                if (prev_label && !strcmp(label, prev_label))
                        type_idx++;
                else
@@ -2781,6 +2780,39 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec)
        return 0;
 }
 
+/* create a shared input with the headphone out */
+static int alc_auto_create_shared_input(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int defcfg;
+       hda_nid_t nid;
+
+       /* only one internal input pin? */
+       if (cfg->num_inputs != 1)
+               return 0;
+       defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
+       if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+               return 0;
+
+       if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
+       else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
+               nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
+       else
+               return 0; /* both not available */
+
+       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
+               return 0; /* no input */
+
+       cfg->inputs[1].pin = nid;
+       cfg->inputs[1].type = AUTO_PIN_MIC;
+       cfg->num_inputs = 2;
+       spec->shared_mic_hp = 1;
+       snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid);
+       return 0;
+}
+
 static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
                               unsigned int pin_type)
 {
@@ -2919,6 +2951,23 @@ static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
        return 0;
 }
 
+/* check whether the DAC is reachable from the pin */
+static bool alc_auto_is_dac_reachable(struct hda_codec *codec,
+                                     hda_nid_t pin, hda_nid_t dac)
+{
+       hda_nid_t srcs[5];
+       int i, num;
+
+       pin = alc_go_down_to_selector(codec, pin);
+       num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
+       for (i = 0; i < num; i++) {
+               hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
+               if (nid == dac)
+                       return true;
+       }
+       return false;
+}
+
 static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
 {
        hda_nid_t sel = alc_go_down_to_selector(codec, pin);
@@ -2949,13 +2998,17 @@ static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
 }
 
 static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-                                  unsigned int location);
+                                  unsigned int location, int offset);
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+                                         hda_nid_t pin, hda_nid_t dac);
 
 /* fill in the dac_nids table from the parsed pin configuration */
 static int alc_auto_fill_dac_nids(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int location, defcfg;
+       int num_pins;
        bool redone = false;
        int i;
 
@@ -3010,13 +3063,10 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
 
        if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
                /* try to fill multi-io first */
-               unsigned int location, defcfg;
-               int num_pins;
-
                defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
                location = get_defcfg_location(defcfg);
 
-               num_pins = alc_auto_fill_multi_ios(codec, location);
+               num_pins = alc_auto_fill_multi_ios(codec, location, 0);
                if (num_pins > 0) {
                        spec->multi_ios = num_pins;
                        spec->ext_channel_count = 2;
@@ -3050,6 +3100,25 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
+       if (!spec->multi_ios &&
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+           cfg->hp_outs) {
+               /* try multi-ios with HP + inputs */
+               defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
+               location = get_defcfg_location(defcfg);
+
+               num_pins = alc_auto_fill_multi_ios(codec, location, 1);
+               if (num_pins > 0) {
+                       spec->multi_ios = num_pins;
+                       spec->ext_channel_count = 2;
+                       spec->multiout.num_dacs = num_pins + 1;
+               }
+       }
+
+       if (cfg->line_out_pins[0])
+               spec->vmaster_nid =
+                       alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
+                                                spec->multiout.dac_nids[0]);
        return 0;
 }
 
@@ -3081,8 +3150,15 @@ static int alc_auto_add_vol_ctl(struct hda_codec *codec,
                                 val);
 }
 
-#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
-       alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
+static int alc_auto_add_stereo_vol(struct hda_codec *codec,
+                                  const char *pfx, int cidx,
+                                  hda_nid_t nid)
+{
+       int chs = 1;
+       if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
+               chs = 3;
+       return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs);
+}
 
 /* create a mute-switch for the given mixer widget;
  * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
@@ -3114,8 +3190,14 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
        return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
 }
 
-#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid)  \
-       alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
+static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx,
+                                 int cidx, hda_nid_t nid)
+{
+       int chs = 1;
+       if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
+               chs = 3;
+       return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs);
+}
 
 static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
                                           hda_nid_t pin, hda_nid_t dac)
@@ -3441,17 +3523,19 @@ static void alc_auto_init_extra_out(struct hda_codec *codec)
  * multi-io helper
  */
 static int alc_auto_fill_multi_ios(struct hda_codec *codec,
-                                  unsigned int location)
+                                  unsigned int location,
+                                  int offset)
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t prime_dac = spec->private_dac_nids[0];
-       int type, i, num_pins = 0;
+       int type, i, dacs, num_pins = 0;
 
+       dacs = spec->multiout.num_dacs;
        for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
                for (i = 0; i < cfg->num_inputs; i++) {
                        hda_nid_t nid = cfg->inputs[i].pin;
-                       hda_nid_t dac;
+                       hda_nid_t dac = 0;
                        unsigned int defcfg, caps;
                        if (cfg->inputs[i].type != type)
                                continue;
@@ -3463,7 +3547,13 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
                        caps = snd_hda_query_pin_caps(codec, nid);
                        if (!(caps & AC_PINCAP_OUT))
                                continue;
-                       dac = alc_auto_look_for_dac(codec, nid);
+                       if (offset && offset + num_pins < dacs) {
+                               dac = spec->private_dac_nids[offset + num_pins];
+                               if (!alc_auto_is_dac_reachable(codec, nid, dac))
+                                       dac = 0;
+                       }
+                       if (!dac)
+                               dac = alc_auto_look_for_dac(codec, nid);
                        if (!dac)
                                continue;
                        spec->multi_io[num_pins].pin = nid;
@@ -3472,11 +3562,11 @@ static int alc_auto_fill_multi_ios(struct hda_codec *codec,
                        spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
                }
        }
-       spec->multiout.num_dacs = 1;
+       spec->multiout.num_dacs = dacs;
        if (num_pins < 2) {
                /* clear up again */
-               memset(spec->private_dac_nids, 0,
-                      sizeof(spec->private_dac_nids));
+               memset(spec->private_dac_nids + dacs, 0,
+                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
                spec->private_dac_nids[0] = prime_dac;
                return 0;
        }
@@ -3700,6 +3790,8 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
                        char boost_label[32];
 
                        label = hda_get_autocfg_input_label(codec, cfg, i);
+                       if (spec->shared_mic_hp && !strcmp(label, "Misc"))
+                               label = "Headphone Mic";
                        if (prev_label && !strcmp(label, prev_label))
                                type_idx++;
                        else
@@ -3812,6 +3904,7 @@ static void set_capture_mixer(struct hda_codec *codec)
 static void alc_auto_init_std(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       spec->use_jack_tbl = 1;
        alc_auto_init_multi_out(codec);
        alc_auto_init_extra_out(codec);
        alc_auto_init_analog_input(codec);
@@ -3902,6 +3995,9 @@ static int alc_parse_auto_config(struct hda_codec *codec,
        if (err < 0)
                return err;
        err = alc_auto_create_speaker_out(codec);
+       if (err < 0)
+               return err;
+       err = alc_auto_create_shared_input(codec);
        if (err < 0)
                return err;
        err = alc_auto_create_input_ctls(codec);
@@ -3950,6 +4046,37 @@ static const struct hda_amp_list alc880_loopbacks[] = {
 };
 #endif
 
+/*
+ * ALC880 fix-ups
+ */
+enum {
+       ALC880_FIXUP_GPIO2,
+       ALC880_FIXUP_MEDION_RIM,
+};
+
+static const struct alc_fixup alc880_fixups[] = {
+       [ALC880_FIXUP_GPIO2] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio2_init_verbs,
+       },
+       [ALC880_FIXUP_MEDION_RIM] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+};
+
+static const struct snd_pci_quirk alc880_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+       {}
+};
+
+
 /*
  * board setups
  */
@@ -3995,6 +4122,11 @@ static int patch_alc880(struct hda_codec *codec)
                board_config = ALC_MODEL_AUTO;
        }
 
+       if (board_config == ALC_MODEL_AUTO) {
+               alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups);
+               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+       }
+
        if (board_config == ALC_MODEL_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc880_parse_auto_config(codec);
@@ -4010,8 +4142,10 @@ static int patch_alc880(struct hda_codec *codec)
 #endif
        }
 
-       if (board_config != ALC_MODEL_AUTO)
+       if (board_config != ALC_MODEL_AUTO) {
+               spec->vmaster_nid = 0x0c;
                setup_preset(codec, &alc880_presets[board_config]);
+       }
 
        if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
@@ -4029,7 +4163,7 @@ static int patch_alc880(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       spec->vmaster_nid = 0x0c;
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
@@ -4137,8 +4271,10 @@ static int patch_alc260(struct hda_codec *codec)
 #endif
        }
 
-       if (board_config != ALC_MODEL_AUTO)
+       if (board_config != ALC_MODEL_AUTO) {
                setup_preset(codec, &alc260_presets[board_config]);
+               spec->vmaster_nid = 0x08;
+       }
 
        if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
@@ -4158,8 +4294,6 @@ static int patch_alc260(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       spec->vmaster_nid = 0x08;
-
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
                spec->init_hook = alc_auto_init_std;
@@ -4196,15 +4330,78 @@ static int patch_alc260(struct hda_codec *codec)
  * Pin config fixes
  */
 enum {
-       PINFIX_ABIT_AW9D_MAX,
-       PINFIX_LENOVO_Y530,
-       PINFIX_PB_M5210,
-       PINFIX_ACER_ASPIRE_7736,
-       PINFIX_ASUS_W90V,
+       ALC882_FIXUP_ABIT_AW9D_MAX,
+       ALC882_FIXUP_LENOVO_Y530,
+       ALC882_FIXUP_PB_M5210,
+       ALC882_FIXUP_ACER_ASPIRE_7736,
+       ALC882_FIXUP_ASUS_W90V,
+       ALC889_FIXUP_VAIO_TT,
+       ALC888_FIXUP_EEE1601,
+       ALC882_FIXUP_EAPD,
+       ALC883_FIXUP_EAPD,
+       ALC883_FIXUP_ACER_EAPD,
+       ALC882_FIXUP_GPIO3,
+       ALC889_FIXUP_COEF,
+       ALC882_FIXUP_ASUS_W2JC,
+       ALC882_FIXUP_ACER_ASPIRE_4930G,
+       ALC882_FIXUP_ACER_ASPIRE_8930G,
+       ALC882_FIXUP_ASPIRE_8930G_VERBS,
+       ALC885_FIXUP_MACPRO_GPIO,
 };
 
+static void alc889_fixup_coef(struct hda_codec *codec,
+                             const struct alc_fixup *fix, int action)
+{
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       alc889_coef_init(codec);
+}
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
+{
+       unsigned int gpiostate, gpiomask, gpiodir;
+
+       gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
+                                      AC_VERB_GET_GPIO_DATA, 0);
+
+       if (!muted)
+               gpiostate |= (1 << pin);
+       else
+               gpiostate &= ~(1 << pin);
+
+       gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
+                                     AC_VERB_GET_GPIO_MASK, 0);
+       gpiomask |= (1 << pin);
+
+       gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
+                                    AC_VERB_GET_GPIO_DIRECTION, 0);
+       gpiodir |= (1 << pin);
+
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpiomask);
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, gpiodir);
+
+       msleep(1);
+
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DATA, gpiostate);
+}
+
+/* set up GPIO at initialization */
+static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
+                                    const struct alc_fixup *fix, int action)
+{
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       alc882_gpio_mute(codec, 0, 0);
+       alc882_gpio_mute(codec, 1, 0);
+}
+
 static const struct alc_fixup alc882_fixups[] = {
-       [PINFIX_ABIT_AW9D_MAX] = {
+       [ALC882_FIXUP_ABIT_AW9D_MAX] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x15, 0x01080104 }, /* side */
@@ -4213,7 +4410,7 @@ static const struct alc_fixup alc882_fixups[] = {
                        { }
                }
        },
-       [PINFIX_LENOVO_Y530] = {
+       [ALC882_FIXUP_LENOVO_Y530] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x15, 0x99130112 }, /* rear int speakers */
@@ -4221,32 +4418,180 @@ static const struct alc_fixup alc882_fixups[] = {
                        { }
                }
        },
-       [PINFIX_PB_M5210] = {
+       [ALC882_FIXUP_PB_M5210] = {
                .type = ALC_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
                        { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
                        {}
                }
        },
-       [PINFIX_ACER_ASPIRE_7736] = {
+       [ALC882_FIXUP_ACER_ASPIRE_7736] = {
                .type = ALC_FIXUP_SKU,
                .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
-       [PINFIX_ASUS_W90V] = {
+       [ALC882_FIXUP_ASUS_W90V] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x16, 0x99130110 }, /* fix sequence for CLFE */
                        { }
                }
        },
+       [ALC889_FIXUP_VAIO_TT] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x17, 0x90170111 }, /* hidden surround speaker */
+                       { }
+               }
+       },
+       [ALC888_FIXUP_EEE1601] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
+                       { }
+               }
+       },
+       [ALC882_FIXUP_EAPD] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+                       { }
+               }
+       },
+       [ALC883_FIXUP_EAPD] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+                       { }
+               }
+       },
+       [ALC883_FIXUP_ACER_EAPD] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* eanable EAPD on Acer laptops */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       { }
+               }
+       },
+       [ALC882_FIXUP_GPIO3] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio3_init_verbs,
+       },
+       [ALC882_FIXUP_ASUS_W2JC] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = alc_gpio1_init_verbs,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_EAPD,
+       },
+       [ALC889_FIXUP_COEF] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc889_fixup_coef,
+       },
+       [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x16, 0x99130111 }, /* CLFE speaker */
+                       { 0x17, 0x99130112 }, /* surround speaker */
+                       { }
+               }
+       },
+       [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x16, 0x99130111 }, /* CLFE speaker */
+                       { 0x1b, 0x99130112 }, /* surround speaker */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
+       },
+       [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
+               /* additional init verbs for Acer Aspire 8930G */
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enable all DACs */
+                       /* DAC DISABLE/MUTE 1? */
+                       /*  setting bits 1-5 disables DAC nids 0x02-0x06
+                        *  apparently. Init=0x38 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+                       /* DAC DISABLE/MUTE 2? */
+                       /*  some bit here disables the other DACs.
+                        *  Init=0x4900 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+                       /* DMIC fix
+                        * This laptop has a stereo digital microphone.
+                        * The mics are only 1cm apart which makes the stereo
+                        * useless. However, either the mic or the ALC889
+                        * makes the signal become a difference/sum signal
+                        * instead of standard stereo, which is annoying.
+                        * So instead we flip this bit which makes the
+                        * codec replicate the sum signal to both channels,
+                        * turning it into a normal mono mic.
+                        */
+                       /* DMIC_CONTROL? Init value = 0x0001 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       { }
+               }
+       },
+       [ALC885_FIXUP_MACPRO_GPIO] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc885_fixup_macpro_gpio,
+       },
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
-       SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", PINFIX_ASUS_W90V),
-       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
-       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
-       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
+       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+                     ALC882_FIXUP_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+                     ALC882_FIXUP_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
+       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
+       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
+       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
+       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+
+       /* All Apple entries are in codec SSIDs */
+       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+
+       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
+       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
        {}
 };
 
@@ -4295,8 +4640,7 @@ static int patch_alc882(struct hda_codec *codec)
                goto error;
 
        board_config = alc_board_config(codec, ALC882_MODEL_LAST,
-                                       alc882_models, alc882_cfg_tbl);
-
+                                       alc882_models, NULL);
        if (board_config < 0)
                board_config = alc_board_codec_sid_config(codec,
                        ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
@@ -4319,18 +4663,12 @@ static int patch_alc882(struct hda_codec *codec)
                err = alc882_parse_auto_config(codec);
                if (err < 0)
                        goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-               else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC882_3ST_DIG;
-               }
-#endif
        }
 
-       if (board_config != ALC_MODEL_AUTO)
+       if (board_config != ALC_MODEL_AUTO) {
                setup_preset(codec, &alc882_presets[board_config]);
+               spec->vmaster_nid = 0x0c;
+       }
 
        if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
@@ -4350,13 +4688,10 @@ static int patch_alc882(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       spec->vmaster_nid = 0x0c;
-
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
                spec->init_hook = alc_auto_init_std;
 
-       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc882_loopbacks;
@@ -4384,12 +4719,17 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
  * Pin config fixes
  */
 enum {
-       PINFIX_FSC_H270,
-       PINFIX_HP_Z200,
+       ALC262_FIXUP_FSC_H270,
+       ALC262_FIXUP_HP_Z200,
+       ALC262_FIXUP_TYAN,
+       ALC262_FIXUP_TOSHIBA_RX1,
+       ALC262_FIXUP_LENOVO_3000,
+       ALC262_FIXUP_BENQ,
+       ALC262_FIXUP_BENQ_T31,
 };
 
 static const struct alc_fixup alc262_fixups[] = {
-       [PINFIX_FSC_H270] = {
+       [ALC262_FIXUP_FSC_H270] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x14, 0x99130110 }, /* speaker */
@@ -4398,18 +4738,68 @@ static const struct alc_fixup alc262_fixups[] = {
                        { }
                }
        },
-       [PINFIX_HP_Z200] = {
+       [ALC262_FIXUP_HP_Z200] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x16, 0x99130120 }, /* internal speaker */
                        { }
                }
        },
+       [ALC262_FIXUP_TYAN] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x1993e1f0 }, /* int AUX */
+                       { }
+               }
+       },
+       [ALC262_FIXUP_TOSHIBA_RX1] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x90170110 }, /* speaker */
+                       { 0x15, 0x0421101f }, /* HP */
+                       { 0x1a, 0x40f000f0 }, /* N/A */
+                       { 0x1b, 0x40f000f0 }, /* N/A */
+                       { 0x1e, 0x40f000f0 }, /* N/A */
+               }
+       },
+       [ALC262_FIXUP_LENOVO_3000] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC262_FIXUP_BENQ,
+       },
+       [ALC262_FIXUP_BENQ] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+                       {}
+               }
+       },
+       [ALC262_FIXUP_BENQ_T31] = {
+               .type = ALC_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       {}
+               }
+       },
 };
 
 static const struct snd_pci_quirk alc262_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
-       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
+       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ),
+       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
+       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
+       SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
+                     ALC262_FIXUP_TOSHIBA_RX1),
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
+       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
+       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
+       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
        {}
 };
 
@@ -4420,14 +4810,9 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 
 /*
  */
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-#include "alc262_quirks.c"
-#endif
-
 static int patch_alc262(struct hda_codec *codec)
 {
        struct alc_spec *spec;
-       int board_config;
        int err;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
@@ -4454,37 +4839,13 @@ static int patch_alc262(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x0a, 10);
 
-       board_config = alc_board_config(codec, ALC262_MODEL_LAST,
-                                       alc262_models, alc262_cfg_tbl);
-
-       if (board_config < 0) {
-               printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-                      codec->chip_name);
-               board_config = ALC_MODEL_AUTO;
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
-               alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-       }
-
-       if (board_config == ALC_MODEL_AUTO) {
-               /* automatic parse from the BIOS config */
-               err = alc262_parse_auto_config(codec);
-               if (err < 0)
-                       goto error;
-#ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
-               else if (!err) {
-                       printk(KERN_INFO
-                              "hda_codec: Cannot set up configuration "
-                              "from BIOS.  Using base mode...\n");
-                       board_config = ALC262_BASIC;
-               }
-#endif
-       }
+       alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
 
-       if (board_config != ALC_MODEL_AUTO)
-               setup_preset(codec, &alc262_presets[board_config]);
+       /* automatic parse from the BIOS config */
+       err = alc262_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
 
        if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
@@ -4504,14 +4865,10 @@ static int patch_alc262(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       spec->vmaster_nid = 0x0c;
-
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc_auto_init_std;
+       spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
-       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc262_loopbacks;
@@ -4618,14 +4975,10 @@ static int patch_alc268(struct hda_codec *codec)
        if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
-       spec->vmaster_nid = 0x02;
-
        codec->patch_ops = alc_patch_ops;
        spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
-       alc_init_jacks(codec);
-
        return 0;
 
  error:
@@ -4967,7 +5320,7 @@ static const struct alc_fixup alc269_fixups[] = {
                        { }
                },
        },
-       [ALC269_FIXUP_DMIC] = {
+       [ALC269VB_FIXUP_DMIC] = {
                .type = ALC_FIXUP_PINS,
                .v.pins = (const struct alc_pincfg[]) {
                        { 0x12, 0x99a3092f }, /* int-mic */
@@ -5174,8 +5527,6 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
-       spec->vmaster_nid = 0x02;
-
        codec->patch_ops = alc_patch_ops;
 #ifdef CONFIG_PM
        codec->patch_ops.resume = alc269_resume;
@@ -5183,7 +5534,6 @@ static int patch_alc269(struct hda_codec *codec)
        spec->init_hook = alc_auto_init_std;
        spec->shutup = alc269_shutup;
 
-       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc269_loopbacks;
@@ -5280,8 +5630,6 @@ static int patch_alc861(struct hda_codec *codec)
                set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
        }
 
-       spec->vmaster_nid = 0x03;
-
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        codec->patch_ops = alc_patch_ops;
@@ -5406,8 +5754,6 @@ static int patch_alc861vd(struct hda_codec *codec)
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
        }
 
-       spec->vmaster_nid = 0x02;
-
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        codec->patch_ops = alc_patch_ops;
@@ -5790,7 +6136,6 @@ static int patch_alc662(struct hda_codec *codec)
                        break;
                }
        }
-       spec->vmaster_nid = 0x02;
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -5798,8 +6143,6 @@ static int patch_alc662(struct hda_codec *codec)
        spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
-       alc_init_jacks(codec);
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc662_loopbacks;
@@ -5846,8 +6189,6 @@ static int patch_alc680(struct hda_codec *codec)
        if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
-       spec->vmaster_nid = 0x02;
-
        codec->patch_ops = alc_patch_ops;
        spec->init_hook = alc_auto_init_std;
 
index 616678fde486d7877ca35bd0a0f72b49647eb833..87e684fa830f83df49bfec3aa5e894d8c97bfa07 100644 (file)
@@ -37,6 +37,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 enum {
        STAC_VREF_EVENT = 1,
@@ -96,7 +97,6 @@ enum {
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
        STAC_DELL_VOSTRO_3500,
-       STAC_92HD83XXX_HP,
        STAC_92HD83XXX_HP_cNB11_INTQUAD,
        STAC_HP_DV7_4000,
        STAC_92HD83XXX_MODELS
@@ -176,13 +176,6 @@ enum {
        STAC_9872_MODELS
 };
 
-struct sigmatel_event {
-       hda_nid_t nid;
-       unsigned char type;
-       unsigned char tag;
-       int data;
-};
-
 struct sigmatel_mic_route {
        hda_nid_t pin;
        signed char mux_idx;
@@ -231,9 +224,6 @@ struct sigmatel_spec {
        const hda_nid_t *pwr_nids;
        const hda_nid_t *dac_list;
 
-       /* events */
-       struct snd_array events;
-
        /* playback */
        struct hda_input_mux *mono_mux;
        unsigned int cur_mmux;
@@ -1094,13 +1084,10 @@ static const char * const slave_sws[] = {
 };
 
 static void stac92xx_free_kctls(struct hda_codec *codec);
-static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
 
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t nid;
        int err;
        int i;
 
@@ -1186,31 +1173,9 @@ static int stac92xx_build_controls(struct hda_codec *codec)
 
        stac92xx_free_kctls(codec); /* no longer needed */
 
-       /* create jack input elements */
-       if (spec->hp_detect) {
-               for (i = 0; i < cfg->hp_outs; i++) {
-                       int type = SND_JACK_HEADPHONE;
-                       nid = cfg->hp_pins[i];
-                       /* jack detection */
-                       if (cfg->hp_outs == i)
-                               type |= SND_JACK_LINEOUT;
-                       err = stac92xx_add_jack(codec, nid, type);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       for (i = 0; i < cfg->line_outs; i++) {
-               err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
-                                       SND_JACK_LINEOUT);
-               if (err < 0)
-                       return err;
-       }
-       for (i = 0; i < cfg->num_inputs; i++) {
-               nid = cfg->inputs[i].pin;
-               err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
-               if (err < 0)
-                       return err;
-       }
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
 
        return 0;       
 }
@@ -1692,7 +1657,6 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
        [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
-       [STAC_92HD83XXX_HP] = "hp",
        [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
        [STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
@@ -1707,8 +1671,6 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                      "unknown Dell", STAC_DELL_S14),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
                      "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
-                         "HP", STAC_92HD83XXX_HP),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
@@ -2875,7 +2837,8 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        }
 
        if (control) {
-               strcpy(name, hda_get_input_pin_label(codec, nid, 1));
+               snd_hda_get_pin_label(codec, nid, &spec->autocfg,
+                                     name, sizeof(name), NULL);
                return stac92xx_add_control(codec->spec, control,
                                        strcat(name, " Jack Mode"), nid);
        }
@@ -3553,7 +3516,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
                int index, type_idx;
-               const char *label;
+               char label[32];
 
                nid = spec->dmic_nids[i];
                if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
@@ -3566,7 +3529,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (index < 0)
                        continue;
 
-               label = hda_get_input_pin_label(codec, nid, 1);
+               snd_hda_get_pin_label(codec, nid, &spec->autocfg,
+                                     label, sizeof(label), NULL);
                snd_hda_add_imux_item(dimux, label, index, &type_idx);
                if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
                        snd_hda_add_imux_item(imux, label, index, &type_idx);
@@ -4164,65 +4128,18 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
                           AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
-static int stac92xx_add_jack(struct hda_codec *codec,
-               hda_nid_t nid, int type)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       int connectivity = get_defcfg_connect(def_conf);
-
-       if (connectivity && connectivity != AC_JACK_PORT_FIXED)
-               return 0;
-
-       return snd_hda_input_jack_add(codec, nid, type, NULL);
-#else
-       return 0;
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-}
-
-static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
                          unsigned char type, int data)
 {
-       struct sigmatel_event *event;
+       struct hda_jack_tbl *event;
 
-       snd_array_init(&spec->events, sizeof(*event), 32);
-       event = snd_array_new(&spec->events);
+       event = snd_hda_jack_tbl_new(codec, nid);
        if (!event)
                return -ENOMEM;
-       event->nid = nid;
-       event->type = type;
-       event->tag = spec->events.used;
-       event->data = data;
-
-       return event->tag;
-}
-
-static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
-                                            hda_nid_t nid)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event = spec->events.list;
-       int i;
-
-       for (i = 0; i < spec->events.used; i++, event++) {
-               if (event->nid == nid)
-                       return event;
-       }
-       return NULL;
-}
-
-static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
-                                                     unsigned char tag)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event = spec->events.list;
-       int i;
+       event->action = type;
+       event->private_data = data;
 
-       for (i = 0; i < spec->events.used; i++, event++) {
-               if (event->tag == tag)
-                       return event;
-       }
-       return NULL;
+       return 0;
 }
 
 /* check if given nid is a valid pin and no other events are assigned
@@ -4232,24 +4149,17 @@ static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
 static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
                             unsigned int type)
 {
-       struct sigmatel_event *event;
-       int tag;
+       struct hda_jack_tbl *event;
 
        if (!is_jack_detectable(codec, nid))
                return 0;
-       event = stac_get_event(codec, nid);
-       if (event) {
-               if (event->type != type)
-                       return 0;
-               tag = event->tag;
-       } else {
-               tag = stac_add_event(codec->spec, nid, type, 0);
-               if (tag < 0)
-                       return 0;
-       }
-       snd_hda_codec_write_cache(codec, nid, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | tag);
+       event = snd_hda_jack_tbl_new(codec, nid);
+       if (!event)
+               return -ENOMEM;
+       if (event->action && event->action != type)
+               return 0;
+       event->action = type;
+       snd_hda_jack_detect_enable(codec, nid, 0);
        return 1;
 }
 
@@ -4326,6 +4236,27 @@ static void stac_store_hints(struct hda_codec *codec)
        }
 }
 
+static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
+                                   const hda_nid_t *pins)
+{
+       while (num_pins--)
+               stac_issue_unsol_event(codec, *pins++);
+}
+
+/* fake event to set up pins */
+static void stac_fake_hp_events(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (spec->autocfg.hp_outs)
+               stac_issue_unsol_events(codec, spec->autocfg.hp_outs,
+                                       spec->autocfg.hp_pins);
+       if (spec->autocfg.line_outs &&
+           spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0])
+               stac_issue_unsol_events(codec, spec->autocfg.line_outs,
+                                       spec->autocfg.line_out_pins);
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4376,10 +4307,7 @@ static int stac92xx_init(struct hda_codec *codec)
                stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
                                AC_PINCTL_OUT_EN);
                /* fake event to set up pins */
-               if (cfg->hp_pins[0])
-                       stac_issue_unsol_event(codec, cfg->hp_pins[0]);
-               else if (cfg->line_out_pins[0])
-                       stac_issue_unsol_event(codec, cfg->line_out_pins[0]);
+               stac_fake_hp_events(codec);
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
@@ -4477,6 +4405,8 @@ static int stac92xx_init(struct hda_codec *codec)
                stac_toggle_power_map(codec, nid, 0);
        }
 
+       snd_hda_jack_report_sync(codec);
+
        /* sync mute LED */
        if (spec->gpio_led)
                hda_call_check_power_status(codec, 0x01);
@@ -4533,8 +4463,6 @@ static void stac92xx_free(struct hda_codec *codec)
                return;
 
        stac92xx_shutup(codec);
-       snd_hda_input_jack_free(codec);
-       snd_array_free(&spec->events);
 
        kfree(spec);
        snd_hda_detach_beep_device(codec);
@@ -4798,26 +4726,13 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
                                          mic->mux_idx);
 }
 
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct sigmatel_event *event = stac_get_event(codec, nid);
-       if (!event)
-               return;
-       codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
-}
-
-static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+static void handle_unsol_event(struct hda_codec *codec,
+                              struct hda_jack_tbl *event)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event;
-       int tag, data;
-
-       tag = (res >> 26) & 0x7f;
-       event = stac_get_event_from_tag(codec, tag);
-       if (!event)
-               return;
+       int data;
 
-       switch (event->type) {
+       switch (event->action) {
        case STAC_HP_EVENT:
        case STAC_LO_EVENT:
                stac92xx_hp_detect(codec);
@@ -4827,7 +4742,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
                break;
        }
 
-       switch (event->type) {
+       switch (event->action) {
        case STAC_HP_EVENT:
        case STAC_LO_EVENT:
        case STAC_MIC_EVENT:
@@ -4835,7 +4750,6 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
                        stac92xx_pin_sense(codec, event->nid);
-               snd_hda_input_jack_report(codec, event->nid);
 
                switch (codec->subsystem_id) {
                case 0x103c308f:
@@ -4860,11 +4774,33 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
                                          AC_VERB_GET_GPIO_DATA, 0);
                /* toggle VREF state based on GPIOx status */
                snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
-                                   !!(data & (1 << event->data)));
+                                   !!(data & (1 << event->private_data)));
                break;
        }
 }
 
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid);
+       if (!event)
+               return;
+       handle_unsol_event(codec, event);
+}
+
+static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct hda_jack_tbl *event;
+       int tag;
+
+       tag = (res >> 26) & 0x7f;
+       event = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (!event)
+               return;
+       event->jack_dirty = 1;
+       handle_unsol_event(codec, event);
+       snd_hda_jack_report_sync(codec);
+}
+
 static int hp_blike_system(u32 subsystem_id);
 
 static void set_hp_led_gpio(struct hda_codec *codec)
@@ -4903,7 +4839,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, int default_polarity)
+static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
 {
        struct sigmatel_spec *spec = codec->spec;
        const struct dmi_device *dev = NULL;
@@ -4939,9 +4875,11 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
 
                /*
                 * Fallback case - if we don't find the DMI strings,
-                * we statically set the GPIO - if not a B-series system.
+                * we statically set the GPIO - if not a B-series system
+                * and default polarity is provided
                 */
-               if (!hp_blike_system(codec->subsystem_id)) {
+               if (!hp_blike_system(codec->subsystem_id) &&
+                       (default_polarity == 0 || default_polarity == 1)) {
                        set_hp_led_gpio(codec);
                        spec->gpio_led_polarity = default_polarity;
                        return 1;
@@ -5028,19 +4966,11 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 #ifdef CONFIG_PM
 static int stac92xx_resume(struct hda_codec *codec)
 {
-       struct sigmatel_spec *spec = codec->spec;
-
        stac92xx_init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        /* fake event to set up pins again to override cached values */
-       if (spec->hp_detect) {
-               if (spec->autocfg.hp_pins[0])
-                       stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
-               else if (spec->autocfg.line_out_pins[0])
-                       stac_issue_unsol_event(codec,
-                                              spec->autocfg.line_out_pins[0]);
-       }
+       stac_fake_hp_events(codec);
        return 0;
 }
 
@@ -5651,7 +5581,7 @@ again:
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       if (find_mute_led_gpio(codec, 0))
+       if (find_mute_led_cfg(codec, -1/*no default cfg*/))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
@@ -5839,15 +5769,13 @@ again:
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
-                       err = stac_add_event(spec, codec->afg,
+                       err = stac_add_event(codec, codec->afg,
                                             STAC_VREF_EVENT, 0x02);
                        if (err < 0)
                                return err;
                        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-                       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | err);
+                       snd_hda_jack_detect_enable(codec, codec->afg, 0);
                        spec->gpio_mask |= 0x02;
                        break;
                }
@@ -5964,7 +5892,7 @@ again:
                }
        }
 
-       if (find_mute_led_gpio(codec, 1))
+       if (find_mute_led_cfg(codec, 1))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
@@ -6318,14 +6246,12 @@ static int patch_stac9205(struct hda_codec *codec)
                snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
-               err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
+               err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01);
                if (err < 0)
                        return err;
                snd_hda_codec_write_cache(codec, codec->afg, 0,
                        AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-               snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                         AC_VERB_SET_UNSOLICITED_ENABLE,
-                                         AC_USRSP_EN | err);
+               snd_hda_jack_detect_enable(codec, codec->afg, 0);
 
                spec->gpio_dir = 0x0b;
                spec->eapd_mask = 0x01;
index b5137629f8e942a75a941e0e183cef98fb58db02..03e63fed9caf7d9e8342373901a5086f884122d9 100644 (file)
@@ -54,6 +54,7 @@
 #include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include "hda_jack.h"
 
 /* Pin Widget NID */
 #define VT1708_HP_PIN_NID      0x20
@@ -1503,6 +1504,11 @@ static int via_build_controls(struct hda_codec *codec)
        analog_low_current_mode(codec);
 
        via_free_kctls(codec); /* no longer needed */
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -1714,6 +1720,7 @@ static void via_unsol_event(struct hda_codec *codec,
                                  unsigned int res)
 {
        res >>= 26;
+       res = snd_hda_jack_get_action(codec, res);
 
        if (res & VIA_JACK_EVENT)
                set_widgets_power_state(codec);
@@ -1724,6 +1731,7 @@ static void via_unsol_event(struct hda_codec *codec,
                via_hp_automute(codec);
        else if (res == VIA_GPIO_EVENT)
                via_gpio_control(codec);
+       snd_hda_jack_report_sync(codec);
 }
 
 #ifdef CONFIG_PM
@@ -2200,7 +2208,10 @@ static int via_auto_create_loopback_switch(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
 
-       if (!spec->aa_mix_nid || !spec->out_mix_path.depth)
+       if (!spec->aa_mix_nid)
+               return 0; /* no loopback switching available */
+       if (!(spec->out_mix_path.depth || spec->hp_mix_path.depth ||
+             spec->speaker_path.depth))
                return 0; /* no loopback switching available */
        if (!via_clone_control(spec, &via_aamix_ctl_enum))
                return -ENOMEM;
@@ -2736,9 +2747,8 @@ static void via_auto_init_unsol_event(struct hda_codec *codec)
        int i;
 
        if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0]))
-               snd_hda_codec_write(codec, cfg->hp_pins[0], 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT);
+               snd_hda_jack_detect_enable(codec, cfg->hp_pins[0],
+                                          VIA_HP_EVENT | VIA_JACK_EVENT);
 
        if (cfg->speaker_pins[0])
                ev = VIA_LINE_EVENT;
@@ -2747,16 +2757,14 @@ static void via_auto_init_unsol_event(struct hda_codec *codec)
        for (i = 0; i < cfg->line_outs; i++) {
                if (cfg->line_out_pins[i] &&
                    is_jack_detectable(codec, cfg->line_out_pins[i]))
-                       snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | ev | VIA_JACK_EVENT);
+                       snd_hda_jack_detect_enable(codec, cfg->line_out_pins[i],
+                                                  ev | VIA_JACK_EVENT);
        }
 
        for (i = 0; i < cfg->num_inputs; i++) {
                if (is_jack_detectable(codec, cfg->inputs[i].pin))
-                       snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | VIA_JACK_EVENT);
+                       snd_hda_jack_detect_enable(codec, cfg->inputs[i].pin,
+                                                  VIA_JACK_EVENT);
        }
 }
 
@@ -2779,6 +2787,7 @@ static int via_init(struct hda_codec *codec)
 
        via_hp_automute(codec);
        vt1708_update_hp_work(spec);
+       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -2789,6 +2798,7 @@ static void vt1708_update_hp_jack_state(struct work_struct *work)
                                             vt1708_hp_work.work);
        if (spec->codec_type != VT1708)
                return;
+       snd_hda_jack_set_dirty_all(spec->codec);
        /* if jack state toggled */
        if (spec->vt1708_hp_present
            != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) {
index e328cfb7620c77bd80d1c3788c373f6ababfc520..e525da2673be3c5a4b12de44eb7c81e6ccadfcdd 100644 (file)
@@ -68,8 +68,11 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
 
 static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice)
 {
-       /* we use pins 39 and 41 of the VT1616 for left and right read outputs */
-       snd_ac97_write_cache(ice->ac97, 0x5a, snd_ac97_read(ice->ac97, 0x5a) & ~0x8000);
+       if (ice->ac97)
+               /* we use pins 39 and 41 of the VT1616 for left and right
+               read outputs */
+               snd_ac97_write_cache(ice->ac97, 0x5a,
+                       snd_ac97_read(ice->ac97, 0x5a) & ~0x8000);
        return 0;
 }
 
index a0c5e009bb4a23eaf4c4ddc97148ed34aea25f36..4ca33a800bc804c4fff992243eef70234c4f0990 100644 (file)
@@ -66,6 +66,7 @@ enum {
 #define     VT1724_CFG_CLOCK384  0x40  /* 16.9344Mhz, 44.1kHz*384 */
 #define   VT1724_CFG_MPU401    0x20            /* MPU401 UARTs */
 #define   VT1724_CFG_ADC_MASK  0x0c    /* one, two or one and S/PDIF, stereo ADCs */
+#define   VT1724_CFG_ADC_NONE  0x0c    /* no ADCs */
 #define   VT1724_CFG_DAC_MASK  0x03    /* one, two, three, four stereo DACs */
 
 #define VT1724_REG_AC97_CFG            0x05    /* byte */
index 44446f2222d942f08ac1ae82468891b391a335a1..132a86e09d07d69adb6f7e5c7516207205f44c13 100644 (file)
@@ -84,9 +84,9 @@ MODULE_SUPPORTED_DEVICE("{"
 
 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_PNP;/* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
 static char *model[SNDRV_CARDS];
-static int omni[SNDRV_CARDS];                          /* Delta44 & 66 Omni I/O support */
+static bool omni[SNDRV_CARDS];                         /* Delta44 & 66 Omni I/O support */
 static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transceiver reset timeout value in msec */
 static int dxr_enable[SNDRV_CARDS];                    /* DXR enable for DMX6FIRE */
 
index 4353e76bf0a687a975ee721bf84e589f6807e2d6..92362973764dbbfebeab03085a669f36d2f21bf9 100644 (file)
@@ -80,7 +80,7 @@ MODULE_SUPPORTED_DEVICE("{"
 
 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_PNP;             /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;            /* Enable this card */
 static char *model[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
@@ -1117,14 +1117,21 @@ static struct snd_pcm_ops snd_vt1724_capture_pro_ops = {
 static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
-       int err;
+       int capt, err;
 
-       err = snd_pcm_new(ice->card, "ICE1724", device, 1, 1, &pcm);
+       if ((ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_ADC_MASK) ==
+           VT1724_CFG_ADC_NONE)
+               capt = 0;
+       else
+               capt = 1;
+       err = snd_pcm_new(ice->card, "ICE1724", device, 1, capt, &pcm);
        if (err < 0)
                return err;
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_pro_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vt1724_capture_pro_ops);
+       if (capt)
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_vt1724_capture_pro_ops);
 
        pcm->private_data = ice;
        pcm->info_flags = 0;
@@ -1825,7 +1832,12 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
 
-       uinfo->value.enumerated.items = hw_rates_count + ice->ext_clock_count;
+       /* internal clocks */
+       uinfo->value.enumerated.items = hw_rates_count;
+       /* external clocks */
+       if (ice->force_rdma1 ||
+           (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN))
+               uinfo->value.enumerated.items += ice->ext_clock_count;
        /* upper limit - keep at top */
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
                uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
@@ -2173,6 +2185,40 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
 
 static struct snd_ice1712_card_info no_matched __devinitdata;
 
+
+/*
+  ooAoo cards with no controls
+*/
+static unsigned char ooaoo_sq210_eeprom[] __devinitdata = {
+       [ICE_EEP2_SYSCONF]     = 0x4c,  /* 49MHz crystal, no mpu401, no ADC,
+                                          1xDACs */
+       [ICE_EEP2_ACLINK]      = 0x80,  /* I2S */
+       [ICE_EEP2_I2S]         = 0x78,  /* no volume, 96k, 24bit, 192k */
+       [ICE_EEP2_SPDIF]       = 0xc1,  /* out-en, out-int, out-ext */
+       [ICE_EEP2_GPIO_DIR]    = 0x00,  /* no GPIOs are used */
+       [ICE_EEP2_GPIO_DIR1]   = 0x00,
+       [ICE_EEP2_GPIO_DIR2]   = 0x00,
+       [ICE_EEP2_GPIO_MASK]   = 0xff,
+       [ICE_EEP2_GPIO_MASK1]  = 0xff,
+       [ICE_EEP2_GPIO_MASK2]  = 0xff,
+
+       [ICE_EEP2_GPIO_STATE]  = 0x00, /* inputs */
+       [ICE_EEP2_GPIO_STATE1] = 0x00, /* all 1, but GPIO_CPLD_RW
+                                         and GPIO15 always zero */
+       [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */
+};
+
+
+struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] __devinitdata = {
+       {
+               .name = "ooAoo SQ210a",
+               .model = "sq210a",
+               .eeprom_size = sizeof(ooaoo_sq210_eeprom),
+               .eeprom_data = ooaoo_sq210_eeprom,
+       },
+       { } /* terminator */
+};
+
 static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_revo_cards,
        snd_vt1724_amp_cards,
@@ -2187,6 +2233,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
        snd_vt1724_wtm_cards,
        snd_vt1724_se_cards,
        snd_vt1724_qtet_cards,
+       snd_vt1724_ooaoo_cards,
        NULL,
 };
 
@@ -2270,7 +2317,7 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
                }
        }
        for (tbl = card_tables; *tbl; tbl++) {
-               for (c = *tbl; c->subvendor; c++) {
+               for (c = *tbl; c->name; c++) {
                        if (modelname && c->model &&
                            !strcmp(modelname, c->model)) {
                                printk(KERN_INFO "ice1724: Using board model %s\n",
@@ -2579,8 +2626,10 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
        ice->ext_clock_count = 0;
 
        for (tbl = card_tables; *tbl; tbl++) {
-               for (c = *tbl; c->subvendor; c++) {
-                       if (c->subvendor == ice->eeprom.subvendor) {
+               for (c = *tbl; c->name; c++) {
+                       if ((model[dev] && c->model &&
+                            !strcmp(model[dev], c->model)) ||
+                           (c->subvendor == ice->eeprom.subvendor)) {
                                strcpy(card->shortname, c->name);
                                if (c->driver) /* specific driver? */
                                        strcpy(card->driver, c->driver);
index 11718b49b2e2459bb930384a4de50a34db6d54f8..40b181bab930bf44963fe639c795784fefce9cb2 100644 (file)
@@ -79,9 +79,9 @@ static int index = SNDRV_DEFAULT_IDX1;        /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int ac97_clock;
 static char *ac97_quirk;
-static int buggy_semaphore;
+static bool buggy_semaphore;
 static int buggy_irq = -1; /* auto-check */
-static int xbox;
+static bool xbox;
 static int spdif_aclink = -1;
 static int inside_vm = -1;
 
@@ -105,7 +105,7 @@ module_param(inside_vm, bool, 0444);
 MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization.");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 static int joystick;
 module_param(joystick, int, 0444);
index 0f7041ec7ddca607c591cd6d16ee94c9b7b81c87..d689913a61be11ba1a2462ab11b8c4e54aac0735 100644 (file)
@@ -68,7 +68,7 @@ module_param(ac97_clock, int, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 /*
index 841864b6b371ca11f8b9c7caf2d1ff1dfc541e1b..8fea45ab5882b241237bdc834205e687b651666b 100644 (file)
@@ -408,7 +408,7 @@ MODULE_FIRMWARE("korg/k1212.dsp");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Korg 1212 soundcard.");
index 924168ef1ed64162b9ec5bae014892467977aacd..375982736858fed1d27f3a848abce3498d581a25 100644 (file)
@@ -35,7 +35,7 @@
 /* Standard options */
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram Lola driver.");
index 04ae84b2a107b0fcc7f0b93284b4ef337c4b619b..d94c0c292bd08c2753f4dabc714bd31c5bbf9239 100644 (file)
@@ -42,7 +42,7 @@ MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface.");
index 863c8bdaecd618a546dbd7a4fe446b0032897bcb..78229b0dad2bcbfcfdcafd4f18c40b775a133498 100644 (file)
@@ -64,8 +64,8 @@ MODULE_FIRMWARE("ess/maestro3_assp_minisrc.fw");
 
 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_PNP; /* all enabled */
-static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* all enabled */
+static bool external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 static int amp_gpio[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 
 module_param_array(index, int, NULL, 0444);
index a0bd1d99793f943a647712a011d263517e2061a0..487837c01c9ff3ae206e30cbd804e02c5de1725e 100644 (file)
@@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard.");
index c6c45d979f7a3b66f1172c417e69a61f41d06956..ade2c64bd606f9ba84eab2c84ab0ebb841f7b146 100644 (file)
@@ -57,12 +57,12 @@ static int index = SNDRV_DEFAULT_IDX1;      /* Index */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static int playback_bufsize = 16;
 static int capture_bufsize = 16;
-static int force_ac97;                 /* disabled as default */
+static bool force_ac97;                        /* disabled as default */
 static int buffer_top;                 /* not specified */
-static int use_cache;                  /* disabled */
-static int vaio_hack;                  /* disabled */
-static int reset_workaround;
-static int reset_workaround_2;
+static bool use_cache;                 /* disabled */
+static bool vaio_hack;                 /* disabled */
+static bool reset_workaround;
+static bool reset_workaround_2;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
@@ -86,7 +86,7 @@ module_param(reset_workaround_2, bool, 0444);
 MODULE_PARM_DESC(reset_workaround_2, "Enable extended AC97 RESET workaround for some other laptops.");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index 5f3a13d4369d6cbad47dbf33b52f668061a810a1..eab663eef1170dd22f508c6f589a2f17f82f35de 100644 (file)
@@ -74,7 +74,7 @@ MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "card index");
index 4149a0cb8b73e107185b185a10361ae1df052a7d..3fdee4950174597db4abaf93e11192e95e2d2f65 100644 (file)
@@ -32,7 +32,7 @@ MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "card index");
index 252719101c4214030c3ba8d664e68a87a02e2d8b..c8febf4b9bd6e10c9763c989ee1d059486f019bc 100644 (file)
@@ -418,6 +418,7 @@ static const struct oxygen_model model_xonar_d1 = {
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
                         CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF |
                         AC97_FMIC_SWITCH,
        .dac_channels_pcm = 8,
        .dac_channels_mixer = 8,
index bc6eb58be380108dc56c15418f1102a617469434..793bdf03d7e07cdc700c93915356896936993806 100644 (file)
@@ -597,7 +597,8 @@ struct oxygen_model model_xonar_dg = {
        .model_data_size = sizeof(struct dg),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
+                        CAPTURE_0_FROM_I2S_2 |
+                        CAPTURE_1_FROM_SPDIF,
        .dac_channels_pcm = 6,
        .dac_channels_mixer = 0,
        .function_flags = OXYGEN_FUNCTION_SPI,
index 42d1ab136217dd1e001d7a1d9621d26cd741285c..478303e6c2b0801c16c2ae52ee4eff0996fac472 100644 (file)
@@ -1274,7 +1274,8 @@ static const struct oxygen_model model_xonar_ds = {
        .model_data_size = sizeof(struct xonar_wm87x6),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_1,
+                        CAPTURE_0_FROM_I2S_1 |
+                        CAPTURE_1_FROM_SPDIF,
        .dac_channels_pcm = 8,
        .dac_channels_mixer = 8,
        .dac_volume_min = 255 - 2*60,
@@ -1306,7 +1307,8 @@ static const struct oxygen_model model_xonar_hdav_slim = {
        .model_data_size = sizeof(struct xonar_wm87x6),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_1,
+                        CAPTURE_0_FROM_I2S_1 |
+                        CAPTURE_1_FROM_SPDIF,
        .dac_channels_pcm = 8,
        .dac_channels_mixer = 2,
        .dac_volume_min = 255 - 2*60,
index 56a52659742d57b176c612d1872928eea517ad58..fd1809ab73b4e4c3a934e895a4039a32f8cc2ba6 100644 (file)
@@ -52,8 +52,8 @@ MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}");
 
 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_PNP;/* Enable this card */
-static int mono[SNDRV_CARDS];                          /* capture  mono only */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+static bool mono[SNDRV_CARDS];                         /* capture  mono only */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard");
index dcbedd33a629e87a133f802b5ff3c25b96af3a4d..0481d94aac9b9e3027467aa744861d947c5373cc 100644 (file)
@@ -122,7 +122,7 @@ MODULE_FIRMWARE("riptide.hex");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
 
 #ifdef SUPPORT_JOYSTICK
 static int joystick_port[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS - 1)] = 0x200 };
index 21bcb47fab50ef5d4de43708d7beb72105d4013d..b4819d5e41dbe04be2f707ead5f7daecb015a281 100644 (file)
@@ -89,8 +89,8 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int fullduplex[SNDRV_CARDS]; // = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
+static bool fullduplex[SNDRV_CARDS]; // = {[0 ... (SNDRV_CARDS - 1)] = 1};
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi32 soundcard.");
index 4585c9729fea43f67507d079156080df7d8b3fda..ba894158e76ceaa62fc335ae8a30a69d28de1b16 100644 (file)
@@ -53,7 +53,7 @@ MODULE_SUPPORTED_DEVICE("{{RME,Digi96},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi96 soundcard.");
index f2a3758dac5229bbfc463df1a22215d516b2dabb..b68cdec03b9e02ebf122d06c4f93ed4aea752961 100644 (file)
@@ -45,7 +45,7 @@
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Hammerfall DSP interface.");
@@ -2640,8 +2640,7 @@ static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd
                uinfo->value.enumerated.items = 3;
                break;
        default:
-               uinfo->value.enumerated.items = 0;
-               break;
+               return -EINVAL;
        }
 
        if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
index 19ee2203cbb50fe7250bca2bad79c14e15a6069b..cc9f6c83d661c93ba35926d475f11f3b85a3d354 100644 (file)
@@ -61,7 +61,7 @@
 
 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_PNP;/* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME HDSPM interface.");
@@ -941,6 +941,8 @@ struct hdspm {
 
        cycles_t last_interrupt;
 
+       unsigned int serial;
+
        struct hdspm_peak_rms peak_rms;
 };
 
@@ -4694,7 +4696,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
 
        snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
                        (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
-                       (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF);
+                       hdspm->serial);
 
        snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
                        hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
@@ -6266,8 +6268,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
                hdspm_version.card_type = hdspm->io_type;
                strncpy(hdspm_version.cardname, hdspm->card_name,
                                sizeof(hdspm_version.cardname));
-               hdspm_version.serial = (hdspm_read(hdspm,
-                                       HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
+               hdspm_version.serial = hdspm->serial;
                hdspm_version.firmware_rev = hdspm->firmware_rev;
                hdspm_version.addons = 0;
                if (hdspm->tco)
@@ -6782,6 +6783,25 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
        tasklet_init(&hdspm->midi_tasklet,
                        hdspm_midi_tasklet, (unsigned long) hdspm);
 
+
+       if (hdspm->io_type != MADIface) {
+               hdspm->serial = (hdspm_read(hdspm,
+                               HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
+               /* id contains either a user-provided value or the default
+                * NULL. If it's the default, we're safe to
+                * fill card->id with the serial number.
+                *
+                * If the serial number is 0xFFFFFF, then we're dealing with
+                * an old PCI revision that comes without a sane number. In
+                * this case, we don't set card->id to avoid collisions
+                * when running with multiple cards.
+                */
+               if (NULL == id[hdspm->dev] && hdspm->serial != 0xFFFFFF) {
+                       sprintf(card->id, "HDSPMx%06x", hdspm->serial);
+                       snd_card_set_id(card, card->id);
+               }
+       }
+
        snd_printdd("create alsa devices.\n");
        err = snd_hdspm_create_alsa_devices(card, hdspm);
        if (err < 0)
@@ -6868,10 +6888,10 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci,
        if (hdspm->io_type != MADIface) {
                sprintf(card->shortname, "%s_%x",
                        hdspm->card_name,
-                       (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF);
+                       hdspm->serial);
                sprintf(card->longname, "%s S/N 0x%x at 0x%lx, irq %d",
                        hdspm->card_name,
-                       (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF,
+                       hdspm->serial,
                        hdspm->port, hdspm->irq);
        } else {
                sprintf(card->shortname, "%s", hdspm->card_name);
index 732c5e8374377d6abc0f98761e9133252ceb1f17..b737d1619cc764ce00137b71db68709363ae2d0b 100644 (file)
@@ -38,8 +38,8 @@
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int precise_ptr[SNDRV_CARDS];                   /* Enable precise pointer */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
+static bool precise_ptr[SNDRV_CARDS];                  /* Enable precise pointer */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard.");
index 28dfafb56dd1d70a9d95e4ef53f6e7ba22fb4faf..ff500a87f7694f09578d032965bdc4815c039d1c 100644 (file)
@@ -40,7 +40,7 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int enable = 1;
+static bool enable = 1;
 static int codecs = 1;
 
 module_param(index, int, 0444);
@@ -983,7 +983,7 @@ timeout:
        mutex_unlock(&sis->ac97_mutex);
 
        if (!count) {
-               printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n",
+               dev_err(&sis->pci->dev, "ac97 codec %d timeout cmd 0x%08x\n",
                                        codec, cmd);
        }
 
@@ -1142,13 +1142,13 @@ static int sis_chip_init(struct sis7019 *sis)
        /* All done, check for errors.
         */
        if (!sis->codecs_present) {
-               printk(KERN_ERR "sis7019: could not find any codecs\n");
+               dev_err(&sis->pci->dev, "could not find any codecs\n");
                return -EIO;
        }
 
        if (sis->codecs_present != codecs) {
-               printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n",
-                      sis->codecs_present, codecs);
+               dev_warn(&sis->pci->dev, "missing codecs, found %0x, expected %0x\n",
+                                        sis->codecs_present, codecs);
        }
 
        /* Let the hardware know that the audio driver is alive,
@@ -1256,18 +1256,18 @@ static int sis_resume(struct pci_dev *pci)
        pci_restore_state(pci);
 
        if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "sis7019: unable to re-enable device\n");
+               dev_err(&pci->dev, "unable to re-enable device\n");
                goto error;
        }
 
        if (sis_chip_init(sis)) {
-               printk(KERN_ERR "sis7019: unable to re-init controller\n");
+               dev_err(&pci->dev, "unable to re-init controller\n");
                goto error;
        }
 
        if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
                        KBUILD_MODNAME, sis)) {
-               printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
+               dev_err(&pci->dev, "unable to regain IRQ %d\n", pci->irq);
                goto error;
        }
 
@@ -1335,8 +1335,7 @@ static int __devinit sis_chip_create(struct snd_card *card,
                goto error_out;
 
        if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0) {
-               printk(KERN_ERR "sis7019: architecture does not support "
-                                       "30-bit PCI busmaster DMA");
+               dev_err(&pci->dev, "architecture does not support 30-bit PCI busmaster DMA");
                goto error_out_enabled;
        }
 
@@ -1350,20 +1349,20 @@ static int __devinit sis_chip_create(struct snd_card *card,
 
        rc = pci_request_regions(pci, "SiS7019");
        if (rc) {
-               printk(KERN_ERR "sis7019: unable request regions\n");
+               dev_err(&pci->dev, "unable request regions\n");
                goto error_out_enabled;
        }
 
        rc = -EIO;
        sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000);
        if (!sis->ioaddr) {
-               printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n");
+               dev_err(&pci->dev, "unable to remap MMIO, aborting\n");
                goto error_out_cleanup;
        }
 
        rc = sis_alloc_suspend(sis);
        if (rc < 0) {
-               printk(KERN_ERR "sis7019: unable to allocate state storage\n");
+               dev_err(&pci->dev, "unable to allocate state storage\n");
                goto error_out_cleanup;
        }
 
@@ -1371,9 +1370,9 @@ static int __devinit sis_chip_create(struct snd_card *card,
        if (rc)
                goto error_out_cleanup;
 
-       if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, sis)) {
-               printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
+       if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED, KBUILD_MODNAME,
+                       sis)) {
+               dev_err(&pci->dev, "unable to allocate irq %d\n", sis->irq);
                goto error_out_cleanup;
        }
 
index 31b6ad3ab1dc48c2f47cbbeb13e58873dfdecf58..54cc802050f705b55b6675be122f7b649ed9b2c3 100644 (file)
@@ -52,9 +52,9 @@ MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
 
 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_PNP;     /* Enable this card */
-static int reverb[SNDRV_CARDS];
-static int mge[SNDRV_CARDS];
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
+static bool reverb[SNDRV_CARDS];
+static bool mge[SNDRV_CARDS];
 static unsigned int dmaio = 0x7a00;    /* DDMA i/o address */
 
 module_param_array(index, int, NULL, 0444);
index deb04b924122e5b2d27284fba322b923370cc031..5f1def7f45e550949e547ea4fffcbded6051503b 100644 (file)
@@ -47,7 +47,7 @@ MODULE_SUPPORTED_DEVICE("{{Trident,4DWave DX},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32};
 static int wavetable_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8192};
 
index ae98d56d05bd0e89583db264ef46ca783a5e26ba..75630408c6db495bf9c124a84738f57eb92c64b5 100644 (file)
@@ -80,7 +80,7 @@ static int index = SNDRV_DEFAULT_IDX1;        /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
 static long mpu_port;
 #ifdef SUPPORT_JOYSTICK
-static int joystick;
+static bool joystick;
 #endif
 static int ac97_clock = 48000;
 static char *ac97_quirk;
@@ -110,7 +110,7 @@ module_param(nodelay, int, 0444);
 MODULE_PARM_DESC(nodelay, "Disable 500ms init delay");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index 80a9c2bf3301f61a706360ab15bfbe5f895e9aaf..5efcbcac506a16f0e392551faa9f1d559dade231 100644 (file)
@@ -66,7 +66,7 @@ module_param(ac97_clock, int, 0444);
 MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
 
 /* just for backward compatibility */
-static int enable;
+static bool enable;
 module_param(enable, bool, 0444);
 
 
index 6765822fb3b7bf8fd1480688f3fd638ff9b298d0..6a534bfe127408b6fe08d4045413508f1d0bec13 100644 (file)
@@ -37,8 +37,8 @@ MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
 
 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_PNP;     /* Enable this card */
-static int mic[SNDRV_CARDS]; /* microphone */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
+static bool mic[SNDRV_CARDS]; /* microphone */
 static int ibl[SNDRV_CARDS]; /* microphone */
 
 module_param_array(index, int, NULL, 0444);
index e97ddcac0d371e11e62dac689af5a459061d7848..e57b89e8aa8926604425b2283d0238327609c63c 100644 (file)
@@ -41,13 +41,13 @@ MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724},"
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 static long fm_port[SNDRV_CARDS];
 static long mpu_port[SNDRV_CARDS];
 #ifdef SUPPORT_JOYSTICK
 static long joystick_port[SNDRV_CARDS];
 #endif
-static int rear_switch[SNDRV_CARDS];
+static bool rear_switch[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
index 6af41d2d8fc516753a91909ce7e8f51e4ccacb47..830839a874b6899ae4e6979ae92f601dbb1fad56 100644 (file)
@@ -39,7 +39,7 @@ MODULE_SUPPORTED_DEVICE("{{Sound Core," CARD_NAME "}}");
 
 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_PNP;     /* Enable switches */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable switches */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
index 9e361c9d5bf33d63e81452458a7e36070080e8c2..512f0b4723756a57012f1551894886e45d0b7d43 100644 (file)
@@ -39,7 +39,7 @@ MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}");
 
 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_PNP;     /* Enable switches */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable switches */
 static int ibl[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
index 65645693c485c629135738acd3661e452eef34ce..5a4e263b5b0fc18822be093c66e78eb294f1f52f 100644 (file)
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
 
 static int index = SNDRV_DEFAULT_IDX1;         /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;          /* ID for this card */
-static int enable_beep = 1;
+static bool enable_beep = 1;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
index 1120ca49edd00c6b668944e6905d2abfb7fbb438..391a38ca58bc767301f74c7baf4a3b116afa3429 100644 (file)
@@ -55,7 +55,7 @@ MODULE_FIRMWARE("aica_firmware.bin");
 #define CARD_NAME "AICA"
 static int index = -1;
 static char *id;
-static int enable = 1;
+static bool enable = 1;
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
 module_param(id, charp, 0444);
index 56bcb46abf0d255693d9b3bec415b328c781abde..b11f82b5718fdb1c49eec15d034bad31c9fd9e6f 100644 (file)
@@ -441,15 +441,4 @@ static struct platform_driver driver = {
        },
 };
 
-static int __init sh_dac_init(void)
-{
-       return platform_driver_register(&driver);
-}
-
-static void __exit sh_dac_exit(void)
-{
-       platform_driver_unregister(&driver);
-}
-
-module_init(sh_dac_init);
-module_exit(sh_dac_exit);
+module_platform_driver(driver);
index 1381db853ef0f8b5d875c6ba220de0f90476add5..35e662d270e6141338669051a784c06a3fe9fbea 100644 (file)
@@ -22,21 +22,6 @@ menuconfig SND_SOC
 
 if SND_SOC
 
-config SND_SOC_CACHE_LZO
-       bool "Support LZO compression for register caches"
-       select LZO_COMPRESS
-       select LZO_DECOMPRESS
-       ---help---
-          Select this to enable LZO compression for register caches.
-          This will allow machine or CODEC drivers to compress register
-          caches in memory, reducing the memory consumption at the
-          expense of performance.  If this is not present and is used
-          the system will fall back to uncompressed caches.
-
-          Usually it is safe to disable this option, where cache
-          compression in used the rbtree option will typically perform
-          better.
-
 config SND_SOC_AC97_BUS
        bool
 
index d1fcc816ce9705c5aca82f68eb327d65618301cd..72b09cfd3dc367d4aa28826e750e27aa2ffb1885 100644 (file)
@@ -26,7 +26,7 @@ config SND_AT91_SOC_SAM9G20_WM8731
 
 config SND_AT91_SOC_AFEB9260
        tristate "SoC Audio support for AFEB9260 board"
-       depends on ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
+       depends on ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
        select SND_ATMEL_SOC_SSC
        select SND_SOC_TLV320AIC23
        help
index f81d4c3f8956efa24d4becf3952b6242554a0866..a21ff459e5d3e0d53a6d50264c3f150dbaf6b0c9 100644 (file)
@@ -367,7 +367,6 @@ static u64 atmel_pcm_dmamask = 0xffffffff;
 static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -376,14 +375,14 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                pr_debug("atmel-pcm:"
                                "Allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -495,17 +494,7 @@ static struct platform_driver atmel_pcm_driver = {
        .remove = __devexit_p(atmel_soc_platform_remove),
 };
 
-static int __init snd_atmel_pcm_init(void)
-{
-       return platform_driver_register(&atmel_pcm_driver);
-}
-module_init(snd_atmel_pcm_init);
-
-static void __exit snd_atmel_pcm_exit(void)
-{
-       platform_driver_unregister(&atmel_pcm_driver);
-}
-module_exit(snd_atmel_pcm_exit);
+module_platform_driver(atmel_pcm_driver);
 
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("Atmel PCM module");
index 71225090c49fc424a7ea1f6c0f2b5168e79480ba..354341ec0f42f1129adbaaf310366af46b866229 100644 (file)
@@ -719,7 +719,7 @@ static int atmel_ssc_remove(struct snd_soc_dai *dai)
 #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_LE |\
                          SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
+static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
        .startup        = atmel_ssc_startup,
        .shutdown       = atmel_ssc_shutdown,
        .prepare        = atmel_ssc_prepare,
@@ -859,17 +859,7 @@ int atmel_ssc_set_audio(int ssc_id)
 }
 EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
 
-static int __init snd_atmel_ssc_init(void)
-{
-       return platform_driver_register(&asoc_ssc_driver);
-}
-module_init(snd_atmel_ssc_init);
-
-static void __exit snd_atmel_ssc_exit(void)
-{
-       platform_driver_unregister(&asoc_ssc_driver);
-}
-module_exit(snd_atmel_ssc_exit);
+module_platform_driver(asoc_ssc_driver);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
index 0377c5451aed9bbe1e9f61f2959dab6b6637da93..c88351488f45c5c6adb0529a212ab257531a90fd 100644 (file)
@@ -189,6 +189,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .name = "AT91SAMG20-EK",
+       .owner = THIS_MODULE,
        .dai_link = &at91sam9g20ek_dai,
        .num_links = 1,
        .set_bias_level = at91sam9g20ek_set_bias_level,
index d427e9217ce4c264ff8f0b8ad44ec41e25d17c31..4ca667d477f9f332e77a9ab60b0ce3805f4418ce 100644 (file)
@@ -135,6 +135,7 @@ static struct snd_soc_dai_link afeb9260_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_machine_afeb9260 = {
        .name = "AFEB9260",
+       .owner = THIS_MODULE,
        .dai_link = &afeb9260_dai,
        .num_links = 1,
 };
index 726bd651a105970053a726cdee18012ea96a508b..c5ac2449563a5140524702c5db367c5a2f52bb5f 100644 (file)
@@ -195,7 +195,7 @@ static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops alchemy_ac97c_ops = {
+static const struct snd_soc_dai_ops alchemy_ac97c_ops = {
        .startup                = alchemy_ac97c_startup,
 };
 
@@ -229,35 +229,34 @@ static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
        struct resource *iores, *dmares;
        struct au1xpsc_audio_data *ctx;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
        mutex_init(&ctx->lock);
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores) {
-               ret = -ENODEV;
-               goto out0;
-       }
+       if (!iores)
+               return -ENODEV;
 
-       ret = -EBUSY;
-       if (!request_mem_region(iores->start, resource_size(iores),
-                               pdev->name))
-               goto out0;
+       if (!devm_request_mem_region(&pdev->dev, iores->start,
+                                    resource_size(iores),
+                                    pdev->name))
+               return -EBUSY;
 
-       ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
+       ctx->mmio = devm_ioremap_nocache(&pdev->dev, iores->start,
+                                        resource_size(iores));
        if (!ctx->mmio)
-               goto out1;
+               return -EBUSY;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
 
        /* switch it on */
@@ -271,33 +270,20 @@ static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
 
        ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
        if (ret)
-               goto out2;
+               return ret;
 
        ac97c_workdata = ctx;
        return 0;
-
-out2:
-       iounmap(ctx->mmio);
-out1:
-       release_mem_region(iores->start, resource_size(iores));
-out0:
-       kfree(ctx);
-       return ret;
 }
 
 static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
-       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        snd_soc_unregister_dai(&pdev->dev);
 
        WR(ctx, AC97_ENABLE, EN_D);     /* clock off, disable */
 
-       iounmap(ctx->mmio);
-       release_mem_region(r->start, resource_size(r));
-       kfree(ctx);
-
        ac97c_workdata = NULL;  /* MDEV */
 
        return 0;
index 127477a5e0c775ad8778eaf0fba722f161ce8697..511d83c11a9a0e2799688df405a590ebc0a19ac4 100644 (file)
@@ -29,6 +29,7 @@ static struct snd_soc_dai_link db1000_ac97_dai = {
 
 static struct snd_soc_card db1000_ac97 = {
        .name           = "DB1000_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1000_ac97_dai,
        .num_links      = 1,
 };
@@ -57,18 +58,7 @@ static struct platform_driver db1000_audio_driver = {
        .remove         = __devexit_p(db1000_audio_remove),
 };
 
-static int __init db1000_audio_load(void)
-{
-       return platform_driver_register(&db1000_audio_driver);
-}
-
-static void __exit db1000_audio_unload(void)
-{
-       platform_driver_unregister(&db1000_audio_driver);
-}
-
-module_init(db1000_audio_load);
-module_exit(db1000_audio_unload);
+module_platform_driver(db1000_audio_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio");
index 289312c14b99bf62d13355e7ae5e585bf297991f..1c629393df782b5d866241ec9c2eded166df2bfe 100644 (file)
@@ -45,6 +45,7 @@ static struct snd_soc_dai_link db1200_ac97_dai = {
 
 static struct snd_soc_card db1200_ac97_machine = {
        .name           = "DB1200_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1200_ac97_dai,
        .num_links      = 1,
 };
@@ -94,6 +95,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
 
 static struct snd_soc_card db1200_i2s_machine = {
        .name           = "DB1200_I2S",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1200_i2s_dai,
        .num_links      = 1,
 };
@@ -133,18 +135,7 @@ static struct platform_driver db1200_audio_driver = {
        .remove         = __devexit_p(db1200_audio_remove),
 };
 
-static int __init db1200_audio_load(void)
-{
-       return platform_driver_register(&db1200_audio_driver);
-}
-
-static void __exit db1200_audio_unload(void)
-{
-       platform_driver_unregister(&db1200_audio_driver);
-}
-
-module_init(db1200_audio_load);
-module_exit(db1200_audio_unload);
+module_platform_driver(db1200_audio_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DB1200 ASoC audio support");
index d7d04e26eee504524f7952c86825b44c5d7a4fa7..8372cd35f0d6bea6701df54c829037a89c4e67cc 100644 (file)
@@ -341,7 +341,7 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 }
 
 /* au1xpsc audio platform */
-struct snd_soc_platform_driver au1xpsc_soc_platform = {
+static struct snd_soc_platform_driver au1xpsc_soc_platform = {
        .ops            = &au1xpsc_pcm_ops,
        .pcm_new        = au1xpsc_pcm_new,
        .pcm_free       = au1xpsc_pcm_free_dma_buffers,
@@ -350,27 +350,21 @@ struct snd_soc_platform_driver au1xpsc_soc_platform = {
 static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 {
        struct au1xpsc_audio_dmadata *dmadata;
-       int ret;
 
-       dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+       dmadata = devm_kzalloc(&pdev->dev,
+                              2 * sizeof(struct au1xpsc_audio_dmadata),
+                              GFP_KERNEL);
        if (!dmadata)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, dmadata);
 
-       ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
-       if (ret)
-               kfree(dmadata);
-
-       return ret;
+       return snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
 }
 
 static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
 {
-       struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
-
        snd_soc_unregister_platform(&pdev->dev);
-       kfree(dmadata);
 
        return 0;
 }
@@ -384,18 +378,7 @@ static struct platform_driver au1xpsc_pcm_driver = {
        .remove         = __devexit_p(au1xpsc_pcm_drvremove),
 };
 
-static int __init au1xpsc_audio_dbdma_load(void)
-{
-       return platform_driver_register(&au1xpsc_pcm_driver);
-}
-
-static void __exit au1xpsc_audio_dbdma_unload(void)
-{
-       platform_driver_unregister(&au1xpsc_pcm_driver);
-}
-
-module_init(au1xpsc_audio_dbdma_load);
-module_exit(au1xpsc_audio_dbdma_unload);
+module_platform_driver(au1xpsc_pcm_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
index 177f7137a9c80e358aa4c6913cfafce00585e11d..0a91b186a86f1baaceae28f921058cf5c72d3e9e 100644 (file)
@@ -316,7 +316,7 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
+static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
        .ops            = &alchemy_pcm_ops,
        .pcm_new        = alchemy_pcm_new,
        .pcm_free       = alchemy_pcm_free_dma_buffers,
@@ -325,27 +325,19 @@ struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
 static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev)
 {
        struct alchemy_pcm_ctx *ctx;
-       int ret;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, ctx);
 
-       ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
-       if (ret)
-               kfree(ctx);
-
-       return ret;
+       return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
 }
 
 static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev)
 {
-       struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev);
-
        snd_soc_unregister_platform(&pdev->dev);
-       kfree(ctx);
 
        return 0;
 }
@@ -359,18 +351,7 @@ static struct platform_driver alchemy_pcmdma_driver = {
        .remove         = __devexit_p(alchemy_pcm_drvremove),
 };
 
-static int __init alchemy_pcmdma_load(void)
-{
-       return platform_driver_register(&alchemy_pcmdma_driver);
-}
-
-static void __exit alchemy_pcmdma_unload(void)
-{
-       platform_driver_unregister(&alchemy_pcmdma_driver);
-}
-
-module_init(alchemy_pcmdma_load);
-module_exit(alchemy_pcmdma_unload);
+module_platform_driver(alchemy_pcmdma_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
index 6bcf48f5884c169b0a5d61004bb91f7652647b35..d4b9e364a47afbeb972f82e1605c9d67566564bf 100644 (file)
@@ -227,69 +227,50 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
 
 static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
 {
-       int ret;
        struct resource *iores, *dmares;
        struct au1xpsc_audio_data *ctx;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores) {
-               ret = -ENODEV;
-               goto out0;
-       }
+       if (!iores)
+               return -ENODEV;
 
-       ret = -EBUSY;
-       if (!request_mem_region(iores->start, resource_size(iores),
-                               pdev->name))
-               goto out0;
+       if (!devm_request_mem_region(&pdev->dev, iores->start,
+                                    resource_size(iores),
+                                    pdev->name))
+               return -EBUSY;
 
-       ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
+       ctx->mmio = devm_ioremap_nocache(&pdev->dev, iores->start,
+                                        resource_size(iores));
        if (!ctx->mmio)
-               goto out1;
+               return -EBUSY;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
 
        platform_set_drvdata(pdev, ctx);
 
-       ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
-       if (ret)
-               goto out2;
-
-       return 0;
-
-out2:
-       iounmap(ctx->mmio);
-out1:
-       release_mem_region(iores->start, resource_size(iores));
-out0:
-       kfree(ctx);
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
 }
 
 static int __devexit au1xi2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
-       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        snd_soc_unregister_dai(&pdev->dev);
 
        WR(ctx, I2S_ENABLE, EN_D);      /* clock off, disable */
 
-       iounmap(ctx->mmio);
-       release_mem_region(r->start, resource_size(r));
-       kfree(ctx);
-
        return 0;
 }
 
@@ -331,18 +312,7 @@ static struct platform_driver au1xi2s_driver = {
        .remove         = __devexit_p(au1xi2s_drvremove),
 };
 
-static int __init au1xi2s_load(void)
-{
-       return platform_driver_register(&au1xi2s_driver);
-}
-
-static void __exit au1xi2s_unload(void)
-{
-       platform_driver_unregister(&au1xi2s_driver);
-}
-
-module_init(au1xi2s_load);
-module_exit(au1xi2s_unload);
+module_platform_driver(au1xi2s_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/1500/1100 I2S ASoC driver");
index 0c6acd54714100b09401fac0278f4b412821f0b9..476b79a1c11a764e4ea80ab484ec4eb8a16701a9 100644 (file)
@@ -337,7 +337,7 @@ static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
        return au1xpsc_ac97_workdata ? 0 : -ENODEV;
 }
 
-static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
        .startup        = au1xpsc_ac97_startup,
        .trigger        = au1xpsc_ac97_trigger,
        .hw_params      = au1xpsc_ac97_hw_params,
@@ -368,35 +368,35 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        unsigned long sel;
        struct au1xpsc_audio_data *wd;
 
-       wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       wd = devm_kzalloc(&pdev->dev, sizeof(struct au1xpsc_audio_data),
+                         GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
 
        mutex_init(&wd->lock);
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores) {
-               ret = -ENODEV;
-               goto out0;
-       }
+       if (!iores)
+               return -ENODEV;
 
-       ret = -EBUSY;
-       if (!request_mem_region(iores->start, resource_size(iores),
-                               pdev->name))
-               goto out0;
+       if (!devm_request_mem_region(&pdev->dev, iores->start,
+                                    resource_size(iores),
+                                    pdev->name))
+               return -EBUSY;
 
-       wd->mmio = ioremap(iores->start, resource_size(iores));
+       wd->mmio = devm_ioremap(&pdev->dev, iores->start,
+                               resource_size(iores));
        if (!wd->mmio)
-               goto out1;
+               return -EBUSY;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
 
        /* configuration: max dma trigger threshold, enable ac97 */
@@ -421,24 +421,15 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
        ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
        if (ret)
-               goto out2;
+               return ret;
 
        au1xpsc_ac97_workdata = wd;
        return 0;
-
-out2:
-       iounmap(wd->mmio);
-out1:
-       release_mem_region(iores->start, resource_size(iores));
-out0:
-       kfree(wd);
-       return ret;
 }
 
 static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
-       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        snd_soc_unregister_dai(&pdev->dev);
 
@@ -448,10 +439,6 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
-       iounmap(wd->mmio);
-       release_mem_region(r->start, resource_size(r));
-       kfree(wd);
-
        au1xpsc_ac97_workdata = NULL;   /* MDEV */
 
        return 0;
index e03c5ce01b304ef680e1790f4fd9c39d1313483d..0607ba3d925831bb79e0221942256e8dc2c191fc 100644 (file)
@@ -265,7 +265,7 @@ static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+static const struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
        .startup        = au1xpsc_i2s_startup,
        .trigger        = au1xpsc_i2s_trigger,
        .hw_params      = au1xpsc_i2s_hw_params,
@@ -295,33 +295,34 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
        int ret;
        struct au1xpsc_audio_data *wd;
 
-       wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
+       wd = devm_kzalloc(&pdev->dev, sizeof(struct au1xpsc_audio_data),
+                         GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores) {
-               ret = -ENODEV;
-               goto out0;
-       }
+       if (!iores)
+               return -ENODEV;
 
        ret = -EBUSY;
-       if (!request_mem_region(iores->start, resource_size(iores),
-                               pdev->name))
-               goto out0;
+       if (!devm_request_mem_region(&pdev->dev, iores->start,
+                                    resource_size(iores),
+                                    pdev->name))
+               return -EBUSY;
 
-       wd->mmio = ioremap(iores->start, resource_size(iores));
+       wd->mmio = devm_ioremap(&pdev->dev, iores->start,
+                               resource_size(iores));
        if (!wd->mmio)
-               goto out1;
+               return -EBUSY;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!dmares)
-               goto out2;
+               return -EBUSY;
        wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
 
        /* preserve PSC clock source set up by platform (dev.platform_data
@@ -349,23 +350,12 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
-       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
-       if (!ret)
-               return 0;
-
-out2:
-       iounmap(wd->mmio);
-out1:
-       release_mem_region(iores->start, resource_size(iores));
-out0:
-       kfree(wd);
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
 }
 
 static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
-       struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        snd_soc_unregister_dai(&pdev->dev);
 
@@ -374,10 +364,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
        au_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
        au_sync();
 
-       iounmap(wd->mmio);
-       release_mem_region(r->start, resource_size(r));
-       kfree(wd);
-
        return 0;
 }
 
@@ -435,18 +421,7 @@ static struct platform_driver au1xpsc_i2s_driver = {
        .remove         = __devexit_p(au1xpsc_i2s_drvremove),
 };
 
-static int __init au1xpsc_i2s_load(void)
-{
-       return platform_driver_register(&au1xpsc_i2s_driver);
-}
-
-static void __exit au1xpsc_i2s_unload(void)
-{
-       platform_driver_unregister(&au1xpsc_i2s_driver);
-}
-
-module_init(au1xpsc_i2s_load);
-module_exit(au1xpsc_i2s_unload);
+module_platform_driver(au1xpsc_i2s_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver");
index 56815c1d47b3fdb36f278e05894fc54a6ace93d7..d7dc9bde09760ce5bc44fe6bd8bf0f4b79843a4d 100644 (file)
@@ -421,7 +421,6 @@ static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -431,14 +430,14 @@ static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -475,17 +474,7 @@ static struct platform_driver bf5xx_pcm_driver = {
        .remove = __devexit_p(bf5xx_soc_platform_remove),
 };
 
-static int __init snd_bf5xx_pcm_init(void)
-{
-       return platform_driver_register(&bf5xx_pcm_driver);
-}
-module_init(snd_bf5xx_pcm_init);
-
-static void __exit snd_bf5xx_pcm_exit(void)
-{
-       platform_driver_unregister(&bf5xx_pcm_driver);
-}
-module_exit(snd_bf5xx_pcm_exit);
+module_platform_driver(bf5xx_pcm_driver);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
index 6d216259088935633c598bb72d0ce516fc31df96..f4e9dc4e262e6c63a6a5e1cf318c4b58cab3b431 100644 (file)
@@ -375,18 +375,7 @@ static struct platform_driver asoc_bfin_ac97_driver = {
        .remove = __devexit_p(asoc_bfin_ac97_remove),
 };
 
-static int __init bfin_ac97_init(void)
-{
-       return platform_driver_register(&asoc_bfin_ac97_driver);
-}
-module_init(bfin_ac97_init);
-
-static void __exit bfin_ac97_exit(void)
-{
-       platform_driver_unregister(&asoc_bfin_ac97_driver);
-}
-module_exit(bfin_ac97_exit);
-
+module_platform_driver(asoc_bfin_ac97_driver);
 
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
index f79d1655e035d845fc0d8118366df2cd2f397989..60962ce6cd4d06c96536ca9ee124a8ac66e10467 100644 (file)
@@ -91,6 +91,7 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
 
 static struct snd_soc_card bf5xx_ad1836 = {
        .name = "bfin-ad1836",
+       .owner = THIS_MODULE,
        .dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
index 5956584ea3a425eae1621679848aed9d4fdd6620..2d8d82dbc159ef6326b553e8ce2916fd0c1e771f 100644 (file)
@@ -119,6 +119,7 @@ static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
 
 static struct snd_soc_card bf5xx_ad193x = {
        .name = "bfin-ad193x",
+       .owner = THIS_MODULE,
        .dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
index 06a84b211b52bcdcb08783ae9623e9ab2ecb9f35..b30f88bbd70332ab09fe9a116e21a6278e6c74d5 100644 (file)
@@ -74,6 +74,7 @@ static struct snd_soc_dai_link bf5xx_board_dai[] = {
 
 static struct snd_soc_card bf5xx_board = {
        .name = "bfin-ad1980",
+       .owner = THIS_MODULE,
        .dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
index b94eb7ef7d1669d2e3ab8808f01fb8d2b2fab0ab..8e49508596dad59911ab3ac3c4ae1baa006cc678 100644 (file)
@@ -192,6 +192,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
 
 static struct snd_soc_card bf5xx_ad73311 = {
        .name = "bfin-ad73311",
+       .owner = THIS_MODULE,
        .probe = bf5xx_probe,
        .dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
index 7565e1576ffa47a04ab165423cda019eb53c7375..63205d723eab769f8ddb5b007bc2d85cfb484bc4 100644 (file)
@@ -260,7 +260,6 @@ static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -270,14 +269,14 @@ static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -314,17 +313,7 @@ static struct platform_driver bfin_i2s_pcm_driver = {
        .remove = __devexit_p(bfin_i2s_soc_platform_remove),
 };
 
-static int __init snd_bfin_i2s_pcm_init(void)
-{
-       return platform_driver_register(&bfin_i2s_pcm_driver);
-}
-module_init(snd_bfin_i2s_pcm_init);
-
-static void __exit snd_bfin_i2s_pcm_exit(void)
-{
-       platform_driver_unregister(&bfin_i2s_pcm_driver);
-}
-module_exit(snd_bfin_i2s_pcm_exit);
+module_platform_driver(bfin_i2s_pcm_driver);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
index 00cc3e00b2fead767ca60cbc54e603b3521f960a..4dccf0374fe744fd54aaf379caf92e3eec5feda6 100644 (file)
@@ -223,7 +223,7 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
         SNDRV_PCM_FMTBIT_S24_LE | \
         SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
+static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
        .shutdown       = bf5xx_i2s_shutdown,
        .hw_params      = bf5xx_i2s_hw_params,
        .set_fmt        = bf5xx_i2s_set_dai_fmt,
@@ -288,18 +288,7 @@ static struct platform_driver bfin_i2s_driver = {
        },
 };
 
-static int __init bfin_i2s_init(void)
-{
-       return platform_driver_register(&bfin_i2s_driver);
-}
-
-static void __exit bfin_i2s_exit(void)
-{
-       platform_driver_unregister(&bfin_i2s_driver);
-}
-
-module_init(bfin_i2s_init);
-module_exit(bfin_i2s_exit);
+module_platform_driver(bfin_i2s_driver);
 
 /* Module information */
 MODULE_AUTHOR("Cliff Cai");
index 767e772a815de3b7b1bc2a6550df126b9525bda1..0303032380420eb7bd12d198ca4be3f5ea684149 100644 (file)
@@ -125,6 +125,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
 
 static struct snd_soc_card bf5xx_ssm2602 = {
        .name = "bfin-ssm2602",
+       .owner = THIS_MODULE,
        .dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 };
index c95cc03d583dd747a80477fd54b9137dc9bccb61..254490cf1876a4234edc363b743cf06aa966fb27 100644 (file)
@@ -286,7 +286,6 @@ static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -295,14 +294,14 @@ static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -339,17 +338,7 @@ static struct platform_driver bfin_tdm_driver = {
        .remove = __devexit_p(bf5xx_soc_platform_remove),
 };
 
-static int __init snd_bfin_tdm_init(void)
-{
-       return platform_driver_register(&bfin_tdm_driver);
-}
-module_init(snd_bfin_tdm_init);
-
-static void __exit snd_bfin_tdm_exit(void)
-{
-       platform_driver_unregister(&bfin_tdm_driver);
-}
-module_exit(snd_bfin_tdm_exit);
+module_platform_driver(bfin_tdm_driver);
 
 MODULE_AUTHOR("Barry Song");
 MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
index a822d1ee1380057db79148c265785e933616d1b2..594f88217c746e0f8639988b9851c105e2f5c0e5 100644 (file)
@@ -226,7 +226,7 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 #define bf5xx_tdm_resume       NULL
 #endif
 
-static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
+static const struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
        .hw_params      = bf5xx_tdm_hw_params,
        .set_fmt        = bf5xx_tdm_set_dai_fmt,
        .shutdown       = bf5xx_tdm_shutdown,
@@ -314,17 +314,7 @@ static struct platform_driver bfin_tdm_driver = {
        },
 };
 
-static int __init bfin_tdm_init(void)
-{
-       return platform_driver_register(&bfin_tdm_driver);
-}
-module_init(bfin_tdm_init);
-
-static void __exit bfin_tdm_exit(void)
-{
-       platform_driver_unregister(&bfin_tdm_driver);
-}
-module_exit(bfin_tdm_exit);
+module_platform_driver(bfin_tdm_driver);
 
 /* Module information */
 MODULE_AUTHOR("Barry Song");
index 8df2a3b0cb3613d9bb1bdc2a2e918f5e5c7b3528..26b271c62efa392825f95c64c627fc7fc63d1a68 100644 (file)
@@ -147,6 +147,7 @@ static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
 
 static struct snd_soc_card bfin_eval_adau1373 = {
        .name = "bfin-eval-adau1373",
+       .owner = THIS_MODULE,
        .dai_link = &bfin_eval_adau1373_dai,
        .num_links = 1,
 
@@ -184,17 +185,7 @@ static struct platform_driver bfin_eval_adau1373_driver = {
        .remove = __devexit_p(bfin_eval_adau1373_remove),
 };
 
-static int __init bfin_eval_adau1373_init(void)
-{
-       return platform_driver_register(&bfin_eval_adau1373_driver);
-}
-module_init(bfin_eval_adau1373_init);
-
-static void __exit bfin_eval_adau1373_exit(void)
-{
-       platform_driver_unregister(&bfin_eval_adau1373_driver);
-}
-module_exit(bfin_eval_adau1373_exit);
+module_platform_driver(bfin_eval_adau1373_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
index e5550acba2c2c1614dc14a8d738fef611214f508..c0064fa1dca653c7395062b5ee0076b5f24fbce2 100644 (file)
@@ -84,6 +84,7 @@ static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = {
 
 static struct snd_soc_card bfin_eval_adau1701 = {
        .name = "bfin-eval-adau1701",
+       .owner = THIS_MODULE,
        .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM],
        .num_links = 1,
 
@@ -121,17 +122,7 @@ static struct platform_driver bfin_eval_adau1701_driver = {
        .remove = __devexit_p(bfin_eval_adau1701_remove),
 };
 
-static int __init bfin_eval_adau1701_init(void)
-{
-       return platform_driver_register(&bfin_eval_adau1701_driver);
-}
-module_init(bfin_eval_adau1701_init);
-
-static void __exit bfin_eval_adau1701_exit(void)
-{
-       platform_driver_unregister(&bfin_eval_adau1701_driver);
-}
-module_exit(bfin_eval_adau1701_exit);
+module_platform_driver(bfin_eval_adau1701_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver");
index 897cfa68a2a668789b8844c00167b51eb1a12887..4ef079f95e2ede670a97f782fad67e573a516eed 100644 (file)
@@ -93,6 +93,7 @@ static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = {
 
 static struct snd_soc_card bfin_eval_adav80x = {
        .name = "bfin-eval-adav80x",
+       .owner = THIS_MODULE,
        .dai_link = bfin_eval_adav80x_dais,
        .num_links = ARRAY_SIZE(bfin_eval_adav80x_dais),
 
@@ -157,17 +158,7 @@ static struct platform_driver bfin_eval_adav80x_driver = {
        .id_table = bfin_eval_adav80x_ids,
 };
 
-static int __init bfin_eval_adav80x_init(void)
-{
-       return platform_driver_register(&bfin_eval_adav80x_driver);
-}
-module_init(bfin_eval_adav80x_init);
-
-static void __exit bfin_eval_adav80x_exit(void)
-{
-       platform_driver_unregister(&bfin_eval_adav80x_driver);
-}
-module_exit(bfin_eval_adav80x_exit);
+module_platform_driver(bfin_eval_adav80x_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver");
index 5ca122e51183a4531c612613c0bbf6c94da9f272..9fd3b6827bba91c6717fdd9a006cf8612ce81d18 100644 (file)
@@ -861,7 +861,7 @@ static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
        PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route pm860x_dapm_routes[] = {
        /* supply */
        {"Left DAC", NULL, "VCODEC"},
        {"Right DAC", NULL, "VCODEC"},
@@ -1198,14 +1198,14 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+static const struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
        .digital_mute   = pm860x_digital_mute,
        .hw_params      = pm860x_pcm_hw_params,
        .set_fmt        = pm860x_pcm_set_dai_fmt,
        .set_sysclk     = pm860x_set_dai_sysclk,
 };
 
-static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+static const struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
        .digital_mute   = pm860x_digital_mute,
        .hw_params      = pm860x_i2s_hw_params,
        .set_fmt        = pm860x_i2s_set_dai_fmt,
@@ -1361,7 +1361,6 @@ EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
 static int pm860x_probe(struct snd_soc_codec *codec)
 {
        struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int i, ret;
 
        pm860x->codec = codec;
@@ -1388,11 +1387,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
                goto out;
        }
 
-       snd_soc_add_controls(codec, pm860x_snd_controls,
-                            ARRAY_SIZE(pm860x_snd_controls));
-       snd_soc_dapm_new_controls(dapm, pm860x_dapm_widgets,
-                                 ARRAY_SIZE(pm860x_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        return 0;
 
 out:
@@ -1420,6 +1414,13 @@ static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
        .reg_cache_size = REG_CACHE_SIZE,
        .reg_word_size  = sizeof(u8),
        .set_bias_level = pm860x_set_bias_level,
+
+       .controls = pm860x_snd_controls,
+       .num_controls = ARRAY_SIZE(pm860x_snd_controls),
+       .dapm_widgets = pm860x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(pm860x_dapm_widgets),
+       .dapm_routes = pm860x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(pm860x_dapm_routes),
 };
 
 static int __devinit pm860x_codec_probe(struct platform_device *pdev)
@@ -1429,7 +1430,8 @@ static int __devinit pm860x_codec_probe(struct platform_device *pdev)
        struct resource *res;
        int i, ret;
 
-       pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+       pm860x = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_priv),
+                             GFP_KERNEL);
        if (pm860x == NULL)
                return -ENOMEM;
 
@@ -1458,17 +1460,13 @@ static int __devinit pm860x_codec_probe(struct platform_device *pdev)
 
 out:
        platform_set_drvdata(pdev, NULL);
-       kfree(pm860x);
        return -EINVAL;
 }
 
 static int __devexit pm860x_codec_remove(struct platform_device *pdev)
 {
-       struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
-
        snd_soc_unregister_codec(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
-       kfree(pm860x);
        return 0;
 }
 
@@ -1481,17 +1479,7 @@ static struct platform_driver pm860x_codec_driver = {
        .remove = __devexit_p(pm860x_codec_remove),
 };
 
-static __init int pm860x_init(void)
-{
-       return platform_driver_register(&pm860x_codec_driver);
-}
-module_init(pm860x_init);
-
-static __exit void pm860x_exit(void)
-{
-       platform_driver_unregister(&pm860x_codec_driver);
-}
-module_exit(pm860x_exit);
+module_platform_driver(pm860x_codec_driver);
 
 MODULE_DESCRIPTION("ASoC 88PM860x driver");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
index fa787d45d74a920a32c4e8327a69c4a8a3544461..7c205e77d83aa8af2439955b56cecc9fc1e7419b 100644 (file)
@@ -26,8 +26,10 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
        select SND_SOC_ALC5623 if I2C
+       select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS42L51 if I2C
+       select SND_SOC_CS42L73 if I2C
        select SND_SOC_CS4270 if I2C
        select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
        select SND_SOC_CX20442
@@ -139,7 +141,7 @@ config SND_SOC_AD73311
        tristate
 
 config SND_SOC_ADAU1701
-       select SIGMA
+       select SND_SOC_SIGMADSP
        tristate
 
 config SND_SOC_ADAU1373
@@ -168,6 +170,8 @@ config SND_SOC_AK4671
 
 config SND_SOC_ALC5623
        tristate
+config SND_SOC_ALC5632
+       tristate
 
 config SND_SOC_CQ0093VC
        tristate
@@ -175,6 +179,9 @@ config SND_SOC_CQ0093VC
 config SND_SOC_CS42L51
        tristate
 
+config SND_SOC_CS42L73
+       tristate
+
 # Cirrus Logic CS4270 Codec
 config SND_SOC_CS4270
        tristate
@@ -227,6 +234,10 @@ config SND_SOC_RT5631
 config SND_SOC_SGTL5000
        tristate
 
+config SND_SOC_SIGMADSP
+       tristate
+       select CRC32
+
 config SND_SOC_SN95031
        tristate
 
@@ -278,6 +289,9 @@ config SND_SOC_WL1273
 config SND_SOC_WM1250_EV1
        tristate
 
+config SND_SOC_WM2000
+       tristate
+
 config SND_SOC_WM5100
        tristate
 
@@ -395,6 +409,9 @@ config SND_SOC_WM8996
 config SND_SOC_WM9081
        tristate
 
+config SND_SOC_WM9090
+       tristate
+
 config SND_SOC_WM9705
        tristate
 
@@ -413,9 +430,3 @@ config SND_SOC_MAX9877
 
 config SND_SOC_TPA6130A2
        tristate
-
-config SND_SOC_WM2000
-       tristate
-
-config SND_SOC_WM9090
-       tristate
index a2c7842e357b6c3aa899a9e93155bed9855c2bbf..de8078178f86be523f75071207a776c6ff2b4657 100644 (file)
@@ -15,13 +15,16 @@ snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l73-objs := cs42l73.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cs4271-objs := cs4271.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
+snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
+snd-soc-lm4857-objs := lm4857.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
@@ -29,6 +32,8 @@ snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-alc5623-objs := alc5623.o
+snd-soc-alc5632-objs := alc5632.o
+snd-soc-sigmadsp-objs := sigmadsp.o
 snd-soc-sn95031-objs := sn95031.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
@@ -45,6 +50,7 @@ snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
+snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
@@ -81,21 +87,18 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
+snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
+snd-soc-wm9090-objs := wm9090.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
-snd-soc-jz4740-codec-objs := jz4740.o
 
 # Amp
-snd-soc-lm4857-objs := lm4857.o
 snd-soc-max9877-objs := max9877.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
-snd-soc-wm2000-objs := wm2000.o
-snd-soc-wm9090-objs := wm9090.o
 
 obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
@@ -113,8 +116,10 @@ obj-$(CONFIG_SND_SOC_AK4641)       += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
+obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS42L51)  += snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L73)  += snd-soc-cs42l73.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CS4271)   += snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
@@ -122,6 +127,7 @@ obj-$(CONFIG_SND_SOC_DA7210)        += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
+obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
@@ -129,6 +135,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)       += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
+obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
 obj-$(CONFIG_SND_SOC_SN95031)  +=snd-soc-sn95031.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
@@ -145,6 +152,7 @@ obj-$(CONFIG_SND_SOC_UDA134X)       += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
+obj-$(CONFIG_SND_SOC_WM2000)   += snd-soc-wm2000.o
 obj-$(CONFIG_SND_SOC_WM5100)   += snd-soc-wm5100.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)   += snd-soc-wm8400.o
@@ -184,14 +192,12 @@ obj-$(CONFIG_SND_SOC_WM8993)      += snd-soc-wm8993.o
 obj-$(CONFIG_SND_SOC_WM8994)   += snd-soc-wm8994.o
 obj-$(CONFIG_SND_SOC_WM8995)   += snd-soc-wm8995.o
 obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
+obj-$(CONFIG_SND_SOC_WM9090)   += snd-soc-wm9090.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
 
 # Amp
-obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
 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
-obj-$(CONFIG_SND_SOC_WM9090)   += snd-soc-wm9090.o
index e715186b430064a33c939b9863da91f734e2af54..1bbad4c16d289fe29f7c20702138db81f4f093d5 100644 (file)
@@ -39,7 +39,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops ac97_dai_ops = {
+static const struct snd_soc_dai_ops ac97_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
@@ -99,7 +99,7 @@ static int ac97_soc_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec)
 {
        snd_ac97_suspend(codec->ac97);
 
@@ -148,17 +148,7 @@ static struct platform_driver ac97_codec_driver = {
        .remove = __devexit_p(ac97_remove),
 };
 
-static int __init ac97_init(void)
-{
-       return platform_driver_register(&ac97_codec_driver);
-}
-module_init(ac97_init);
-
-static void __exit ac97_exit(void)
-{
-       platform_driver_unregister(&ac97_codec_driver);
-}
-module_exit(ac97_exit);
+module_platform_driver(ac97_codec_driver);
 
 MODULE_DESCRIPTION("Soc Generic AC97 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 4e5c5726366b12f4f2377e15da2bdea4598e6e98..982d201c2e8699589ab049544e517d2f69db3678 100644 (file)
@@ -189,7 +189,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops ad1836_dai_ops = {
+static const struct snd_soc_dai_ops ad1836_dai_ops = {
        .hw_params = ad1836_hw_params,
        .set_fmt = ad1836_set_dai_fmt,
 };
@@ -223,7 +223,7 @@ static struct snd_soc_dai_driver ad183x_dais[] = {
 };
 
 #ifdef CONFIG_PM
-static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int ad1836_suspend(struct snd_soc_codec *codec)
 {
        /* reset clock control mode */
        return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
@@ -341,7 +341,8 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
        struct ad1836_priv *ad1836;
        int ret;
 
-       ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+       ad1836 = devm_kzalloc(&spi->dev, sizeof(struct ad1836_priv),
+                             GFP_KERNEL);
        if (ad1836 == NULL)
                return -ENOMEM;
 
@@ -351,17 +352,15 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1);
-       if (ret < 0)
-               kfree(ad1836);
        return ret;
 }
 
 static int __devexit ad1836_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
+
 static const struct spi_device_id ad1836_ids[] = {
        { "ad1835", AD1835 },
        { "ad1836", AD1836 },
index 120602130b5c0a667cc612ab97877d016bb5a667..a4a6bef2c0bbd1372fafe48bde8129687138dc85 100644 (file)
@@ -30,21 +30,23 @@ struct ad193x_priv {
 /*
  * AD193X volume/mute/de-emphasis etc. controls
  */
-static const char *ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
+static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
 
 static const struct soc_enum ad193x_deemp_enum =
        SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp);
 
+static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0);
+
 static const struct snd_kcontrol_new ad193x_snd_controls[] = {
        /* DAC volume control */
-       SOC_DOUBLE_R("DAC1 Volume", AD193X_DAC_L1_VOL,
-                       AD193X_DAC_R1_VOL, 0, 0xFF, 1),
-       SOC_DOUBLE_R("DAC2 Volume", AD193X_DAC_L2_VOL,
-                       AD193X_DAC_R2_VOL, 0, 0xFF, 1),
-       SOC_DOUBLE_R("DAC3 Volume", AD193X_DAC_L3_VOL,
-                       AD193X_DAC_R3_VOL, 0, 0xFF, 1),
-       SOC_DOUBLE_R("DAC4 Volume", AD193X_DAC_L4_VOL,
-                       AD193X_DAC_R4_VOL, 0, 0xFF, 1),
+       SOC_DOUBLE_R_TLV("DAC1 Volume", AD193X_DAC_L1_VOL,
+                       AD193X_DAC_R1_VOL, 0, 0xFF, 1, adau193x_tlv),
+       SOC_DOUBLE_R_TLV("DAC2 Volume", AD193X_DAC_L2_VOL,
+                       AD193X_DAC_R2_VOL, 0, 0xFF, 1, adau193x_tlv),
+       SOC_DOUBLE_R_TLV("DAC3 Volume", AD193X_DAC_L3_VOL,
+                       AD193X_DAC_R3_VOL, 0, 0xFF, 1, adau193x_tlv),
+       SOC_DOUBLE_R_TLV("DAC4 Volume", AD193X_DAC_L4_VOL,
+                       AD193X_DAC_R4_VOL, 0, 0xFF, 1, adau193x_tlv),
 
        /* ADC switch control */
        SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
@@ -75,6 +77,7 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
        SND_SOC_DAPM_OUTPUT("DAC1OUT"),
        SND_SOC_DAPM_OUTPUT("DAC2OUT"),
        SND_SOC_DAPM_OUTPUT("DAC3OUT"),
@@ -84,16 +87,17 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route audio_paths[] = {
-       { "DAC", NULL, "PLL_PWR" },
-       { "ADC", NULL, "PLL_PWR" },
+       { "DAC", NULL, "SYSCLK" },
+       { "ADC", NULL, "SYSCLK" },
        { "DAC", NULL, "ADC_PWR" },
        { "ADC", NULL, "ADC_PWR" },
-       { "DAC1OUT", "DAC1 Switch", "DAC" },
-       { "DAC2OUT", "DAC2 Switch", "DAC" },
-       { "DAC3OUT", "DAC3 Switch", "DAC" },
-       { "DAC4OUT", "DAC4 Switch", "DAC" },
-       { "ADC", "ADC1 Switch", "ADC1IN" },
-       { "ADC", "ADC2 Switch", "ADC2IN" },
+       { "DAC1OUT", NULL, "DAC" },
+       { "DAC2OUT", NULL, "DAC" },
+       { "DAC3OUT", NULL, "DAC" },
+       { "DAC4OUT", NULL, "DAC" },
+       { "ADC", NULL, "ADC1IN" },
+       { "ADC", NULL, "ADC2IN" },
+       { "SYSCLK", NULL, "PLL_PWR" },
 };
 
 /*
@@ -102,14 +106,14 @@ static const struct snd_soc_dapm_route audio_paths[] = {
 
 static int ad193x_mute(struct snd_soc_dai *dai, int mute)
 {
-       struct snd_soc_codec *codec = dai->codec;
+       struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
 
        if (mute)
-               snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+               regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
                                    AD193X_DAC_MASTER_MUTE,
                                    AD193X_DAC_MASTER_MUTE);
        else
-               snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+               regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
                                    AD193X_DAC_MASTER_MUTE, 0);
 
        return 0;
@@ -118,36 +122,30 @@ static int ad193x_mute(struct snd_soc_dai *dai, int mute)
 static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                               unsigned int rx_mask, int slots, int width)
 {
-       struct snd_soc_codec *codec = dai->codec;
-       int dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1);
-       int adc_reg = snd_soc_read(codec, AD193X_ADC_CTRL2);
-
-       dac_reg &= ~AD193X_DAC_CHAN_MASK;
-       adc_reg &= ~AD193X_ADC_CHAN_MASK;
+       struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(dai->codec);
+       unsigned int channels;
 
        switch (slots) {
        case 2:
-               dac_reg |= AD193X_DAC_2_CHANNELS << AD193X_DAC_CHAN_SHFT;
-               adc_reg |= AD193X_ADC_2_CHANNELS << AD193X_ADC_CHAN_SHFT;
+               channels = AD193X_2_CHANNELS;
                break;
        case 4:
-               dac_reg |= AD193X_DAC_4_CHANNELS << AD193X_DAC_CHAN_SHFT;
-               adc_reg |= AD193X_ADC_4_CHANNELS << AD193X_ADC_CHAN_SHFT;
+               channels = AD193X_4_CHANNELS;
                break;
        case 8:
-               dac_reg |= AD193X_DAC_8_CHANNELS << AD193X_DAC_CHAN_SHFT;
-               adc_reg |= AD193X_ADC_8_CHANNELS << AD193X_ADC_CHAN_SHFT;
+               channels = AD193X_8_CHANNELS;
                break;
        case 16:
-               dac_reg |= AD193X_DAC_16_CHANNELS << AD193X_DAC_CHAN_SHFT;
-               adc_reg |= AD193X_ADC_16_CHANNELS << AD193X_ADC_CHAN_SHFT;
+               channels = AD193X_16_CHANNELS;
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg);
-       snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg);
+       regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
+               AD193X_DAC_CHAN_MASK, channels << AD193X_DAC_CHAN_SHFT);
+       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+               AD193X_ADC_CHAN_MASK, channels << AD193X_ADC_CHAN_SHFT);
 
        return 0;
 }
@@ -155,24 +153,20 @@ static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
-       struct snd_soc_codec *codec = codec_dai->codec;
-       int adc_reg1, adc_reg2, dac_reg;
-
-       adc_reg1 = snd_soc_read(codec, AD193X_ADC_CTRL1);
-       adc_reg2 = snd_soc_read(codec, AD193X_ADC_CTRL2);
-       dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1);
+       struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec_dai->codec);
+       unsigned int adc_serfmt = 0;
+       unsigned int adc_fmt = 0;
+       unsigned int dac_fmt = 0;
 
        /* 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)
         */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               adc_reg1 &= ~AD193X_ADC_SERFMT_MASK;
-               adc_reg1 |= AD193X_ADC_SERFMT_TDM;
+               adc_serfmt |= AD193X_ADC_SERFMT_TDM;
                break;
        case SND_SOC_DAIFMT_DSP_A:
-               adc_reg1 &= ~AD193X_ADC_SERFMT_MASK;
-               adc_reg1 |= AD193X_ADC_SERFMT_AUX;
+               adc_serfmt |= AD193X_ADC_SERFMT_AUX;
                break;
        default:
                return -EINVAL;
@@ -180,29 +174,20 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
-               adc_reg2 &= ~AD193X_ADC_LEFT_HIGH;
-               adc_reg2 &= ~AD193X_ADC_BCLK_INV;
-               dac_reg &= ~AD193X_DAC_LEFT_HIGH;
-               dac_reg &= ~AD193X_DAC_BCLK_INV;
                break;
        case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
-               adc_reg2 |= AD193X_ADC_LEFT_HIGH;
-               adc_reg2 &= ~AD193X_ADC_BCLK_INV;
-               dac_reg |= AD193X_DAC_LEFT_HIGH;
-               dac_reg &= ~AD193X_DAC_BCLK_INV;
+               adc_fmt |= AD193X_ADC_LEFT_HIGH;
+               dac_fmt |= AD193X_DAC_LEFT_HIGH;
                break;
        case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
-               adc_reg2 &= ~AD193X_ADC_LEFT_HIGH;
-               adc_reg2 |= AD193X_ADC_BCLK_INV;
-               dac_reg &= ~AD193X_DAC_LEFT_HIGH;
-               dac_reg |= AD193X_DAC_BCLK_INV;
+               adc_fmt |= AD193X_ADC_BCLK_INV;
+               dac_fmt |= AD193X_DAC_BCLK_INV;
                break;
-
        case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
-               adc_reg2 |= AD193X_ADC_LEFT_HIGH;
-               adc_reg2 |= AD193X_ADC_BCLK_INV;
-               dac_reg |= AD193X_DAC_LEFT_HIGH;
-               dac_reg |= AD193X_DAC_BCLK_INV;
+               adc_fmt |= AD193X_ADC_LEFT_HIGH;
+               adc_fmt |= AD193X_ADC_BCLK_INV;
+               dac_fmt |= AD193X_DAC_LEFT_HIGH;
+               dac_fmt |= AD193X_DAC_BCLK_INV;
                break;
        default:
                return -EINVAL;
@@ -210,36 +195,31 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
-               adc_reg2 |= AD193X_ADC_LCR_MASTER;
-               adc_reg2 |= AD193X_ADC_BCLK_MASTER;
-               dac_reg |= AD193X_DAC_LCR_MASTER;
-               dac_reg |= AD193X_DAC_BCLK_MASTER;
+               adc_fmt |= AD193X_ADC_LCR_MASTER;
+               adc_fmt |= AD193X_ADC_BCLK_MASTER;
+               dac_fmt |= AD193X_DAC_LCR_MASTER;
+               dac_fmt |= AD193X_DAC_BCLK_MASTER;
                break;
        case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
-               adc_reg2 |= AD193X_ADC_LCR_MASTER;
-               adc_reg2 &= ~AD193X_ADC_BCLK_MASTER;
-               dac_reg |= AD193X_DAC_LCR_MASTER;
-               dac_reg &= ~AD193X_DAC_BCLK_MASTER;
+               adc_fmt |= AD193X_ADC_LCR_MASTER;
+               dac_fmt |= AD193X_DAC_LCR_MASTER;
                break;
        case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
-               adc_reg2 &= ~AD193X_ADC_LCR_MASTER;
-               adc_reg2 |= AD193X_ADC_BCLK_MASTER;
-               dac_reg &= ~AD193X_DAC_LCR_MASTER;
-               dac_reg |= AD193X_DAC_BCLK_MASTER;
+               adc_fmt |= AD193X_ADC_BCLK_MASTER;
+               dac_fmt |= AD193X_DAC_BCLK_MASTER;
                break;
        case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
-               adc_reg2 &= ~AD193X_ADC_LCR_MASTER;
-               adc_reg2 &= ~AD193X_ADC_BCLK_MASTER;
-               dac_reg &= ~AD193X_DAC_LCR_MASTER;
-               dac_reg &= ~AD193X_DAC_BCLK_MASTER;
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_write(codec, AD193X_ADC_CTRL1, adc_reg1);
-       snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg2);
-       snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg);
+       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
+               AD193X_ADC_SERFMT_MASK, adc_serfmt);
+       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL2,
+               AD193X_ADC_FMT_MASK, adc_fmt);
+       regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL1,
+               AD193X_DAC_FMT_MASK, dac_fmt);
 
        return 0;
 }
@@ -299,20 +279,20 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       snd_soc_update_bits(codec, AD193X_PLL_CLK_CTRL0,
+       regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL0,
                            AD193X_PLL_INPUT_MASK, master_rate);
 
-       snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
+       regmap_update_bits(ad193x->regmap, AD193X_DAC_CTRL2,
                            AD193X_DAC_WORD_LEN_MASK,
                            word_len << AD193X_DAC_WORD_LEN_SHFT);
 
-       snd_soc_update_bits(codec, AD193X_ADC_CTRL1,
+       regmap_update_bits(ad193x->regmap, AD193X_ADC_CTRL1,
                            AD193X_ADC_WORD_LEN_MASK, word_len);
 
        return 0;
 }
 
-static struct snd_soc_dai_ops ad193x_dai_ops = {
+static const struct snd_soc_dai_ops ad193x_dai_ops = {
        .hw_params = ad193x_hw_params,
        .digital_mute = ad193x_mute,
        .set_tdm_slot = ad193x_set_tdm_slot,
@@ -345,7 +325,6 @@ static struct snd_soc_dai_driver ad193x_dai = {
 static int ad193x_probe(struct snd_soc_codec *codec)
 {
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        codec->control_data = ad193x->regmap;
@@ -358,32 +337,37 @@ static int ad193x_probe(struct snd_soc_codec *codec)
        /* default setting for ad193x */
 
        /* unmute dac channels */
-       snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
+       regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
        /* de-emphasis: 48kHz, powedown dac */
-       snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
+       regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
        /* powerdown dac, dac in tdm mode */
-       snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
+       regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41);
        /* high-pass filter enable */
-       snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
+       regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
        /* sata delay=1, adc aux mode */
-       snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
+       regmap_write(ad193x->regmap, AD193X_ADC_CTRL1, 0x43);
        /* pll input: mclki/xi */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
-
-       snd_soc_add_controls(codec, ad193x_snd_controls,
-                            ARRAY_SIZE(ad193x_snd_controls));
-       snd_soc_dapm_new_controls(dapm, ad193x_dapm_widgets,
-                                 ARRAY_SIZE(ad193x_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
+       regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+       regmap_write(ad193x->regmap, AD193X_PLL_CLK_CTRL1, 0x04);
 
        return ret;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
        .probe =        ad193x_probe,
+       .controls = ad193x_snd_controls,
+       .num_controls = ARRAY_SIZE(ad193x_snd_controls),
+       .dapm_widgets = ad193x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ad193x_dapm_widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
 };
 
+static bool adau193x_reg_volatile(struct device *dev, unsigned int reg)
+{
+       return false;
+}
+
 #if defined(CONFIG_SPI_MASTER)
 
 static const struct regmap_config ad193x_spi_regmap_config = {
@@ -391,6 +375,9 @@ static const struct regmap_config ad193x_spi_regmap_config = {
        .reg_bits = 16,
        .read_flag_mask = 0x09,
        .write_flag_mask = 0x08,
+
+       .max_register = AD193X_NUM_REGS - 1,
+       .volatile_reg = adau193x_reg_volatile,
 };
 
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
@@ -398,14 +385,15 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
        struct ad193x_priv *ad193x;
        int ret;
 
-       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),
+                             GFP_KERNEL);
        if (ad193x == NULL)
                return -ENOMEM;
 
        ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
        if (IS_ERR(ad193x->regmap)) {
                ret = PTR_ERR(ad193x->regmap);
-               goto err_free;
+               goto err_out;
        }
 
        spi_set_drvdata(spi, ad193x);
@@ -419,9 +407,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
 
 err_regmap_exit:
        regmap_exit(ad193x->regmap);
-err_free:
-       kfree(ad193x);
-
+err_out:
        return ret;
 }
 
@@ -431,7 +417,6 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
        snd_soc_unregister_codec(&spi->dev);
        regmap_exit(ad193x->regmap);
-       kfree(ad193x);
        return 0;
 }
 
@@ -450,6 +435,9 @@ static struct spi_driver ad193x_spi_driver = {
 static const struct regmap_config ad193x_i2c_regmap_config = {
        .val_bits = 8,
        .reg_bits = 8,
+
+       .max_register = AD193X_NUM_REGS - 1,
+       .volatile_reg = adau193x_reg_volatile,
 };
 
 static const struct i2c_device_id ad193x_id[] = {
@@ -465,14 +453,15 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
        struct ad193x_priv *ad193x;
        int ret;
 
-       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
+                             GFP_KERNEL);
        if (ad193x == NULL)
                return -ENOMEM;
 
        ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
        if (IS_ERR(ad193x->regmap)) {
                ret = PTR_ERR(ad193x->regmap);
-               goto err_free;
+               goto err_out;
        }
 
        i2c_set_clientdata(client, ad193x);
@@ -486,8 +475,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
 
 err_regmap_exit:
        regmap_exit(ad193x->regmap);
-err_free:
-       kfree(ad193x);
+err_out:
        return ret;
 }
 
@@ -497,7 +485,6 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
        snd_soc_unregister_codec(&client->dev);
        regmap_exit(ad193x->regmap);
-       kfree(ad193x);
        return 0;
 }
 
index 1507eaa425a3a06d8114e6c42ca3d7e175c17b51..47338804999233d2aaf4b6e61b79322a95848d87 100644 (file)
 #define AD193X_DAC_SERFMT_STEREO       (0 << 6)
 #define AD193X_DAC_SERFMT_TDM          (1 << 6)
 #define AD193X_DAC_CTRL1        0x03
-#define AD193X_DAC_2_CHANNELS   0
-#define AD193X_DAC_4_CHANNELS   1
-#define AD193X_DAC_8_CHANNELS   2
-#define AD193X_DAC_16_CHANNELS  3
 #define AD193X_DAC_CHAN_SHFT    1
 #define AD193X_DAC_CHAN_MASK    (3 << AD193X_DAC_CHAN_SHFT)
 #define AD193X_DAC_LCR_MASTER   (1 << 4)
 #define AD193X_DAC_BCLK_MASTER  (1 << 5)
 #define AD193X_DAC_LEFT_HIGH    (1 << 3)
 #define AD193X_DAC_BCLK_INV     (1 << 7)
+#define AD193X_DAC_FMT_MASK    (AD193X_DAC_LCR_MASTER | \
+       AD193X_DAC_BCLK_MASTER | AD193X_DAC_LEFT_HIGH | AD193X_DAC_BCLK_INV)
 #define AD193X_DAC_CTRL2        0x04
 #define AD193X_DAC_WORD_LEN_SHFT        3
 #define AD193X_DAC_WORD_LEN_MASK        0x18
 #define AD193X_ADC_SERFMT_AUX          (2 << 5)
 #define AD193X_ADC_WORD_LEN_MASK       0x3
 #define AD193X_ADC_CTRL2        0x10
-#define AD193X_ADC_2_CHANNELS   0
-#define AD193X_ADC_4_CHANNELS   1
-#define AD193X_ADC_8_CHANNELS   2
-#define AD193X_ADC_16_CHANNELS  3
 #define AD193X_ADC_CHAN_SHFT    4
 #define AD193X_ADC_CHAN_MASK    (3 << AD193X_ADC_CHAN_SHFT)
 #define AD193X_ADC_LCR_MASTER   (1 << 3)
 #define AD193X_ADC_BCLK_MASTER  (1 << 6)
 #define AD193X_ADC_LEFT_HIGH    (1 << 2)
 #define AD193X_ADC_BCLK_INV     (1 << 1)
+#define AD193X_ADC_FMT_MASK    (AD193X_ADC_LCR_MASTER | \
+       AD193X_ADC_BCLK_MASTER | AD193X_ADC_LEFT_HIGH | AD193X_ADC_BCLK_INV)
+
+#define AD193X_2_CHANNELS   0
+#define AD193X_4_CHANNELS   1
+#define AD193X_8_CHANNELS   2
+#define AD193X_16_CHANNELS  3
 
 #define AD193X_NUM_REGS          17
 
index e3931cc5e66c6736d75fa053e7755acfda7a8b8e..9bba7f849464391778e5c33f0076c0e20b3ea44f 100644 (file)
@@ -277,17 +277,7 @@ static struct platform_driver ad1980_codec_driver = {
        .remove = __devexit_p(ad1980_remove),
 };
 
-static int __init ad1980_init(void)
-{
-       return platform_driver_register(&ad1980_codec_driver);
-}
-module_init(ad1980_init);
-
-static void __exit ad1980_exit(void)
-{
-       platform_driver_unregister(&ad1980_codec_driver);
-}
-module_exit(ad1980_exit);
+module_platform_driver(ad1980_codec_driver);
 
 MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
 MODULE_AUTHOR("Roy Huang, Cliff Cai");
index 8d793e993e9a8a7110d2601141649a72072baee6..ee7a68dcefd2442b1650b16395025bc2eed39990 100644 (file)
@@ -63,17 +63,7 @@ static struct platform_driver ad73311_codec_driver = {
        .remove = __devexit_p(ad73311_remove),
 };
 
-static int __init ad73311_init(void)
-{
-       return platform_driver_register(&ad73311_codec_driver);
-}
-module_init(ad73311_init);
-
-static void __exit ad73311_exit(void)
-{
-       platform_driver_unregister(&ad73311_codec_driver);
-}
-module_exit(ad73311_exit);
+module_platform_driver(ad73311_codec_driver);
 
 MODULE_DESCRIPTION("ASoC ad73311 driver");
 MODULE_AUTHOR("Cliff Cai ");
index 45c63028b40d1636b56f6aa3e5f13e0d110b9a5d..971ba45291717d9c9c87dc662b07b23deb2b55a2 100644 (file)
@@ -1321,7 +1321,7 @@ static int adau1373_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int adau1373_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int adau1373_suspend(struct snd_soc_codec *codec)
 {
        return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
@@ -1360,7 +1360,7 @@ static int __devinit adau1373_i2c_probe(struct i2c_client *client,
        struct adau1373 *adau1373;
        int ret;
 
-       adau1373 = kzalloc(sizeof(*adau1373), GFP_KERNEL);
+       adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL);
        if (!adau1373)
                return -ENOMEM;
 
@@ -1368,16 +1368,12 @@ static int __devinit adau1373_i2c_probe(struct i2c_client *client,
 
        ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver,
                        adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver));
-       if (ret < 0)
-               kfree(adau1373);
-
        return ret;
 }
 
 static int __devexit adau1373_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(dev_get_drvdata(&client->dev));
        return 0;
 }
 
index 8b7e1c50d6e9df43d2a25956a698094eb2bb6738..6b325ea03869f4758247cec758c96ed71ab60b7e 100644 (file)
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
-#include <linux/sigma.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
+#include "sigmadsp.h"
 #include "adau1701.h"
 
 #define ADAU1701_DSPCTRL       0x1c
@@ -496,23 +496,19 @@ static __devinit int adau1701_i2c_probe(struct i2c_client *client,
        struct adau1701 *adau1701;
        int ret;
 
-       adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL);
+       adau1701 = devm_kzalloc(&client->dev, sizeof(*adau1701), GFP_KERNEL);
        if (!adau1701)
                return -ENOMEM;
 
        i2c_set_clientdata(client, adau1701);
        ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
                        &adau1701_dai, 1);
-       if (ret < 0)
-               kfree(adau1701);
-
        return ret;
 }
 
 static __devexit int adau1701_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index f9f08948e5e878f12d40a1f337d6d40c7247119e..ebd7b37b902bb4019dee2059a633c120d20cc4f7 100644 (file)
@@ -798,7 +798,7 @@ static int adav80x_probe(struct snd_soc_codec *codec)
        return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 }
 
-static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int adav80x_suspend(struct snd_soc_codec *codec)
 {
        return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
index 9082e0f729f307d626cd467bc0c777993cd987f8..8103b938b8c001214858e9a628ae60908424cde3 100644 (file)
@@ -58,17 +58,7 @@ static struct platform_driver ads117x_codec_driver = {
        .remove = __devexit_p(ads117x_remove),
 };
 
-static int __init ads117x_init(void)
-{
-       return platform_driver_register(&ads117x_codec_driver);
-}
-module_init(ads117x_init);
-
-static void __exit ads117x_exit(void)
-{
-       platform_driver_unregister(&ads117x_codec_driver);
-}
-module_exit(ads117x_exit);
+module_platform_driver(ads117x_codec_driver);
 
 MODULE_DESCRIPTION("ASoC ads117x driver");
 MODULE_AUTHOR("Graeme Gregory");
index d3b29dce6ed7f27c080e7059ed5fc067d0d3ad0a..d27b5e4cce99b58339300b860bc4bad1b924b87d 100644 (file)
@@ -170,7 +170,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
        return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
 }
 
-static struct snd_soc_dai_ops ak4101_dai_ops = {
+static const struct snd_soc_dai_ops ak4101_dai_ops = {
        .hw_params = ak4104_hw_params,
        .set_fmt = ak4104_set_dai_fmt,
 };
@@ -261,7 +261,8 @@ static int ak4104_spi_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
-       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+       ak4104 = devm_kzalloc(&spi->dev, sizeof(struct ak4104_private),
+                             GFP_KERNEL);
        if (ak4104 == NULL)
                return -ENOMEM;
 
@@ -271,15 +272,12 @@ static int ak4104_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_device_ak4104, &ak4104_dai, 1);
-       if (ret < 0)
-               kfree(ak4104);
        return ret;
 }
 
 static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
index 95d782d86e7d5fc906e122c23dd7ae48ff39fd4a..9e809e05d06644aa52fb11bf4ad96867c5c63aef 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -331,7 +330,7 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
                SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops ak4535_dai_ops = {
+static const struct snd_soc_dai_ops ak4535_dai_ops = {
        .hw_params      = ak4535_hw_params,
        .set_fmt        = ak4535_set_dai_fmt,
        .digital_mute   = ak4535_mute,
@@ -355,7 +354,7 @@ static struct snd_soc_dai_driver ak4535_dai = {
        .ops = &ak4535_dai_ops,
 };
 
-static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec)
 {
        ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -417,7 +416,8 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
        struct ak4535_priv *ak4535;
        int ret;
 
-       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+       ak4535 = devm_kzalloc(&i2c->dev, sizeof(struct ak4535_priv),
+                             GFP_KERNEL);
        if (ak4535 == NULL)
                return -ENOMEM;
 
@@ -426,15 +426,12 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_ak4535, &ak4535_dai, 1);
-       if (ret < 0)
-               kfree(ak4535);
        return ret;
 }
 
 static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 77838586f3588ffc61960f70cfaea2a29b6bfccf..c4d165a4bddf522f3557d86d111ccbfc1bc9148e 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/gpio.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -340,6 +339,7 @@ static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        u8 btif;
+       int ret;
 
        /* interface format */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -359,7 +359,11 @@ static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+       ret = snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -442,14 +446,14 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
                         SNDRV_PCM_RATE_16000)
 #define AK4641_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
-static struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
+static const struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
        .hw_params    = ak4641_i2s_hw_params,
        .set_fmt      = ak4641_i2s_set_dai_fmt,
        .digital_mute = ak4641_mute,
        .set_sysclk   = ak4641_set_dai_sysclk,
 };
 
-static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
+static const struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
        .hw_params    = NULL, /* rates are controlled by BT chip */
        .set_fmt      = ak4641_pcm_set_dai_fmt,
        .digital_mute = ak4641_mute,
@@ -499,7 +503,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
 },
 };
 
-static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int ak4641_suspend(struct snd_soc_codec *codec)
 {
        ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -603,7 +607,8 @@ static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
        struct ak4641_priv *ak4641;
        int ret;
 
-       ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL);
+       ak4641 = devm_kzalloc(&i2c->dev, sizeof(struct ak4641_priv),
+                             GFP_KERNEL);
        if (!ak4641)
                return -ENOMEM;
 
@@ -611,16 +616,12 @@ static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
                                ak4641_dai, ARRAY_SIZE(ak4641_dai));
-       if (ret < 0)
-               kfree(ak4641);
-
        return ret;
 }
 
 static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
 {
        snd_soc_unregister_codec(&i2c->dev);
-       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
index 12c1bdef67323f5f260290c037ce23f50dff42de..5ef70b5d27e4eae85f6e4e1a1c310ea273e0eb60 100644 (file)
  * This is very simple driver.
  * It can use headphone output / stereo input only
  *
- * AK4642 is not tested.
+ * AK4642 is tested.
  * AK4643 is tested.
+ * AK4648 is tested.
  */
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#define AK4642_VERSION "0.0.1"
-
 #define PW_MGMT1       0x00
 #define PW_MGMT2       0x01
 #define SG_SL1         0x02
@@ -71,8 +69,6 @@
 #define HP_MS          0x23
 #define SPK_MS         0x24
 
-#define AK4642_CACHEREGNUM     0x25
-
 /* PW_MGMT1*/
 #define PMVCM          (1 << 6) /* VCOM Power Management */
 #define PMMIN          (1 << 5) /* MIN Input Power Management */
@@ -150,8 +146,52 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
 
        SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
                         0, 0xFF, 1, out_tlv),
+
+       SOC_SINGLE("Headphone Switch", PW_MGMT2, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4642_hpout_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACH", MD_CTL4, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = {
+       SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
+
+       /* Outputs */
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT"),
+
+       SND_SOC_DAPM_MIXER("HPOUTL Mixer", PW_MGMT2, 5, 0,
+                          &ak4642_hpout_mixer_controls[0],
+                          ARRAY_SIZE(ak4642_hpout_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("HPOUTR Mixer", PW_MGMT2, 4, 0,
+                          &ak4642_hpout_mixer_controls[0],
+                          ARRAY_SIZE(ak4642_hpout_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("LINEOUT Mixer", PW_MGMT1, 3, 0,
+                          &ak4642_lout_mixer_controls[0],
+                          ARRAY_SIZE(ak4642_lout_mixer_controls)),
+
+       /* DAC */
+       SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0),
 };
 
+static const struct snd_soc_dapm_route ak4642_intercon[] = {
+
+       /* Outputs */
+       {"HPOUTL", NULL, "HPOUTL Mixer"},
+       {"HPOUTR", NULL, "HPOUTR Mixer"},
+       {"LINEOUT", NULL, "LINEOUT Mixer"},
+
+       {"HPOUTL Mixer", "DACH", "DAC"},
+       {"HPOUTR Mixer", "DACH", "DAC"},
+       {"LINEOUT Mixer", "DACL", "DAC"},
+};
 
 /* codec private data */
 struct ak4642_priv {
@@ -162,7 +202,7 @@ struct ak4642_priv {
 /*
  * ak4642 register cache
  */
-static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
+static const u8 ak4642_reg[] = {
        0x00, 0x00, 0x01, 0x00,
        0x02, 0x00, 0x00, 0x00,
        0xe1, 0xe1, 0x18, 0x00,
@@ -175,6 +215,19 @@ static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
        0x00,
 };
 
+static const u8 ak4648_reg[] = {
+       0x00, 0x00, 0x01, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0xe1, 0xe1, 0x18, 0x00,
+       0xe1, 0x18, 0x11, 0xb8,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x88, 0x88, 0x08,
+};
+
 static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
@@ -192,14 +245,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                 * This operation came from example code of
                 * "ASAHI KASEI AK4642" (japanese) manual p97.
                 */
-               snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
-               snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
                snd_soc_write(codec, L_IVC, 0x91); /* volume */
                snd_soc_write(codec, R_IVC, 0x91); /* volume */
-               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
-                                                    PMVCM | PMMIN | PMDAC);
-               snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
-               snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     HPMTN);
        } else {
                /*
                 * start stereo input
@@ -217,8 +264,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                snd_soc_write(codec, SG_SL1, PMMP | MGAIN0);
                snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
                snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
-               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
-                                                    PMVCM | PMADL);
+               snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL);
                snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
        }
 
@@ -232,12 +278,6 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
 
        if (is_play) {
-               /* stop headphone output */
-               snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     0);
-               snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
-               snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
-               snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
-               snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
        } else {
                /* stop stereo input */
                snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
@@ -376,7 +416,23 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops ak4642_dai_ops = {
+static int ak4642_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, PW_MGMT1, 0x00);
+               break;
+       default:
+               snd_soc_update_bits(codec, PW_MGMT1, PMVCM, PMVCM);
+               break;
+       }
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ak4642_dai_ops = {
        .startup        = ak4642_dai_startup,
        .shutdown       = ak4642_dai_shutdown,
        .set_sysclk     = ak4642_dai_set_sysclk,
@@ -414,8 +470,6 @@ static int ak4642_probe(struct snd_soc_codec *codec)
        struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -425,15 +479,43 @@ static int ak4642_probe(struct snd_soc_codec *codec)
        snd_soc_add_controls(codec, ak4642_snd_controls,
                             ARRAY_SIZE(ak4642_snd_controls));
 
+       ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+static int ak4642_remove(struct snd_soc_codec *codec)
+{
+       ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
        .probe                  = ak4642_probe,
+       .remove                 = ak4642_remove,
+       .resume                 = ak4642_resume,
+       .set_bias_level         = ak4642_set_bias_level,
+       .reg_cache_default      = ak4642_reg,                   /* ak4642 reg */
+       .reg_cache_size         = ARRAY_SIZE(ak4642_reg),       /* ak4642 reg */
+       .reg_word_size          = sizeof(u8),
+       .dapm_widgets           = ak4642_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(ak4642_dapm_widgets),
+       .dapm_routes            = ak4642_intercon,
+       .num_dapm_routes        = ARRAY_SIZE(ak4642_intercon),
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
+       .probe                  = ak4642_probe,
+       .remove                 = ak4642_remove,
        .resume                 = ak4642_resume,
-       .reg_cache_size         = ARRAY_SIZE(ak4642_reg),
+       .set_bias_level         = ak4642_set_bias_level,
+       .reg_cache_default      = ak4648_reg,                   /* ak4648 reg */
+       .reg_cache_size         = ARRAY_SIZE(ak4648_reg),       /* ak4648 reg */
        .reg_word_size          = sizeof(u8),
-       .reg_cache_default      = ak4642_reg,
+       .dapm_widgets           = ak4642_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(ak4642_dapm_widgets),
+       .dapm_routes            = ak4642_intercon,
+       .num_dapm_routes        = ARRAY_SIZE(ak4642_intercon),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -443,7 +525,8 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
        struct ak4642_priv *ak4642;
        int ret;
 
-       ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
+       ak4642 = devm_kzalloc(&i2c->dev, sizeof(struct ak4642_priv),
+                             GFP_KERNEL);
        if (!ak4642)
                return -ENOMEM;
 
@@ -451,22 +534,21 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
        ak4642->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
-                       &soc_codec_dev_ak4642, &ak4642_dai, 1);
-       if (ret < 0)
-               kfree(ak4642);
+                               (struct snd_soc_codec_driver *)id->driver_data,
+                               &ak4642_dai, 1);
        return ret;
 }
 
 static __devexit int ak4642_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
 static const struct i2c_device_id ak4642_i2c_id[] = {
-       { "ak4642", 0 },
-       { "ak4643", 0 },
+       { "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
+       { "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
+       { "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
index de9ff66d3721d5dd367b2fc3f60178d9d5ee9e7c..a53b152e6a07a529fc4e1298fc33bc4ccb3abdb2 100644 (file)
@@ -594,7 +594,7 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
 
 #define AK4671_FORMATS         SNDRV_PCM_FMTBIT_S16_LE
 
-static struct snd_soc_dai_ops ak4671_dai_ops = {
+static const struct snd_soc_dai_ops ak4671_dai_ops = {
        .hw_params      = ak4671_hw_params,
        .set_sysclk     = ak4671_set_dai_sysclk,
        .set_fmt        = ak4671_set_dai_fmt,
@@ -661,7 +661,8 @@ static int __devinit ak4671_i2c_probe(struct i2c_client *client,
        struct ak4671_priv *ak4671;
        int ret;
 
-       ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
+       ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv),
+                             GFP_KERNEL);
        if (ak4671 == NULL)
                return -ENOMEM;
 
@@ -670,15 +671,12 @@ static int __devinit ak4671_i2c_probe(struct i2c_client *client,
 
        ret = snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_ak4671, &ak4671_dai, 1);
-       if (ret < 0)
-               kfree(ak4671);
        return ret;
 }
 
 static __devexit int ak4671_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 984b14bcb6054bfbaa3d5f84ac7d60613d0f5c2c..3feee569ceea1bacab11ac78ad6b83bbf01bab7b 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -100,7 +99,7 @@ static const unsigned int boost_tlv[] = {
 };
 static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
 
-static const struct snd_kcontrol_new rt5621_vol_snd_controls[] = {
+static const struct snd_kcontrol_new alc5621_vol_snd_controls[] = {
        SOC_DOUBLE_TLV("Speaker Playback Volume",
                        ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
        SOC_DOUBLE("Speaker Playback Switch",
@@ -111,7 +110,7 @@ static const struct snd_kcontrol_new rt5621_vol_snd_controls[] = {
                        ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
 };
 
-static const struct snd_kcontrol_new rt5622_vol_snd_controls[] = {
+static const struct snd_kcontrol_new alc5622_vol_snd_controls[] = {
        SOC_DOUBLE_TLV("Speaker Playback Volume",
                        ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
        SOC_DOUBLE("Speaker Playback Switch",
@@ -839,7 +838,7 @@ static int alc5623_set_bias_level(struct snd_soc_codec *codec,
                        | SNDRV_PCM_FMTBIT_S24_LE \
                        | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops alc5623_dai_ops = {
+static const struct snd_soc_dai_ops alc5623_dai_ops = {
                .hw_params = alc5623_pcm_hw_params,
                .digital_mute = alc5623_mute,
                .set_fmt = alc5623_set_dai_fmt,
@@ -869,7 +868,7 @@ static struct snd_soc_dai_driver alc5623_dai = {
        .ops = &alc5623_dai_ops,
 };
 
-static int alc5623_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
+static int alc5623_suspend(struct snd_soc_codec *codec)
 {
        alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -926,12 +925,12 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 
        switch (alc5623->id) {
        case 0x21:
-               snd_soc_add_controls(codec, rt5621_vol_snd_controls,
-                       ARRAY_SIZE(rt5621_vol_snd_controls));
+               snd_soc_add_controls(codec, alc5621_vol_snd_controls,
+                       ARRAY_SIZE(alc5621_vol_snd_controls));
                break;
        case 0x22:
-               snd_soc_add_controls(codec, rt5622_vol_snd_controls,
-                       ARRAY_SIZE(rt5622_vol_snd_controls));
+               snd_soc_add_controls(codec, alc5622_vol_snd_controls,
+                       ARRAY_SIZE(alc5622_vol_snd_controls));
                break;
        case 0x23:
                snd_soc_add_controls(codec, alc5623_vol_snd_controls,
@@ -1023,7 +1022,8 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 
        dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2);
 
-       alc5623 = kzalloc(sizeof(struct alc5623_priv), GFP_KERNEL);
+       alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
+                              GFP_KERNEL);
        if (alc5623 == NULL)
                return -ENOMEM;
 
@@ -1045,7 +1045,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
                alc5623_dai.name = "alc5623-hifi";
                break;
        default:
-               kfree(alc5623);
                return -EINVAL;
        }
 
@@ -1054,20 +1053,15 @@ static int alc5623_i2c_probe(struct i2c_client *client,
 
        ret =  snd_soc_register_codec(&client->dev,
                &soc_codec_device_alc5623, &alc5623_dai, 1);
-       if (ret != 0) {
+       if (ret != 0)
                dev_err(&client->dev, "Failed to register codec: %d\n", ret);
-               kfree(alc5623);
-       }
 
        return ret;
 }
 
 static int alc5623_i2c_remove(struct i2c_client *client)
 {
-       struct alc5623_priv *alc5623 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       kfree(alc5623);
        return 0;
 }
 
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
new file mode 100644 (file)
index 0000000..390e437
--- /dev/null
@@ -0,0 +1,1159 @@
+/*
+* alc5632.c  --  ALC5632 ALSA SoC Audio Codec
+*
+* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+*
+* Authors:  Leon Romanovsky <leon@leon.nu>
+*           Andrey Danin <danindrey@mail.ru>
+*           Ilya Petrov <ilya.muromec@gmail.com>
+*           Marc Dietrich <marvin24@gmx.de>
+*
+* Based on alc5623.c by Arnaud Patard
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include "alc5632.h"
+
+/*
+ * ALC5632 register cache
+ */
+static struct reg_default  alc5632_reg_defaults[] = {
+       {   2, 0x8080 },        /* R2   - Speaker Output Volume */
+       {   4, 0x8080 },        /* R4   - Headphone Output Volume */
+       {   6, 0x8080 },        /* R6   - AUXOUT Volume */
+       {   8, 0xC800 },        /* R8   - Phone Input */
+       {  10, 0xE808 },        /* R10  - LINE_IN Volume */
+       {  12, 0x1010 },        /* R12  - STEREO DAC Input Volume */
+       {  14, 0x0808 },        /* R14  - MIC Input Volume */
+       {  16, 0xEE0F },        /* R16  - Stereo DAC and MIC Routing Control */
+       {  18, 0xCBCB },        /* R18  - ADC Record Gain */
+       {  20, 0x7F7F },        /* R20  - ADC Record Mixer Control */
+       {  24, 0xE010 },        /* R24  - Voice DAC Volume */
+       {  28, 0x8008 },        /* R28  - Output Mixer Control */
+       {  34, 0x0000 },        /* R34  - Microphone Control */
+       {  36, 0x00C0 },    /* R36  - Codec Digital MIC/Digital Boost
+                                                  Control */
+       {  46, 0x0000 },        /* R46  - Stereo DAC/Voice DAC/Stereo ADC
+                                                  Function Select */
+       {  52, 0x8000 },        /* R52  - Main Serial Data Port Control
+                                                  (Stereo I2S) */
+       {  54, 0x0000 },        /* R54  - Extend Serial Data Port Control
+                                                  (VoDAC_I2S/PCM) */
+       {  58, 0x0000 },        /* R58  - Power Management Addition 1 */
+       {  60, 0x0000 },        /* R60  - Power Management Addition 2 */
+       {  62, 0x8000 },        /* R62  - Power Management Addition 3 */
+       {  64, 0x0C0A },        /* R64  - General Purpose Control Register 1 */
+       {  66, 0x0000 },        /* R66  - General Purpose Control Register 2 */
+       {  68, 0x0000 },        /* R68  - PLL1 Control */
+       {  70, 0x0000 },        /* R70  - PLL2 Control */
+       {  76, 0xBE3E },        /* R76  - GPIO Pin Configuration */
+       {  78, 0xBE3E },        /* R78  - GPIO Pin Polarity */
+       {  80, 0x0000 },        /* R80  - GPIO Pin Sticky */
+       {  82, 0x0000 },        /* R82  - GPIO Pin Wake Up */
+       {  86, 0x0000 },        /* R86  - Pin Sharing */
+       {  90, 0x0009 },        /* R90  - Soft Volume Control Setting */
+       {  92, 0x0000 },        /* R92  - GPIO_Output Pin Control */
+       {  94, 0x3000 },        /* R94  - MISC Control */
+       {  96, 0x3075 },        /* R96  - Stereo DAC Clock Control_1 */
+       {  98, 0x1010 },        /* R98  - Stereo DAC Clock Control_2 */
+       { 100, 0x3110 },        /* R100 - VoDAC_PCM Clock Control_1 */
+       { 104, 0x0553 },        /* R104 - Pseudo Stereo and Spatial Effect
+                                                  Block Control */
+       { 106, 0x0000 },        /* R106 - Private Register Address */
+};
+
+/* codec private data */
+struct alc5632_priv {
+       struct regmap *regmap;
+       u8 id;
+       unsigned int sysclk;
+};
+
+static bool alc5632_volatile_register(struct device *dev,
+                                                       unsigned int reg)
+{
+       switch (reg) {
+       case ALC5632_RESET:
+       case ALC5632_PWR_DOWN_CTRL_STATUS:
+       case ALC5632_GPIO_PIN_STATUS:
+       case ALC5632_OVER_CURR_STATUS:
+       case ALC5632_HID_CTRL_DATA:
+       case ALC5632_EQ_CTRL:
+       case ALC5632_VENDOR_ID1:
+       case ALC5632_VENDOR_ID2:
+               return true;
+
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static inline int alc5632_reset(struct regmap *map)
+{
+       return regmap_write(map, ALC5632_RESET, 0x59B4);
+}
+
+static int amp_mixer_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       /* to power-on/off class-d amp generators/speaker */
+       /* need to write to 'index-46h' register :        */
+       /* so write index num (here 0x46) to reg 0x6a     */
+       /* and then 0xffff/0 to reg 0x6c                  */
+       snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0);
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * ALC5632 Controls
+ */
+
+/* -34.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
+/* -46.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
+/* -16.5db min scale, 1.5db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
+static const unsigned int boost_tlv[] = {
+       TLV_DB_RANGE_HEAD(3),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+/* 0db min scale, 6 db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
+/* 0db min scalem 0.75db steps, no mute */
+static const DECLARE_TLV_DB_SCALE(vdac_tlv, -3525, 075, 0);
+
+static const struct snd_kcontrol_new alc5632_vol_snd_controls[] = {
+       /* left starts at bit 8, right at bit 0 */
+       /* 31 steps (5 bit), -46.5db scale */
+       SOC_DOUBLE_TLV("Speaker Playback Volume",
+                       ALC5632_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       /* bit 15 mutes left, bit 7 right */
+       SOC_DOUBLE("Speaker Playback Switch",
+                       ALC5632_SPK_OUT_VOL, 15, 7, 1, 1),
+       SOC_DOUBLE_TLV("Headphone Playback Volume",
+                       ALC5632_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Headphone Playback Switch",
+                       ALC5632_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_snd_controls[] = {
+       SOC_DOUBLE_TLV("Auxout Playback Volume",
+                       ALC5632_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Auxout Playback Switch",
+                       ALC5632_AUX_OUT_VOL, 15, 7, 1, 1),
+       SOC_SINGLE_TLV("Voice DAC Playback Volume",
+                       ALC5632_VOICE_DAC_VOL, 0, 63, 0, vdac_tlv),
+       SOC_SINGLE_TLV("Phone Capture Volume",
+                       ALC5632_PHONE_IN_VOL, 8, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("LineIn Capture Volume",
+                       ALC5632_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("Master Playback Volume",
+                       ALC5632_STEREO_DAC_IN_VOL, 8, 0, 63, 1, vdac_tlv),
+       SOC_DOUBLE("Master Playback Switch",
+                       ALC5632_STEREO_DAC_IN_VOL, 15, 7, 1, 1),
+       SOC_SINGLE_TLV("Mic1 Capture Volume",
+                       ALC5632_MIC_VOL, 8, 31, 1, vol_tlv),
+       SOC_SINGLE_TLV("Mic2 Capture Volume",
+                       ALC5632_MIC_VOL, 0, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("Rec Capture Volume",
+                       ALC5632_ADC_REC_GAIN, 8, 0, 31, 0, adc_rec_tlv),
+       SOC_SINGLE_TLV("Mic 1 Boost Volume",
+                       ALC5632_MIC_CTRL, 10, 2, 0, boost_tlv),
+       SOC_SINGLE_TLV("Mic 2 Boost Volume",
+                       ALC5632_MIC_CTRL, 8, 2, 0, boost_tlv),
+       SOC_SINGLE_TLV("Digital Boost Volume",
+                       ALC5632_DIGI_BOOST_CTRL, 0, 7, 0, dig_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+static const struct snd_kcontrol_new alc5632_hp_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5632_LINE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("PHONE2HP Playback Switch", ALC5632_PHONE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("VOICE2HP Playback Switch", ALC5632_VOICE_DAC_VOL, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_hpl_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5632_ADC_REC_GAIN, 15, 1, 1),
+SOC_DAPM_SINGLE("DACL2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 3, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_hpr_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5632_ADC_REC_GAIN, 7, 1, 1),
+SOC_DAPM_SINGLE("DACR2HP Playback Switch", ALC5632_MIC_ROUTING_CTRL, 2, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5632_ADC_REC_GAIN, 14, 1, 1),
+SOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5632_ADC_REC_GAIN, 6, 1, 1),
+SOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5632_LINE_IN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC12MONO Playback Switch",
+                                       ALC5632_MIC_ROUTING_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC22MONO Playback Switch",
+                                       ALC5632_MIC_ROUTING_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5632_MIC_ROUTING_CTRL, 0, 1, 1),
+SOC_DAPM_SINGLE("VOICE2MONO Playback Switch", ALC5632_VOICE_DAC_VOL, 13, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5632_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2SPK Playback Switch", ALC5632_LINE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("PHONE2SPK Playback Switch", ALC5632_PHONE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC12SPK Playback Switch",
+                                       ALC5632_MIC_ROUTING_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22SPK Playback Switch",
+                                       ALC5632_MIC_ROUTING_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("DAC2SPK Playback Switch", ALC5632_MIC_ROUTING_CTRL, 1, 1, 1),
+SOC_DAPM_SINGLE("VOICE2SPK Playback Switch", ALC5632_VOICE_DAC_VOL, 14, 1, 1),
+};
+
+/* Left Record Mixer */
+static const struct snd_kcontrol_new alc5632_captureL_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("LineInL Capture Switch", ALC5632_ADC_REC_MIXER, 12, 1, 1),
+SOC_DAPM_SINGLE("Left Phone Capture Switch", ALC5632_ADC_REC_MIXER, 11, 1, 1),
+SOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5632_ADC_REC_MIXER, 10, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 9, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 8, 1, 1),
+};
+
+/* Right Record Mixer */
+static const struct snd_kcontrol_new alc5632_captureR_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5632_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5632_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("LineInR Capture Switch", ALC5632_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("Right Phone Capture Switch", ALC5632_ADC_REC_MIXER, 3, 1, 1),
+SOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5632_ADC_REC_MIXER, 2, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5632_ADC_REC_MIXER, 1, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5632_ADC_REC_MIXER, 0, 1, 1),
+};
+
+static const char *alc5632_spk_n_sour_sel[] = {
+               "RN/-R", "RP/+R", "LN/-R", "Mute"};
+static const char *alc5632_hpl_out_input_sel[] = {
+               "Vmid", "HP Left Mix"};
+static const char *alc5632_hpr_out_input_sel[] = {
+               "Vmid", "HP Right Mix"};
+static const char *alc5632_spkout_input_sel[] = {
+               "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char *alc5632_aux_out_input_sel[] = {
+               "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+
+/* auxout output mux */
+static const struct soc_enum alc5632_aux_out_input_enum =
+SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel);
+static const struct snd_kcontrol_new alc5632_auxout_mux_controls =
+SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum);
+
+/* speaker output mux */
+static const struct soc_enum alc5632_spkout_input_enum =
+SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel);
+static const struct snd_kcontrol_new alc5632_spkout_mux_controls =
+SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum);
+
+/* headphone left output mux */
+static const struct soc_enum alc5632_hpl_out_input_enum =
+SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel);
+static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum);
+
+/* headphone right output mux */
+static const struct soc_enum alc5632_hpr_out_input_enum =
+SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel);
+static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum);
+
+/* speaker output N select */
+static const struct soc_enum alc5632_spk_n_sour_enum =
+SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel);
+static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls =
+SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum);
+
+/* speaker amplifier */
+static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"};
+static const struct soc_enum alc5632_amp_enum =
+       SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names);
+static const struct snd_kcontrol_new alc5632_amp_mux_controls =
+       SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum);
+
+
+static const struct snd_soc_dapm_widget alc5632_dapm_widgets[] = {
+/* Muxes */
+SND_SOC_DAPM_MUX("AuxOut Mux", SND_SOC_NOPM, 0, 0,
+       &alc5632_auxout_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut Mux", SND_SOC_NOPM, 0, 0,
+       &alc5632_spkout_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+       &alc5632_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+       &alc5632_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0,
+       &alc5632_spkoutn_mux_controls),
+
+/* output mixers */
+SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0,
+       &alc5632_hp_mixer_controls[0],
+       ARRAY_SIZE(alc5632_hp_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPR Mix", ALC5632_PWR_MANAG_ADD2, 4, 0,
+       &alc5632_hpr_mixer_controls[0],
+       ARRAY_SIZE(alc5632_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPL Mix", ALC5632_PWR_MANAG_ADD2, 5, 0,
+       &alc5632_hpl_mixer_controls[0],
+       ARRAY_SIZE(alc5632_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPOut Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Mono Mix", ALC5632_PWR_MANAG_ADD2, 2, 0,
+       &alc5632_mono_mixer_controls[0],
+       ARRAY_SIZE(alc5632_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mix", ALC5632_PWR_MANAG_ADD2, 3, 0,
+       &alc5632_speaker_mixer_controls[0],
+       ARRAY_SIZE(alc5632_speaker_mixer_controls)),
+
+/* input mixers */
+SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5632_PWR_MANAG_ADD2, 1, 0,
+       &alc5632_captureL_mixer_controls[0],
+       ARRAY_SIZE(alc5632_captureL_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Capture Mix", ALC5632_PWR_MANAG_ADD2, 0, 0,
+       &alc5632_captureR_mixer_controls[0],
+       ARRAY_SIZE(alc5632_captureR_mixer_controls)),
+
+SND_SOC_DAPM_DAC("Left DAC", "HiFi Playback",
+       ALC5632_PWR_MANAG_ADD2, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", "HiFi Playback",
+       ALC5632_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_MIXER("DAC Left Channel", ALC5632_PWR_MANAG_ADD1, 15, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("DAC Right Channel",
+       ALC5632_PWR_MANAG_ADD1, 14, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("I2S Mix", ALC5632_PWR_MANAG_ADD1, 11, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Phone Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_ADC("Left ADC", "HiFi Capture",
+       ALC5632_PWR_MANAG_ADD2, 7, 0),
+SND_SOC_DAPM_ADC("Right ADC", "HiFi Capture",
+       ALC5632_PWR_MANAG_ADD2, 6, 0),
+SND_SOC_DAPM_PGA("Left Headphone", ALC5632_PWR_MANAG_ADD3, 11, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", ALC5632_PWR_MANAG_ADD3, 10, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left Speaker", ALC5632_PWR_MANAG_ADD3, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Speaker", ALC5632_PWR_MANAG_ADD3, 12, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Aux Out", ALC5632_PWR_MANAG_ADD3, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left LineIn", ALC5632_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right LineIn", ALC5632_PWR_MANAG_ADD3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Phone", ALC5632_PWR_MANAG_ADD3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Phone ADMix", ALC5632_PWR_MANAG_ADD3, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 PGA", ALC5632_PWR_MANAG_ADD3, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 PGA", ALC5632_PWR_MANAG_ADD3, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 Pre Amp", ALC5632_PWR_MANAG_ADD3, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 Pre Amp", ALC5632_PWR_MANAG_ADD3, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ALC5632_PWR_MANAG_ADD1, 3, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ALC5632_PWR_MANAG_ADD1, 2, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_E("D Amp", ALC5632_PWR_MANAG_ADD2, 14, 0, NULL, 0,
+       amp_mixer_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA("AB Amp", ALC5632_PWR_MANAG_ADD2, 15, 0, NULL, 0),
+SND_SOC_DAPM_MUX("AB-D Amp Mux", ALC5632_PWR_MANAG_ADD1, 10, 0,
+       &alc5632_amp_mux_controls),
+
+SND_SOC_DAPM_OUTPUT("AUXOUT"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("PHONEP"),
+SND_SOC_DAPM_INPUT("PHONEN"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_VMID("Vmid"),
+};
+
+
+static const struct snd_soc_dapm_route alc5632_dapm_routes[] = {
+       /* virtual mixer - mixes left & right channels */
+       {"I2S Mix",     NULL,   "Left DAC"},
+       {"I2S Mix",     NULL,   "Right DAC"},
+       {"Line Mix",    NULL,   "Right LineIn"},
+       {"Line Mix",    NULL,   "Left LineIn"},
+       {"Phone Mix",   NULL,   "Phone"},
+       {"Phone Mix",   NULL,   "Phone ADMix"},
+       {"AUXOUT",              NULL,   "Aux Out"},
+
+       /* DAC */
+       {"DAC Right Channel",   NULL,   "I2S Mix"},
+       {"DAC Left Channel",    NULL,   "I2S Mix"},
+
+       /* HP mixer */
+       {"HPL Mix",     "ADC2HP_L Playback Switch",     "Left Capture Mix"},
+       {"HPL Mix", NULL,                                       "HP Mix"},
+       {"HPR Mix", "ADC2HP_R Playback Switch", "Right Capture Mix"},
+       {"HPR Mix", NULL,                                       "HP Mix"},
+       {"HP Mix",      "LI2HP Playback Switch",        "Line Mix"},
+       {"HP Mix",      "PHONE2HP Playback Switch",     "Phone Mix"},
+       {"HP Mix",      "MIC12HP Playback Switch",      "MIC1 PGA"},
+       {"HP Mix",      "MIC22HP Playback Switch",      "MIC2 PGA"},
+
+       {"HPR Mix", "DACR2HP Playback Switch",  "DAC Right Channel"},
+       {"HPL Mix", "DACL2HP Playback Switch",  "DAC Left Channel"},
+
+       /* speaker mixer */
+       {"Speaker Mix", "LI2SPK Playback Switch",       "Line Mix"},
+       {"Speaker Mix", "PHONE2SPK Playback Switch", "Phone Mix"},
+       {"Speaker Mix", "MIC12SPK Playback Switch",     "MIC1 PGA"},
+       {"Speaker Mix", "MIC22SPK Playback Switch",     "MIC2 PGA"},
+       {"Speaker Mix", "DAC2SPK Playback Switch",      "DAC Left Channel"},
+
+
+
+       /* mono mixer */
+       {"Mono Mix", "ADC2MONO_L Playback Switch",      "Left Capture Mix"},
+       {"Mono Mix", "ADC2MONO_R Playback Switch",      "Right Capture Mix"},
+       {"Mono Mix", "LI2MONO Playback Switch",         "Line Mix"},
+       {"Mono Mix", "VOICE2MONO Playback Switch",      "Phone Mix"},
+       {"Mono Mix", "MIC12MONO Playback Switch",       "MIC1 PGA"},
+       {"Mono Mix", "MIC22MONO Playback Switch",       "MIC2 PGA"},
+       {"Mono Mix", "DAC2MONO Playback Switch",        "DAC Left Channel"},
+
+       /* Left record mixer */
+       {"Left Capture Mix", "LineInL Capture Switch",  "LINEINL"},
+       {"Left Capture Mix", "Left Phone Capture Switch", "PHONEN"},
+       {"Left Capture Mix", "Mic1 Capture Switch",     "MIC1 Pre Amp"},
+       {"Left Capture Mix", "Mic2 Capture Switch",     "MIC2 Pre Amp"},
+       {"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"},
+       {"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+       {"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+       /*Right record mixer */
+       {"Right Capture Mix", "LineInR Capture Switch", "LINEINR"},
+       {"Right Capture Mix", "Right Phone Capture Switch",     "PHONEP"},
+       {"Right Capture Mix", "Mic1 Capture Switch",    "MIC1 Pre Amp"},
+       {"Right Capture Mix", "Mic2 Capture Switch",    "MIC2 Pre Amp"},
+       {"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"},
+       {"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+       {"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+       /* headphone left mux */
+       {"Left Headphone Mux", "HP Left Mix",           "HPL Mix"},
+       {"Left Headphone Mux", "Vmid",                  "Vmid"},
+
+       /* headphone right mux */
+       {"Right Headphone Mux", "HP Right Mix",         "HPR Mix"},
+       {"Right Headphone Mux", "Vmid",                 "Vmid"},
+
+       /* speaker out mux */
+       {"SpeakerOut Mux", "Vmid",                      "Vmid"},
+       {"SpeakerOut Mux", "HPOut Mix",                 "HPOut Mix"},
+       {"SpeakerOut Mux", "Speaker Mix",               "Speaker Mix"},
+       {"SpeakerOut Mux", "Mono Mix",                  "Mono Mix"},
+
+       /* Mono/Aux Out mux */
+       {"AuxOut Mux", "Vmid",                          "Vmid"},
+       {"AuxOut Mux", "HPOut Mix",                     "HPOut Mix"},
+       {"AuxOut Mux", "Speaker Mix",                   "Speaker Mix"},
+       {"AuxOut Mux", "Mono Mix",                      "Mono Mix"},
+
+       /* output pga */
+       {"HPL", NULL,                                   "Left Headphone"},
+       {"Left Headphone", NULL,                        "Left Headphone Mux"},
+       {"HPR", NULL,                                   "Right Headphone"},
+       {"Right Headphone", NULL,                       "Right Headphone Mux"},
+       {"Aux Out", NULL,                               "AuxOut Mux"},
+
+       /* input pga */
+       {"Left LineIn", NULL,                           "LINEINL"},
+       {"Right LineIn", NULL,                          "LINEINR"},
+       {"Phone", NULL,                         "PHONEP"},
+       {"MIC1 Pre Amp", NULL,                          "MIC1"},
+       {"MIC2 Pre Amp", NULL,                          "MIC2"},
+       {"MIC1 PGA", NULL,                              "MIC1 Pre Amp"},
+       {"MIC2 PGA", NULL,                              "MIC2 Pre Amp"},
+
+       /* left ADC */
+       {"Left ADC", NULL,                              "Left Capture Mix"},
+
+       /* right ADC */
+       {"Right ADC", NULL,                             "Right Capture Mix"},
+
+       {"SpeakerOut N Mux", "RN/-R",                   "Left Speaker"},
+       {"SpeakerOut N Mux", "RP/+R",                   "Left Speaker"},
+       {"SpeakerOut N Mux", "LN/-R",                   "Left Speaker"},
+       {"SpeakerOut N Mux", "Mute",                    "Vmid"},
+
+       {"SpeakerOut N Mux", "RN/-R",                   "Right Speaker"},
+       {"SpeakerOut N Mux", "RP/+R",                   "Right Speaker"},
+       {"SpeakerOut N Mux", "LN/-R",                   "Right Speaker"},
+       {"SpeakerOut N Mux", "Mute",                    "Vmid"},
+
+       {"AB Amp", NULL,                                "SpeakerOut Mux"},
+       {"D Amp", NULL,                                 "SpeakerOut Mux"},
+       {"AB-D Amp Mux", "AB Amp",                      "AB Amp"},
+       {"AB-D Amp Mux", "D Amp",                       "D Amp"},
+       {"Left Speaker", NULL,                          "AB-D Amp Mux"},
+       {"Right Speaker", NULL,                         "AB-D Amp Mux"},
+
+       {"SPKOUT", NULL,                                "Left Speaker"},
+       {"SPKOUT", NULL,                                "Right Speaker"},
+
+       {"SPKOUTN", NULL,                               "SpeakerOut N Mux"},
+
+};
+
+/* PLL divisors */
+struct _pll_div {
+       u32 pll_in;
+       u32 pll_out;
+       u16 regvalue;
+};
+
+/* Note : pll code from original alc5632 driver. Not sure of how good it is */
+/* usefull only for master mode */
+static const struct _pll_div codec_master_pll_div[] = {
+
+       {  2048000,  8192000,   0x0ea0},
+       {  3686400,  8192000,   0x4e27},
+       { 12000000,  8192000,   0x456b},
+       { 13000000,  8192000,   0x495f},
+       { 13100000,  8192000,   0x0320},
+       {  2048000,  11289600,  0xf637},
+       {  3686400,  11289600,  0x2f22},
+       { 12000000,  11289600,  0x3e2f},
+       { 13000000,  11289600,  0x4d5b},
+       { 13100000,  11289600,  0x363b},
+       {  2048000,  16384000,  0x1ea0},
+       {  3686400,  16384000,  0x9e27},
+       { 12000000,  16384000,  0x452b},
+       { 13000000,  16384000,  0x542f},
+       { 13100000,  16384000,  0x03a0},
+       {  2048000,  16934400,  0xe625},
+       {  3686400,  16934400,  0x9126},
+       { 12000000,  16934400,  0x4d2c},
+       { 13000000,  16934400,  0x742f},
+       { 13100000,  16934400,  0x3c27},
+       {  2048000,  22579200,  0x2aa0},
+       {  3686400,  22579200,  0x2f20},
+       { 12000000,  22579200,  0x7e2f},
+       { 13000000,  22579200,  0x742f},
+       { 13100000,  22579200,  0x3c27},
+       {  2048000,  24576000,  0x2ea0},
+       {  3686400,  24576000,  0xee27},
+       { 12000000,  24576000,  0x2915},
+       { 13000000,  24576000,  0x772e},
+       { 13100000,  24576000,  0x0d20},
+};
+
+/* FOUT = MCLK*(N+2)/((M+2)*(K+2))
+   N: bit 15:8 (div 2 .. div 257)
+   K: bit  6:4 typical 2
+   M: bit  3:0 (div 2 .. div 17)
+
+   same as for 5623 - thanks!
+*/
+
+static const struct _pll_div codec_slave_pll_div[] = {
+
+       {  1024000,  16384000,  0x3ea0},
+       {  1411200,  22579200,  0x3ea0},
+       {  1536000,  24576000,  0x3ea0},
+       {  2048000,  16384000,  0x1ea0},
+       {  2822400,  22579200,  0x1ea0},
+       {  3072000,  24576000,  0x1ea0},
+
+};
+
+static int alc5632_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
+{
+       int i;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int gbl_clk = 0, pll_div = 0;
+       u16 reg;
+
+       if (pll_id < ALC5632_PLL_FR_MCLK || pll_id > ALC5632_PLL_FR_VBCLK)
+               return -EINVAL;
+
+       /* Disable PLL power */
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_ADD2_PLL1,
+                               0);
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_ADD2_PLL2,
+                               0);
+
+       /* pll is not used in slave mode */
+       reg = snd_soc_read(codec, ALC5632_DAI_CONTROL);
+       if (reg & ALC5632_DAI_SDP_SLAVE_MODE)
+               return 0;
+
+       if (!freq_in || !freq_out)
+               return 0;
+
+       switch (pll_id) {
+       case ALC5632_PLL_FR_MCLK:
+               for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) {
+                       if (codec_master_pll_div[i].pll_in == freq_in
+                          && codec_master_pll_div[i].pll_out == freq_out) {
+                               /* PLL source from MCLK */
+                               pll_div  = codec_master_pll_div[i].regvalue;
+                               break;
+                       }
+               }
+               break;
+       case ALC5632_PLL_FR_BCLK:
+               for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+                       if (codec_slave_pll_div[i].pll_in == freq_in
+                          && codec_slave_pll_div[i].pll_out == freq_out) {
+                               /* PLL source from Bitclk */
+                               gbl_clk = ALC5632_PLL_FR_BCLK;
+                               pll_div = codec_slave_pll_div[i].regvalue;
+                               break;
+                       }
+               }
+               break;
+       case ALC5632_PLL_FR_VBCLK:
+               for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+                       if (codec_slave_pll_div[i].pll_in == freq_in
+                          && codec_slave_pll_div[i].pll_out == freq_out) {
+                               /* PLL source from voice clock */
+                               gbl_clk = ALC5632_PLL_FR_VBCLK;
+                               pll_div = codec_slave_pll_div[i].regvalue;
+                               break;
+                       }
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!pll_div)
+               return -EINVAL;
+
+       /* choose MCLK/BCLK/VBCLK */
+       snd_soc_write(codec, ALC5632_GPCR2, gbl_clk);
+       /* choose PLL1 clock rate */
+       snd_soc_write(codec, ALC5632_PLL1_CTRL, pll_div);
+       /* enable PLL1 */
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_ADD2_PLL1,
+                               ALC5632_PWR_ADD2_PLL1);
+       /* enable PLL2 */
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_ADD2_PLL2,
+                               ALC5632_PWR_ADD2_PLL2);
+       /* use PLL1 as main SYSCLK */
+       snd_soc_update_bits(codec, ALC5632_GPCR1,
+                       ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1,
+                       ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1);
+
+       return 0;
+}
+
+struct _coeff_div {
+       u16 fs;
+       u16 regvalue;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+/* values inspired from column BCLK=32Fs of Appendix A table */
+static const struct _coeff_div coeff_div[] = {
+       {512*1, 0x3075},
+};
+
+static int get_coeff(struct snd_soc_codec *codec, int rate)
+{
+       struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].fs * rate == alc5632->sysclk)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int alc5632_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 alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+
+       switch (freq) {
+       case  8192000:
+       case 11289600:
+       case 12288000:
+       case 16384000:
+       case 16934400:
+       case 18432000:
+       case 22579200:
+       case 24576000:
+               alc5632->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface = ALC5632_DAI_SDP_MASTER_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iface = ALC5632_DAI_SDP_SLAVE_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= ALC5632_DAI_I2S_DF_I2S;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= ALC5632_DAI_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= ALC5632_DAI_I2S_DF_PCM_A;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= ALC5632_DAI_I2S_DF_PCM_B;
+               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 |= ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_write(codec, ALC5632_DAI_CONTROL, iface);
+}
+
+static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       int coeff, rate;
+       u16 iface;
+
+       iface = snd_soc_read(codec, ALC5632_DAI_CONTROL);
+       iface &= ~ALC5632_DAI_I2S_DL_MASK;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iface |= ALC5632_DAI_I2S_DL_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= ALC5632_DAI_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= ALC5632_DAI_I2S_DL_24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set iface & srate */
+       snd_soc_write(codec, ALC5632_DAI_CONTROL, iface);
+       rate = params_rate(params);
+       coeff = get_coeff(codec, rate);
+       if (coeff < 0)
+               return -EINVAL;
+
+       coeff = coeff_div[coeff].regvalue;
+       snd_soc_write(codec, ALC5632_DAC_CLK_CTRL1, coeff);
+
+       return 0;
+}
+
+static int alc5632_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 hp_mute = ALC5632_MISC_HP_DEPOP_MUTE_L
+                                               |ALC5632_MISC_HP_DEPOP_MUTE_R;
+       u16 mute_reg = snd_soc_read(codec, ALC5632_MISC_CTRL) & ~hp_mute;
+
+       if (mute)
+               mute_reg |= hp_mute;
+
+       return snd_soc_write(codec, ALC5632_MISC_CTRL, mute_reg);
+}
+
+#define ALC5632_ADD2_POWER_EN (ALC5632_PWR_ADD2_VREF)
+
+#define ALC5632_ADD3_POWER_EN (ALC5632_PWR_ADD3_MIC1_BOOST_AD)
+
+#define ALC5632_ADD1_POWER_EN \
+               (ALC5632_PWR_ADD1_DAC_REF \
+               | ALC5632_PWR_ADD1_SOFTGEN_EN \
+               | ALC5632_PWR_ADD1_HP_OUT_AMP \
+               | ALC5632_PWR_ADD1_HP_OUT_ENH_AMP \
+               | ALC5632_PWR_ADD1_MAIN_BIAS)
+
+static void enable_power_depop(struct snd_soc_codec *codec)
+{
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+                               ALC5632_PWR_ADD1_SOFTGEN_EN,
+                               ALC5632_PWR_ADD1_SOFTGEN_EN);
+
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
+                               ALC5632_ADD3_POWER_EN,
+                               ALC5632_ADD3_POWER_EN);
+
+       snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
+                               ALC5632_MISC_HP_DEPOP_MODE2_EN,
+                               ALC5632_MISC_HP_DEPOP_MODE2_EN);
+
+       /* "normal" mode: 0 @ 26 */
+       /* set all PR0-7 mixers to 0 */
+       snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
+                               ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
+                               0);
+
+       msleep(500);
+
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_ADD2_POWER_EN,
+                               ALC5632_ADD2_POWER_EN);
+
+       snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+                               ALC5632_ADD1_POWER_EN,
+                               ALC5632_ADD1_POWER_EN);
+
+       /* disable HP Depop2 */
+       snd_soc_update_bits(codec, ALC5632_MISC_CTRL,
+                               ALC5632_MISC_HP_DEPOP_MODE2_EN,
+                               0);
+
+}
+
+static int alc5632_set_bias_level(struct snd_soc_codec *codec,
+                                     enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               enable_power_depop(codec);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* everything off except vref/vmid, */
+               snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+                               ALC5632_PWR_MANAG_ADD1_MASK,
+                               ALC5632_PWR_ADD1_MAIN_BIAS);
+               snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_MANAG_ADD2_MASK,
+                               ALC5632_PWR_ADD2_VREF);
+               /* "normal" mode: 0 @ 26 */
+               snd_soc_update_bits(codec, ALC5632_PWR_DOWN_CTRL_STATUS,
+                               ALC5632_PWR_DOWN_CTRL_STATUS_MASK,
+                               0xffff ^ (ALC5632_PWR_VREF_PR3
+                               | ALC5632_PWR_VREF_PR2));
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD2,
+                               ALC5632_PWR_MANAG_ADD2_MASK, 0);
+               snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD3,
+                               ALC5632_PWR_MANAG_ADD3_MASK, 0);
+               snd_soc_update_bits(codec, ALC5632_PWR_MANAG_ADD1,
+                               ALC5632_PWR_MANAG_ADD1_MASK, 0);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define ALC5632_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE \
+                       | SNDRV_PCM_FMTBIT_S24_LE \
+                       | SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops alc5632_dai_ops = {
+               .hw_params = alc5632_pcm_hw_params,
+               .digital_mute = alc5632_mute,
+               .set_fmt = alc5632_set_dai_fmt,
+               .set_sysclk = alc5632_set_dai_sysclk,
+               .set_pll = alc5632_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver alc5632_dai = {
+       .name = "alc5632-hifi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rate_min =     8000,
+               .rate_max =     48000,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = ALC5632_FORMATS,},
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rate_min =     8000,
+               .rate_max =     48000,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = ALC5632_FORMATS,},
+
+       .ops = &alc5632_dai_ops,
+       .symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int alc5632_suspend(struct snd_soc_codec *codec)
+{
+       alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int alc5632_resume(struct snd_soc_codec *codec)
+{
+       struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+
+       regcache_sync(alc5632->regmap);
+
+       alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define        alc5632_suspend NULL
+#define        alc5632_resume  NULL
+#endif
+
+static int alc5632_probe(struct snd_soc_codec *codec)
+{
+       struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       codec->control_data = alc5632->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* power on device  */
+       alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       switch (alc5632->id) {
+       case 0x5c:
+               snd_soc_add_controls(codec, alc5632_vol_snd_controls,
+                       ARRAY_SIZE(alc5632_vol_snd_controls));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/* power down chip */
+static int alc5632_remove(struct snd_soc_codec *codec)
+{
+       alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
+       .probe = alc5632_probe,
+       .remove = alc5632_remove,
+       .suspend = alc5632_suspend,
+       .resume = alc5632_resume,
+       .set_bias_level = alc5632_set_bias_level,
+       .controls = alc5632_snd_controls,
+       .num_controls = ARRAY_SIZE(alc5632_snd_controls),
+       .dapm_widgets = alc5632_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets),
+       .dapm_routes = alc5632_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
+};
+
+static struct regmap_config alc5632_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = ALC5632_MAX_REGISTER,
+       .reg_defaults = alc5632_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(alc5632_reg_defaults),
+       .volatile_reg = alc5632_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+/*
+ * alc5632 2 wire address is determined by A1 pin
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static __devinit int alc5632_i2c_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct alc5632_priv *alc5632;
+       int ret, ret1, ret2;
+       unsigned int vid1, vid2;
+
+       alc5632 = devm_kzalloc(&client->dev,
+                        sizeof(struct alc5632_priv), GFP_KERNEL);
+       if (alc5632 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, alc5632);
+
+       alc5632->regmap = regmap_init_i2c(client, &alc5632_regmap);
+       if (IS_ERR(alc5632->regmap)) {
+               ret = PTR_ERR(alc5632->regmap);
+               dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       ret1 = regmap_read(alc5632->regmap, ALC5632_VENDOR_ID1, &vid1);
+       ret2 = regmap_read(alc5632->regmap, ALC5632_VENDOR_ID2, &vid2);
+       if (ret1 != 0 || ret2 != 0) {
+               dev_err(&client->dev,
+               "Failed to read chip ID: ret1=%d, ret2=%d\n", ret1, ret2);
+               regmap_exit(alc5632->regmap);
+               return -EIO;
+       }
+
+       vid2 >>= 8;
+
+       if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
+               dev_err(&client->dev,
+               "Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
+               regmap_exit(alc5632->regmap);
+               return -EINVAL;
+       }
+
+       ret = alc5632_reset(alc5632->regmap);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to issue reset\n");
+               regmap_exit(alc5632->regmap);
+               return ret;
+       }
+
+       alc5632->id = vid2;
+       switch (alc5632->id) {
+       case 0x5c:
+               alc5632_dai.name = "alc5632-hifi";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = snd_soc_register_codec(&client->dev,
+               &soc_codec_device_alc5632, &alc5632_dai, 1);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+               regmap_exit(alc5632->regmap);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int alc5632_i2c_remove(struct i2c_client *client)
+{
+       struct alc5632_priv *alc5632 = i2c_get_clientdata(client);
+       snd_soc_unregister_codec(&client->dev);
+       regmap_exit(alc5632->regmap);
+       return 0;
+}
+
+static const struct i2c_device_id alc5632_i2c_table[] = {
+       {"alc5632", 0x5c},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table);
+
+/* i2c codec control layer */
+static struct i2c_driver alc5632_i2c_driver = {
+       .driver = {
+               .name = "alc5632",
+               .owner = THIS_MODULE,
+       },
+       .probe = alc5632_i2c_probe,
+       .remove =  __devexit_p(alc5632_i2c_remove),
+       .id_table = alc5632_i2c_table,
+};
+
+static int __init alc5632_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&alc5632_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "%s: can't add i2c driver", __func__);
+               return ret;
+       }
+
+       return ret;
+}
+module_init(alc5632_modinit);
+
+static void __exit alc5632_modexit(void)
+{
+       i2c_del_driver(&alc5632_i2c_driver);
+}
+module_exit(alc5632_modexit);
+
+MODULE_DESCRIPTION("ASoC ALC5632 driver");
+MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/alc5632.h b/sound/soc/codecs/alc5632.h
new file mode 100644 (file)
index 0000000..357651e
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+* alc5632.h  --  ALC5632 ALSA SoC Audio Codec
+*
+* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+*
+* Authors:  Leon Romanovsky <leon@leon.nu>
+*           Andrey Danin <danindrey@mail.ru>
+*           Ilya Petrov <ilya.muromec@gmail.com>
+*           Marc Dietrich <marvin24@gmx.de>
+*
+* Based on alc5623.h by Arnaud Patard
+*
+* This program is free software; you can 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 _ALC5632_H
+#define _ALC5632_H
+
+#define ALC5632_RESET                          0x00
+/* speaker output vol             2    2           */
+/* line output vol                      4    2      */
+/* HP output vol                  4    0    4      */
+#define ALC5632_SPK_OUT_VOL                    0x02 /* spe out vol */
+#define ALC5632_SPK_OUT_VOL_STEP               1.5
+#define ALC5632_HP_OUT_VOL                     0x04 /* hp out vol */
+#define ALC5632_AUX_OUT_VOL                    0x06 /* aux out vol */
+#define ALC5632_PHONE_IN_VOL                   0x08 /* phone in vol */
+#define ALC5632_LINE_IN_VOL                    0x0A /* line in vol */
+#define ALC5632_STEREO_DAC_IN_VOL              0x0C /* stereo dac in vol */
+#define ALC5632_MIC_VOL                                0x0E /* mic in vol */
+/* stero dac/mic routing */
+#define ALC5632_MIC_ROUTING_CTRL               0x10
+#define ALC5632_MIC_ROUTE_MONOMIX              (1 << 0)
+#define ALC5632_MIC_ROUTE_SPK                  (1 << 1)
+#define ALC5632_MIC_ROUTE_HP                   (1 << 2)
+
+#define ALC5632_ADC_REC_GAIN                   0x12 /* rec gain */
+#define ALC5632_ADC_REC_GAIN_RANGE             0x1F1F
+#define ALC5632_ADC_REC_GAIN_BASE              (-16.5)
+#define ALC5632_ADC_REC_GAIN_STEP              1.5
+
+#define ALC5632_ADC_REC_MIXER                  0x14 /* mixer control */
+#define ALC5632_ADC_REC_MIC1                   (1 << 6)
+#define ALC5632_ADC_REC_MIC2                   (1 << 5)
+#define ALC5632_ADC_REC_LINE_IN                        (1 << 4)
+#define ALC5632_ADC_REC_AUX                    (1 << 3)
+#define ALC5632_ADC_REC_HP                     (1 << 2)
+#define ALC5632_ADC_REC_SPK                    (1 << 1)
+#define ALC5632_ADC_REC_MONOMIX                        (1 << 0)
+
+#define ALC5632_VOICE_DAC_VOL                  0x18 /* voice dac vol */
+/* ALC5632_OUTPUT_MIXER_CTRL :                 */
+/* same remark as for reg 2 line vs speaker    */
+#define ALC5632_OUTPUT_MIXER_CTRL              0x1C /* out mix ctrl */
+#define ALC5632_OUTPUT_MIXER_RP                        (1 << 14)
+#define ALC5632_OUTPUT_MIXER_WEEK              (1 << 12)
+#define ALC5632_OUTPUT_MIXER_HP                        (1 << 10)
+#define ALC5632_OUTPUT_MIXER_AUX_SPK           (2 <<  6)
+#define ALC5632_OUTPUT_MIXER_AUX_HP_LR          (1 << 6)
+#define ALC5632_OUTPUT_MIXER_HP_R               (1 << 8)
+#define ALC5632_OUTPUT_MIXER_HP_L               (1 << 9)
+
+#define ALC5632_MIC_CTRL                       0x22 /* mic phone ctrl */
+#define ALC5632_MIC_BOOST_BYPASS               0
+#define ALC5632_MIC_BOOST_20DB                 1
+#define ALC5632_MIC_BOOST_30DB                 2
+#define ALC5632_MIC_BOOST_40DB                 3
+
+#define ALC5632_DIGI_BOOST_CTRL                        0x24 /* digi mic / bost ctl */
+#define ALC5632_MIC_BOOST_RANGE                        7
+#define ALC5632_MIC_BOOST_STEP                 6
+#define ALC5632_PWR_DOWN_CTRL_STATUS           0x26
+#define ALC5632_PWR_DOWN_CTRL_STATUS_MASK      0xEF00
+#define ALC5632_PWR_VREF_PR3                   (1 << 11)
+#define ALC5632_PWR_VREF_PR2                   (1 << 10)
+#define ALC5632_PWR_VREF_STATUS                        (1 << 3)
+#define ALC5632_PWR_AMIX_STATUS                        (1 << 2)
+#define ALC5632_PWR_DAC_STATUS                 (1 << 1)
+#define ALC5632_PWR_ADC_STATUS                 (1 << 0)
+/* stereo/voice DAC / stereo adc func ctrl */
+#define ALC5632_DAC_FUNC_SELECT                        0x2E
+
+/* Main serial data port ctrl (i2s) */
+#define ALC5632_DAI_CONTROL                    0x34
+
+#define ALC5632_DAI_SDP_MASTER_MODE            (0 << 15)
+#define ALC5632_DAI_SDP_SLAVE_MODE             (1 << 15)
+#define ALC5632_DAI_SADLRCK_MODE               (1 << 14)
+/* 0:voice, 1:main */
+#define ALC5632_DAI_MAIN_I2S_SYSCLK_SEL                (1 <<  8)
+#define ALC5632_DAI_MAIN_I2S_BCLK_POL_CTRL     (1 <<  7)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_MAIN_I2S_LRCK_INV          (1 <<  6)
+#define ALC5632_DAI_I2S_DL_MASK                        (3 <<  2)
+#define ALC5632_DAI_I2S_DL_8                   (3 <<  2)
+#define        ALC5632_DAI_I2S_DL_24                   (2 <<  2)
+#define        ALC5632_DAI_I2S_DL_20                   (1 <<  2)
+#define ALC5632_DAI_I2S_DL_16                  (0 <<  2)
+#define ALC5632_DAI_I2S_DF_MASK                        (3 <<  0)
+#define ALC5632_DAI_I2S_DF_PCM_B               (3 <<  0)
+#define        ALC5632_DAI_I2S_DF_PCM_A                (2 <<  0)
+#define ALC5632_DAI_I2S_DF_LEFT                        (1 <<  0)
+#define ALC5632_DAI_I2S_DF_I2S                 (0 <<  0)
+/* extend serial data port control (VoDAC_i2c/pcm) */
+#define ALC5632_DAI_CONTROL2                   0x36
+/* 0:gpio func, 1:voice pcm */
+#define ALC5632_DAI_VOICE_PCM_ENABLE           (1 << 15)
+/* 0:master, 1:slave */
+#define ALC5632_DAI_VOICE_MODE_SEL             (1 << 14)
+/* 0:disable, 1:enable */
+#define ALC5632_DAI_HPF_CLK_CTRL               (1 << 13)
+/* 0:main, 1:voice */
+#define ALC5632_DAI_VOICE_I2S_SYSCLK_SEL       (1 <<  8)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_VOICE_VBCLK_SYSCLK_SEL     (1 <<  7)
+/* 0:normal, 1:invert */
+#define ALC5632_DAI_VOICE_I2S_LR_INV           (1 <<  6)
+#define ALC5632_DAI_VOICE_DL_MASK              (3 <<  2)
+#define ALC5632_DAI_VOICE_DL_16                        (0 <<  2)
+#define ALC5632_DAI_VOICE_DL_20                        (1 <<  2)
+#define ALC5632_DAI_VOICE_DL_24                        (2 <<  2)
+#define ALC5632_DAI_VOICE_DL_8                 (3 <<  2)
+#define ALC5632_DAI_VOICE_DF_MASK              (3 <<  0)
+#define ALC5632_DAI_VOICE_DF_I2S               (0 <<  0)
+#define ALC5632_DAI_VOICE_DF_LEFT              (1 <<  0)
+#define ALC5632_DAI_VOICE_DF_PCM_A             (2 <<  0)
+#define ALC5632_DAI_VOICE_DF_PCM_B             (3 <<  0)
+
+#define        ALC5632_PWR_MANAG_ADD1                  0x3A
+#define        ALC5632_PWR_MANAG_ADD1_MASK             0xEFFF
+#define ALC5632_PWR_ADD1_DAC_L_EN              (1 << 15)
+#define ALC5632_PWR_ADD1_DAC_R_EN              (1 << 14)
+#define ALC5632_PWR_ADD1_ZERO_CROSS            (1 << 13)
+#define ALC5632_PWR_ADD1_MAIN_I2S_EN           (1 << 11)
+#define ALC5632_PWR_ADD1_SPK_AMP_EN            (1 << 10)
+#define ALC5632_PWR_ADD1_HP_OUT_AMP            (1 <<  9)
+#define ALC5632_PWR_ADD1_HP_OUT_ENH_AMP                (1 <<  8)
+#define ALC5632_PWR_ADD1_VOICE_DAC_MIX         (1 <<  7)
+#define        ALC5632_PWR_ADD1_SOFTGEN_EN             (1 <<  6)
+#define        ALC5632_PWR_ADD1_MIC1_SHORT_CURR        (1 <<  5)
+#define        ALC5632_PWR_ADD1_MIC2_SHORT_CURR        (1 <<  4)
+#define        ALC5632_PWR_ADD1_MIC1_EN                (1 <<  3)
+#define        ALC5632_PWR_ADD1_MIC2_EN                (1 <<  2)
+#define ALC5632_PWR_ADD1_MAIN_BIAS             (1 <<  1)
+#define ALC5632_PWR_ADD1_DAC_REF               (1 <<  0)
+
+#define ALC5632_PWR_MANAG_ADD2                 0x3C
+#define ALC5632_PWR_MANAG_ADD2_MASK            0x7FFF
+#define ALC5632_PWR_ADD2_PLL1                  (1 << 15)
+#define ALC5632_PWR_ADD2_PLL2                  (1 << 14)
+#define ALC5632_PWR_ADD2_VREF                  (1 << 13)
+#define ALC5632_PWR_ADD2_OVT_DET               (1 << 12)
+#define ALC5632_PWR_ADD2_VOICE_DAC             (1 << 10)
+#define ALC5632_PWR_ADD2_L_DAC_CLK             (1 <<  9)
+#define ALC5632_PWR_ADD2_R_DAC_CLK             (1 <<  8)
+#define ALC5632_PWR_ADD2_L_ADC_CLK_GAIN                (1 <<  7)
+#define ALC5632_PWR_ADD2_R_ADC_CLK_GAIN                (1 <<  6)
+#define ALC5632_PWR_ADD2_L_HP_MIXER            (1 <<  5)
+#define ALC5632_PWR_ADD2_R_HP_MIXER            (1 <<  4)
+#define ALC5632_PWR_ADD2_SPK_MIXER             (1 <<  3)
+#define ALC5632_PWR_ADD2_MONO_MIXER            (1 <<  2)
+#define ALC5632_PWR_ADD2_L_ADC_REC_MIXER       (1 <<  1)
+#define ALC5632_PWR_ADD2_R_ADC_REC_MIXER       (1 <<  0)
+
+#define ALC5632_PWR_MANAG_ADD3                 0x3E
+#define ALC5632_PWR_MANAG_ADD3_MASK            0x7CFF
+#define ALC5632_PWR_ADD3_AUXOUT_VOL            (1 << 14)
+#define ALC5632_PWR_ADD3_SPK_L_OUT             (1 << 13)
+#define ALC5632_PWR_ADD3_SPK_R_OUT             (1 << 12)
+#define ALC5632_PWR_ADD3_HP_L_OUT_VOL          (1 << 11)
+#define ALC5632_PWR_ADD3_HP_R_OUT_VOL          (1 << 10)
+#define ALC5632_PWR_ADD3_LINEIN_L_VOL          (1 <<  7)
+#define ALC5632_PWR_ADD3_LINEIN_R_VOL          (1 <<  6)
+#define ALC5632_PWR_ADD3_AUXIN_VOL             (1 <<  5)
+#define ALC5632_PWR_ADD3_AUXIN_MIX             (1 <<  4)
+#define ALC5632_PWR_ADD3_MIC1_VOL              (1 <<  3)
+#define ALC5632_PWR_ADD3_MIC2_VOL              (1 <<  2)
+#define ALC5632_PWR_ADD3_MIC1_BOOST_AD         (1 <<  1)
+#define ALC5632_PWR_ADD3_MIC2_BOOST_AD         (1 <<  0)
+
+#define ALC5632_GPCR1                          0x40
+#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_PLL1     (1 << 15)
+#define ALC5632_GPCR1_CLK_SYS_SRC_SEL_MCLK     (0 << 15)
+#define ALC5632_GPCR1_DAC_HI_FLT_EN            (1 << 10)
+#define ALC5632_GPCR1_SPK_AMP_CTRL             (7 <<  1)
+#define ALC5632_GPCR1_VDD_100                  (5 <<  1)
+#define ALC5632_GPCR1_VDD_125                  (4 <<  1)
+#define ALC5632_GPCR1_VDD_150                  (3 <<  1)
+#define ALC5632_GPCR1_VDD_175                  (2 <<  1)
+#define ALC5632_GPCR1_VDD_200                  (1 <<  1)
+#define ALC5632_GPCR1_VDD_225                  (0 <<  1)
+
+#define        ALC5632_GPCR2                           0x42
+#define ALC5632_GPCR2_PLL1_SOUR_SEL            (3 << 12)
+#define ALC5632_PLL_FR_MCLK                    (0 << 12)
+#define ALC5632_PLL_FR_BCLK                    (2 << 12)
+#define ALC5632_PLL_FR_VBCLK                   (3 << 12)
+#define ALC5632_GPCR2_CLK_PLL_PRE_DIV1         (0 <<  0)
+
+#define ALC5632_PLL1_CTRL                      0x44
+#define ALC5632_PLL1_CTRL_N_VAL(n)             (((n) & 0x0f) << 8)
+#define ALC5632_PLL1_M_BYPASS                  (1 <<  7)
+#define ALC5632_PLL1_CTRL_K_VAL(k)             (((k) & 0x07) << 4)
+#define ALC5632_PLL1_CTRL_M_VAL(m)             (((m) & 0x0f) << 0)
+
+#define ALC5632_PLL2_CTRL                      0x46
+#define ALC5632_PLL2_EN                                (1 << 15)
+#define ALC5632_PLL2_RATIO                     (0 << 15)
+
+#define ALC5632_GPIO_PIN_CONFIG                        0x4C
+#define ALC5632_GPIO_PIN_POLARITY              0x4E
+#define ALC5632_GPIO_PIN_STICKY                        0x50
+#define ALC5632_GPIO_PIN_WAKEUP                        0x52
+#define ALC5632_GPIO_PIN_STATUS                        0x54
+#define ALC5632_GPIO_PIN_SHARING               0x56
+#define        ALC5632_OVER_CURR_STATUS                0x58
+#define ALC5632_SOFTVOL_CTRL                   0x5A
+#define ALC5632_GPIO_OUPUT_PIN_CTRL            0x5C
+
+#define ALC5632_MISC_CTRL                      0x5E
+#define ALC5632_MISC_DISABLE_FAST_VREG         (1 << 15)
+#define ALC5632_MISC_AVC_TRGT_SEL              (3 << 12)
+#define ALC5632_MISC_AVC_TRGT_RIGHT            (1 << 12)
+#define ALC5632_MISC_AVC_TRGT_LEFT             (2 << 12)
+#define ALC5632_MISC_AVC_TRGT_BOTH             (3 << 12)
+#define ALC5632_MISC_HP_DEPOP_MODE1_EN         (1 <<  9)
+#define ALC5632_MISC_HP_DEPOP_MODE2_EN         (1 <<  8)
+#define ALC5632_MISC_HP_DEPOP_MUTE_L           (1 <<  7)
+#define ALC5632_MISC_HP_DEPOP_MUTE_R           (1 <<  6)
+#define ALC5632_MISC_HP_DEPOP_MUTE             (1 <<  5)
+#define ALC5632_MISC_GPIO_WAKEUP_CTRL          (1 <<  1)
+#define ALC5632_MISC_IRQOUT_INV_CTRL           (1 <<  0)
+
+#define ALC5632_DAC_CLK_CTRL1                  0x60
+#define ALC5632_DAC_CLK_CTRL2                  0x62
+#define ALC5632_DAC_CLK_CTRL2_DIV1_2           (1 << 0)
+#define ALC5632_VOICE_DAC_PCM_CLK_CTRL1                0x64
+#define ALC5632_PSEUDO_SPATIAL_CTRL            0x68
+#define ALC5632_HID_CTRL_INDEX                 0x6A
+#define ALC5632_HID_CTRL_DATA                  0x6C
+#define ALC5632_EQ_CTRL                                0x6E
+
+/* undocumented */
+#define ALC5632_VENDOR_ID1                     0x7C
+#define ALC5632_VENDOR_ID2                     0x7E
+
+#define ALC5632_MAX_REGISTER        0x7E
+
+#endif
index 46dbfd067f79647b7fca338eb85addd177eda966..4854b472d5fdb98ca5d6cae18863286a17f3b408 100644 (file)
@@ -122,7 +122,7 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
 #define CQ93VC_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
 #define CQ93VC_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
 
-static struct snd_soc_dai_ops cq93vc_dai_ops = {
+static const struct snd_soc_dai_ops cq93vc_dai_ops = {
        .digital_mute   = cq93vc_mute,
        .set_sysclk     = cq93vc_set_dai_sysclk,
 };
@@ -206,17 +206,7 @@ static struct platform_driver cq93vc_codec_driver = {
        .remove = __devexit_p(cq93vc_platform_remove),
 };
 
-static int __init cq93vc_init(void)
-{
-       return platform_driver_register(&cq93vc_codec_driver);
-}
-module_init(cq93vc_init);
-
-static void __exit cq93vc_exit(void)
-{
-       platform_driver_unregister(&cq93vc_codec_driver);
-}
-module_exit(cq93vc_exit);
+module_platform_driver(cq93vc_codec_driver);
 
 MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC CQ0093 Voice Codec Driver");
 MODULE_AUTHOR("Miguel Aguilar");
index 73f46eb459f15fa43c5aadc89c2d5a61346fb351..055536645da917e15308cd4abb17d13f2a43bf67 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/soc.h>
@@ -447,7 +446,7 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
                snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
-static struct snd_soc_dai_ops cs4270_dai_ops = {
+static const struct snd_soc_dai_ops cs4270_dai_ops = {
        .hw_params      = cs4270_hw_params,
        .set_sysclk     = cs4270_set_dai_sysclk,
        .set_fmt        = cs4270_set_dai_fmt,
@@ -579,7 +578,7 @@ static int cs4270_remove(struct snd_soc_codec *codec)
  * and all registers are written back to the hardware when resuming.
  */
 
-static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
+static int cs4270_soc_suspend(struct snd_soc_codec *codec)
 {
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int reg, ret;
@@ -672,7 +671,8 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
                i2c_client->addr);
        dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
 
-       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+       cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private),
+                             GFP_KERNEL);
        if (!cs4270) {
                dev_err(&i2c_client->dev, "could not allocate codec\n");
                return -ENOMEM;
@@ -683,8 +683,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
 
        ret = snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_device_cs4270, &cs4270_dai, 1);
-       if (ret < 0)
-               kfree(cs4270);
        return ret;
 }
 
@@ -697,7 +695,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
 static int cs4270_i2c_remove(struct i2c_client *i2c_client)
 {
        snd_soc_unregister_codec(&i2c_client->dev);
-       kfree(i2c_get_clientdata(i2c_client));
        return 0;
 }
 
index 69fde1506fe1fde2fe312ff80176723171ccef07..f6fe846b6a6c3d76f8778140261c96b0ed7a65eb 100644 (file)
@@ -402,7 +402,7 @@ static const struct snd_kcontrol_new cs4271_snd_controls[] = {
                7, 1, 1),
 };
 
-static struct snd_soc_dai_ops cs4271_dai_ops = {
+static const struct snd_soc_dai_ops cs4271_dai_ops = {
        .hw_params      = cs4271_hw_params,
        .set_sysclk     = cs4271_set_dai_sysclk,
        .set_fmt        = cs4271_set_dai_fmt,
@@ -430,7 +430,7 @@ static struct snd_soc_dai_driver cs4271_dai = {
 };
 
 #ifdef CONFIG_PM
-static int cs4271_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
+static int cs4271_soc_suspend(struct snd_soc_codec *codec)
 {
        int ret;
        /* Set power-down bit */
index 1ee66361f61b946e5738798daf03d61baf2f8ecb..a8bf588e8740ee248e039bf4028f346383bd9f4a 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/soc.h>
@@ -175,21 +174,18 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
 static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
-       unsigned long value;
-
-       value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
-       value &= ~CS42L51_POWER_CTL1_PDN;
-
        switch (event) {
        case SND_SOC_DAPM_PRE_PMD:
-               value |= CS42L51_POWER_CTL1_PDN;
+               snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+                                   CS42L51_POWER_CTL1_PDN,
+                                   CS42L51_POWER_CTL1_PDN);
                break;
        default:
        case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+                                   CS42L51_POWER_CTL1_PDN, 0);
                break;
        }
-       snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
-               CS42L51_POWER_CTL1_PDN, value);
 
        return 0;
 }
@@ -486,7 +482,7 @@ static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
        return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
 }
 
-static struct snd_soc_dai_ops cs42l51_dai_ops = {
+static const struct snd_soc_dai_ops cs42l51_dai_ops = {
        .hw_params      = cs42l51_hw_params,
        .set_sysclk     = cs42l51_set_dai_sysclk,
        .set_fmt        = cs42l51_set_dai_fmt,
@@ -515,7 +511,6 @@ static struct snd_soc_dai_driver cs42l51_dai = {
 static int cs42l51_probe(struct snd_soc_codec *codec)
 {
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret, reg;
 
        ret = cs42l51_fill_cache(codec);
@@ -543,20 +538,20 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
        if (ret < 0)
                return ret;
 
-       snd_soc_add_controls(codec, cs42l51_snd_controls,
-               ARRAY_SIZE(cs42l51_snd_controls));
-       snd_soc_dapm_new_controls(dapm, cs42l51_dapm_widgets,
-               ARRAY_SIZE(cs42l51_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, cs42l51_routes,
-               ARRAY_SIZE(cs42l51_routes));
-
        return 0;
 }
 
 static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
-       .probe =        cs42l51_probe,
+       .probe = cs42l51_probe,
        .reg_cache_size = CS42L51_NUMREGS + 1,
        .reg_word_size = sizeof(u8),
+
+       .controls = cs42l51_snd_controls,
+       .num_controls = ARRAY_SIZE(cs42l51_snd_controls),
+       .dapm_widgets = cs42l51_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs42l51_dapm_widgets),
+       .dapm_routes = cs42l51_routes,
+       .num_dapm_routes = ARRAY_SIZE(cs42l51_routes),
 };
 
 static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
@@ -582,7 +577,8 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
        dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
                                ret & 7);
 
-       cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+       cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private),
+                              GFP_KERNEL);
        if (!cs42l51) {
                dev_err(&i2c_client->dev, "could not allocate codec\n");
                return -ENOMEM;
@@ -593,18 +589,13 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
 
        ret =  snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_device_cs42l51, &cs42l51_dai, 1);
-       if (ret < 0)
-               kfree(cs42l51);
 error:
        return ret;
 }
 
 static int cs42l51_i2c_remove(struct i2c_client *client)
 {
-       struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       kfree(cs42l51);
        return 0;
 }
 
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
new file mode 100644 (file)
index 0000000..9d38db8
--- /dev/null
@@ -0,0 +1,1453 @@
+/*
+ * cs42l73.c  --  CS42L73 ALSA Soc Audio driver
+ *
+ * Copyright 2011 Cirrus Logic, Inc.
+ *
+ * Authors: Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>
+ *         Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "cs42l73.h"
+
+struct sp_config {
+       u8 spc, mmcc, spfs;
+       u32 srate;
+};
+struct  cs42l73_private {
+       struct sp_config config[3];
+       struct regmap *regmap;
+       u32 sysclk;
+       u8 mclksel;
+       u32 mclk;
+};
+
+static const struct reg_default cs42l73_reg_defaults[] = {
+       { 1, 0x42 },    /* r01  - Device ID A&B */
+       { 2, 0xA7 },    /* r02  - Device ID C&D */
+       { 3, 0x30 },    /* r03  - Device ID E */
+       { 6, 0xF1 },    /* r06  - Power Ctl 1 */
+       { 7, 0xDF },    /* r07  - Power Ctl 2 */
+       { 8, 0x3F },    /* r08  - Power Ctl 3 */
+       { 9, 0x50 },    /* r09  - Charge Pump Freq */
+       { 10, 0x53 },   /* r0A  - Output Load MicBias Short Detect */
+       { 11, 0x00 },   /* r0B  - DMIC Master Clock Ctl */
+       { 12, 0x00 },   /* r0C  - Aux PCM Ctl */
+       { 13, 0x15 },   /* r0D  - Aux PCM Master Clock Ctl */
+       { 14, 0x00 },   /* r0E  - Audio PCM Ctl */
+       { 15, 0x15 },   /* r0F  - Audio PCM Master Clock Ctl */
+       { 16, 0x00 },   /* r10  - Voice PCM Ctl */
+       { 17, 0x15 },   /* r11  - Voice PCM Master Clock Ctl */
+       { 18, 0x00 },   /* r12  - Voice/Aux Sample Rate */
+       { 19, 0x06 },   /* r13  - Misc I/O Path Ctl */
+       { 20, 0x00 },   /* r14  - ADC Input Path Ctl */
+       { 21, 0x00 },   /* r15  - MICA Preamp, PGA Volume */
+       { 22, 0x00 },   /* r16  - MICB Preamp, PGA Volume */
+       { 23, 0x00 },   /* r17  - Input Path A Digital Volume */
+       { 24, 0x00 },   /* r18  - Input Path B Digital Volume */
+       { 25, 0x00 },   /* r19  - Playback Digital Ctl */
+       { 26, 0x00 },   /* r1A  - HP/LO Left Digital Volume */
+       { 27, 0x00 },   /* r1B  - HP/LO Right Digital Volume */
+       { 28, 0x00 },   /* r1C  - Speakerphone Digital Volume */
+       { 29, 0x00 },   /* r1D  - Ear/SPKLO Digital Volume */
+       { 30, 0x00 },   /* r1E  - HP Left Analog Volume */
+       { 31, 0x00 },   /* r1F  - HP Right Analog Volume */
+       { 32, 0x00 },   /* r20  - LO Left Analog Volume */
+       { 33, 0x00 },   /* r21  - LO Right Analog Volume */
+       { 34, 0x00 },   /* r22  - Stereo Input Path Advisory Volume */
+       { 35, 0x00 },   /* r23  - Aux PCM Input Advisory Volume */
+       { 36, 0x00 },   /* r24  - Audio PCM Input Advisory Volume */
+       { 37, 0x00 },   /* r25  - Voice PCM Input Advisory Volume */
+       { 38, 0x00 },   /* r26  - Limiter Attack Rate HP/LO */
+       { 39, 0x7F },   /* r27  - Limter Ctl, Release Rate HP/LO */
+       { 40, 0x00 },   /* r28  - Limter Threshold HP/LO */
+       { 41, 0x00 },   /* r29  - Limiter Attack Rate Speakerphone */
+       { 42, 0x3F },   /* r2A  - Limter Ctl, Release Rate Speakerphone */
+       { 43, 0x00 },   /* r2B  - Limter Threshold Speakerphone */
+       { 44, 0x00 },   /* r2C  - Limiter Attack Rate Ear/SPKLO */
+       { 45, 0x3F },   /* r2D  - Limter Ctl, Release Rate Ear/SPKLO */
+       { 46, 0x00 },   /* r2E  - Limter Threshold Ear/SPKLO */
+       { 47, 0x00 },   /* r2F  - ALC Enable, Attack Rate Left/Right */
+       { 48, 0x3F },   /* r30  - ALC Release Rate Left/Right */
+       { 49, 0x00 },   /* r31  - ALC Threshold Left/Right */
+       { 50, 0x00 },   /* r32  - Noise Gate Ctl Left/Right */
+       { 51, 0x00 },   /* r33  - ALC/NG Misc Ctl */
+       { 52, 0x18 },   /* r34  - Mixer Ctl */
+       { 53, 0x3F },   /* r35  - HP/LO Left Mixer Input Path Volume */
+       { 54, 0x3F },   /* r36  - HP/LO Right Mixer Input Path Volume */
+       { 55, 0x3F },   /* r37  - HP/LO Left Mixer Aux PCM Volume */
+       { 56, 0x3F },   /* r38  - HP/LO Right Mixer Aux PCM Volume */
+       { 57, 0x3F },   /* r39  - HP/LO Left Mixer Audio PCM Volume */
+       { 58, 0x3F },   /* r3A  - HP/LO Right Mixer Audio PCM Volume */
+       { 59, 0x3F },   /* r3B  - HP/LO Left Mixer Voice PCM Mono Volume */
+       { 60, 0x3F },   /* r3C  - HP/LO Right Mixer Voice PCM Mono Volume */
+       { 61, 0x3F },   /* r3D  - Aux PCM Left Mixer Input Path Volume */
+       { 62, 0x3F },   /* r3E  - Aux PCM Right Mixer Input Path Volume */
+       { 63, 0x3F },   /* r3F  - Aux PCM Left Mixer Volume */
+       { 64, 0x3F },   /* r40  - Aux PCM Left Mixer Volume */
+       { 65, 0x3F },   /* r41  - Aux PCM Left Mixer Audio PCM L Volume */
+       { 66, 0x3F },   /* r42  - Aux PCM Right Mixer Audio PCM R Volume */
+       { 67, 0x3F },   /* r43  - Aux PCM Left Mixer Voice PCM Volume */
+       { 68, 0x3F },   /* r44  - Aux PCM Right Mixer Voice PCM Volume */
+       { 69, 0x3F },   /* r45  - Audio PCM Left Input Path Volume */
+       { 70, 0x3F },   /* r46  - Audio PCM Right Input Path Volume */
+       { 71, 0x3F },   /* r47  - Audio PCM Left Mixer Aux PCM L Volume */
+       { 72, 0x3F },   /* r48  - Audio PCM Right Mixer Aux PCM R Volume */
+       { 73, 0x3F },   /* r49  - Audio PCM Left Mixer Volume */
+       { 74, 0x3F },   /* r4A  - Audio PCM Right Mixer Volume */
+       { 75, 0x3F },   /* r4B  - Audio PCM Left Mixer Voice PCM Volume */
+       { 76, 0x3F },   /* r4C  - Audio PCM Right Mixer Voice PCM Volume */
+       { 77, 0x3F },   /* r4D  - Voice PCM Left Input Path Volume */
+       { 78, 0x3F },   /* r4E  - Voice PCM Right Input Path Volume */
+       { 79, 0x3F },   /* r4F  - Voice PCM Left Mixer Aux PCM L Volume */
+       { 80, 0x3F },   /* r50  - Voice PCM Right Mixer Aux PCM R Volume */
+       { 81, 0x3F },   /* r51  - Voice PCM Left Mixer Audio PCM L Volume */
+       { 82, 0x3F },   /* r52  - Voice PCM Right Mixer Audio PCM R Volume */
+       { 83, 0x3F },   /* r53  - Voice PCM Left Mixer Voice PCM Volume */
+       { 84, 0x3F },   /* r54  - Voice PCM Right Mixer Voice PCM Volume */
+       { 85, 0xAA },   /* r55  - Mono Mixer Ctl */
+       { 86, 0x3F },   /* r56  - SPK Mono Mixer Input Path Volume */
+       { 87, 0x3F },   /* r57  - SPK Mono Mixer Aux PCM Mono/L/R Volume */
+       { 88, 0x3F },   /* r58  - SPK Mono Mixer Audio PCM Mono/L/R Volume */
+       { 89, 0x3F },   /* r59  - SPK Mono Mixer Voice PCM Mono Volume */
+       { 90, 0x3F },   /* r5A  - SPKLO Mono Mixer Input Path Mono Volume */
+       { 91, 0x3F },   /* r5B  - SPKLO Mono Mixer Aux Mono/L/R Volume */
+       { 92, 0x3F },   /* r5C  - SPKLO Mono Mixer Audio Mono/L/R Volume */
+       { 93, 0x3F },   /* r5D  - SPKLO Mono Mixer Voice Mono Volume */
+       { 94, 0x00 },   /* r5E  - Interrupt Mask 1 */
+       { 95, 0x00 },   /* r5F  - Interrupt Mask 2 */
+};
+
+static bool cs42l73_volatile_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L73_IS1:
+       case CS42L73_IS2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool cs42l73_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case CS42L73_DEVID_AB:
+       case CS42L73_DEVID_CD:
+       case CS42L73_DEVID_E:
+       case CS42L73_REVID:
+       case CS42L73_PWRCTL1:
+       case CS42L73_PWRCTL2:
+       case CS42L73_PWRCTL3:
+       case CS42L73_CPFCHC:
+       case CS42L73_OLMBMSDC:
+       case CS42L73_DMMCC:
+       case CS42L73_XSPC:
+       case CS42L73_XSPMMCC:
+       case CS42L73_ASPC:
+       case CS42L73_ASPMMCC:
+       case CS42L73_VSPC:
+       case CS42L73_VSPMMCC:
+       case CS42L73_VXSPFS:
+       case CS42L73_MIOPC:
+       case CS42L73_ADCIPC:
+       case CS42L73_MICAPREPGAAVOL:
+       case CS42L73_MICBPREPGABVOL:
+       case CS42L73_IPADVOL:
+       case CS42L73_IPBDVOL:
+       case CS42L73_PBDC:
+       case CS42L73_HLADVOL:
+       case CS42L73_HLBDVOL:
+       case CS42L73_SPKDVOL:
+       case CS42L73_ESLDVOL:
+       case CS42L73_HPAAVOL:
+       case CS42L73_HPBAVOL:
+       case CS42L73_LOAAVOL:
+       case CS42L73_LOBAVOL:
+       case CS42L73_STRINV:
+       case CS42L73_XSPINV:
+       case CS42L73_ASPINV:
+       case CS42L73_VSPINV:
+       case CS42L73_LIMARATEHL:
+       case CS42L73_LIMRRATEHL:
+       case CS42L73_LMAXHL:
+       case CS42L73_LIMARATESPK:
+       case CS42L73_LIMRRATESPK:
+       case CS42L73_LMAXSPK:
+       case CS42L73_LIMARATEESL:
+       case CS42L73_LIMRRATEESL:
+       case CS42L73_LMAXESL:
+       case CS42L73_ALCARATE:
+       case CS42L73_ALCRRATE:
+       case CS42L73_ALCMINMAX:
+       case CS42L73_NGCAB:
+       case CS42L73_ALCNGMC:
+       case CS42L73_MIXERCTL:
+       case CS42L73_HLAIPAA:
+       case CS42L73_HLBIPBA:
+       case CS42L73_HLAXSPAA:
+       case CS42L73_HLBXSPBA:
+       case CS42L73_HLAASPAA:
+       case CS42L73_HLBASPBA:
+       case CS42L73_HLAVSPMA:
+       case CS42L73_HLBVSPMA:
+       case CS42L73_XSPAIPAA:
+       case CS42L73_XSPBIPBA:
+       case CS42L73_XSPAXSPAA:
+       case CS42L73_XSPBXSPBA:
+       case CS42L73_XSPAASPAA:
+       case CS42L73_XSPAASPBA:
+       case CS42L73_XSPAVSPMA:
+       case CS42L73_XSPBVSPMA:
+       case CS42L73_ASPAIPAA:
+       case CS42L73_ASPBIPBA:
+       case CS42L73_ASPAXSPAA:
+       case CS42L73_ASPBXSPBA:
+       case CS42L73_ASPAASPAA:
+       case CS42L73_ASPBASPBA:
+       case CS42L73_ASPAVSPMA:
+       case CS42L73_ASPBVSPMA:
+       case CS42L73_VSPAIPAA:
+       case CS42L73_VSPBIPBA:
+       case CS42L73_VSPAXSPAA:
+       case CS42L73_VSPBXSPBA:
+       case CS42L73_VSPAASPAA:
+       case CS42L73_VSPBASPBA:
+       case CS42L73_VSPAVSPMA:
+       case CS42L73_VSPBVSPMA:
+       case CS42L73_MMIXCTL:
+       case CS42L73_SPKMIPMA:
+       case CS42L73_SPKMXSPA:
+       case CS42L73_SPKMASPA:
+       case CS42L73_SPKMVSPMA:
+       case CS42L73_ESLMIPMA:
+       case CS42L73_ESLMXSPA:
+       case CS42L73_ESLMASPA:
+       case CS42L73_ESLMVSPMA:
+       case CS42L73_IM1:
+       case CS42L73_IM2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const unsigned int hpaloa_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 13, TLV_DB_SCALE_ITEM(-7600, 200, 0),
+       14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0),
+};
+
+static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2500, 0);
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(micpga_tlv, -600, 50, 0);
+
+static const unsigned int limiter_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+       3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
+
+static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };
+static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" };
+
+static const struct soc_enum pgaa_enum =
+       SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3,
+               ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text);
+
+static const struct soc_enum pgab_enum =
+       SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7,
+               ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text);
+
+static const struct snd_kcontrol_new pgaa_mux =
+       SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
+
+static const struct snd_kcontrol_new pgab_mux =
+       SOC_DAPM_ENUM("Right Analog Input Capture Mux", pgab_enum);
+
+static const struct snd_kcontrol_new input_left_mixer[] = {
+       SOC_DAPM_SINGLE("ADC Left Input", CS42L73_PWRCTL1,
+                       5, 1, 1),
+       SOC_DAPM_SINGLE("DMIC Left Input", CS42L73_PWRCTL1,
+                       4, 1, 1),
+};
+
+static const struct snd_kcontrol_new input_right_mixer[] = {
+       SOC_DAPM_SINGLE("ADC Right Input", CS42L73_PWRCTL1,
+                       7, 1, 1),
+       SOC_DAPM_SINGLE("DMIC Right Input", CS42L73_PWRCTL1,
+                       6, 1, 1),
+};
+
+static const char * const cs42l73_ng_delay_text[] = {
+       "50ms", "100ms", "150ms", "200ms" };
+
+static const struct soc_enum ng_delay_enum =
+       SOC_ENUM_SINGLE(CS42L73_NGCAB, 0,
+               ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
+
+static const char * const charge_pump_freq_text[] = {
+       "0", "1", "2", "3", "4",
+       "5", "6", "7", "8", "9",
+       "10", "11", "12", "13", "14", "15" };
+
+static const struct soc_enum charge_pump_enum =
+       SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4,
+               ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text);
+
+static const char * const cs42l73_mono_mix_texts[] = {
+       "Left", "Right", "Mono Mix"};
+
+static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
+
+static const struct soc_enum spk_asp_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 1,
+                             ARRAY_SIZE(cs42l73_mono_mix_texts),
+                             cs42l73_mono_mix_texts,
+                             cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new spk_asp_mixer =
+       SOC_DAPM_ENUM("Route", spk_asp_enum);
+
+static const struct soc_enum spk_xsp_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 4, 3,
+                             ARRAY_SIZE(cs42l73_mono_mix_texts),
+                             cs42l73_mono_mix_texts,
+                             cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new spk_xsp_mixer =
+       SOC_DAPM_ENUM("Route", spk_xsp_enum);
+
+static const struct soc_enum esl_asp_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 5,
+                             ARRAY_SIZE(cs42l73_mono_mix_texts),
+                             cs42l73_mono_mix_texts,
+                             cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new esl_asp_mixer =
+       SOC_DAPM_ENUM("Route", esl_asp_enum);
+
+static const struct soc_enum esl_xsp_enum =
+       SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 7,
+                             ARRAY_SIZE(cs42l73_mono_mix_texts),
+                             cs42l73_mono_mix_texts,
+                             cs42l73_mono_mix_values);
+
+static const struct snd_kcontrol_new esl_xsp_mixer =
+       SOC_DAPM_ENUM("Route", esl_xsp_enum);
+
+static const char * const cs42l73_ip_swap_text[] = {
+       "Stereo", "Mono A", "Mono B", "Swap A-B"};
+
+static const struct soc_enum ip_swap_enum =
+       SOC_ENUM_SINGLE(CS42L73_MIOPC, 6,
+               ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text);
+
+static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"};
+
+static const struct soc_enum vsp_output_mux_enum =
+       SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5,
+               ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+
+static const struct soc_enum xsp_output_mux_enum =
+       SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4,
+               ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
+
+static const struct snd_kcontrol_new vsp_output_mux =
+       SOC_DAPM_ENUM("Route", vsp_output_mux_enum);
+
+static const struct snd_kcontrol_new xsp_output_mux =
+       SOC_DAPM_ENUM("Route", xsp_output_mux_enum);
+
+static const struct snd_kcontrol_new hp_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new lo_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 1, 1, 1);
+
+static const struct snd_kcontrol_new spk_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new spklo_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new ear_amp_ctl =
+       SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 3, 1, 1);
+
+static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
+       SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
+                       CS42L73_HPAAVOL, CS42L73_HPBAVOL, 7,
+                       0xffffffC1, 0x0C, hpaloa_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
+                       CS42L73_LOBAVOL, 7, 0xffffffC1, 0x0C, hpaloa_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
+                       CS42L73_MICBPREPGABVOL, 5, 0xffffff35,
+                       0x34, micpga_tlv),
+
+       SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
+                       CS42L73_MICBPREPGABVOL, 6, 1, 1),
+
+       SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
+                       CS42L73_IPBDVOL, 7, 0xffffffA0, 0xA0, ipd_tlv),
+
+       SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
+                       CS42L73_HLADVOL, CS42L73_HLBDVOL, 7, 0xffffffE5,
+                       0xE4, hl_tlv),
+
+       SOC_SINGLE_TLV("ADC A Boost Volume",
+                       CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
+
+       SOC_SINGLE_TLV("ADC B Boost Volume",
+                       CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+
+       SOC_SINGLE_TLV("Speakerphone Digital Playback Volume",
+                       CS42L73_SPKDVOL, 0, 0xE4, 1, hl_tlv),
+
+       SOC_SINGLE_TLV("Ear Speaker Digital Playback Volume",
+                       CS42L73_ESLDVOL, 0, 0xE4, 1, hl_tlv),
+
+       SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
+                       CS42L73_HPBAVOL, 7, 1, 1),
+
+       SOC_DOUBLE_R("LineOut Analog Playback Switch", CS42L73_LOAAVOL,
+                       CS42L73_LOBAVOL, 7, 1, 1),
+       SOC_DOUBLE("Input Path Digital Switch", CS42L73_ADCIPC, 0, 4, 1, 1),
+       SOC_DOUBLE("HL Digital Playback Switch", CS42L73_PBDC, 0,
+                       1, 1, 1),
+       SOC_SINGLE("Speakerphone Digital Playback Switch", CS42L73_PBDC, 2, 1,
+                       1),
+       SOC_SINGLE("Ear Speaker Digital Playback Switch", CS42L73_PBDC, 3, 1,
+                       1),
+
+       SOC_SINGLE("PGA Soft-Ramp Switch", CS42L73_MIOPC, 3, 1, 0),
+       SOC_SINGLE("Analog Zero Cross Switch", CS42L73_MIOPC, 2, 1, 0),
+       SOC_SINGLE("Digital Soft-Ramp Switch", CS42L73_MIOPC, 1, 1, 0),
+       SOC_SINGLE("Analog Output Soft-Ramp Switch", CS42L73_MIOPC, 0, 1, 0),
+
+       SOC_DOUBLE("ADC Signal Polarity Switch", CS42L73_ADCIPC, 1, 5, 1,
+                       0),
+
+       SOC_SINGLE("HL Limiter Attack Rate", CS42L73_LIMARATEHL, 0, 0x3F,
+                       0),
+       SOC_SINGLE("HL Limiter Release Rate", CS42L73_LIMRRATEHL, 0,
+                       0x3F, 0),
+
+
+       SOC_SINGLE("HL Limiter Switch", CS42L73_LIMRRATEHL, 7, 1, 0),
+       SOC_SINGLE("HL Limiter All Channels Switch", CS42L73_LIMRRATEHL, 6, 1,
+                       0),
+
+       SOC_SINGLE_TLV("HL Limiter Max Threshold Volume", CS42L73_LMAXHL, 5, 7,
+                       1, limiter_tlv),
+
+       SOC_SINGLE_TLV("HL Limiter Cushion Volume", CS42L73_LMAXHL, 2, 7, 1,
+                       limiter_tlv),
+
+       SOC_SINGLE("SPK Limiter Attack Rate Volume", CS42L73_LIMARATESPK, 0,
+                       0x3F, 0),
+       SOC_SINGLE("SPK Limiter Release Rate Volume", CS42L73_LIMRRATESPK, 0,
+                       0x3F, 0),
+       SOC_SINGLE("SPK Limiter Switch", CS42L73_LIMRRATESPK, 7, 1, 0),
+       SOC_SINGLE("SPK Limiter All Channels Switch", CS42L73_LIMRRATESPK,
+                       6, 1, 0),
+       SOC_SINGLE_TLV("SPK Limiter Max Threshold Volume", CS42L73_LMAXSPK, 5,
+                       7, 1, limiter_tlv),
+
+       SOC_SINGLE_TLV("SPK Limiter Cushion Volume", CS42L73_LMAXSPK, 2, 7, 1,
+                       limiter_tlv),
+
+       SOC_SINGLE("ESL Limiter Attack Rate Volume", CS42L73_LIMARATEESL, 0,
+                       0x3F, 0),
+       SOC_SINGLE("ESL Limiter Release Rate Volume", CS42L73_LIMRRATEESL, 0,
+                       0x3F, 0),
+       SOC_SINGLE("ESL Limiter Switch", CS42L73_LIMRRATEESL, 7, 1, 0),
+       SOC_SINGLE_TLV("ESL Limiter Max Threshold Volume", CS42L73_LMAXESL, 5,
+                       7, 1, limiter_tlv),
+
+       SOC_SINGLE_TLV("ESL Limiter Cushion Volume", CS42L73_LMAXESL, 2, 7, 1,
+                       limiter_tlv),
+
+       SOC_SINGLE("ALC Attack Rate Volume", CS42L73_ALCARATE, 0, 0x3F, 0),
+       SOC_SINGLE("ALC Release Rate Volume", CS42L73_ALCRRATE, 0, 0x3F, 0),
+       SOC_DOUBLE("ALC Switch", CS42L73_ALCARATE, 6, 7, 1, 0),
+       SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L73_ALCMINMAX, 5, 7, 0,
+                       limiter_tlv),
+       SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L73_ALCMINMAX, 2, 7, 0,
+                       limiter_tlv),
+
+       SOC_DOUBLE("NG Enable Switch", CS42L73_NGCAB, 6, 7, 1, 0),
+       SOC_SINGLE("NG Boost Switch", CS42L73_NGCAB, 5, 1, 0),
+       /*
+           NG Threshold depends on NG_BOOTSAB, which selects
+           between two threshold scales in decibels.
+           Set linear values for now ..
+       */
+       SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),
+       SOC_ENUM("NG Delay", ng_delay_enum),
+
+       SOC_ENUM("Charge Pump Frequency", charge_pump_enum),
+
+       SOC_DOUBLE_R_TLV("XSP-IP Volume",
+                       CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("XSP-XSP Volume",
+                       CS42L73_XSPAXSPAA, CS42L73_XSPBXSPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("XSP-ASP Volume",
+                       CS42L73_XSPAASPAA, CS42L73_XSPAASPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("XSP-VSP Volume",
+                       CS42L73_XSPAVSPMA, CS42L73_XSPBVSPMA, 0, 0x3F, 1,
+                       attn_tlv),
+
+       SOC_DOUBLE_R_TLV("ASP-IP Volume",
+                       CS42L73_ASPAIPAA, CS42L73_ASPBIPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("ASP-XSP Volume",
+                       CS42L73_ASPAXSPAA, CS42L73_ASPBXSPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("ASP-ASP Volume",
+                       CS42L73_ASPAASPAA, CS42L73_ASPBASPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("ASP-VSP Volume",
+                       CS42L73_ASPAVSPMA, CS42L73_ASPBVSPMA, 0, 0x3F, 1,
+                       attn_tlv),
+
+       SOC_DOUBLE_R_TLV("VSP-IP Volume",
+                       CS42L73_VSPAIPAA, CS42L73_VSPBIPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("VSP-XSP Volume",
+                       CS42L73_VSPAXSPAA, CS42L73_VSPBXSPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("VSP-ASP Volume",
+                       CS42L73_VSPAASPAA, CS42L73_VSPBASPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("VSP-VSP Volume",
+                       CS42L73_VSPAVSPMA, CS42L73_VSPBVSPMA, 0, 0x3F, 1,
+                       attn_tlv),
+
+       SOC_DOUBLE_R_TLV("HL-IP Volume",
+                       CS42L73_HLAIPAA, CS42L73_HLBIPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("HL-XSP Volume",
+                       CS42L73_HLAXSPAA, CS42L73_HLBXSPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("HL-ASP Volume",
+                       CS42L73_HLAASPAA, CS42L73_HLBASPBA, 0, 0x3F, 1,
+                       attn_tlv),
+       SOC_DOUBLE_R_TLV("HL-VSP Volume",
+                       CS42L73_HLAVSPMA, CS42L73_HLBVSPMA, 0, 0x3F, 1,
+                       attn_tlv),
+
+       SOC_SINGLE_TLV("SPK-IP Mono Volume",
+                       CS42L73_SPKMIPMA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("SPK-XSP Mono Volume",
+                       CS42L73_SPKMXSPA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("SPK-ASP Mono Volume",
+                       CS42L73_SPKMASPA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("SPK-VSP Mono Volume",
+                       CS42L73_SPKMVSPMA, 0, 0x3E, 1, attn_tlv),
+
+       SOC_SINGLE_TLV("ESL-IP Mono Volume",
+                       CS42L73_ESLMIPMA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("ESL-XSP Mono Volume",
+                       CS42L73_ESLMXSPA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("ESL-ASP Mono Volume",
+                       CS42L73_ESLMASPA, 0, 0x3E, 1, attn_tlv),
+       SOC_SINGLE_TLV("ESL-VSP Mono Volume",
+                       CS42L73_ESLMVSPMA, 0, 0x3E, 1, attn_tlv),
+
+       SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum),
+
+       SOC_ENUM("VSPOUT Mono/Stereo Select", vsp_output_mux_enum),
+       SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
+};
+
+static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("LINEINA"),
+       SND_SOC_DAPM_INPUT("LINEINB"),
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_SUPPLY("MIC1 Bias", CS42L73_PWRCTL2, 6, 1, NULL, 0),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
+
+       SND_SOC_DAPM_AIF_OUT("XSPOUTL", "XSP Capture",  0,
+                       CS42L73_PWRCTL2, 1, 1),
+       SND_SOC_DAPM_AIF_OUT("XSPOUTR", "XSP Capture",  0,
+                       CS42L73_PWRCTL2, 1, 1),
+       SND_SOC_DAPM_AIF_OUT("ASPOUTL", "ASP Capture",  0,
+                       CS42L73_PWRCTL2, 3, 1),
+       SND_SOC_DAPM_AIF_OUT("ASPOUTR", "ASP Capture",  0,
+                       CS42L73_PWRCTL2, 3, 1),
+       SND_SOC_DAPM_AIF_OUT("VSPOUTL", "VSP Capture",  0,
+                       CS42L73_PWRCTL2, 4, 1),
+       SND_SOC_DAPM_AIF_OUT("VSPOUTR", "VSP Capture",  0,
+                       CS42L73_PWRCTL2, 4, 1),
+
+       SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("PGA Right", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("PGA Left Mux", SND_SOC_NOPM, 0, 0, &pgaa_mux),
+       SND_SOC_DAPM_MUX("PGA Right Mux", SND_SOC_NOPM, 0, 0, &pgab_mux),
+
+       SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L73_PWRCTL1, 7, 1),
+       SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L73_PWRCTL1, 5, 1),
+       SND_SOC_DAPM_ADC("DMIC Left", NULL, CS42L73_PWRCTL1, 6, 1),
+       SND_SOC_DAPM_ADC("DMIC Right", NULL, CS42L73_PWRCTL1, 4, 1),
+
+       SND_SOC_DAPM_MIXER_NAMED_CTL("Input Left Capture", SND_SOC_NOPM,
+                        0, 0, input_left_mixer,
+                        ARRAY_SIZE(input_left_mixer)),
+
+       SND_SOC_DAPM_MIXER_NAMED_CTL("Input Right Capture", SND_SOC_NOPM,
+                       0, 0, input_right_mixer,
+                       ARRAY_SIZE(input_right_mixer)),
+
+       SND_SOC_DAPM_MIXER("ASPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_AIF_IN("XSPINL", "XSP Playback", 0,
+                               CS42L73_PWRCTL2, 0, 1),
+       SND_SOC_DAPM_AIF_IN("XSPINR", "XSP Playback", 0,
+                               CS42L73_PWRCTL2, 0, 1),
+       SND_SOC_DAPM_AIF_IN("XSPINM", "XSP Playback", 0,
+                               CS42L73_PWRCTL2, 0, 1),
+
+       SND_SOC_DAPM_AIF_IN("ASPINL", "ASP Playback", 0,
+                               CS42L73_PWRCTL2, 2, 1),
+       SND_SOC_DAPM_AIF_IN("ASPINR", "ASP Playback", 0,
+                               CS42L73_PWRCTL2, 2, 1),
+       SND_SOC_DAPM_AIF_IN("ASPINM", "ASP Playback", 0,
+                               CS42L73_PWRCTL2, 2, 1),
+
+       SND_SOC_DAPM_AIF_IN("VSPIN", "VSP Playback", 0,
+                               CS42L73_PWRCTL2, 4, 1),
+
+       SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("HL Right Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("SPK Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ESL Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("ESL-XSP Mux", SND_SOC_NOPM,
+                        0, 0, &esl_xsp_mixer),
+
+       SND_SOC_DAPM_MUX("ESL-ASP Mux", SND_SOC_NOPM,
+                        0, 0, &esl_asp_mixer),
+
+       SND_SOC_DAPM_MUX("SPK-ASP Mux", SND_SOC_NOPM,
+                        0, 0, &spk_asp_mixer),
+
+       SND_SOC_DAPM_MUX("SPK-XSP Mux", SND_SOC_NOPM,
+                        0, 0, &spk_xsp_mixer),
+
+       SND_SOC_DAPM_PGA("HL Left DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HL Right DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1,
+                           &hp_amp_ctl),
+       SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1,
+                           &lo_amp_ctl),
+       SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1,
+                           &spk_amp_ctl),
+       SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1,
+                           &ear_amp_ctl),
+       SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
+                           &spklo_amp_ctl),
+
+       SND_SOC_DAPM_OUTPUT("HPOUTA"),
+       SND_SOC_DAPM_OUTPUT("HPOUTB"),
+       SND_SOC_DAPM_OUTPUT("LINEOUTA"),
+       SND_SOC_DAPM_OUTPUT("LINEOUTB"),
+       SND_SOC_DAPM_OUTPUT("EAROUT"),
+       SND_SOC_DAPM_OUTPUT("SPKOUT"),
+       SND_SOC_DAPM_OUTPUT("SPKLINEOUT"),
+};
+
+static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
+
+       /* SPKLO EARSPK Paths */
+       {"EAROUT", NULL, "EAR Amp"},
+       {"SPKLINEOUT", NULL, "SPKLO Amp"},
+
+       {"EAR Amp", "Switch", "ESL DAC"},
+       {"SPKLO Amp", "Switch", "ESL DAC"},
+
+       {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"},
+       {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"},
+       {"ESL DAC", "ESL-VSP Mono Volume", "VSPIN"},
+       /* Loopback */
+       {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"},
+       {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"},
+
+       {"ESL Mixer", NULL, "ESL-ASP Mux"},
+       {"ESL Mixer", NULL, "ESL-XSP Mux"},
+
+       {"ESL-ASP Mux", "Left", "ASPINL"},
+       {"ESL-ASP Mux", "Right", "ASPINR"},
+       {"ESL-ASP Mux", "Mono Mix", "ASPINM"},
+
+       {"ESL-XSP Mux", "Left", "XSPINL"},
+       {"ESL-XSP Mux", "Right", "XSPINR"},
+       {"ESL-XSP Mux", "Mono Mix", "XSPINM"},
+
+       /* Speakerphone Paths */
+       {"SPKOUT", NULL, "SPK Amp"},
+       {"SPK Amp", "Switch", "SPK DAC"},
+
+       {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"},
+       {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"},
+       {"SPK DAC", "SPK-VSP Mono Volume", "VSPIN"},
+       /* Loopback */
+       {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"},
+       {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"},
+
+       {"SPK Mixer", NULL, "SPK-ASP Mux"},
+       {"SPK Mixer", NULL, "SPK-XSP Mux"},
+
+       {"SPK-ASP Mux", "Left", "ASPINL"},
+       {"SPK-ASP Mux", "Mono Mix", "ASPINM"},
+       {"SPK-ASP Mux", "Right", "ASPINR"},
+
+       {"SPK-XSP Mux", "Left", "XSPINL"},
+       {"SPK-XSP Mux", "Mono Mix", "XSPINM"},
+       {"SPK-XSP Mux", "Right", "XSPINR"},
+
+       /* HP LineOUT Paths */
+       {"HPOUTA", NULL, "HP Amp"},
+       {"HPOUTB", NULL, "HP Amp"},
+       {"LINEOUTA", NULL, "LO Amp"},
+       {"LINEOUTB", NULL, "LO Amp"},
+
+       {"HP Amp", "Switch", "HL Left DAC"},
+       {"HP Amp", "Switch", "HL Right DAC"},
+       {"LO Amp", "Switch", "HL Left DAC"},
+       {"LO Amp", "Switch", "HL Right DAC"},
+
+       {"HL Left DAC", "HL-XSP Volume", "HL Left Mixer"},
+       {"HL Right DAC", "HL-XSP Volume", "HL Right Mixer"},
+       {"HL Left DAC", "HL-ASP Volume", "HL Left Mixer"},
+       {"HL Right DAC", "HL-ASP Volume", "HL Right Mixer"},
+       {"HL Left DAC", "HL-VSP Volume", "HL Left Mixer"},
+       {"HL Right DAC", "HL-VSP Volume", "HL Right Mixer"},
+       /* Loopback */
+       {"HL Left DAC", "HL-IP Volume", "HL Left Mixer"},
+       {"HL Right DAC", "HL-IP Volume", "HL Right Mixer"},
+       {"HL Left Mixer", NULL, "Input Left Capture"},
+       {"HL Right Mixer", NULL, "Input Right Capture"},
+
+       {"HL Left Mixer", NULL, "ASPINL"},
+       {"HL Right Mixer", NULL, "ASPINR"},
+       {"HL Left Mixer", NULL, "XSPINL"},
+       {"HL Right Mixer", NULL, "XSPINR"},
+       {"HL Left Mixer", NULL, "VSPIN"},
+       {"HL Right Mixer", NULL, "VSPIN"},
+
+       /* Capture Paths */
+       {"MIC1", NULL, "MIC1 Bias"},
+       {"PGA Left Mux", "Mic 1", "MIC1"},
+       {"MIC2", NULL, "MIC2 Bias"},
+       {"PGA Right Mux", "Mic 2", "MIC2"},
+
+       {"PGA Left Mux", "Line A", "LINEINA"},
+       {"PGA Right Mux", "Line B", "LINEINB"},
+
+       {"PGA Left", NULL, "PGA Left Mux"},
+       {"PGA Right", NULL, "PGA Right Mux"},
+
+       {"ADC Left", NULL, "PGA Left"},
+       {"ADC Right", NULL, "PGA Right"},
+
+       {"Input Left Capture", "ADC Left Input", "ADC Left"},
+       {"Input Right Capture", "ADC Right Input", "ADC Right"},
+       {"Input Left Capture", "DMIC Left Input", "DMIC Left"},
+       {"Input Right Capture", "DMIC Right Input", "DMIC Right"},
+
+       /* Audio Capture */
+       {"ASPL Output Mixer", NULL, "Input Left Capture"},
+       {"ASPR Output Mixer", NULL, "Input Right Capture"},
+
+       {"ASPOUTL", "ASP-IP Volume", "ASPL Output Mixer"},
+       {"ASPOUTR", "ASP-IP Volume", "ASPR Output Mixer"},
+
+       /* Auxillary Capture */
+       {"XSPL Output Mixer", NULL, "Input Left Capture"},
+       {"XSPR Output Mixer", NULL, "Input Right Capture"},
+
+       {"XSPOUTL", "XSP-IP Volume", "XSPL Output Mixer"},
+       {"XSPOUTR", "XSP-IP Volume", "XSPR Output Mixer"},
+
+       {"XSPOUTL", NULL, "XSPL Output Mixer"},
+       {"XSPOUTR", NULL, "XSPR Output Mixer"},
+
+       /* Voice Capture */
+       {"VSPL Output Mixer", NULL, "Input Left Capture"},
+       {"VSPR Output Mixer", NULL, "Input Left Capture"},
+
+       {"VSPOUTL", "VSP-IP Volume", "VSPL Output Mixer"},
+       {"VSPOUTR", "VSP-IP Volume", "VSPR Output Mixer"},
+
+       {"VSPOUTL", NULL, "VSPL Output Mixer"},
+       {"VSPOUTR", NULL, "VSPR Output Mixer"},
+};
+
+struct cs42l73_mclk_div {
+       u32 mclk;
+       u32 srate;
+       u8 mmcc;
+};
+
+static struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
+       /* MCLK, Sample Rate, xMMCC[5:0] */
+       {5644800, 11025, 0x30},
+       {5644800, 22050, 0x20},
+       {5644800, 44100, 0x10},
+
+       {6000000,  8000, 0x39},
+       {6000000, 11025, 0x33},
+       {6000000, 12000, 0x31},
+       {6000000, 16000, 0x29},
+       {6000000, 22050, 0x23},
+       {6000000, 24000, 0x21},
+       {6000000, 32000, 0x19},
+       {6000000, 44100, 0x13},
+       {6000000, 48000, 0x11},
+
+       {6144000,  8000, 0x38},
+       {6144000, 12000, 0x30},
+       {6144000, 16000, 0x28},
+       {6144000, 24000, 0x20},
+       {6144000, 32000, 0x18},
+       {6144000, 48000, 0x10},
+
+       {6500000,  8000, 0x3C},
+       {6500000, 11025, 0x35},
+       {6500000, 12000, 0x34},
+       {6500000, 16000, 0x2C},
+       {6500000, 22050, 0x25},
+       {6500000, 24000, 0x24},
+       {6500000, 32000, 0x1C},
+       {6500000, 44100, 0x15},
+       {6500000, 48000, 0x14},
+
+       {6400000,  8000, 0x3E},
+       {6400000, 11025, 0x37},
+       {6400000, 12000, 0x36},
+       {6400000, 16000, 0x2E},
+       {6400000, 22050, 0x27},
+       {6400000, 24000, 0x26},
+       {6400000, 32000, 0x1E},
+       {6400000, 44100, 0x17},
+       {6400000, 48000, 0x16},
+};
+
+struct cs42l73_mclkx_div {
+       u32 mclkx;
+       u8 ratio;
+       u8 mclkdiv;
+};
+
+static struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
+       {5644800,  1, 0},       /* 5644800 */
+       {6000000,  1, 0},       /* 6000000 */
+       {6144000,  1, 0},       /* 6144000 */
+       {11289600, 2, 2},       /* 5644800 */
+       {12288000, 2, 2},       /* 6144000 */
+       {12000000, 2, 2},       /* 6000000 */
+       {13000000, 2, 2},       /* 6500000 */
+       {19200000, 3, 3},       /* 6400000 */
+       {24000000, 4, 4},       /* 6000000 */
+       {26000000, 4, 4},       /* 6500000 */
+       {38400000, 6, 5}        /* 6400000 */
+};
+
+static int cs42l73_get_mclkx_coeff(int mclkx)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cs42l73_mclkx_coeffs); i++) {
+               if (cs42l73_mclkx_coeffs[i].mclkx == mclkx)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int cs42l73_get_mclk_coeff(int mclk, int srate)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cs42l73_mclk_coeffs); i++) {
+               if (cs42l73_mclk_coeffs[i].mclk == mclk &&
+                   cs42l73_mclk_coeffs[i].srate == srate)
+                       return i;
+       }
+       return -EINVAL;
+
+}
+
+static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       int mclkx_coeff;
+       u32 mclk = 0;
+       u8 dmmcc = 0;
+
+       /* MCLKX -> MCLK */
+       mclkx_coeff = cs42l73_get_mclkx_coeff(freq);
+
+       mclk = cs42l73_mclkx_coeffs[mclkx_coeff].mclkx /
+               cs42l73_mclkx_coeffs[mclkx_coeff].ratio;
+
+       dev_dbg(codec->dev, "MCLK%u %u  <-> internal MCLK %u\n",
+                priv->mclksel + 1, cs42l73_mclkx_coeffs[mclkx_coeff].mclkx,
+                mclk);
+
+       dmmcc = (priv->mclksel << 4) |
+               (cs42l73_mclkx_coeffs[mclkx_coeff].mclkdiv << 1);
+
+       snd_soc_write(codec, CS42L73_DMMCC, dmmcc);
+
+       priv->sysclk = mclkx_coeff;
+       priv->mclk = mclk;
+
+       return 0;
+}
+
+static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
+                             int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case CS42L73_CLKID_MCLK1:
+               break;
+       case CS42L73_CLKID_MCLK2:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if ((cs42l73_set_mclk(dai, freq)) < 0) {
+               dev_err(codec->dev, "Unable to set MCLK for dai %s\n",
+                       dai->name);
+               return -EINVAL;
+       }
+
+       priv->mclksel = clk_id;
+
+       return 0;
+}
+
+static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       u8 id = codec_dai->id;
+       unsigned int inv, format;
+       u8 spc, mmcc;
+
+       spc = snd_soc_read(codec, CS42L73_SPC(id));
+       mmcc = snd_soc_read(codec, CS42L73_MMCC(id));
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               mmcc |= MS_MASTER;
+               break;
+
+       case SND_SOC_DAIFMT_CBS_CFS:
+               mmcc &= ~MS_MASTER;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+       inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
+
+       switch (format) {
+       case SND_SOC_DAIFMT_I2S:
+               spc &= ~SPDIF_PCM;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               if (mmcc & MS_MASTER) {
+                       dev_err(codec->dev,
+                               "PCM format in slave mode only\n");
+                       return -EINVAL;
+               }
+               if (id == CS42L73_ASP) {
+                       dev_err(codec->dev,
+                               "PCM format is not supported on ASP port\n");
+                       return -EINVAL;
+               }
+               spc |= SPDIF_PCM;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (spc & SPDIF_PCM) {
+               /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */
+               spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER);
+               switch (format) {
+               case SND_SOC_DAIFMT_DSP_B:
+                       if (inv == SND_SOC_DAIFMT_IB_IF)
+                               spc |= PCM_MODE0;
+                       if (inv == SND_SOC_DAIFMT_IB_NF)
+                               spc |= PCM_MODE1;
+               break;
+               case SND_SOC_DAIFMT_DSP_A:
+                       if (inv == SND_SOC_DAIFMT_IB_IF)
+                               spc |= PCM_MODE1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       priv->config[id].spc = spc;
+       priv->config[id].mmcc = mmcc;
+
+       return 0;
+}
+
+static u32 cs42l73_asrc_rates[] = {
+       8000, 11025, 12000, 16000, 22050,
+       24000, 32000, 44100, 48000
+};
+
+static unsigned int cs42l73_get_xspfs_coeff(u32 rate)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(cs42l73_asrc_rates); i++) {
+               if (cs42l73_asrc_rates[i] == rate)
+                       return i + 1;
+       }
+       return 0;               /* 0 = Don't know */
+}
+
+static void cs42l73_update_asrc(struct snd_soc_codec *codec, int id, int srate)
+{
+       u8 spfs = 0;
+
+       if (srate > 0)
+               spfs = cs42l73_get_xspfs_coeff(srate);
+
+       switch (id) {
+       case CS42L73_XSP:
+               snd_soc_update_bits(codec, CS42L73_VXSPFS, 0x0f, spfs);
+       break;
+       case CS42L73_ASP:
+               snd_soc_update_bits(codec, CS42L73_ASPC, 0x3c, spfs << 2);
+       break;
+       case CS42L73_VSP:
+               snd_soc_update_bits(codec, CS42L73_VXSPFS, 0xf0, spfs << 4);
+       break;
+       default:
+       break;
+       }
+}
+
+static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       int id = dai->id;
+       int mclk_coeff;
+       int srate = params_rate(params);
+
+       if (priv->config[id].mmcc & MS_MASTER) {
+               /* CS42L73 Master */
+               /* MCLK -> srate */
+               mclk_coeff =
+                   cs42l73_get_mclk_coeff(priv->mclk, srate);
+
+               if (mclk_coeff < 0)
+                       return -EINVAL;
+
+               dev_dbg(codec->dev,
+                        "DAI[%d]: MCLK %u, srate %u, MMCC[5:0] = %x\n",
+                        id, priv->mclk, srate,
+                        cs42l73_mclk_coeffs[mclk_coeff].mmcc);
+
+               priv->config[id].mmcc &= 0xC0;
+               priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
+               priv->config[id].spc &= 0xFC;
+               priv->config[id].spc &= MCK_SCLK_64FS;
+       } else {
+               /* CS42L73 Slave */
+               priv->config[id].spc &= 0xFC;
+               priv->config[id].spc |= MCK_SCLK_64FS;
+       }
+       /* Update ASRCs */
+       priv->config[id].srate = srate;
+
+       snd_soc_write(codec, CS42L73_SPC(id), priv->config[id].spc);
+       snd_soc_write(codec, CS42L73_MMCC(id), priv->config[id].mmcc);
+
+       cs42l73_update_asrc(codec, id, srate);
+
+       return 0;
+}
+
+static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0);
+               snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0);
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       regcache_cache_only(cs42l73->regmap, false);
+                       regcache_sync(cs42l73->regmap);
+               }
+               snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+               snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int id = dai->id;
+
+       return snd_soc_update_bits(codec, CS42L73_SPC(id),
+                                       0x7F, tristate << 7);
+}
+
+static struct snd_pcm_hw_constraint_list constraints_12_24 = {
+       .count  = ARRAY_SIZE(cs42l73_asrc_rates),
+       .list   = cs42l73_asrc_rates,
+};
+
+static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       &constraints_12_24);
+       return 0;
+}
+
+/* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */
+#define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+
+#define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+       SNDRV_PCM_FMTBIT_S24_LE)
+
+static const struct snd_soc_dai_ops cs42l73_ops = {
+       .startup = cs42l73_pcm_startup,
+       .hw_params = cs42l73_pcm_hw_params,
+       .set_fmt = cs42l73_set_dai_fmt,
+       .set_sysclk = cs42l73_set_sysclk,
+       .set_tristate = cs42l73_set_tristate,
+};
+
+static struct snd_soc_dai_driver cs42l73_dai[] = {
+       {
+               .name = "cs42l73-xsp",
+               .id = CS42L73_XSP,
+               .playback = {
+                       .stream_name = "XSP Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "XSP Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .ops = &cs42l73_ops,
+               .symmetric_rates = 1,
+        },
+       {
+               .name = "cs42l73-asp",
+               .id = CS42L73_ASP,
+               .playback = {
+                       .stream_name = "ASP Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "ASP Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .ops = &cs42l73_ops,
+               .symmetric_rates = 1,
+        },
+       {
+               .name = "cs42l73-vsp",
+               .id = CS42L73_VSP,
+               .playback = {
+                       .stream_name = "VSP Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "VSP Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = CS42L73_RATES,
+                       .formats = CS42L73_FORMATS,
+               },
+               .ops = &cs42l73_ops,
+               .symmetric_rates = 1,
+        }
+};
+
+static int cs42l73_suspend(struct snd_soc_codec *codec)
+{
+       cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int cs42l73_resume(struct snd_soc_codec *codec)
+{
+       cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+
+static int cs42l73_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec);
+
+       codec->control_data = cs42l73->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       regcache_cache_only(cs42l73->regmap, true);
+
+       cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */
+       cs42l73->mclk = 0;
+
+       return ret;
+}
+
+static int cs42l73_remove(struct snd_soc_codec *codec)
+{
+       cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
+       .probe = cs42l73_probe,
+       .remove = cs42l73_remove,
+       .suspend = cs42l73_suspend,
+       .resume = cs42l73_resume,
+       .set_bias_level = cs42l73_set_bias_level,
+
+       .dapm_widgets = cs42l73_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
+       .dapm_routes = cs42l73_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map),
+
+       .controls = cs42l73_snd_controls,
+       .num_controls = ARRAY_SIZE(cs42l73_snd_controls),
+};
+
+static struct regmap_config cs42l73_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = CS42L73_MAX_REGISTER,
+       .reg_defaults = cs42l73_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs42l73_reg_defaults),
+       .volatile_reg = cs42l73_volatile_register,
+       .readable_reg = cs42l73_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client,
+                                      const struct i2c_device_id *id)
+{
+       struct cs42l73_private *cs42l73;
+       int ret;
+       unsigned int devid = 0;
+       unsigned int reg;
+
+       cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private),
+                              GFP_KERNEL);
+       if (!cs42l73) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs42l73);
+
+       cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap);
+       if (IS_ERR(cs42l73->regmap)) {
+               ret = PTR_ERR(cs42l73->regmap);
+               dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+               goto err;
+       }
+       /* initialize codec */
+       ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
+       devid = (reg & 0xFF) << 12;
+
+       ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_CD, &reg);
+       devid |= (reg & 0xFF) << 4;
+
+       ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, &reg);
+       devid |= (reg & 0xF0) >> 4;
+
+
+       if (devid != CS42L73_DEVID) {
+               ret = -ENODEV;
+               dev_err(&i2c_client->dev,
+                       "CS42L73 Device ID (%X). Expected %X\n",
+                       devid, CS42L73_DEVID);
+               goto err_regmap;
+       }
+
+       ret = regmap_read(cs42l73->regmap, CS42L73_REVID, &reg);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "Get Revision ID failed\n");
+               goto err_regmap;
+       }
+
+       dev_info(&i2c_client->dev,
+                "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
+
+       regcache_cache_only(cs42l73->regmap, true);
+
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_dev_cs42l73, cs42l73_dai,
+                       ARRAY_SIZE(cs42l73_dai));
+       if (ret < 0)
+               goto err_regmap;
+       return 0;
+
+err_regmap:
+       regmap_exit(cs42l73->regmap);
+
+err:
+       return ret;
+}
+
+static __devexit int cs42l73_i2c_remove(struct i2c_client *client)
+{
+       struct cs42l73_private *cs42l73 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       regmap_exit(cs42l73->regmap);
+
+       return 0;
+}
+
+static const struct i2c_device_id cs42l73_id[] = {
+       {"cs42l73", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs42l73_id);
+
+static struct i2c_driver cs42l73_i2c_driver = {
+       .driver = {
+                  .name = "cs42l73",
+                  .owner = THIS_MODULE,
+                  },
+       .id_table = cs42l73_id,
+       .probe = cs42l73_i2c_probe,
+       .remove = __devexit_p(cs42l73_i2c_remove),
+
+};
+
+static int __init cs42l73_modinit(void)
+{
+       int ret;
+       ret = i2c_add_driver(&cs42l73_i2c_driver);
+       if (ret != 0) {
+               pr_err("Failed to register CS42L73 I2C driver: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+module_init(cs42l73_modinit);
+
+static void __exit cs42l73_exit(void)
+{
+       i2c_del_driver(&cs42l73_i2c_driver);
+}
+
+module_exit(cs42l73_exit);
+
+MODULE_DESCRIPTION("ASoC CS42L73 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h
new file mode 100644 (file)
index 0000000..f30a4c4
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * ALSA SoC CS42L73 codec driver
+ *
+ * Copyright 2011 Cirrus Logic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ *        Brian Austin <brian.austin@cirrus.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 __CS42L73_H__
+#define __CS42L73_H__
+
+/* I2C Registers */
+/* I2C Address: 1001010[R/W] - 10010100 = 0x94(Write); 10010101 = 0x95(Read) */
+#define CS42L73_CHIP_ID                0x4a
+#define CS42L73_DEVID_AB       0x01    /* Device ID A & B [RO]. */
+#define CS42L73_DEVID_CD       0x02    /* Device ID C & D [RO]. */
+#define CS42L73_DEVID_E                0x03    /* Device ID E [RO]. */
+#define CS42L73_REVID          0x05    /* Revision ID [RO]. */
+#define CS42L73_PWRCTL1                0x06    /* Power Control 1. */
+#define CS42L73_PWRCTL2                0x07    /* Power Control 2. */
+#define CS42L73_PWRCTL3                0x08    /* Power Control 3. */
+#define CS42L73_CPFCHC         0x09    /* Charge Pump Freq. Class H Ctl. */
+#define CS42L73_OLMBMSDC       0x0A    /* Output Load, MIC Bias, MIC2 SDT */
+#define CS42L73_DMMCC          0x0B    /* Digital MIC & Master Clock Ctl. */
+#define CS42L73_XSPC           0x0C    /* Auxiliary Serial Port (XSP) Ctl. */
+#define CS42L73_XSPMMCC                0x0D    /* XSP Master Mode Clocking Control. */
+#define CS42L73_ASPC           0x0E    /* Audio Serial Port (ASP) Control. */
+#define CS42L73_ASPMMCC                0x0F    /* ASP Master Mode Clocking Control. */
+#define CS42L73_VSPC           0x10    /* Voice Serial Port (VSP) Control. */
+#define CS42L73_VSPMMCC                0x11    /* VSP Master Mode Clocking Control. */
+#define CS42L73_VXSPFS         0x12    /* VSP & XSP Sample Rate. */
+#define CS42L73_MIOPC          0x13    /* Misc. Input & Output Path Control. */
+#define CS42L73_ADCIPC         0x14    /* ADC/IP Control. */
+#define CS42L73_MICAPREPGAAVOL 0x15    /* MIC 1 [A] PreAmp, PGAA Vol. */
+#define CS42L73_MICBPREPGABVOL 0x16    /* MIC 2 [B] PreAmp, PGAB Vol. */
+#define CS42L73_IPADVOL                0x17    /* Input Pat7h A Digital Volume. */
+#define CS42L73_IPBDVOL                0x18    /* Input Path B Digital Volume. */
+#define CS42L73_PBDC           0x19    /* Playback Digital Control. */
+#define CS42L73_HLADVOL                0x1A    /* HP/Line A Out Digital Vol. */
+#define CS42L73_HLBDVOL                0x1B    /* HP/Line B Out Digital Vol. */
+#define CS42L73_SPKDVOL                0x1C    /* Spkphone Out [A] Digital Vol. */
+#define CS42L73_ESLDVOL                0x1D    /* Ear/Spkphone LO [B] Digital */
+#define CS42L73_HPAAVOL                0x1E    /* HP A Analog Volume. */
+#define CS42L73_HPBAVOL                0x1F    /* HP B Analog Volume. */
+#define CS42L73_LOAAVOL                0x20    /* Line Out A Analog Volume. */
+#define CS42L73_LOBAVOL                0x21    /* Line Out B Analog Volume. */
+#define CS42L73_STRINV         0x22    /* Stereo Input Path Adv. Vol. */
+#define CS42L73_XSPINV         0x23    /* Auxiliary Port Input Advisory Vol. */
+#define CS42L73_ASPINV         0x24    /* Audio Port Input Advisory Vol. */
+#define CS42L73_VSPINV         0x25    /* Voice Port Input Advisory Vol. */
+#define CS42L73_LIMARATEHL     0x26    /* Lmtr Attack Rate HP/Line. */
+#define CS42L73_LIMRRATEHL     0x27    /* Lmtr Ctl, Rel.Rate HP/Line. */
+#define CS42L73_LMAXHL         0x28    /* Lmtr Thresholds HP/Line. */
+#define CS42L73_LIMARATESPK    0x29    /* Lmtr Attack Rate Spkphone [A]. */
+#define CS42L73_LIMRRATESPK    0x2A    /* Lmtr Ctl,Release Rate Spk. [A]. */
+#define CS42L73_LMAXSPK                0x2B    /* Lmtr Thresholds Spkphone [A]. */
+#define CS42L73_LIMARATEESL    0x2C    /* Lmtr Attack Rate  */
+#define CS42L73_LIMRRATEESL    0x2D    /* Lmtr Ctl,Release Rate */
+#define CS42L73_LMAXESL                0x2E    /* Lmtr Thresholds */
+#define CS42L73_ALCARATE       0x2F    /* ALC Enable, Attack Rate AB. */
+#define CS42L73_ALCRRATE       0x30    /* ALC Release Rate AB.  */
+#define CS42L73_ALCMINMAX      0x31    /* ALC Thresholds AB. */
+#define CS42L73_NGCAB          0x32    /* Noise Gate Ctl AB. */
+#define CS42L73_ALCNGMC                0x33    /* ALC & Noise Gate Misc Ctl. */
+#define CS42L73_MIXERCTL       0x34    /* Mixer Control. */
+#define CS42L73_HLAIPAA                0x35    /* HP/LO Left Mixer: L. */
+#define CS42L73_HLBIPBA                0x36    /* HP/LO Right Mixer: R.  */
+#define CS42L73_HLAXSPAA       0x37    /* HP/LO Left Mixer: XSP L */
+#define CS42L73_HLBXSPBA       0x38    /* HP/LO Right Mixer: XSP R */
+#define CS42L73_HLAASPAA       0x39    /* HP/LO Left Mixer: ASP L */
+#define CS42L73_HLBASPBA       0x3A    /* HP/LO Right Mixer: ASP R */
+#define CS42L73_HLAVSPMA       0x3B    /* HP/LO Left Mixer: VSP. */
+#define CS42L73_HLBVSPMA       0x3C    /* HP/LO Right Mixer: VSP */
+#define CS42L73_XSPAIPAA       0x3D    /* XSP Left Mixer: Left */
+#define CS42L73_XSPBIPBA       0x3E    /* XSP Rt. Mixer: Right */
+#define CS42L73_XSPAXSPAA      0x3F    /* XSP Left Mixer: XSP L */
+#define CS42L73_XSPBXSPBA      0x40    /* XSP Rt. Mixer: XSP R */
+#define CS42L73_XSPAASPAA      0x41    /* XSP Left Mixer: ASP L */
+#define CS42L73_XSPAASPBA      0x42    /* XSP Rt. Mixer: ASP R */
+#define CS42L73_XSPAVSPMA      0x43    /* XSP Left Mixer: VSP */
+#define CS42L73_XSPBVSPMA      0x44    /* XSP Rt. Mixer: VSP */
+#define CS42L73_ASPAIPAA       0x45    /* ASP Left Mixer: Left */
+#define CS42L73_ASPBIPBA       0x46    /* ASP Rt. Mixer: Right */
+#define CS42L73_ASPAXSPAA      0x47    /* ASP Left Mixer: XSP L */
+#define CS42L73_ASPBXSPBA      0x48    /* ASP Rt. Mixer: XSP R */
+#define CS42L73_ASPAASPAA      0x49    /* ASP Left Mixer: ASP L */
+#define CS42L73_ASPBASPBA      0x4A    /* ASP Rt. Mixer: ASP R */
+#define CS42L73_ASPAVSPMA      0x4B    /* ASP Left Mixer: VSP */
+#define CS42L73_ASPBVSPMA      0x4C    /* ASP Rt. Mixer: VSP */
+#define CS42L73_VSPAIPAA       0x4D    /* VSP Left Mixer: Left */
+#define CS42L73_VSPBIPBA       0x4E    /* VSP Rt. Mixer: Right */
+#define CS42L73_VSPAXSPAA      0x4F    /* VSP Left Mixer: XSP L */
+#define CS42L73_VSPBXSPBA      0x50    /* VSP Rt. Mixer: XSP R */
+#define CS42L73_VSPAASPAA      0x51    /* VSP Left Mixer: ASP Left */
+#define CS42L73_VSPBASPBA      0x52    /* VSP Rt. Mixer: ASP Right */
+#define CS42L73_VSPAVSPMA      0x53    /* VSP Left Mixer: VSP */
+#define CS42L73_VSPBVSPMA      0x54    /* VSP Rt. Mixer: VSP */
+#define CS42L73_MMIXCTL                0x55    /* Mono Mixer Controls. */
+#define CS42L73_SPKMIPMA       0x56    /* SPK Mono Mixer: In. Path */
+#define CS42L73_SPKMXSPA       0x57    /* SPK Mono Mixer: XSP Mono/L/R Att. */
+#define CS42L73_SPKMASPA       0x58    /* SPK Mono Mixer: ASP Mono/L/R Att. */
+#define CS42L73_SPKMVSPMA      0x59    /* SPK Mono Mixer: VSP Mono Atten. */
+#define CS42L73_ESLMIPMA       0x5A    /* Ear/SpLO Mono Mixer: */
+#define CS42L73_ESLMXSPA       0x5B    /* Ear/SpLO Mono Mixer: XSP */
+#define CS42L73_ESLMASPA       0x5C    /* Ear/SpLO Mono Mixer: ASP */
+#define CS42L73_ESLMVSPMA      0x5D    /* Ear/SpLO Mono Mixer: VSP */
+#define CS42L73_IM1            0x5E    /* Interrupt Mask 1.  */
+#define CS42L73_IM2            0x5F    /* Interrupt Mask 2. */
+#define CS42L73_IS1            0x60    /* Interrupt Status 1 [RO]. */
+#define CS42L73_IS2            0x61    /* Interrupt Status 2 [RO]. */
+#define CS42L73_MAX_REGISTER   0x61    /* Total Registers */
+/* Bitfield Definitions */
+
+/* CS42L73_PWRCTL1 */
+#define PDN_ADCB               (1 << 7)
+#define PDN_DMICB              (1 << 6)
+#define PDN_ADCA               (1 << 5)
+#define PDN_DMICA              (1 << 4)
+#define PDN_LDO                        (1 << 2)
+#define DISCHG_FILT            (1 << 1)
+#define PDN                    (1 << 0)
+
+/* CS42L73_PWRCTL2 */
+#define PDN_MIC2_BIAS          (1 << 7)
+#define PDN_MIC1_BIAS          (1 << 6)
+#define PDN_VSP                        (1 << 4)
+#define PDN_ASP_SDOUT          (1 << 3)
+#define PDN_ASP_SDIN           (1 << 2)
+#define PDN_XSP_SDOUT          (1 << 1)
+#define PDN_XSP_SDIN           (1 << 0)
+
+/* CS42L73_PWRCTL3 */
+#define PDN_THMS               (1 << 5)
+#define PDN_SPKLO              (1 << 4)
+#define PDN_EAR                        (1 << 3)
+#define PDN_SPK                        (1 << 2)
+#define PDN_LO                 (1 << 1)
+#define PDN_HP                 (1 << 0)
+
+/* Thermal Overload Detect. Requires interrupt ... */
+#define THMOVLD_150C           0
+#define THMOVLD_132C           1
+#define THMOVLD_115C           2
+#define THMOVLD_098C           3
+
+
+/* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */
+#define        SP_3ST                  (1 << 7)
+#define SPDIF_I2S              (0 << 6)
+#define SPDIF_PCM              (1 << 6)
+#define PCM_MODE0              (0 << 4)
+#define PCM_MODE1              (1 << 4)
+#define PCM_MODE2              (2 << 4)
+#define PCM_MODE_MASK          (3 << 4)
+#define PCM_BIT_ORDER          (1 << 3)
+#define MCK_SCLK_64FS          (0 << 0)
+#define MCK_SCLK_MCLK          (2 << 0)
+#define MCK_SCLK_PREMCLK       (3 << 0)
+
+/* CS42L73_xSPMMCC */
+#define MS_MASTER              (1 << 7)
+
+
+/* CS42L73_DMMCC */
+#define MCLKDIS                        (1 << 0)
+#define MCLKSEL_MCLK2          (1 << 4)
+#define MCLKSEL_MCLK1          (0 << 4)
+
+/* CS42L73 MCLK derived from MCLK1 or MCLK2 */
+#define CS42L73_CLKID_MCLK1     0
+#define CS42L73_CLKID_MCLK2     1
+
+#define CS42L73_MCLKXDIV       0
+#define CS42L73_MMCCDIV         1
+
+#define CS42L73_XSP            0
+#define CS42L73_ASP            1
+#define CS42L73_VSP            2
+
+/* IS1, IM1 */
+#define MIC2_SDET              (1 << 6)
+#define THMOVLD                        (1 << 4)
+#define DIGMIXOVFL             (1 << 3)
+#define IPBOVFL                        (1 << 1)
+#define IPAOVFL                        (1 << 0)
+
+/* Analog Softramp */
+#define ANLGOSFT               (1 << 0)
+
+/* HP A/B Analog Mute */
+#define HPA_MUTE               (1 << 7)
+/* LO A/B Analog Mute  */
+#define LOA_MUTE               (1 << 7)
+/* Digital Mute */
+#define HLAD_MUTE              (1 << 0)
+#define HLBD_MUTE              (1 << 1)
+#define SPKD_MUTE              (1 << 2)
+#define ESLD_MUTE              (1 << 3)
+
+/* Misc defines for codec */
+#define CS42L73_RESET_GPIO 143
+
+#define CS42L73_DEVID          0x00042A73
+#define CS42L73_MCLKX_MIN      5644800
+#define CS42L73_MCLKX_MAX      38400000
+
+#define CS42L73_SPC(id)                (CS42L73_XSPC + (id << 1))
+#define CS42L73_MMCC(id)       (CS42L73_XSPMMCC + (id << 1))
+#define CS42L73_SPFS(id)       ((id == CS42L73_ASP) ? CS42L73_ASPC : CS42L73_VXSPFS)
+
+#endif /* __CS42L73_H__ */
index bc7067db8ae4ec54697c4163e23f97af3670bd19..d5fd00a64748097ad1794ed9cc45178c513c6b68 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/regulator/consumer.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
@@ -25,8 +26,8 @@
 
 
 struct cx20442_priv {
-       enum snd_soc_control_type control_type;
        void *control_data;
+       struct regulator *por;
 };
 
 #define CX20442_PM             0x0
@@ -324,6 +325,38 @@ static struct snd_soc_dai_driver cx20442_dai = {
        },
 };
 
+static int cx20442_set_bias_level(struct snd_soc_codec *codec,
+               enum snd_soc_bias_level level)
+{
+       struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
+       int err = 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (codec->dapm.bias_level != SND_SOC_BIAS_STANDBY)
+                       break;
+               if (IS_ERR(cx20442->por))
+                       err = PTR_ERR(cx20442->por);
+               else
+                       err = regulator_enable(cx20442->por);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level != SND_SOC_BIAS_PREPARE)
+                       break;
+               if (IS_ERR(cx20442->por))
+                       err = PTR_ERR(cx20442->por);
+               else
+                       err = regulator_disable(cx20442->por);
+               break;
+       default:
+               break;
+       }
+       if (!err)
+               codec->dapm.bias_level = level;
+
+       return err;
+}
+
 static int cx20442_codec_probe(struct snd_soc_codec *codec)
 {
        struct cx20442_priv *cx20442;
@@ -331,9 +364,13 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
        cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
        if (cx20442 == NULL)
                return -ENOMEM;
-       snd_soc_codec_set_drvdata(codec, cx20442);
 
+       cx20442->por = regulator_get(codec->dev, "POR");
+       if (IS_ERR(cx20442->por))
+               dev_warn(codec->dev, "failed to get the regulator");
        cx20442->control_data = NULL;
+
+       snd_soc_codec_set_drvdata(codec, cx20442);
        codec->hw_write = NULL;
        codec->card->pop_time = 0;
 
@@ -350,6 +387,12 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
                        tty_hangup(tty);
        }
 
+       if (!IS_ERR(cx20442->por)) {
+               /* should be already in STANDBY, hence disabled */
+               regulator_put(cx20442->por);
+       }
+
+       snd_soc_codec_set_drvdata(codec, NULL);
        kfree(cx20442);
        return 0;
 }
@@ -359,6 +402,7 @@ static const u8 cx20442_reg;
 static struct snd_soc_codec_driver cx20442_codec_dev = {
        .probe =        cx20442_codec_probe,
        .remove =       cx20442_codec_remove,
+       .set_bias_level = cx20442_set_bias_level,
        .reg_cache_default = &cx20442_reg,
        .reg_cache_size = 1,
        .reg_word_size = sizeof(u8),
@@ -391,17 +435,7 @@ static struct platform_driver cx20442_platform_driver = {
        .remove = __exit_p(cx20442_platform_remove),
 };
 
-static int __init cx20442_init(void)
-{
-       return platform_driver_register(&cx20442_platform_driver);
-}
-module_init(cx20442_init);
-
-static void __exit cx20442_exit(void)
-{
-       platform_driver_unregister(&cx20442_platform_driver);
-}
-module_exit(cx20442_exit);
+module_platform_driver(cx20442_platform_driver);
 
 MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
 MODULE_AUTHOR("Janusz Krzysztofik");
index b545b7d3722271dd14e43213a34992a0b5174525..ab38e93c3543220d7ea55b33c0172487d00783cd 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <sound/pcm.h>
 
 /* AUX1_L bit fields */
 #define DA7210_AUX1_L_VOL              (0x3F << 0)
+#define DA7210_AUX1_L_EN               (1 << 7)
 
 /* AUX1_R bit fields */
 #define DA7210_AUX1_R_VOL              (0x3F << 0)
+#define DA7210_AUX1_R_EN               (1 << 7)
+
+/* AUX2 bit fields */
+#define DA7210_AUX2_EN                 (1 << 3)
 
 /* Minimum INPGA and AUX1 volume to enable noise suppression */
 #define DA7210_INPGA_MIN_VOL_NS                0x0A  /* 10.5dB */
@@ -235,12 +239,22 @@ static const unsigned int mono_vol_tlv[] = {
        0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
 };
 
+static const unsigned int aux1_vol_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+       /* -48dB to 21dB */
+       0x11, 0x3f, TLV_DB_SCALE_ITEM(-4800, 150, 0)
+};
+
 static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
 static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1);
 static const DECLARE_TLV_DB_SCALE(dac_gain_tlv, -7725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(aux2_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(inpga_gain_tlv, -450, 150, 0);
 
 /* ADC and DAC high pass filter f0 value */
-static const char const *da7210_hpf_cutoff_txt[] = {
+static const char * const da7210_hpf_cutoff_txt[] = {
        "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
 };
 
@@ -251,7 +265,7 @@ static const struct soc_enum da7210_adc_hpf_cutoff =
        SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt);
 
 /* ADC and DAC voice (8kHz) high pass cutoff value */
-static const char const *da7210_vf_cutoff_txt[] = {
+static const char * const da7210_vf_cutoff_txt[] = {
        "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
 };
 
@@ -345,6 +359,17 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
        SOC_SINGLE_TLV("Mono Playback Volume", DA7210_OUT2, 0, 0x7, 0,
                       mono_vol_tlv),
 
+       SOC_DOUBLE_R_TLV("Mic Capture Volume",
+                        DA7210_MIC_L, DA7210_MIC_R,
+                        0, 0x5, 0, mic_vol_tlv),
+       SOC_DOUBLE_R_TLV("Aux1 Capture Volume",
+                        DA7210_AUX1_L, DA7210_AUX1_R,
+                        0, 0x3f, 0, aux1_vol_tlv),
+       SOC_SINGLE_TLV("Aux2 Capture Volume", DA7210_AUX2, 0, 0x3, 0,
+                      aux2_vol_tlv),
+       SOC_DOUBLE_TLV("In PGA Capture Volume", DA7210_IN_GAIN, 0, 4, 0xF, 0,
+                      inpga_gain_tlv),
+
        /* DAC Equalizer  controls */
        SOC_SINGLE("DAC EQ Switch", DA7210_DAC_EQ5, 7, 1, 0),
        SOC_SINGLE_TLV("DAC EQ1 Volume", DA7210_DAC_EQ1_2, 0, 0xf, 1,
@@ -422,26 +447,42 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
 static const struct snd_kcontrol_new da7210_dapm_inmixl_controls[] = {
        SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_L, 0, 1, 0),
        SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_L, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_INMIX_L, 2, 1, 0),
+       SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_L, 3, 1, 0),
+       SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_INMIX_L, 4, 1, 0),
 };
 
 /* In Mixer Right */
 static const struct snd_kcontrol_new da7210_dapm_inmixr_controls[] = {
        SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_R, 0, 1, 0),
        SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_R, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_INMIX_R, 2, 1, 0),
+       SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_R, 3, 1, 0),
+       SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_INMIX_R, 4, 1, 0),
 };
 
 /* Out Mixer Left */
 static const struct snd_kcontrol_new da7210_dapm_outmixl_controls[] = {
+       SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_OUTMIX_L, 0, 1, 0),
+       SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_L, 1, 1, 0),
+       SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_L, 2, 1, 0),
+       SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_L, 3, 1, 0),
        SOC_DAPM_SINGLE("DAC Left Switch", DA7210_OUTMIX_L, 4, 1, 0),
 };
 
 /* Out Mixer Right */
 static const struct snd_kcontrol_new da7210_dapm_outmixr_controls[] = {
+       SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_OUTMIX_R, 0, 1, 0),
+       SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_R, 1, 1, 0),
+       SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_R, 2, 1, 0),
+       SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_R, 3, 1, 0),
        SOC_DAPM_SINGLE("DAC Right Switch", DA7210_OUTMIX_R, 4, 1, 0),
 };
 
 /* Mono Mixer */
 static const struct snd_kcontrol_new da7210_dapm_monomix_controls[] = {
+       SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUT2, 3, 1, 0),
+       SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUT2, 4, 1, 0),
        SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_OUT2, 5, 1, 0),
        SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_OUT2, 6, 1, 0),
 };
@@ -452,14 +493,23 @@ static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = {
        /* Input Lines */
        SND_SOC_DAPM_INPUT("MICL"),
        SND_SOC_DAPM_INPUT("MICR"),
+       SND_SOC_DAPM_INPUT("AUX1L"),
+       SND_SOC_DAPM_INPUT("AUX1R"),
+       SND_SOC_DAPM_INPUT("AUX2"),
 
        /* Input PGAs */
        SND_SOC_DAPM_PGA("Mic Left", DA7210_STARTUP3, 0, 1, NULL, 0),
        SND_SOC_DAPM_PGA("Mic Right", DA7210_STARTUP3, 1, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Aux1 Left", DA7210_STARTUP3, 2, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Aux1 Right", DA7210_STARTUP3, 3, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Aux2 Mono", DA7210_STARTUP3, 4, 1, NULL, 0),
 
        SND_SOC_DAPM_PGA("INPGA Left", DA7210_INMIX_L, 7, 0, NULL, 0),
        SND_SOC_DAPM_PGA("INPGA Right", DA7210_INMIX_R, 7, 0, NULL, 0),
 
+       /* MICBIAS */
+       SND_SOC_DAPM_SUPPLY("Mic Bias", DA7210_MIC_L, 6, 0, NULL, 0),
+
        /* Input Mixers */
        SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
                &da7210_dapm_inmixl_controls[0],
@@ -515,12 +565,21 @@ static const struct snd_soc_dapm_route da7210_audio_map[] = {
        /* Input path */
        {"Mic Left", NULL, "MICL"},
        {"Mic Right", NULL, "MICR"},
+       {"Aux1 Left", NULL, "AUX1L"},
+       {"Aux1 Right", NULL, "AUX1R"},
+       {"Aux2 Mono", NULL, "AUX2"},
 
        {"In Mixer Left", "Mic Left Switch", "Mic Left"},
        {"In Mixer Left", "Mic Right Switch", "Mic Right"},
+       {"In Mixer Left", "Aux1 Left Switch", "Aux1 Left"},
+       {"In Mixer Left", "Aux2 Switch", "Aux2 Mono"},
+       {"In Mixer Left", "Outmix Left Switch", "Out Mixer Left"},
 
        {"In Mixer Right", "Mic Right Switch", "Mic Right"},
        {"In Mixer Right", "Mic Left Switch", "Mic Left"},
+       {"In Mixer Right", "Aux1 Right Switch", "Aux1 Right"},
+       {"In Mixer Right", "Aux2 Switch", "Aux2 Mono"},
+       {"In Mixer Right", "Outmix Right Switch", "Out Mixer Right"},
 
        {"INPGA Left", NULL, "In Mixer Left"},
        {"ADC Left", NULL, "INPGA Left"},
@@ -529,9 +588,20 @@ static const struct snd_soc_dapm_route da7210_audio_map[] = {
        {"ADC Right", NULL, "INPGA Right"},
 
        /* Output path */
+       {"Out Mixer Left", "Aux1 Left Switch", "Aux1 Left"},
+       {"Out Mixer Left", "Aux2 Switch", "Aux2 Mono"},
+       {"Out Mixer Left", "INPGA Left Switch", "INPGA Left"},
+       {"Out Mixer Left", "INPGA Right Switch", "INPGA Right"},
        {"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+
+       {"Out Mixer Right", "Aux1 Right Switch", "Aux1 Right"},
+       {"Out Mixer Right", "Aux2 Switch", "Aux2 Mono"},
+       {"Out Mixer Right", "INPGA Right Switch", "INPGA Right"},
+       {"Out Mixer Right", "INPGA Left Switch", "INPGA Left"},
        {"Out Mixer Right", "DAC Right Switch", "DAC Right"},
 
+       {"Mono Mixer", "INPGA Right Switch", "INPGA Right"},
+       {"Mono Mixer", "INPGA Left Switch", "INPGA Left"},
        {"Mono Mixer", "Outmix Right Switch", "Out Mixer Right"},
        {"Mono Mixer", "Outmix Left Switch", "Out Mixer Left"},
 
@@ -761,7 +831,7 @@ static int da7210_mute(struct snd_soc_dai *dai, int mute)
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 /* DAI operations */
-static struct snd_soc_dai_ops da7210_dai_ops = {
+static const struct snd_soc_dai_ops da7210_dai_ops = {
        .hw_params      = da7210_hw_params,
        .set_fmt        = da7210_set_dai_fmt,
        .digital_mute   = da7210_mute,
@@ -888,6 +958,12 @@ static int da7210_probe(struct snd_soc_codec *codec)
        snd_soc_write(codec, DA7210_OUT2, DA7210_OUT2_EN |
                     DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R);
 
+       /* Enable Aux1 */
+       snd_soc_write(codec, DA7210_AUX1_L, DA7210_AUX1_L_EN);
+       snd_soc_write(codec, DA7210_AUX1_R, DA7210_AUX1_R_EN);
+       /* Enable Aux2 */
+       snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN);
+
        /* Diable PLL and bypass it */
        snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
 
@@ -945,7 +1021,8 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
        struct da7210_priv *da7210;
        int ret;
 
-       da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
+       da7210 = devm_kzalloc(&i2c->dev, sizeof(struct da7210_priv),
+                             GFP_KERNEL);
        if (!da7210)
                return -ENOMEM;
 
@@ -954,16 +1031,12 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_da7210, &da7210_dai, 1);
-       if (ret < 0)
-               kfree(da7210);
-
        return ret;
 }
 
 static int __devexit da7210_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 704bbde65737577aec3739fa4159307a70f61ee2..bfe46aa90362fe262b7894d0bd9451ad3042f23f 100644 (file)
@@ -55,17 +55,7 @@ static struct platform_driver dfmcs320_driver = {
        .remove = __devexit_p(dfbmcs320_remove),
 };
 
-static int __init dfbmcs320_init(void)
-{
-       return platform_driver_register(&dfmcs320_driver);
-}
-module_init(dfbmcs320_init);
-
-static void __exit dfbmcs320_exit(void)
-{
-       platform_driver_unregister(&dfmcs320_driver);
-}
-module_exit(dfbmcs320_exit);
+module_platform_driver(dfmcs320_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver");
index 6fae765e3ad8baf3611f7251bd3240e2c6591a06..3e929f079a1f0eb4b3fa472482d68503703da8c4 100644 (file)
@@ -89,17 +89,7 @@ static struct platform_driver dmic_driver = {
        .remove = __devexit_p(dmic_dev_remove),
 };
 
-static int __init dmic_init(void)
-{
-       return platform_driver_register(&dmic_driver);
-}
-module_init(dmic_init);
-
-static void __exit dmic_exit(void)
-{
-       platform_driver_unregister(&dmic_driver);
-}
-module_exit(dmic_exit);
+module_platform_driver(dmic_driver);
 
 MODULE_DESCRIPTION("Generic DMIC driver");
 MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
index 3e1f4e172bfb90c318e4150d8aebbe782b78d4ab..4624e752a188cdc13689fc3b29bacfd1d5e4bf84 100644 (file)
@@ -207,7 +207,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
+static const struct snd_soc_dai_ops jz4740_codec_dai_ops = {
        .hw_params = jz4740_codec_hw_params,
 };
 
@@ -312,7 +312,7 @@ static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
 
 #ifdef CONFIG_PM_SLEEP
 
-static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int jz4740_codec_suspend(struct snd_soc_codec *codec)
 {
        return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
@@ -353,7 +353,8 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
        struct jz4740_codec *jz4740_codec;
        struct resource *mem;
 
-       jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
+       jz4740_codec = devm_kzalloc(&pdev->dev, sizeof(*jz4740_codec),
+                                   GFP_KERNEL);
        if (!jz4740_codec)
                return -ENOMEM;
 
@@ -361,14 +362,14 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
        if (!mem) {
                dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
                ret = -ENOENT;
-               goto err_free_codec;
+               goto err_out;
        }
 
        mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
        if (!mem) {
                dev_err(&pdev->dev, "Failed to request mmio memory region\n");
                ret = -EBUSY;
-               goto err_free_codec;
+               goto err_out;
        }
 
        jz4740_codec->base = ioremap(mem->start, resource_size(mem));
@@ -394,9 +395,7 @@ err_iounmap:
        iounmap(jz4740_codec->base);
 err_release_mem_region:
        release_mem_region(mem->start, resource_size(mem));
-err_free_codec:
-       kfree(jz4740_codec);
-
+err_out:
        return ret;
 }
 
@@ -411,7 +410,6 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev)
        release_mem_region(mem->start, resource_size(mem));
 
        platform_set_drvdata(pdev, NULL);
-       kfree(jz4740_codec);
 
        return 0;
 }
@@ -425,17 +423,7 @@ static struct platform_driver jz4740_codec_driver = {
        },
 };
 
-static int __init jz4740_codec_init(void)
-{
-       return platform_driver_register(&jz4740_codec_driver);
-}
-module_init(jz4740_codec_init);
-
-static void __exit jz4740_codec_exit(void)
-{
-       platform_driver_unregister(&jz4740_codec_driver);
-}
-module_exit(jz4740_codec_exit);
+module_platform_driver(jz4740_codec_driver);
 
 MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index c387dafc6ab6970245f03ec8ad6a32712e0c31fd..319039240e0fafe25412110e81fc548b011df072 100644 (file)
@@ -215,7 +215,7 @@ static int __devinit lm4857_i2c_probe(struct i2c_client *i2c,
        struct lm4857 *lm4857;
        int ret;
 
-       lm4857 = kzalloc(sizeof(*lm4857), GFP_KERNEL);
+       lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
        if (!lm4857)
                return -ENOMEM;
 
@@ -225,21 +225,12 @@ static int __devinit lm4857_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
 
-       if (ret) {
-               kfree(lm4857);
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static int __devexit lm4857_i2c_remove(struct i2c_client *i2c)
 {
-       struct lm4857 *lm4857 = i2c_get_clientdata(i2c);
-
        snd_soc_unregister_codec(&i2c->dev);
-       kfree(lm4857);
-
        return 0;
 }
 
index ebbf63c79c34e2873088aa2faaf6bcce400d99a0..006efcfe6dda84b486330bb79cdb0d36b8389efe 100644 (file)
@@ -15,7 +15,6 @@
 #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>
@@ -1650,14 +1649,14 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
 #define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
 #define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops max98088_dai1_ops = {
+static const struct snd_soc_dai_ops max98088_dai1_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai1_set_fmt,
        .hw_params = max98088_dai1_hw_params,
        .digital_mute = max98088_dai1_digital_mute,
 };
 
-static struct snd_soc_dai_ops max98088_dai2_ops = {
+static const struct snd_soc_dai_ops max98088_dai2_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai2_set_fmt,
        .hw_params = max98088_dai2_hw_params,
@@ -1947,7 +1946,7 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int max98088_suspend(struct snd_soc_codec *codec)
 {
        max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -2070,7 +2069,8 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
        struct max98088_priv *max98088;
        int ret;
 
-       max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+       max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
+                              GFP_KERNEL);
        if (max98088 == NULL)
                return -ENOMEM;
 
@@ -2081,15 +2081,12 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_max98088, &max98088_dai[0], 2);
-       if (ret < 0)
-               kfree(max98088);
        return ret;
 }
 
 static int __devexit max98088_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 26d7b089fb9c27836c2a6721dceec1350bc5300f..fcfa7497d7b74aac4777def9e7b7d186ec7c58ef 100644 (file)
@@ -15,7 +15,6 @@
 #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>
@@ -1782,19 +1781,19 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
 #define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
 #define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops max98095_dai1_ops = {
+static const struct snd_soc_dai_ops max98095_dai1_ops = {
        .set_sysclk = max98095_dai_set_sysclk,
        .set_fmt = max98095_dai1_set_fmt,
        .hw_params = max98095_dai1_hw_params,
 };
 
-static struct snd_soc_dai_ops max98095_dai2_ops = {
+static const struct snd_soc_dai_ops max98095_dai2_ops = {
        .set_sysclk = max98095_dai_set_sysclk,
        .set_fmt = max98095_dai2_set_fmt,
        .hw_params = max98095_dai2_hw_params,
 };
 
-static struct snd_soc_dai_ops max98095_dai3_ops = {
+static const struct snd_soc_dai_ops max98095_dai3_ops = {
        .set_sysclk = max98095_dai_set_sysclk,
        .set_fmt = max98095_dai3_set_fmt,
        .hw_params = max98095_dai3_hw_params,
@@ -2175,7 +2174,7 @@ static void max98095_handle_pdata(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int max98095_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int max98095_suspend(struct snd_soc_codec *codec)
 {
        max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -2341,7 +2340,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
        struct max98095_priv *max98095;
        int ret;
 
-       max98095 = kzalloc(sizeof(struct max98095_priv), GFP_KERNEL);
+       max98095 = devm_kzalloc(&i2c->dev, sizeof(struct max98095_priv),
+                               GFP_KERNEL);
        if (max98095 == NULL)
                return -ENOMEM;
 
@@ -2351,16 +2351,12 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095,
                                     max98095_dai, ARRAY_SIZE(max98095_dai));
-       if (ret < 0)
-               kfree(max98095);
        return ret;
 }
 
 static int __devexit max98095_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
-
        return 0;
 }
 
index 208d2ee618558c980df83b9ad0b35de9920bd145..a1913091f56ca5641fd58a4066890065deb0d5d6 100644 (file)
@@ -86,7 +86,7 @@ SND_SOC_DAPM_INPUT("INL"),
 SND_SOC_DAPM_INPUT("INR"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route max9850_dapm_routes[] = {
        /* output mixer */
        {"Output Mixer", NULL, "DAC"},
        {"Output Mixer", "Line In Switch", "Line Input"},
@@ -254,7 +254,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
 #define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops max9850_dai_ops = {
+static const struct snd_soc_dai_ops max9850_dai_ops = {
        .hw_params      = max9850_hw_params,
        .set_sysclk     = max9850_set_dai_sysclk,
        .set_fmt        = max9850_set_dai_fmt,
@@ -273,7 +273,7 @@ static struct snd_soc_dai_driver max9850_dai = {
 };
 
 #ifdef CONFIG_PM
-static int max9850_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int max9850_suspend(struct snd_soc_codec *codec)
 {
        max9850_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -293,7 +293,6 @@ static int max9850_resume(struct snd_soc_codec *codec)
 
 static int max9850_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
@@ -309,13 +308,6 @@ static int max9850_probe(struct snd_soc_codec *codec)
        /* set slew-rate 125ms */
        snd_soc_update_bits(codec, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
 
-       snd_soc_dapm_new_controls(dapm, max9850_dapm_widgets,
-                                 ARRAY_SIZE(max9850_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       snd_soc_add_controls(codec, max9850_controls,
-                       ARRAY_SIZE(max9850_controls));
-
        return 0;
 }
 
@@ -328,6 +320,13 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
        .reg_word_size = sizeof(u8),
        .reg_cache_default = max9850_reg,
        .volatile_register = max9850_volatile_register,
+
+       .controls = max9850_controls,
+       .num_controls = ARRAY_SIZE(max9850_controls),
+       .dapm_widgets = max9850_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max9850_dapm_widgets),
+       .dapm_routes = max9850_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(max9850_dapm_routes),
 };
 
 static int __devinit max9850_i2c_probe(struct i2c_client *i2c,
@@ -336,7 +335,8 @@ static int __devinit max9850_i2c_probe(struct i2c_client *i2c,
        struct max9850_priv *max9850;
        int ret;
 
-       max9850 = kzalloc(sizeof(struct max9850_priv), GFP_KERNEL);
+       max9850 = devm_kzalloc(&i2c->dev, sizeof(struct max9850_priv),
+                              GFP_KERNEL);
        if (max9850 == NULL)
                return -ENOMEM;
 
@@ -344,15 +344,12 @@ static int __devinit max9850_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_max9850, &max9850_dai, 1);
-       if (ret < 0)
-               kfree(max9850);
        return ret;
 }
 
 static __devexit int max9850_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index f7316519432c42dcdb6122bd17009672217ad72f..edcaa7ea548757b3825acb27a1af9fd958d9121b 100644 (file)
@@ -118,7 +118,7 @@ static int pcm3008_soc_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
+static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
 {
        struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
@@ -172,17 +172,7 @@ static struct platform_driver pcm3008_codec_driver = {
        },
 };
 
-static int __init pcm3008_modinit(void)
-{
-       return platform_driver_register(&pcm3008_codec_driver);
-}
-module_init(pcm3008_modinit);
-
-static void __exit pcm3008_exit(void)
-{
-       platform_driver_unregister(&pcm3008_codec_driver);
-}
-module_exit(pcm3008_exit);
+module_platform_driver(pcm3008_codec_driver);
 
 MODULE_DESCRIPTION("Soc PCM3008 driver");
 MODULE_AUTHOR("Hugo Villeneuve");
index 4646e808b90a334e0d59935a1e93244672d276be..20c324c7c3492814a803130cbbc80a8ab75380d0 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1642,7 +1641,7 @@ static int rt5631_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int rt5631_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int rt5631_suspend(struct snd_soc_codec *codec)
 {
        rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1664,7 +1663,7 @@ static int rt5631_resume(struct snd_soc_codec *codec)
                        SNDRV_PCM_FMTBIT_S24_LE | \
                        SNDRV_PCM_FMTBIT_S8)
 
-static struct snd_soc_dai_ops rt5631_ops = {
+static const struct snd_soc_dai_ops rt5631_ops = {
        .hw_params = rt5631_hifi_pcm_params,
        .set_fmt = rt5631_hifi_codec_set_dai_fmt,
        .set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
@@ -1725,7 +1724,8 @@ static int rt5631_i2c_probe(struct i2c_client *i2c,
        struct rt5631_priv *rt5631;
        int ret;
 
-       rt5631 = kzalloc(sizeof(struct rt5631_priv), GFP_KERNEL);
+       rt5631 = devm_kzalloc(&i2c->dev, sizeof(struct rt5631_priv),
+                             GFP_KERNEL);
        if (NULL == rt5631)
                return -ENOMEM;
 
@@ -1733,16 +1733,12 @@ static int rt5631_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
                        rt5631_dai, ARRAY_SIZE(rt5631_dai));
-       if (ret < 0)
-               kfree(rt5631);
-
        return ret;
 }
 
 static __devexit int rt5631_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index f6b6551940ab29b80ec2a806f720801e6a72b10c..d7bd91831611cb3a7a45395a76a82f34b10177df 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/clk.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
@@ -923,7 +922,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
                        SNDRV_PCM_FMTBIT_S24_LE |\
                        SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops sgtl5000_ops = {
+static const struct snd_soc_dai_ops sgtl5000_ops = {
        .hw_params = sgtl5000_pcm_hw_params,
        .digital_mute = sgtl5000_digital_mute,
        .set_fmt = sgtl5000_set_dai_fmt,
@@ -968,7 +967,7 @@ static int sgtl5000_volatile_register(struct snd_soc_codec *codec,
 }
 
 #ifdef CONFIG_SUSPEND
-static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int sgtl5000_suspend(struct snd_soc_codec *codec)
 {
        sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1077,7 +1076,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
        /* according to datasheet, maximum voltage of supplies */
        if (vdda > 3600 || vddio > 3600 || vddd > 1980) {
                dev_err(codec->dev,
-                       "exceed max voltage vdda %dmv vddio %dma vddd %dma\n",
+                       "exceed max voltage vdda %dmV vddio %dmV vddd %dmV\n",
                        vdda, vddio, vddd);
 
                return -EINVAL;
@@ -1402,7 +1401,8 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
        struct sgtl5000_priv *sgtl5000;
        int ret;
 
-       sgtl5000 = kzalloc(sizeof(struct sgtl5000_priv), GFP_KERNEL);
+       sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
+                                                               GFP_KERNEL);
        if (!sgtl5000)
                return -ENOMEM;
 
@@ -1410,22 +1410,13 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
 
        ret = snd_soc_register_codec(&client->dev,
                        &sgtl5000_driver, &sgtl5000_dai, 1);
-       if (ret) {
-               dev_err(&client->dev, "Failed to register codec: %d\n", ret);
-               kfree(sgtl5000);
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static __devexit int sgtl5000_i2c_remove(struct i2c_client *client)
 {
-       struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
 
-       kfree(sgtl5000);
        return 0;
 }
 
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
new file mode 100644 (file)
index 0000000..5be42bf
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Load Analog Devices SigmaStudio firmware files
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+
+#include "sigmadsp.h"
+
+#define SIGMA_MAGIC "ADISIGM"
+
+struct sigma_firmware_header {
+       unsigned char magic[7];
+       u8 version;
+       __le32 crc;
+} __packed;
+
+enum {
+       SIGMA_ACTION_WRITEXBYTES = 0,
+       SIGMA_ACTION_WRITESINGLE,
+       SIGMA_ACTION_WRITESAFELOAD,
+       SIGMA_ACTION_DELAY,
+       SIGMA_ACTION_PLLWAIT,
+       SIGMA_ACTION_NOOP,
+       SIGMA_ACTION_END,
+};
+
+struct sigma_action {
+       u8 instr;
+       u8 len_hi;
+       __le16 len;
+       __be16 addr;
+       unsigned char payload[];
+} __packed;
+
+struct sigma_firmware {
+       const struct firmware *fw;
+       size_t pos;
+
+       void *control_data;
+       int (*write)(void *control_data, const struct sigma_action *sa,
+                       size_t len);
+};
+
+static inline u32 sigma_action_len(struct sigma_action *sa)
+{
+       return (sa->len_hi << 16) | le16_to_cpu(sa->len);
+}
+
+static size_t sigma_action_size(struct sigma_action *sa)
+{
+       size_t payload = 0;
+
+       switch (sa->instr) {
+       case SIGMA_ACTION_WRITEXBYTES:
+       case SIGMA_ACTION_WRITESINGLE:
+       case SIGMA_ACTION_WRITESAFELOAD:
+               payload = sigma_action_len(sa);
+               break;
+       default:
+               break;
+       }
+
+       payload = ALIGN(payload, 2);
+
+       return payload + sizeof(struct sigma_action);
+}
+
+/*
+ * Returns a negative error value in case of an error, 0 if processing of
+ * the firmware should be stopped after this action, 1 otherwise.
+ */
+static int
+process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
+{
+       size_t len = sigma_action_len(sa);
+       int ret;
+
+       pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
+               sa->instr, sa->addr, len);
+
+       switch (sa->instr) {
+       case SIGMA_ACTION_WRITEXBYTES:
+       case SIGMA_ACTION_WRITESINGLE:
+       case SIGMA_ACTION_WRITESAFELOAD:
+               ret = ssfw->write(ssfw->control_data, sa, len);
+               if (ret < 0)
+                       return -EINVAL;
+               break;
+       case SIGMA_ACTION_DELAY:
+               udelay(len);
+               len = 0;
+               break;
+       case SIGMA_ACTION_END:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+
+       return 1;
+}
+
+static int
+process_sigma_actions(struct sigma_firmware *ssfw)
+{
+       struct sigma_action *sa;
+       size_t size;
+       int ret;
+
+       while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
+               sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
+
+               size = sigma_action_size(sa);
+               ssfw->pos += size;
+               if (ssfw->pos > ssfw->fw->size || size == 0)
+                       break;
+
+               ret = process_sigma_action(ssfw, sa);
+
+               pr_debug("%s: action returned %i\n", __func__, ret);
+
+               if (ret <= 0)
+                       return ret;
+       }
+
+       if (ssfw->pos != ssfw->fw->size)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int _process_sigma_firmware(struct device *dev,
+       struct sigma_firmware *ssfw, const char *name)
+{
+       int ret;
+       struct sigma_firmware_header *ssfw_head;
+       const struct firmware *fw;
+       u32 crc;
+
+       pr_debug("%s: loading firmware %s\n", __func__, name);
+
+       /* first load the blob */
+       ret = request_firmware(&fw, name, dev);
+       if (ret) {
+               pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
+               return ret;
+       }
+       ssfw->fw = fw;
+
+       /* then verify the header */
+       ret = -EINVAL;
+
+       /*
+        * Reject too small or unreasonable large files. The upper limit has been
+        * chosen a bit arbitrarily, but it should be enough for all practical
+        * purposes and having the limit makes it easier to avoid integer
+        * overflows later in the loading process.
+        */
+       if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
+               dev_err(dev, "Failed to load firmware: Invalid size\n");
+               goto done;
+       }
+
+       ssfw_head = (void *)fw->data;
+       if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
+               dev_err(dev, "Failed to load firmware: Invalid magic\n");
+               goto done;
+       }
+
+       crc = crc32(0, fw->data + sizeof(*ssfw_head),
+                       fw->size - sizeof(*ssfw_head));
+       pr_debug("%s: crc=%x\n", __func__, crc);
+       if (crc != le32_to_cpu(ssfw_head->crc)) {
+               dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
+                       le32_to_cpu(ssfw_head->crc), crc);
+               goto done;
+       }
+
+       ssfw->pos = sizeof(*ssfw_head);
+
+       /* finally process all of the actions */
+       ret = process_sigma_actions(ssfw);
+
+ done:
+       release_firmware(fw);
+
+       pr_debug("%s: loaded %s\n", __func__, name);
+
+       return ret;
+}
+
+#if IS_ENABLED(CONFIG_I2C)
+
+static int sigma_action_write_i2c(void *control_data,
+       const struct sigma_action *sa, size_t len)
+{
+       return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
+               len);
+}
+
+int process_sigma_firmware(struct i2c_client *client, const char *name)
+{
+       struct sigma_firmware ssfw;
+
+       ssfw.control_data = client;
+       ssfw.write = sigma_action_write_i2c;
+
+       return _process_sigma_firmware(&client->dev, &ssfw, name);
+}
+EXPORT_SYMBOL(process_sigma_firmware);
+
+#endif
+
+#if IS_ENABLED(CONFIG_REGMAP)
+
+static int sigma_action_write_regmap(void *control_data,
+       const struct sigma_action *sa, size_t len)
+{
+       return regmap_raw_write(control_data, le16_to_cpu(sa->addr),
+               sa->payload, len - 2);
+}
+
+int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
+       const char *name)
+{
+       struct sigma_firmware ssfw;
+
+       ssfw.control_data = regmap;
+       ssfw.write = sigma_action_write_regmap;
+
+       return _process_sigma_firmware(dev, &ssfw, name);
+}
+EXPORT_SYMBOL(process_sigma_firmware_regmap);
+
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
new file mode 100644 (file)
index 0000000..e439cbd
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Load firmware files from Analog Devices SigmaStudio
+ *
+ * Copyright 2009-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __SIGMA_FIRMWARE_H__
+#define __SIGMA_FIRMWARE_H__
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+
+struct i2c_client;
+
+extern int process_sigma_firmware(struct i2c_client *client, const char *name);
+extern int process_sigma_firmware_regmap(struct device *dev,
+               struct regmap *regmap, const char *name);
+
+#endif
index 887d618f4a639720b7e0698e086333f203175a7a..f99baa0b8c39133b5cbc342368b4ac98f79cb365 100644 (file)
@@ -698,21 +698,21 @@ static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
 }
 
 /* Codec DAI section */
-static struct snd_soc_dai_ops sn95031_headset_dai_ops = {
+static const struct snd_soc_dai_ops sn95031_headset_dai_ops = {
        .digital_mute   = sn95031_pcm_hs_mute,
        .hw_params      = sn95031_pcm_hw_params,
 };
 
-static struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
+static const struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
        .digital_mute   = sn95031_pcm_spkr_mute,
        .hw_params      = sn95031_pcm_hw_params,
 };
 
-static struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
+static const struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
        .hw_params      = sn95031_pcm_hw_params,
 };
 
-static struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
+static const struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
        .hw_params      = sn95031_pcm_hw_params,
 };
 
@@ -920,19 +920,7 @@ static struct platform_driver sn95031_codec_driver = {
        .remove         = __devexit_p(sn95031_device_remove),
 };
 
-static int __init sn95031_init(void)
-{
-       pr_debug("driver init called\n");
-       return platform_driver_register(&sn95031_codec_driver);
-}
-module_init(sn95031_init);
-
-static void __exit sn95031_exit(void)
-{
-       pr_debug("driver exit called\n");
-       platform_driver_unregister(&sn95031_codec_driver);
-}
-module_exit(sn95031_exit);
+module_platform_driver(sn95031_codec_driver);
 
 MODULE_DESCRIPTION("ASoC TI SN95031 codec driver");
 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
index 6a1a7e705cd767ffd11365252c88b70fe7c98ad1..112a49d66e3967847517b495872baa606a967189 100644 (file)
@@ -61,18 +61,7 @@ static struct platform_driver spdif_dit_driver = {
        },
 };
 
-static int __init dit_modinit(void)
-{
-       return platform_driver_register(&spdif_dit_driver);
-}
-
-static void __exit dit_exit(void)
-{
-       platform_driver_unregister(&spdif_dit_driver);
-}
-
-module_init(dit_modinit);
-module_exit(dit_exit);
+module_platform_driver(spdif_dit_driver);
 
 MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
 MODULE_DESCRIPTION("SPDIF dummy codec driver");
index 3cb3271c5fe2019501cde20e9f1b73f872476282..333dd98af39ce538868d706a2281f2e7514152ab 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -498,7 +497,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 #define SSM2602_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 ssm2602_dai_ops = {
+static const struct snd_soc_dai_ops ssm2602_dai_ops = {
        .startup        = ssm2602_startup,
        .hw_params      = ssm2602_hw_params,
        .shutdown       = ssm2602_shutdown,
@@ -524,7 +523,7 @@ static struct snd_soc_dai_driver ssm2602_dai = {
        .ops = &ssm2602_dai_ops,
 };
 
-static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec)
 {
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -653,7 +652,8 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)
        struct ssm2602_priv *ssm2602;
        int ret;
 
-       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv),
+                              GFP_KERNEL);
        if (ssm2602 == NULL)
                return -ENOMEM;
 
@@ -663,15 +663,12 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
-       if (ret < 0)
-               kfree(ssm2602);
        return ret;
 }
 
 static int __devexit ssm2602_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -698,7 +695,8 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
        struct ssm2602_priv *ssm2602;
        int ret;
 
-       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv),
+                              GFP_KERNEL);
        if (ssm2602 == NULL)
                return -ENOMEM;
 
@@ -708,15 +706,12 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
-       if (ret < 0)
-               kfree(ssm2602);
        return ret;
 }
 
 static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index d2f37152f940cebc67f93a5bff140e64a67a07e7..7db6fa515028d566cfd75c5ee048db8b52f2ca54 100644 (file)
@@ -24,9 +24,9 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -35,6 +35,7 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
+#include <sound/sta32x.h>
 #include "sta32x.h"
 
 #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \
@@ -73,11 +74,14 @@ static const char *sta32x_supply_names[] = {
 struct sta32x_priv {
        struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
        struct snd_soc_codec *codec;
+       struct sta32x_platform_data *pdata;
 
        unsigned int mclk;
        unsigned int format;
 
        u32 coef_shadow[STA32X_COEF_COUNT];
+       struct delayed_work watchdog_work;
+       int shutdown;
 };
 
 static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
@@ -260,7 +264,7 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
+static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 {
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        unsigned int cfud;
@@ -285,7 +289,7 @@ int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
        return 0;
 }
 
-int sta32x_cache_sync(struct snd_soc_codec *codec)
+static int sta32x_cache_sync(struct snd_soc_codec *codec)
 {
        unsigned int mute;
        int rc;
@@ -302,6 +306,46 @@ int sta32x_cache_sync(struct snd_soc_codec *codec)
        return rc;
 }
 
+/* work around ESD issue where sta32x resets and loses all configuration */
+static void sta32x_watchdog(struct work_struct *work)
+{
+       struct sta32x_priv *sta32x = container_of(work, struct sta32x_priv,
+                                                 watchdog_work.work);
+       struct snd_soc_codec *codec = sta32x->codec;
+       unsigned int confa, confa_cached;
+
+       /* check if sta32x has reset itself */
+       confa_cached = snd_soc_read(codec, STA32X_CONFA);
+       codec->cache_bypass = 1;
+       confa = snd_soc_read(codec, STA32X_CONFA);
+       codec->cache_bypass = 0;
+       if (confa != confa_cached) {
+               codec->cache_sync = 1;
+               sta32x_cache_sync(codec);
+       }
+
+       if (!sta32x->shutdown)
+               schedule_delayed_work(&sta32x->watchdog_work,
+                                     round_jiffies_relative(HZ));
+}
+
+static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
+{
+       if (sta32x->pdata->needs_esd_watchdog) {
+               sta32x->shutdown = 0;
+               schedule_delayed_work(&sta32x->watchdog_work,
+                                     round_jiffies_relative(HZ));
+       }
+}
+
+static void sta32x_watchdog_stop(struct sta32x_priv *sta32x)
+{
+       if (sta32x->pdata->needs_esd_watchdog) {
+               sta32x->shutdown = 1;
+               cancel_delayed_work_sync(&sta32x->watchdog_work);
+       }
+}
+
 #define SINGLE_COEF(xname, index) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = sta32x_coefficient_info, \
@@ -478,6 +522,7 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                                rate_min = fs;
                                        if (fs > rate_max)
                                                rate_max = fs;
+                                       break;
                                }
                        }
                }
@@ -712,6 +757,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                        }
 
                        sta32x_cache_sync(codec);
+                       sta32x_watchdog_start(sta32x);
                }
 
                /* Power up to mute */
@@ -728,7 +774,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                                    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
                                    STA32X_CONFF_PWDN);
                msleep(300);
-
+               sta32x_watchdog_stop(sta32x);
                regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
                                       sta32x->supplies);
                break;
@@ -737,7 +783,7 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static struct snd_soc_dai_ops sta32x_dai_ops = {
+static const struct snd_soc_dai_ops sta32x_dai_ops = {
        .hw_params      = sta32x_hw_params,
        .set_sysclk     = sta32x_set_dai_sysclk,
        .set_fmt        = sta32x_set_dai_fmt,
@@ -756,7 +802,7 @@ static struct snd_soc_dai_driver sta32x_dai = {
 };
 
 #ifdef CONFIG_PM
-static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int sta32x_suspend(struct snd_soc_codec *codec)
 {
        sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -775,9 +821,10 @@ static int sta32x_resume(struct snd_soc_codec *codec)
 static int sta32x_probe(struct snd_soc_codec *codec)
 {
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       int i, ret = 0;
+       int i, ret = 0, thermal = 0;
 
        sta32x->codec = codec;
+       sta32x->pdata = dev_get_platdata(codec->dev);
 
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
@@ -820,25 +867,34 @@ static int sta32x_probe(struct snd_soc_codec *codec)
        snd_soc_cache_write(codec, STA32X_AUTO3, 0x00);
        snd_soc_cache_write(codec, STA32X_C3CFG, 0x40);
 
-       /* FIXME enable thermal warning adjustment and recovery  */
+       /* set thermal warning adjustment and recovery */
+       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
+               thermal |= STA32X_CONFA_TWAB;
+       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
+               thermal |= STA32X_CONFA_TWRB;
        snd_soc_update_bits(codec, STA32X_CONFA,
-                           STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0);
+                           STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
+                           thermal);
 
-       /* FIXME select 2.1 mode  */
+       /* select output configuration  */
        snd_soc_update_bits(codec, STA32X_CONFF,
                            STA32X_CONFF_OCFG_MASK,
-                           1 << STA32X_CONFF_OCFG_SHIFT);
+                           sta32x->pdata->output_conf
+                           << STA32X_CONFF_OCFG_SHIFT);
 
-       /* FIXME channel to output mapping */
+       /* channel to output mapping */
        snd_soc_update_bits(codec, STA32X_C1CFG,
                            STA32X_CxCFG_OM_MASK,
-                           0 << STA32X_CxCFG_OM_SHIFT);
+                           sta32x->pdata->ch1_output_mapping
+                           << STA32X_CxCFG_OM_SHIFT);
        snd_soc_update_bits(codec, STA32X_C2CFG,
                            STA32X_CxCFG_OM_MASK,
-                           1 << STA32X_CxCFG_OM_SHIFT);
+                           sta32x->pdata->ch2_output_mapping
+                           << STA32X_CxCFG_OM_SHIFT);
        snd_soc_update_bits(codec, STA32X_C3CFG,
                            STA32X_CxCFG_OM_MASK,
-                           2 << STA32X_CxCFG_OM_SHIFT);
+                           sta32x->pdata->ch3_output_mapping
+                           << STA32X_CxCFG_OM_SHIFT);
 
        /* initialize coefficient shadow RAM with reset values */
        for (i = 4; i <= 49; i += 5)
@@ -851,6 +907,9 @@ static int sta32x_probe(struct snd_soc_codec *codec)
        sta32x->coef_shadow[60] = 0x400000;
        sta32x->coef_shadow[61] = 0x400000;
 
+       if (sta32x->pdata->needs_esd_watchdog)
+               INIT_DELAYED_WORK(&sta32x->watchdog_work, sta32x_watchdog);
+
        sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@@ -867,6 +926,7 @@ static int sta32x_remove(struct snd_soc_codec *codec)
 {
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 
+       sta32x_watchdog_stop(sta32x);
        sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
        regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
@@ -909,28 +969,23 @@ static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
        struct sta32x_priv *sta32x;
        int ret;
 
-       sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL);
+       sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
+                             GFP_KERNEL);
        if (!sta32x)
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, sta32x);
 
        ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
-       if (ret != 0) {
+       if (ret != 0)
                dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
-               kfree(sta32x);
-               return ret;
-       }
 
-       return 0;
+       return ret;
 }
 
 static __devexit int sta32x_i2c_remove(struct i2c_client *client)
 {
-       struct sta32x_priv *sta32x = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       kfree(sta32x);
        return 0;
 }
 
index 78b2b50271e25893ade9c8b0ce3b0f0be6ab4e92..cc0566c22ec12ecfcf3f67d486b6330fea448f47 100644 (file)
@@ -256,8 +256,7 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
        return 0;
 }
 
-static int stac9766_codec_suspend(struct snd_soc_codec *codec,
-                                 pm_message_t state)
+static int stac9766_codec_suspend(struct snd_soc_codec *codec)
 {
        stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -286,11 +285,11 @@ reset:
        return 0;
 }
 
-static struct snd_soc_dai_ops stac9766_dai_ops_analog = {
+static const struct snd_soc_dai_ops stac9766_dai_ops_analog = {
        .prepare = ac97_analog_prepare,
 };
 
-static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
+static const struct snd_soc_dai_ops stac9766_dai_ops_digital = {
        .prepare = ac97_digital_prepare,
 };
 
@@ -380,7 +379,7 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
        .remove = stac9766_codec_remove,
        .suspend = stac9766_codec_suspend,
        .resume = stac9766_codec_resume,
-       .reg_cache_size = sizeof(stac9766_reg),
+       .reg_cache_size = ARRAY_SIZE(stac9766_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_step = 2,
        .reg_cache_default = stac9766_reg,
@@ -408,17 +407,7 @@ static struct platform_driver stac9766_codec_driver = {
        .remove = __devexit_p(stac9766_remove),
 };
 
-static int __init stac9766_init(void)
-{
-       return platform_driver_register(&stac9766_codec_driver);
-}
-module_init(stac9766_init);
-
-static void __exit stac9766_exit(void)
-{
-       platform_driver_unregister(&stac9766_codec_driver);
-}
-module_exit(stac9766_exit);
+module_platform_driver(stac9766_codec_driver);
 
 MODULE_DESCRIPTION("ASoC stac9766 driver");
 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
index 336de8f69a026e9a6da20af04f3b821d5ba69a33..dfa41a96599b8c61884c04392c6a878e7e715372 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -503,7 +502,7 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
 #define AIC23_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
+static const struct snd_soc_dai_ops tlv320aic23_dai_ops = {
        .prepare        = tlv320aic23_pcm_prepare,
        .hw_params      = tlv320aic23_hw_params,
        .shutdown       = tlv320aic23_shutdown,
@@ -529,8 +528,7 @@ static struct snd_soc_dai_driver tlv320aic23_dai = {
        .ops = &tlv320aic23_dai_ops,
 };
 
-static int tlv320aic23_suspend(struct snd_soc_codec *codec,
-                              pm_message_t state)
+static int tlv320aic23_suspend(struct snd_soc_codec *codec)
 {
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -636,7 +634,7 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EINVAL;
 
-       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+       aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL);
        if (aic23 == NULL)
                return -ENOMEM;
 
@@ -645,14 +643,11 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
-       if (ret < 0)
-               kfree(aic23);
        return ret;
 }
 static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
 {
        snd_soc_unregister_codec(&i2c->dev);
-       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
index 7859bdcc93db4064cad1474a8fe2533e19026f1e..a038daec682bfba9dd6997b9acfbb4e0c4855ca2 100644 (file)
@@ -275,7 +275,7 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 #define AIC26_FORMATS  (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_S16_BE |\
                         SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
-static struct snd_soc_dai_ops aic26_dai_ops = {
+static const struct snd_soc_dai_ops aic26_dai_ops = {
        .hw_params      = aic26_hw_params,
        .digital_mute   = aic26_mute,
        .set_sysclk     = aic26_set_sysclk,
@@ -416,7 +416,7 @@ static int aic26_spi_probe(struct spi_device *spi)
        dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
 
        /* Allocate driver data */
-       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+       aic26 = devm_kzalloc(&spi->dev, sizeof *aic26, GFP_KERNEL);
        if (!aic26)
                return -ENOMEM;
 
@@ -427,18 +427,12 @@ static int aic26_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &aic26_soc_codec_dev, &aic26_dai, 1);
-       if (ret < 0)
-               kfree(aic26);
        return ret;
-
-       dev_dbg(&spi->dev, "SPI device initialized\n");
-       return 0;
 }
 
 static int aic26_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
index b21c610051c0f53c03ab2f6c42bf9b12ef20dda9..eb401ef021fb7130055d8c73d9385d19daada0ff 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/cdev.h>
 #include <linux/slab.h>
 
@@ -597,7 +596,7 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
 #define AIC32X4_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
                         | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops aic32x4_ops = {
+static const struct snd_soc_dai_ops aic32x4_ops = {
        .hw_params = aic32x4_hw_params,
        .digital_mute = aic32x4_mute,
        .set_fmt = aic32x4_set_dai_fmt,
@@ -622,7 +621,7 @@ static struct snd_soc_dai_driver aic32x4_dai = {
        .symmetric_rates = 1,
 };
 
-static int aic32x4_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int aic32x4_suspend(struct snd_soc_codec *codec)
 {
        aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -710,7 +709,8 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c,
        struct aic32x4_priv *aic32x4;
        int ret;
 
-       aic32x4 = kzalloc(sizeof(struct aic32x4_priv), GFP_KERNEL);
+       aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv),
+                              GFP_KERNEL);
        if (aic32x4 == NULL)
                return -ENOMEM;
 
@@ -729,15 +729,12 @@ static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_aic32x4, &aic32x4_dai, 1);
-       if (ret < 0)
-               kfree(aic32x4);
        return ret;
 }
 
 static __devexit int aic32x4_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 87d5ef188e29484fe303931c71cc45ac30005cce..492f22f8a4d7bd8ae30bbd2bb4ae6dae3488ccad 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -833,7 +832,6 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
        u16 d, pll_d = 1;
-       u8 reg;
        int clk;
 
        /* select data word length */
@@ -869,14 +867,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
                snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
                /* disable PLL if it is bypassed */
-               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+               snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLL_ENABLE, 0);
 
        } else {
                snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
                /* enable PLL when it is used */
-               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+               snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+                                   PLL_ENABLE, PLL_ENABLE);
        }
 
        /* Route Left DAC to left channel input and
@@ -1156,7 +1153,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
-       u8 reg;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -1165,9 +1161,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY &&
                    aic3x->master) {
                        /* enable pll */
-                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
-                                     reg | PLL_ENABLE);
+                       snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+                                           PLL_ENABLE, PLL_ENABLE);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
@@ -1176,9 +1171,8 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE &&
                    aic3x->master) {
                        /* disable pll */
-                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
-                                     reg & ~PLL_ENABLE);
+                       snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG,
+                                           PLL_ENABLE, 0);
                }
                break;
        case SND_SOC_BIAS_OFF:
@@ -1249,7 +1243,7 @@ EXPORT_SYMBOL_GPL(aic3x_button_pressed);
 #define AIC3X_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops aic3x_dai_ops = {
+static const struct snd_soc_dai_ops aic3x_dai_ops = {
        .hw_params      = aic3x_hw_params,
        .digital_mute   = aic3x_mute,
        .set_sysclk     = aic3x_set_dai_sysclk,
@@ -1274,7 +1268,7 @@ static struct snd_soc_dai_driver aic3x_dai = {
        .symmetric_rates = 1,
 };
 
-static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int aic3x_suspend(struct snd_soc_codec *codec)
 {
        aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1295,7 +1289,6 @@ static int aic3x_resume(struct snd_soc_codec *codec)
 static int aic3x_init(struct snd_soc_codec *codec)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
-       int reg;
 
        snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
        snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
@@ -1317,20 +1310,13 @@ static int aic3x_init(struct snd_soc_codec *codec)
        snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
        /* unmute all outputs */
-       reg = snd_soc_read(codec, LLOPM_CTRL);
-       snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, RLOPM_CTRL);
-       snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, MONOLOPM_CTRL);
-       snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, HPLOUT_CTRL);
-       snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, HPROUT_CTRL);
-       snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, HPLCOM_CTRL);
-       snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE);
-       reg = snd_soc_read(codec, HPRCOM_CTRL);
-       snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+       snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE);
+       snd_soc_update_bits(codec, HPRCOM_CTRL, UNMUTE, UNMUTE);
 
        /* ADC default volume and unmute */
        snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
@@ -1494,7 +1480,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
        .resume = aic3x_resume,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * AIC3X 2 wire address can be up to 4 devices with device addresses
  * 0x18, 0x19, 0x1A, 0x1B
@@ -1519,7 +1504,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
        struct aic3x_priv *aic3x;
        int ret;
 
-       aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+       aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
        if (aic3x == NULL) {
                dev_err(&i2c->dev, "failed to create private data\n");
                return -ENOMEM;
@@ -1539,15 +1524,12 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_aic3x, &aic3x_dai, 1);
-       if (ret < 0)
-               kfree(aic3x);
        return ret;
 }
 
 static int aic3x_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1561,27 +1543,22 @@ static struct i2c_driver aic3x_i2c_driver = {
        .remove = aic3x_i2c_remove,
        .id_table = aic3x_i2c_id,
 };
-#endif
 
 static int __init aic3x_modinit(void)
 {
        int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&aic3x_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
                       ret);
        }
-#endif
        return ret;
 }
 module_init(aic3x_modinit);
 
 static void __exit aic3x_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&aic3x_i2c_driver);
-#endif
 }
 module_exit(aic3x_exit);
 
index dc8a2b2bdc1ce73b939cc0455f7ba4931c153c2e..f0aad26cdb3166ea18456cdfafec5bce35835ac5 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
@@ -1461,7 +1460,7 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec)
 {
        dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1499,7 +1498,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
                         SNDRV_PCM_RATE_48000)
 #define DAC33_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops dac33_dai_ops = {
+static const struct snd_soc_dai_ops dac33_dai_ops = {
        .startup        = dac33_startup,
        .shutdown       = dac33_shutdown,
        .hw_params      = dac33_hw_params,
@@ -1533,7 +1532,8 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
        }
        pdata = client->dev.platform_data;
 
-       dac33 = kzalloc(sizeof(struct tlv320dac33_priv), GFP_KERNEL);
+       dac33 = devm_kzalloc(&client->dev, sizeof(struct tlv320dac33_priv),
+                            GFP_KERNEL);
        if (dac33 == NULL)
                return -ENOMEM;
 
@@ -1588,7 +1588,6 @@ err_get:
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
 err_gpio:
-       kfree(dac33);
        return ret;
 }
 
@@ -1605,8 +1604,6 @@ static int __devexit dac33_i2c_remove(struct i2c_client *client)
        regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 
        snd_soc_unregister_codec(&client->dev);
-       kfree(dac33);
-
        return 0;
 }
 
index 7eeca79d738784e612a3cca65bb15faa67a0a4b8..363b99dad8e9539e09cc29134e7d215243dddbc8 100644 (file)
@@ -376,7 +376,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL) {
                dev_err(dev, "Can not allocate memory\n");
                return -ENOMEM;
@@ -450,7 +450,6 @@ err_regulator:
        if (data->power_gpio >= 0)
                gpio_free(data->power_gpio);
 err_gpio:
-       kfree(data);
        tpa6130a2_client = NULL;
 
        return ret;
@@ -466,8 +465,6 @@ static int __devexit tpa6130a2_remove(struct i2c_client *client)
                gpio_free(data->power_gpio);
 
        regulator_put(data->supply);
-
-       kfree(data);
        tpa6130a2_client = NULL;
 
        return 0;
index f798247ac1b2071e7316200be605734ed87faf6d..18e71014cc2e87a93d82abdca853b62d29ab8a54 100644 (file)
@@ -2149,7 +2149,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 #define TWL4030_RATES   (SNDRV_PCM_RATE_8000_48000)
 #define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
+static const struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
        .startup        = twl4030_startup,
        .shutdown       = twl4030_shutdown,
        .hw_params      = twl4030_hw_params,
@@ -2158,7 +2158,7 @@ static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
        .set_tristate   = twl4030_set_tristate,
 };
 
-static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
+static const struct snd_soc_dai_ops twl4030_dai_voice_ops = {
        .startup        = twl4030_voice_startup,
        .shutdown       = twl4030_voice_shutdown,
        .hw_params      = twl4030_voice_hw_params,
@@ -2202,7 +2202,7 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
 },
 };
 
-static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int twl4030_soc_suspend(struct snd_soc_codec *codec)
 {
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -2294,17 +2294,7 @@ static struct platform_driver twl4030_codec_driver = {
        },
 };
 
-static int __init twl4030_modinit(void)
-{
-       return platform_driver_register(&twl4030_codec_driver);
-}
-module_init(twl4030_modinit);
-
-static void __exit twl4030_exit(void)
-{
-       platform_driver_unregister(&twl4030_codec_driver);
-}
-module_exit(twl4030_exit);
+module_platform_driver(twl4030_codec_driver);
 
 MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
 MODULE_AUTHOR("Steve Sakoman");
index 73e11f022dedc944c1010064435b17402b96194c..5b9c79b6f65e104fdbbae4779452d15821752c58 100644 (file)
@@ -33,6 +33,7 @@
 #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>
 
@@ -1012,6 +1013,28 @@ static int twl6040_pll_put_enum(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+int twl6040_get_dl1_gain(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       if (snd_soc_dapm_get_pin_status(dapm, "EP"))
+               return -1; /* -1dB */
+
+       if (snd_soc_dapm_get_pin_status(dapm, "HSOR") ||
+               snd_soc_dapm_get_pin_status(dapm, "HSOL")) {
+
+               u8 val = snd_soc_read(codec, TWL6040_REG_HSLCTL);
+               if (val & TWL6040_HSDACMODE)
+                       /* HSDACL in LP mode */
+                       return -8; /* -8dB */
+               else
+                       /* HSDACL in HP mode */
+                       return -1; /* -1dB */
+       }
+       return 0; /* 0dB */
+}
+EXPORT_SYMBOL_GPL(twl6040_get_dl1_gain);
+
 int twl6040_get_clk_id(struct snd_soc_codec *codec)
 {
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
@@ -1397,7 +1420,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-static struct snd_soc_dai_ops twl6040_dai_ops = {
+static const struct snd_soc_dai_ops twl6040_dai_ops = {
        .startup        = twl6040_startup,
        .hw_params      = twl6040_hw_params,
        .prepare        = twl6040_prepare,
@@ -1470,7 +1493,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 };
 
 #ifdef CONFIG_PM
-static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int twl6040_suspend(struct snd_soc_codec *codec)
 {
        twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1620,17 +1643,7 @@ static struct platform_driver twl6040_codec_driver = {
        .remove = __devexit_p(twl6040_codec_remove),
 };
 
-static int __init twl6040_codec_init(void)
-{
-       return platform_driver_register(&twl6040_codec_driver);
-}
-module_init(twl6040_codec_init);
-
-static void __exit twl6040_codec_exit(void)
-{
-       platform_driver_unregister(&twl6040_codec_driver);
-}
-module_exit(twl6040_codec_exit);
+module_platform_driver(twl6040_codec_driver);
 
 MODULE_DESCRIPTION("ASoC TWL6040 codec driver");
 MODULE_AUTHOR("Misael Lopez Cruz");
index a83277bdb851129c5fb7a3db84e11e42d50dab0e..ef273f1fac2f838add14ecc8b01465e4677097af 100644 (file)
@@ -34,6 +34,7 @@ enum twl6040_trim {
 #define TWL6040_HSF_TRIM_LEFT(x)       (x & 0x0f)
 #define TWL6040_HSF_TRIM_RIGHT(x)      ((x >> 4) & 0x0f)
 
+int twl6040_get_dl1_gain(struct snd_soc_codec *codec);
 void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
                            struct snd_soc_jack *jack, int report);
 int twl6040_get_clk_id(struct snd_soc_codec *codec);
index a7b8f301bad39b3ef7a691273d4d3ba4bf4b9097..8f4f469d64115cb52ae8c58fd60fcc78d9669e50 100644 (file)
@@ -452,7 +452,7 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
 };
 
-static struct snd_soc_dai_ops uda134x_dai_ops = {
+static const struct snd_soc_dai_ops uda134x_dai_ops = {
        .startup        = uda134x_startup,
        .shutdown       = uda134x_shutdown,
        .hw_params      = uda134x_hw_params,
@@ -571,8 +571,7 @@ static int uda134x_soc_remove(struct snd_soc_codec *codec)
 }
 
 #if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct snd_soc_codec *codec,
-                                               pm_message_t state)
+static int uda134x_soc_suspend(struct snd_soc_codec *codec)
 {
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -625,17 +624,7 @@ static struct platform_driver uda134x_codec_driver = {
        .remove = __devexit_p(uda134x_codec_remove),
 };
 
-static int __init uda134x_codec_init(void)
-{
-       return platform_driver_register(&uda134x_codec_driver);
-}
-module_init(uda134x_codec_init);
-
-static void __exit uda134x_codec_exit(void)
-{
-       platform_driver_unregister(&uda134x_codec_driver);
-}
-module_exit(uda134x_codec_exit);
+module_platform_driver(uda134x_codec_driver);
 
 MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
index 0441893e270ed2b5621833fecc997b6b20f85159..4f1b23d7e4043eb28789133bd707298aa613e090 100644 (file)
@@ -373,7 +373,7 @@ static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route uda1380_dapm_routes[] = {
 
        /* output mux */
        {"HeadPhone Driver", NULL, "Output Mux"},
@@ -410,17 +410,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Right PGA", NULL, "VINR"},
 };
 
-static int uda1380_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
-                                 ARRAY_SIZE(uda1380_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
                unsigned int fmt)
 {
@@ -643,21 +632,21 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                       SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops uda1380_dai_ops = {
+static const struct snd_soc_dai_ops uda1380_dai_ops = {
        .hw_params      = uda1380_pcm_hw_params,
        .shutdown       = uda1380_pcm_shutdown,
        .trigger        = uda1380_trigger,
        .set_fmt        = uda1380_set_dai_fmt_both,
 };
 
-static struct snd_soc_dai_ops uda1380_dai_ops_playback = {
+static const struct snd_soc_dai_ops uda1380_dai_ops_playback = {
        .hw_params      = uda1380_pcm_hw_params,
        .shutdown       = uda1380_pcm_shutdown,
        .trigger        = uda1380_trigger,
        .set_fmt        = uda1380_set_dai_fmt_playback,
 };
 
-static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
+static const struct snd_soc_dai_ops uda1380_dai_ops_capture = {
        .hw_params      = uda1380_pcm_hw_params,
        .shutdown       = uda1380_pcm_shutdown,
        .trigger        = uda1380_trigger,
@@ -705,7 +694,7 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
 },
 };
 
-static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int uda1380_suspend(struct snd_soc_codec *codec)
 {
        uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -732,27 +721,21 @@ static int uda1380_probe(struct snd_soc_codec *codec)
                return -EINVAL;
 
        if (gpio_is_valid(pdata->gpio_reset)) {
-               ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+               ret = gpio_request_one(pdata->gpio_reset, GPIOF_OUT_INIT_LOW,
+                                      "uda1380 reset");
                if (ret)
                        goto err_out;
-               ret = gpio_direction_output(pdata->gpio_reset, 0);
-               if (ret)
-                       goto err_gpio_reset_conf;
        }
 
        if (gpio_is_valid(pdata->gpio_power)) {
-               ret = gpio_request(pdata->gpio_power, "uda1380 power");
+               ret = gpio_request_one(pdata->gpio_power, GPIOF_OUT_INIT_LOW,
+                                  "uda1380 power");
                if (ret)
-                       goto err_gpio;
-               ret = gpio_direction_output(pdata->gpio_power, 0);
-               if (ret)
-                       goto err_gpio_power_conf;
+                       goto err_free_gpio;
        } else {
                ret = uda1380_reset(codec);
-               if (ret) {
-                       dev_err(codec->dev, "Failed to issue reset\n");
-                       goto err_reset;
-               }
+               if (ret)
+                       goto err_free_gpio;
        }
 
        INIT_WORK(&uda1380->work, uda1380_flush_work);
@@ -770,19 +753,9 @@ static int uda1380_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       snd_soc_add_controls(codec, uda1380_snd_controls,
-                               ARRAY_SIZE(uda1380_snd_controls));
-       uda1380_add_widgets(codec);
-
        return 0;
 
-err_reset:
-err_gpio_power_conf:
-       if (gpio_is_valid(pdata->gpio_power))
-               gpio_free(pdata->gpio_power);
-
-err_gpio_reset_conf:
-err_gpio:
+err_free_gpio:
        if (gpio_is_valid(pdata->gpio_reset))
                gpio_free(pdata->gpio_reset);
 err_out:
@@ -814,6 +787,13 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
        .reg_word_size = sizeof(u16),
        .reg_cache_default = uda1380_reg,
        .reg_cache_step = 1,
+
+       .controls = uda1380_snd_controls,
+       .num_controls = ARRAY_SIZE(uda1380_snd_controls),
+       .dapm_widgets = uda1380_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+       .dapm_routes = uda1380_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -823,7 +803,8 @@ static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
        struct uda1380_priv *uda1380;
        int ret;
 
-       uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
+       uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv),
+                              GFP_KERNEL);
        if (uda1380 == NULL)
                return -ENOMEM;
 
@@ -832,15 +813,12 @@ static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
-       if (ret < 0)
-               kfree(uda1380);
        return ret;
 }
 
 static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
 {
        snd_soc_unregister_codec(&i2c->dev);
-       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
index a854989829911a62eae6fdf3cf3336b917f748c4..44aacf927ba99d6a533524b39859eac9d565c265 100644 (file)
@@ -386,7 +386,7 @@ static int wl1273_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops wl1273_dai_ops = {
+static const struct snd_soc_dai_ops wl1273_dai_ops = {
        .startup        = wl1273_startup,
        .hw_params      = wl1273_hw_params,
 };
@@ -510,17 +510,7 @@ static struct platform_driver wl1273_platform_driver = {
        .remove         = __devexit_p(wl1273_platform_remove),
 };
 
-static int __init wl1273_init(void)
-{
-       return platform_driver_register(&wl1273_platform_driver);
-}
-module_init(wl1273_init);
-
-static void __exit wl1273_exit(void)
-{
-       platform_driver_unregister(&wl1273_platform_driver);
-}
-module_exit(wl1273_exit);
+module_platform_driver(wl1273_platform_driver);
 
 MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
 MODULE_DESCRIPTION("ASoC WL1273 codec driver");
index cd0ec0fd1dbab536579b296884275cc14828326a..aefb4f89be0eb23b108e01581e86a52299961904 100644 (file)
@@ -116,7 +116,7 @@ static int __devinit wm1250_ev1_pdata(struct i2c_client *i2c)
        if (!pdata)
                return 0;
 
-       wm1250 = kzalloc(sizeof(*wm1250), GFP_KERNEL);
+       wm1250 = devm_kzalloc(&i2c->dev, sizeof(*wm1250), GFP_KERNEL);
        if (!wm1250) {
                dev_err(&i2c->dev, "Unable to allocate private data\n");
                ret = -ENOMEM;
@@ -134,15 +134,13 @@ static int __devinit wm1250_ev1_pdata(struct i2c_client *i2c)
        ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret);
-               goto err_alloc;
+               goto err;
        }
 
        dev_set_drvdata(&i2c->dev, wm1250);
 
        return ret;
 
-err_alloc:
-       kfree(wm1250);
 err:
        return ret;
 }
@@ -151,10 +149,8 @@ static void wm1250_ev1_free(struct i2c_client *i2c)
 {
        struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev);
 
-       if (wm1250) {
+       if (wm1250)
                gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
-               kfree(wm1250);
-       }
 }
 
 static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
index a3b9cbb20ee9bc07ca849fbe4f7af593048da9c8..c2880907fcedc0e74aed4b377e697d5223bee579 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -52,6 +52,7 @@ enum wm2000_anc_mode {
 
 struct wm2000_priv {
        struct i2c_client *i2c;
+       struct regmap *regmap;
 
        enum wm2000_anc_mode anc_mode;
 
@@ -66,59 +67,24 @@ struct wm2000_priv {
        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;
+       struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
+       return regmap_write(wm2000->regmap, reg, value);
 }
 
 static unsigned int wm2000_read(struct i2c_client *i2c, unsigned int r)
 {
-       struct i2c_msg xfer[2];
-       u8 reg[2];
-       u8 data;
+       struct wm2000_priv *wm2000 = i2c_get_clientdata(i2c);
+       unsigned int val;
        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);
+       ret = regmap_read(wm2000->regmap, r, &val);
+       if (ret < 0)
+               return -1;
 
-       return data;
+       return val;
 }
 
 static void wm2000_reset(struct wm2000_priv *wm2000)
@@ -612,7 +578,8 @@ static int wm2000_anc_set_mode(struct wm2000_priv *wm2000)
 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);
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
        ucontrol->value.enumerated.item[0] = wm2000->anc_active;
 
@@ -622,7 +589,8 @@ static int wm2000_anc_mode_get(struct snd_kcontrol *kcontrol,
 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);
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int anc_active = ucontrol->value.enumerated.item[0];
 
        if (anc_active > 1)
@@ -636,7 +604,8 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
 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);
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
        ucontrol->value.enumerated.item[0] = wm2000->spk_ena;
 
@@ -646,7 +615,8 @@ static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
 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);
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int val = ucontrol->value.enumerated.item[0];
 
        if (val > 1)
@@ -669,7 +639,8 @@ static const struct snd_kcontrol_new wm2000_controls[] = {
 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);
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
        if (SND_SOC_DAPM_EVENT_ON(event))
                wm2000->anc_eng_ena = 1;
@@ -682,11 +653,11 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
 
 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_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
 
-SND_SOC_DAPM_INPUT("WM2000 LINN"),
-SND_SOC_DAPM_INPUT("WM2000 LINP"),
+SND_SOC_DAPM_INPUT("LINN"),
+SND_SOC_DAPM_INPUT("LINP"),
 
 SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0,
                   wm2000_anc_power_event,
@@ -694,37 +665,67 @@ SND_SOC_DAPM_PGA_E("ANC Engine", SND_SOC_NOPM, 0, 0, NULL, 0,
 };
 
 /* 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" },
+static const struct snd_soc_dapm_route wm2000_audio_map[] = {
+       { "SPKN", NULL, "ANC Engine" },
+       { "SPKP", NULL, "ANC Engine" },
+       { "ANC Engine", NULL, "LINN" },
+       { "ANC Engine", NULL, "LINP" },
 };
 
-/* Called from the machine driver */
-int wm2000_add_controls(struct snd_soc_codec *codec)
+#ifdef CONFIG_PM
+static int wm2000_suspend(struct snd_soc_codec *codec)
 {
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       if (!wm2000_i2c) {
-               pr_err("WM2000 not yet probed\n");
-               return -ENODEV;
-       }
+       return wm2000_anc_transition(wm2000, ANC_OFF);
+}
 
-       ret = snd_soc_dapm_new_controls(dapm, wm2000_dapm_widgets,
-                                       ARRAY_SIZE(wm2000_dapm_widgets));
-       if (ret < 0)
-               return ret;
+static int wm2000_resume(struct snd_soc_codec *codec)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-       if (ret < 0)
-               return ret;
+       return wm2000_anc_set_mode(wm2000);
+}
+#else
+#define wm2000_suspend NULL
+#define wm2000_resume NULL
+#endif
+
+static const struct regmap_config wm2000_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int wm2000_probe(struct snd_soc_codec *codec)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
+
+       /* This will trigger a transition to standby mode by default */
+       wm2000_anc_set_mode(wm2000);
+
+       return 0;
+}
+
+static int wm2000_remove(struct snd_soc_codec *codec)
+{
+       struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
 
-       return snd_soc_add_controls(codec, wm2000_controls,
-                       ARRAY_SIZE(wm2000_controls));
+       return wm2000_anc_transition(wm2000, ANC_OFF);
 }
-EXPORT_SYMBOL_GPL(wm2000_add_controls);
+
+static struct snd_soc_codec_driver soc_codec_dev_wm2000 = {
+       .probe = wm2000_probe,
+       .remove = wm2000_remove,
+       .suspend = wm2000_suspend,
+       .resume = wm2000_resume,
+
+       .dapm_widgets = wm2000_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm2000_dapm_widgets),
+       .dapm_routes = wm2000_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(wm2000_audio_map),
+       .controls = wm2000_controls,
+       .num_controls = ARRAY_SIZE(wm2000_controls),
+};
 
 static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *i2c_id)
@@ -736,17 +737,23 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        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);
+       wm2000 = devm_kzalloc(&i2c->dev, sizeof(struct wm2000_priv),
+                             GFP_KERNEL);
        if (wm2000 == NULL) {
                dev_err(&i2c->dev, "Unable to allocate private data\n");
                return -ENOMEM;
        }
 
+       dev_set_drvdata(&i2c->dev, wm2000);
+
+       wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap);
+       if (IS_ERR(wm2000->regmap)) {
+               ret = PTR_ERR(wm2000->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               goto err;
+       }
+
        /* Verify that this is a WM2000 */
        reg = wm2000_read(i2c, WM2000_REG_ID1);
        id = reg << 8;
@@ -756,7 +763,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        if (id != 0x2000) {
                dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
                ret = -ENODEV;
-               goto err;
+               goto err_regmap;
        }
 
        reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -775,12 +782,14 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        ret = request_firmware(&fw, filename, &i2c->dev);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
-               goto err;
+               goto err_regmap;
        }
 
        /* 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);
+       wm2000->anc_download = devm_kzalloc(&i2c->dev,
+                                           wm2000->anc_download_size,
+                                           GFP_KERNEL);
        if (wm2000->anc_download == NULL) {
                dev_err(&i2c->dev, "Out of memory\n");
                ret = -ENOMEM;
@@ -793,7 +802,6 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 
        release_firmware(fw);
 
-       dev_set_drvdata(&i2c->dev, wm2000);
        wm2000->anc_eng_ena = 1;
        wm2000->anc_active = 1;
        wm2000->spk_ena = 1;
@@ -801,17 +809,18 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 
        wm2000_reset(wm2000);
 
-       /* This will trigger a transition to standby mode by default */
-       wm2000_anc_set_mode(wm2000);    
-
-       wm2000_i2c = i2c;
+       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000,
+                                    NULL, 0);
+       if (ret != 0)
+               goto err_fw;
 
        return 0;
 
 err_fw:
        release_firmware(fw);
+err_regmap:
+       regmap_exit(wm2000->regmap);
 err:
-       kfree(wm2000);
        return ret;
 }
 
@@ -819,42 +828,12 @@ 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);
+       snd_soc_unregister_codec(&i2c->dev);
+       regmap_exit(wm2000->regmap);
 
        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 device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
-
-       return wm2000_anc_transition(wm2000, ANC_OFF);
-}
-
-static int wm2000_i2c_resume(struct device *dev)
-{
-       struct i2c_client *i2c = to_i2c_client(dev);
-       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
-
-       return wm2000_anc_set_mode(wm2000);
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(wm2000_pm, wm2000_i2c_suspend, wm2000_i2c_resume);
-
 static const struct i2c_device_id wm2000_i2c_id[] = {
        { "wm2000", 0 },
        { }
@@ -865,11 +844,9 @@ static struct i2c_driver wm2000_i2c_driver = {
        .driver = {
                .name = "wm2000",
                .owner = THIS_MODULE,
-               .pm = &wm2000_pm,
        },
        .probe = wm2000_i2c_probe,
        .remove = __devexit_p(wm2000_i2c_remove),
-       .shutdown = wm2000_i2c_shutdown,
        .id_table = wm2000_i2c_id,
 };
 
index 0b6f056f73cc53a80ab0fedc5733641573bc4974..abcd82a93995b357ba8052b0559178912990923b 100644 (file)
@@ -9,13 +9,6 @@
 #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);
-
 #define WM2000_REG_SYS_START       0x8000
 #define WM2000_REG_SPEECH_CLARITY   0x8fef
 #define WM2000_REG_SYS_WATCHDOG     0x8ff6
index e9ce81a57b856af0d4cc57f510195f75bba8c7c7..9a18fae68204f790a19c75e7fc527e1b25d3a1f5 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "wm5100.h"
 
-int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+bool wm5100_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM5100_SOFTWARE_RESET:
@@ -36,7 +36,7 @@ int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
        }
 }
 
-int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg)
+bool wm5100_readable_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM5100_SOFTWARE_RESET:
@@ -85,6 +85,7 @@ int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg)
        case WM5100_MIC_DETECT_1:
        case WM5100_MIC_DETECT_2:
        case WM5100_MIC_DETECT_3:
+       case WM5100_MISC_CONTROL:
        case WM5100_INPUT_ENABLES:
        case WM5100_INPUT_ENABLES_STATUS:
        case WM5100_IN1L_CONTROL:
@@ -696,836 +697,668 @@ int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg)
        case WM5100_HPLPF3_2:
        case WM5100_HPLPF4_1:
        case WM5100_HPLPF4_2:
-       case WM5100_DSP1_DM_0:
-       case WM5100_DSP1_DM_1:
-       case WM5100_DSP1_DM_2:
-       case WM5100_DSP1_DM_3:
-       case WM5100_DSP1_DM_508:
-       case WM5100_DSP1_DM_509:
-       case WM5100_DSP1_DM_510:
-       case WM5100_DSP1_DM_511:
-       case WM5100_DSP1_PM_0:
-       case WM5100_DSP1_PM_1:
-       case WM5100_DSP1_PM_2:
-       case WM5100_DSP1_PM_3:
-       case WM5100_DSP1_PM_4:
-       case WM5100_DSP1_PM_5:
-       case WM5100_DSP1_PM_1530:
-       case WM5100_DSP1_PM_1531:
-       case WM5100_DSP1_PM_1532:
-       case WM5100_DSP1_PM_1533:
-       case WM5100_DSP1_PM_1534:
-       case WM5100_DSP1_PM_1535:
-       case WM5100_DSP1_ZM_0:
-       case WM5100_DSP1_ZM_1:
-       case WM5100_DSP1_ZM_2:
-       case WM5100_DSP1_ZM_3:
-       case WM5100_DSP1_ZM_2044:
-       case WM5100_DSP1_ZM_2045:
-       case WM5100_DSP1_ZM_2046:
-       case WM5100_DSP1_ZM_2047:
-       case WM5100_DSP2_DM_0:
-       case WM5100_DSP2_DM_1:
-       case WM5100_DSP2_DM_2:
-       case WM5100_DSP2_DM_3:
-       case WM5100_DSP2_DM_508:
-       case WM5100_DSP2_DM_509:
-       case WM5100_DSP2_DM_510:
-       case WM5100_DSP2_DM_511:
-       case WM5100_DSP2_PM_0:
-       case WM5100_DSP2_PM_1:
-       case WM5100_DSP2_PM_2:
-       case WM5100_DSP2_PM_3:
-       case WM5100_DSP2_PM_4:
-       case WM5100_DSP2_PM_5:
-       case WM5100_DSP2_PM_1530:
-       case WM5100_DSP2_PM_1531:
-       case WM5100_DSP2_PM_1532:
-       case WM5100_DSP2_PM_1533:
-       case WM5100_DSP2_PM_1534:
-       case WM5100_DSP2_PM_1535:
-       case WM5100_DSP2_ZM_0:
-       case WM5100_DSP2_ZM_1:
-       case WM5100_DSP2_ZM_2:
-       case WM5100_DSP2_ZM_3:
-       case WM5100_DSP2_ZM_2044:
-       case WM5100_DSP2_ZM_2045:
-       case WM5100_DSP2_ZM_2046:
-       case WM5100_DSP2_ZM_2047:
-       case WM5100_DSP3_DM_0:
-       case WM5100_DSP3_DM_1:
-       case WM5100_DSP3_DM_2:
-       case WM5100_DSP3_DM_3:
-       case WM5100_DSP3_DM_508:
-       case WM5100_DSP3_DM_509:
-       case WM5100_DSP3_DM_510:
-       case WM5100_DSP3_DM_511:
-       case WM5100_DSP3_PM_0:
-       case WM5100_DSP3_PM_1:
-       case WM5100_DSP3_PM_2:
-       case WM5100_DSP3_PM_3:
-       case WM5100_DSP3_PM_4:
-       case WM5100_DSP3_PM_5:
-       case WM5100_DSP3_PM_1530:
-       case WM5100_DSP3_PM_1531:
-       case WM5100_DSP3_PM_1532:
-       case WM5100_DSP3_PM_1533:
-       case WM5100_DSP3_PM_1534:
-       case WM5100_DSP3_PM_1535:
-       case WM5100_DSP3_ZM_0:
-       case WM5100_DSP3_ZM_1:
-       case WM5100_DSP3_ZM_2:
-       case WM5100_DSP3_ZM_3:
-       case WM5100_DSP3_ZM_2044:
-       case WM5100_DSP3_ZM_2045:
-       case WM5100_DSP3_ZM_2046:
-       case WM5100_DSP3_ZM_2047:
                return 1;
        default:
                return 0;
        }
 }
 
-u16 wm5100_reg_defaults[WM5100_MAX_REGISTER + 1] = {
-       [0x0000] = 0x0000,     /* R0     - software reset */
-       [0x0001] = 0x0000,     /* R1     - Device Revision */
-       [0x0010] = 0x0801,     /* R16    - Ctrl IF 1 */
-       [0x0020] = 0x0000,     /* R32    - Tone Generator 1 */
-       [0x0030] = 0x0000,     /* R48    - PWM Drive 1 */
-       [0x0031] = 0x0100,     /* R49    - PWM Drive 2 */
-       [0x0032] = 0x0100,     /* R50    - PWM Drive 3 */
-       [0x0100] = 0x0002,     /* R256   - Clocking 1 */
-       [0x0101] = 0x0000,     /* R257   - Clocking 3 */
-       [0x0102] = 0x0011,     /* R258   - Clocking 4 */
-       [0x0103] = 0x0011,     /* R259   - Clocking 5 */
-       [0x0104] = 0x0011,     /* R260   - Clocking 6 */
-       [0x0107] = 0x0000,     /* R263   - Clocking 7 */
-       [0x0108] = 0x0000,     /* R264   - Clocking 8 */
-       [0x0120] = 0x0000,     /* R288   - ASRC_ENABLE */
-       [0x0121] = 0x0000,     /* R289   - ASRC_STATUS */
-       [0x0122] = 0x0000,     /* R290   - ASRC_RATE1 */
-       [0x0141] = 0x8000,     /* R321   - ISRC 1 CTRL 1 */
-       [0x0142] = 0x0000,     /* R322   - ISRC 1 CTRL 2 */
-       [0x0143] = 0x8000,     /* R323   - ISRC 2 CTRL1 */
-       [0x0144] = 0x0000,     /* R324   - ISRC 2 CTRL 2 */
-       [0x0182] = 0x0000,     /* R386   - FLL1 Control 1 */
-       [0x0183] = 0x0000,     /* R387   - FLL1 Control 2 */
-       [0x0184] = 0x0000,     /* R388   - FLL1 Control 3 */
-       [0x0186] = 0x0177,     /* R390   - FLL1 Control 5 */
-       [0x0187] = 0x0001,     /* R391   - FLL1 Control 6 */
-       [0x0188] = 0x0000,     /* R392   - FLL1 EFS 1 */
-       [0x01A2] = 0x0000,     /* R418   - FLL2 Control 1 */
-       [0x01A3] = 0x0000,     /* R419   - FLL2 Control 2 */
-       [0x01A4] = 0x0000,     /* R420   - FLL2 Control 3 */
-       [0x01A6] = 0x0177,     /* R422   - FLL2 Control 5 */
-       [0x01A7] = 0x0001,     /* R423   - FLL2 Control 6 */
-       [0x01A8] = 0x0000,     /* R424   - FLL2 EFS 1 */
-       [0x0200] = 0x0020,     /* R512   - Mic Charge Pump 1 */
-       [0x0201] = 0xB084,     /* R513   - Mic Charge Pump 2 */
-       [0x0202] = 0xBBDE,     /* R514   - HP Charge Pump 1 */
-       [0x0211] = 0x20D4,     /* R529   - LDO1 Control */
-       [0x0215] = 0x0062,     /* R533   - Mic Bias Ctrl 1 */
-       [0x0216] = 0x0062,     /* R534   - Mic Bias Ctrl 2 */
-       [0x0217] = 0x0062,     /* R535   - Mic Bias Ctrl 3 */
-       [0x0280] = 0x0004,     /* R640   - Accessory Detect Mode 1 */
-       [0x0288] = 0x0020,     /* R648   - Headphone Detect 1 */
-       [0x0289] = 0x0000,     /* R649   - Headphone Detect 2 */
-       [0x0290] = 0x1100,     /* R656   - Mic Detect 1 */
-       [0x0291] = 0x009F,     /* R657   - Mic Detect 2 */
-       [0x0292] = 0x0000,     /* R658   - Mic Detect 3 */
-       [0x0301] = 0x0000,     /* R769   - Input Enables */
-       [0x0302] = 0x0000,     /* R770   - Input Enables Status */
-       [0x0310] = 0x2280,     /* R784   - Status */
-       [0x0311] = 0x0080,     /* R785   - IN1R Control */
-       [0x0312] = 0x2280,     /* R786   - IN2L Control */
-       [0x0313] = 0x0080,     /* R787   - IN2R Control */
-       [0x0314] = 0x2280,     /* R788   - IN3L Control */
-       [0x0315] = 0x0080,     /* R789   - IN3R Control */
-       [0x0316] = 0x2280,     /* R790   - IN4L Control */
-       [0x0317] = 0x0080,     /* R791   - IN4R Control */
-       [0x0318] = 0x0000,     /* R792   - RXANC_SRC */
-       [0x0319] = 0x0022,     /* R793   - Input Volume Ramp */
-       [0x0320] = 0x0180,     /* R800   - ADC Digital Volume 1L */
-       [0x0321] = 0x0180,     /* R801   - ADC Digital Volume 1R */
-       [0x0322] = 0x0180,     /* R802   - ADC Digital Volume 2L */
-       [0x0323] = 0x0180,     /* R803   - ADC Digital Volume 2R */
-       [0x0324] = 0x0180,     /* R804   - ADC Digital Volume 3L */
-       [0x0325] = 0x0180,     /* R805   - ADC Digital Volume 3R */
-       [0x0326] = 0x0180,     /* R806   - ADC Digital Volume 4L */
-       [0x0327] = 0x0180,     /* R807   - ADC Digital Volume 4R */
-       [0x0401] = 0x0000,     /* R1025  - Output Enables 2 */
-       [0x0402] = 0x0000,     /* R1026  - Output Status 1 */
-       [0x0403] = 0x0000,     /* R1027  - Output Status 2 */
-       [0x0408] = 0x0000,     /* R1032  - Channel Enables 1 */
-       [0x0410] = 0x0080,     /* R1040  - Out Volume 1L */
-       [0x0411] = 0x0080,     /* R1041  - Out Volume 1R */
-       [0x0412] = 0x0080,     /* R1042  - DAC Volume Limit 1L */
-       [0x0413] = 0x0080,     /* R1043  - DAC Volume Limit 1R */
-       [0x0414] = 0x0080,     /* R1044  - Out Volume 2L */
-       [0x0415] = 0x0080,     /* R1045  - Out Volume 2R */
-       [0x0416] = 0x0080,     /* R1046  - DAC Volume Limit 2L */
-       [0x0417] = 0x0080,     /* R1047  - DAC Volume Limit 2R */
-       [0x0418] = 0x0080,     /* R1048  - Out Volume 3L */
-       [0x0419] = 0x0080,     /* R1049  - Out Volume 3R */
-       [0x041A] = 0x0080,     /* R1050  - DAC Volume Limit 3L */
-       [0x041B] = 0x0080,     /* R1051  - DAC Volume Limit 3R */
-       [0x041C] = 0x0080,     /* R1052  - Out Volume 4L */
-       [0x041D] = 0x0080,     /* R1053  - Out Volume 4R */
-       [0x041E] = 0x0080,     /* R1054  - DAC Volume Limit 5L */
-       [0x041F] = 0x0080,     /* R1055  - DAC Volume Limit 5R */
-       [0x0420] = 0x0080,     /* R1056  - DAC Volume Limit 6L */
-       [0x0421] = 0x0080,     /* R1057  - DAC Volume Limit 6R */
-       [0x0440] = 0x0000,     /* R1088  - DAC AEC Control 1 */
-       [0x0441] = 0x0022,     /* R1089  - Output Volume Ramp */
-       [0x0480] = 0x0180,     /* R1152  - DAC Digital Volume 1L */
-       [0x0481] = 0x0180,     /* R1153  - DAC Digital Volume 1R */
-       [0x0482] = 0x0180,     /* R1154  - DAC Digital Volume 2L */
-       [0x0483] = 0x0180,     /* R1155  - DAC Digital Volume 2R */
-       [0x0484] = 0x0180,     /* R1156  - DAC Digital Volume 3L */
-       [0x0485] = 0x0180,     /* R1157  - DAC Digital Volume 3R */
-       [0x0486] = 0x0180,     /* R1158  - DAC Digital Volume 4L */
-       [0x0487] = 0x0180,     /* R1159  - DAC Digital Volume 4R */
-       [0x0488] = 0x0180,     /* R1160  - DAC Digital Volume 5L */
-       [0x0489] = 0x0180,     /* R1161  - DAC Digital Volume 5R */
-       [0x048A] = 0x0180,     /* R1162  - DAC Digital Volume 6L */
-       [0x048B] = 0x0180,     /* R1163  - DAC Digital Volume 6R */
-       [0x04C0] = 0x0069,     /* R1216  - PDM SPK1 CTRL 1 */
-       [0x04C1] = 0x0000,     /* R1217  - PDM SPK1 CTRL 2 */
-       [0x04C2] = 0x0069,     /* R1218  - PDM SPK2 CTRL 1 */
-       [0x04C3] = 0x0000,     /* R1219  - PDM SPK2 CTRL 2 */
-       [0x0500] = 0x000C,     /* R1280  - Audio IF 1_1 */
-       [0x0501] = 0x0008,     /* R1281  - Audio IF 1_2 */
-       [0x0502] = 0x0000,     /* R1282  - Audio IF 1_3 */
-       [0x0503] = 0x0000,     /* R1283  - Audio IF 1_4 */
-       [0x0504] = 0x0000,     /* R1284  - Audio IF 1_5 */
-       [0x0505] = 0x0300,     /* R1285  - Audio IF 1_6 */
-       [0x0506] = 0x0300,     /* R1286  - Audio IF 1_7 */
-       [0x0507] = 0x1820,     /* R1287  - Audio IF 1_8 */
-       [0x0508] = 0x1820,     /* R1288  - Audio IF 1_9 */
-       [0x0509] = 0x0000,     /* R1289  - Audio IF 1_10 */
-       [0x050A] = 0x0001,     /* R1290  - Audio IF 1_11 */
-       [0x050B] = 0x0002,     /* R1291  - Audio IF 1_12 */
-       [0x050C] = 0x0003,     /* R1292  - Audio IF 1_13 */
-       [0x050D] = 0x0004,     /* R1293  - Audio IF 1_14 */
-       [0x050E] = 0x0005,     /* R1294  - Audio IF 1_15 */
-       [0x050F] = 0x0006,     /* R1295  - Audio IF 1_16 */
-       [0x0510] = 0x0007,     /* R1296  - Audio IF 1_17 */
-       [0x0511] = 0x0000,     /* R1297  - Audio IF 1_18 */
-       [0x0512] = 0x0001,     /* R1298  - Audio IF 1_19 */
-       [0x0513] = 0x0002,     /* R1299  - Audio IF 1_20 */
-       [0x0514] = 0x0003,     /* R1300  - Audio IF 1_21 */
-       [0x0515] = 0x0004,     /* R1301  - Audio IF 1_22 */
-       [0x0516] = 0x0005,     /* R1302  - Audio IF 1_23 */
-       [0x0517] = 0x0006,     /* R1303  - Audio IF 1_24 */
-       [0x0518] = 0x0007,     /* R1304  - Audio IF 1_25 */
-       [0x0519] = 0x0000,     /* R1305  - Audio IF 1_26 */
-       [0x051A] = 0x0000,     /* R1306  - Audio IF 1_27 */
-       [0x0540] = 0x000C,     /* R1344  - Audio IF 2_1 */
-       [0x0541] = 0x0008,     /* R1345  - Audio IF 2_2 */
-       [0x0542] = 0x0000,     /* R1346  - Audio IF 2_3 */
-       [0x0543] = 0x0000,     /* R1347  - Audio IF 2_4 */
-       [0x0544] = 0x0000,     /* R1348  - Audio IF 2_5 */
-       [0x0545] = 0x0300,     /* R1349  - Audio IF 2_6 */
-       [0x0546] = 0x0300,     /* R1350  - Audio IF 2_7 */
-       [0x0547] = 0x1820,     /* R1351  - Audio IF 2_8 */
-       [0x0548] = 0x1820,     /* R1352  - Audio IF 2_9 */
-       [0x0549] = 0x0000,     /* R1353  - Audio IF 2_10 */
-       [0x054A] = 0x0001,     /* R1354  - Audio IF 2_11 */
-       [0x0551] = 0x0000,     /* R1361  - Audio IF 2_18 */
-       [0x0552] = 0x0001,     /* R1362  - Audio IF 2_19 */
-       [0x0559] = 0x0000,     /* R1369  - Audio IF 2_26 */
-       [0x055A] = 0x0000,     /* R1370  - Audio IF 2_27 */
-       [0x0580] = 0x000C,     /* R1408  - Audio IF 3_1 */
-       [0x0581] = 0x0008,     /* R1409  - Audio IF 3_2 */
-       [0x0582] = 0x0000,     /* R1410  - Audio IF 3_3 */
-       [0x0583] = 0x0000,     /* R1411  - Audio IF 3_4 */
-       [0x0584] = 0x0000,     /* R1412  - Audio IF 3_5 */
-       [0x0585] = 0x0300,     /* R1413  - Audio IF 3_6 */
-       [0x0586] = 0x0300,     /* R1414  - Audio IF 3_7 */
-       [0x0587] = 0x1820,     /* R1415  - Audio IF 3_8 */
-       [0x0588] = 0x1820,     /* R1416  - Audio IF 3_9 */
-       [0x0589] = 0x0000,     /* R1417  - Audio IF 3_10 */
-       [0x058A] = 0x0001,     /* R1418  - Audio IF 3_11 */
-       [0x0591] = 0x0000,     /* R1425  - Audio IF 3_18 */
-       [0x0592] = 0x0001,     /* R1426  - Audio IF 3_19 */
-       [0x0599] = 0x0000,     /* R1433  - Audio IF 3_26 */
-       [0x059A] = 0x0000,     /* R1434  - Audio IF 3_27 */
-       [0x0640] = 0x0000,     /* R1600  - PWM1MIX Input 1 Source */
-       [0x0641] = 0x0080,     /* R1601  - PWM1MIX Input 1 Volume */
-       [0x0642] = 0x0000,     /* R1602  - PWM1MIX Input 2 Source */
-       [0x0643] = 0x0080,     /* R1603  - PWM1MIX Input 2 Volume */
-       [0x0644] = 0x0000,     /* R1604  - PWM1MIX Input 3 Source */
-       [0x0645] = 0x0080,     /* R1605  - PWM1MIX Input 3 Volume */
-       [0x0646] = 0x0000,     /* R1606  - PWM1MIX Input 4 Source */
-       [0x0647] = 0x0080,     /* R1607  - PWM1MIX Input 4 Volume */
-       [0x0648] = 0x0000,     /* R1608  - PWM2MIX Input 1 Source */
-       [0x0649] = 0x0080,     /* R1609  - PWM2MIX Input 1 Volume */
-       [0x064A] = 0x0000,     /* R1610  - PWM2MIX Input 2 Source */
-       [0x064B] = 0x0080,     /* R1611  - PWM2MIX Input 2 Volume */
-       [0x064C] = 0x0000,     /* R1612  - PWM2MIX Input 3 Source */
-       [0x064D] = 0x0080,     /* R1613  - PWM2MIX Input 3 Volume */
-       [0x064E] = 0x0000,     /* R1614  - PWM2MIX Input 4 Source */
-       [0x064F] = 0x0080,     /* R1615  - PWM2MIX Input 4 Volume */
-       [0x0680] = 0x0000,     /* R1664  - OUT1LMIX Input 1 Source */
-       [0x0681] = 0x0080,     /* R1665  - OUT1LMIX Input 1 Volume */
-       [0x0682] = 0x0000,     /* R1666  - OUT1LMIX Input 2 Source */
-       [0x0683] = 0x0080,     /* R1667  - OUT1LMIX Input 2 Volume */
-       [0x0684] = 0x0000,     /* R1668  - OUT1LMIX Input 3 Source */
-       [0x0685] = 0x0080,     /* R1669  - OUT1LMIX Input 3 Volume */
-       [0x0686] = 0x0000,     /* R1670  - OUT1LMIX Input 4 Source */
-       [0x0687] = 0x0080,     /* R1671  - OUT1LMIX Input 4 Volume */
-       [0x0688] = 0x0000,     /* R1672  - OUT1RMIX Input 1 Source */
-       [0x0689] = 0x0080,     /* R1673  - OUT1RMIX Input 1 Volume */
-       [0x068A] = 0x0000,     /* R1674  - OUT1RMIX Input 2 Source */
-       [0x068B] = 0x0080,     /* R1675  - OUT1RMIX Input 2 Volume */
-       [0x068C] = 0x0000,     /* R1676  - OUT1RMIX Input 3 Source */
-       [0x068D] = 0x0080,     /* R1677  - OUT1RMIX Input 3 Volume */
-       [0x068E] = 0x0000,     /* R1678  - OUT1RMIX Input 4 Source */
-       [0x068F] = 0x0080,     /* R1679  - OUT1RMIX Input 4 Volume */
-       [0x0690] = 0x0000,     /* R1680  - OUT2LMIX Input 1 Source */
-       [0x0691] = 0x0080,     /* R1681  - OUT2LMIX Input 1 Volume */
-       [0x0692] = 0x0000,     /* R1682  - OUT2LMIX Input 2 Source */
-       [0x0693] = 0x0080,     /* R1683  - OUT2LMIX Input 2 Volume */
-       [0x0694] = 0x0000,     /* R1684  - OUT2LMIX Input 3 Source */
-       [0x0695] = 0x0080,     /* R1685  - OUT2LMIX Input 3 Volume */
-       [0x0696] = 0x0000,     /* R1686  - OUT2LMIX Input 4 Source */
-       [0x0697] = 0x0080,     /* R1687  - OUT2LMIX Input 4 Volume */
-       [0x0698] = 0x0000,     /* R1688  - OUT2RMIX Input 1 Source */
-       [0x0699] = 0x0080,     /* R1689  - OUT2RMIX Input 1 Volume */
-       [0x069A] = 0x0000,     /* R1690  - OUT2RMIX Input 2 Source */
-       [0x069B] = 0x0080,     /* R1691  - OUT2RMIX Input 2 Volume */
-       [0x069C] = 0x0000,     /* R1692  - OUT2RMIX Input 3 Source */
-       [0x069D] = 0x0080,     /* R1693  - OUT2RMIX Input 3 Volume */
-       [0x069E] = 0x0000,     /* R1694  - OUT2RMIX Input 4 Source */
-       [0x069F] = 0x0080,     /* R1695  - OUT2RMIX Input 4 Volume */
-       [0x06A0] = 0x0000,     /* R1696  - OUT3LMIX Input 1 Source */
-       [0x06A1] = 0x0080,     /* R1697  - OUT3LMIX Input 1 Volume */
-       [0x06A2] = 0x0000,     /* R1698  - OUT3LMIX Input 2 Source */
-       [0x06A3] = 0x0080,     /* R1699  - OUT3LMIX Input 2 Volume */
-       [0x06A4] = 0x0000,     /* R1700  - OUT3LMIX Input 3 Source */
-       [0x06A5] = 0x0080,     /* R1701  - OUT3LMIX Input 3 Volume */
-       [0x06A6] = 0x0000,     /* R1702  - OUT3LMIX Input 4 Source */
-       [0x06A7] = 0x0080,     /* R1703  - OUT3LMIX Input 4 Volume */
-       [0x06A8] = 0x0000,     /* R1704  - OUT3RMIX Input 1 Source */
-       [0x06A9] = 0x0080,     /* R1705  - OUT3RMIX Input 1 Volume */
-       [0x06AA] = 0x0000,     /* R1706  - OUT3RMIX Input 2 Source */
-       [0x06AB] = 0x0080,     /* R1707  - OUT3RMIX Input 2 Volume */
-       [0x06AC] = 0x0000,     /* R1708  - OUT3RMIX Input 3 Source */
-       [0x06AD] = 0x0080,     /* R1709  - OUT3RMIX Input 3 Volume */
-       [0x06AE] = 0x0000,     /* R1710  - OUT3RMIX Input 4 Source */
-       [0x06AF] = 0x0080,     /* R1711  - OUT3RMIX Input 4 Volume */
-       [0x06B0] = 0x0000,     /* R1712  - OUT4LMIX Input 1 Source */
-       [0x06B1] = 0x0080,     /* R1713  - OUT4LMIX Input 1 Volume */
-       [0x06B2] = 0x0000,     /* R1714  - OUT4LMIX Input 2 Source */
-       [0x06B3] = 0x0080,     /* R1715  - OUT4LMIX Input 2 Volume */
-       [0x06B4] = 0x0000,     /* R1716  - OUT4LMIX Input 3 Source */
-       [0x06B5] = 0x0080,     /* R1717  - OUT4LMIX Input 3 Volume */
-       [0x06B6] = 0x0000,     /* R1718  - OUT4LMIX Input 4 Source */
-       [0x06B7] = 0x0080,     /* R1719  - OUT4LMIX Input 4 Volume */
-       [0x06B8] = 0x0000,     /* R1720  - OUT4RMIX Input 1 Source */
-       [0x06B9] = 0x0080,     /* R1721  - OUT4RMIX Input 1 Volume */
-       [0x06BA] = 0x0000,     /* R1722  - OUT4RMIX Input 2 Source */
-       [0x06BB] = 0x0080,     /* R1723  - OUT4RMIX Input 2 Volume */
-       [0x06BC] = 0x0000,     /* R1724  - OUT4RMIX Input 3 Source */
-       [0x06BD] = 0x0080,     /* R1725  - OUT4RMIX Input 3 Volume */
-       [0x06BE] = 0x0000,     /* R1726  - OUT4RMIX Input 4 Source */
-       [0x06BF] = 0x0080,     /* R1727  - OUT4RMIX Input 4 Volume */
-       [0x06C0] = 0x0000,     /* R1728  - OUT5LMIX Input 1 Source */
-       [0x06C1] = 0x0080,     /* R1729  - OUT5LMIX Input 1 Volume */
-       [0x06C2] = 0x0000,     /* R1730  - OUT5LMIX Input 2 Source */
-       [0x06C3] = 0x0080,     /* R1731  - OUT5LMIX Input 2 Volume */
-       [0x06C4] = 0x0000,     /* R1732  - OUT5LMIX Input 3 Source */
-       [0x06C5] = 0x0080,     /* R1733  - OUT5LMIX Input 3 Volume */
-       [0x06C6] = 0x0000,     /* R1734  - OUT5LMIX Input 4 Source */
-       [0x06C7] = 0x0080,     /* R1735  - OUT5LMIX Input 4 Volume */
-       [0x06C8] = 0x0000,     /* R1736  - OUT5RMIX Input 1 Source */
-       [0x06C9] = 0x0080,     /* R1737  - OUT5RMIX Input 1 Volume */
-       [0x06CA] = 0x0000,     /* R1738  - OUT5RMIX Input 2 Source */
-       [0x06CB] = 0x0080,     /* R1739  - OUT5RMIX Input 2 Volume */
-       [0x06CC] = 0x0000,     /* R1740  - OUT5RMIX Input 3 Source */
-       [0x06CD] = 0x0080,     /* R1741  - OUT5RMIX Input 3 Volume */
-       [0x06CE] = 0x0000,     /* R1742  - OUT5RMIX Input 4 Source */
-       [0x06CF] = 0x0080,     /* R1743  - OUT5RMIX Input 4 Volume */
-       [0x06D0] = 0x0000,     /* R1744  - OUT6LMIX Input 1 Source */
-       [0x06D1] = 0x0080,     /* R1745  - OUT6LMIX Input 1 Volume */
-       [0x06D2] = 0x0000,     /* R1746  - OUT6LMIX Input 2 Source */
-       [0x06D3] = 0x0080,     /* R1747  - OUT6LMIX Input 2 Volume */
-       [0x06D4] = 0x0000,     /* R1748  - OUT6LMIX Input 3 Source */
-       [0x06D5] = 0x0080,     /* R1749  - OUT6LMIX Input 3 Volume */
-       [0x06D6] = 0x0000,     /* R1750  - OUT6LMIX Input 4 Source */
-       [0x06D7] = 0x0080,     /* R1751  - OUT6LMIX Input 4 Volume */
-       [0x06D8] = 0x0000,     /* R1752  - OUT6RMIX Input 1 Source */
-       [0x06D9] = 0x0080,     /* R1753  - OUT6RMIX Input 1 Volume */
-       [0x06DA] = 0x0000,     /* R1754  - OUT6RMIX Input 2 Source */
-       [0x06DB] = 0x0080,     /* R1755  - OUT6RMIX Input 2 Volume */
-       [0x06DC] = 0x0000,     /* R1756  - OUT6RMIX Input 3 Source */
-       [0x06DD] = 0x0080,     /* R1757  - OUT6RMIX Input 3 Volume */
-       [0x06DE] = 0x0000,     /* R1758  - OUT6RMIX Input 4 Source */
-       [0x06DF] = 0x0080,     /* R1759  - OUT6RMIX Input 4 Volume */
-       [0x0700] = 0x0000,     /* R1792  - AIF1TX1MIX Input 1 Source */
-       [0x0701] = 0x0080,     /* R1793  - AIF1TX1MIX Input 1 Volume */
-       [0x0702] = 0x0000,     /* R1794  - AIF1TX1MIX Input 2 Source */
-       [0x0703] = 0x0080,     /* R1795  - AIF1TX1MIX Input 2 Volume */
-       [0x0704] = 0x0000,     /* R1796  - AIF1TX1MIX Input 3 Source */
-       [0x0705] = 0x0080,     /* R1797  - AIF1TX1MIX Input 3 Volume */
-       [0x0706] = 0x0000,     /* R1798  - AIF1TX1MIX Input 4 Source */
-       [0x0707] = 0x0080,     /* R1799  - AIF1TX1MIX Input 4 Volume */
-       [0x0708] = 0x0000,     /* R1800  - AIF1TX2MIX Input 1 Source */
-       [0x0709] = 0x0080,     /* R1801  - AIF1TX2MIX Input 1 Volume */
-       [0x070A] = 0x0000,     /* R1802  - AIF1TX2MIX Input 2 Source */
-       [0x070B] = 0x0080,     /* R1803  - AIF1TX2MIX Input 2 Volume */
-       [0x070C] = 0x0000,     /* R1804  - AIF1TX2MIX Input 3 Source */
-       [0x070D] = 0x0080,     /* R1805  - AIF1TX2MIX Input 3 Volume */
-       [0x070E] = 0x0000,     /* R1806  - AIF1TX2MIX Input 4 Source */
-       [0x070F] = 0x0080,     /* R1807  - AIF1TX2MIX Input 4 Volume */
-       [0x0710] = 0x0000,     /* R1808  - AIF1TX3MIX Input 1 Source */
-       [0x0711] = 0x0080,     /* R1809  - AIF1TX3MIX Input 1 Volume */
-       [0x0712] = 0x0000,     /* R1810  - AIF1TX3MIX Input 2 Source */
-       [0x0713] = 0x0080,     /* R1811  - AIF1TX3MIX Input 2 Volume */
-       [0x0714] = 0x0000,     /* R1812  - AIF1TX3MIX Input 3 Source */
-       [0x0715] = 0x0080,     /* R1813  - AIF1TX3MIX Input 3 Volume */
-       [0x0716] = 0x0000,     /* R1814  - AIF1TX3MIX Input 4 Source */
-       [0x0717] = 0x0080,     /* R1815  - AIF1TX3MIX Input 4 Volume */
-       [0x0718] = 0x0000,     /* R1816  - AIF1TX4MIX Input 1 Source */
-       [0x0719] = 0x0080,     /* R1817  - AIF1TX4MIX Input 1 Volume */
-       [0x071A] = 0x0000,     /* R1818  - AIF1TX4MIX Input 2 Source */
-       [0x071B] = 0x0080,     /* R1819  - AIF1TX4MIX Input 2 Volume */
-       [0x071C] = 0x0000,     /* R1820  - AIF1TX4MIX Input 3 Source */
-       [0x071D] = 0x0080,     /* R1821  - AIF1TX4MIX Input 3 Volume */
-       [0x071E] = 0x0000,     /* R1822  - AIF1TX4MIX Input 4 Source */
-       [0x071F] = 0x0080,     /* R1823  - AIF1TX4MIX Input 4 Volume */
-       [0x0720] = 0x0000,     /* R1824  - AIF1TX5MIX Input 1 Source */
-       [0x0721] = 0x0080,     /* R1825  - AIF1TX5MIX Input 1 Volume */
-       [0x0722] = 0x0000,     /* R1826  - AIF1TX5MIX Input 2 Source */
-       [0x0723] = 0x0080,     /* R1827  - AIF1TX5MIX Input 2 Volume */
-       [0x0724] = 0x0000,     /* R1828  - AIF1TX5MIX Input 3 Source */
-       [0x0725] = 0x0080,     /* R1829  - AIF1TX5MIX Input 3 Volume */
-       [0x0726] = 0x0000,     /* R1830  - AIF1TX5MIX Input 4 Source */
-       [0x0727] = 0x0080,     /* R1831  - AIF1TX5MIX Input 4 Volume */
-       [0x0728] = 0x0000,     /* R1832  - AIF1TX6MIX Input 1 Source */
-       [0x0729] = 0x0080,     /* R1833  - AIF1TX6MIX Input 1 Volume */
-       [0x072A] = 0x0000,     /* R1834  - AIF1TX6MIX Input 2 Source */
-       [0x072B] = 0x0080,     /* R1835  - AIF1TX6MIX Input 2 Volume */
-       [0x072C] = 0x0000,     /* R1836  - AIF1TX6MIX Input 3 Source */
-       [0x072D] = 0x0080,     /* R1837  - AIF1TX6MIX Input 3 Volume */
-       [0x072E] = 0x0000,     /* R1838  - AIF1TX6MIX Input 4 Source */
-       [0x072F] = 0x0080,     /* R1839  - AIF1TX6MIX Input 4 Volume */
-       [0x0730] = 0x0000,     /* R1840  - AIF1TX7MIX Input 1 Source */
-       [0x0731] = 0x0080,     /* R1841  - AIF1TX7MIX Input 1 Volume */
-       [0x0732] = 0x0000,     /* R1842  - AIF1TX7MIX Input 2 Source */
-       [0x0733] = 0x0080,     /* R1843  - AIF1TX7MIX Input 2 Volume */
-       [0x0734] = 0x0000,     /* R1844  - AIF1TX7MIX Input 3 Source */
-       [0x0735] = 0x0080,     /* R1845  - AIF1TX7MIX Input 3 Volume */
-       [0x0736] = 0x0000,     /* R1846  - AIF1TX7MIX Input 4 Source */
-       [0x0737] = 0x0080,     /* R1847  - AIF1TX7MIX Input 4 Volume */
-       [0x0738] = 0x0000,     /* R1848  - AIF1TX8MIX Input 1 Source */
-       [0x0739] = 0x0080,     /* R1849  - AIF1TX8MIX Input 1 Volume */
-       [0x073A] = 0x0000,     /* R1850  - AIF1TX8MIX Input 2 Source */
-       [0x073B] = 0x0080,     /* R1851  - AIF1TX8MIX Input 2 Volume */
-       [0x073C] = 0x0000,     /* R1852  - AIF1TX8MIX Input 3 Source */
-       [0x073D] = 0x0080,     /* R1853  - AIF1TX8MIX Input 3 Volume */
-       [0x073E] = 0x0000,     /* R1854  - AIF1TX8MIX Input 4 Source */
-       [0x073F] = 0x0080,     /* R1855  - AIF1TX8MIX Input 4 Volume */
-       [0x0740] = 0x0000,     /* R1856  - AIF2TX1MIX Input 1 Source */
-       [0x0741] = 0x0080,     /* R1857  - AIF2TX1MIX Input 1 Volume */
-       [0x0742] = 0x0000,     /* R1858  - AIF2TX1MIX Input 2 Source */
-       [0x0743] = 0x0080,     /* R1859  - AIF2TX1MIX Input 2 Volume */
-       [0x0744] = 0x0000,     /* R1860  - AIF2TX1MIX Input 3 Source */
-       [0x0745] = 0x0080,     /* R1861  - AIF2TX1MIX Input 3 Volume */
-       [0x0746] = 0x0000,     /* R1862  - AIF2TX1MIX Input 4 Source */
-       [0x0747] = 0x0080,     /* R1863  - AIF2TX1MIX Input 4 Volume */
-       [0x0748] = 0x0000,     /* R1864  - AIF2TX2MIX Input 1 Source */
-       [0x0749] = 0x0080,     /* R1865  - AIF2TX2MIX Input 1 Volume */
-       [0x074A] = 0x0000,     /* R1866  - AIF2TX2MIX Input 2 Source */
-       [0x074B] = 0x0080,     /* R1867  - AIF2TX2MIX Input 2 Volume */
-       [0x074C] = 0x0000,     /* R1868  - AIF2TX2MIX Input 3 Source */
-       [0x074D] = 0x0080,     /* R1869  - AIF2TX2MIX Input 3 Volume */
-       [0x074E] = 0x0000,     /* R1870  - AIF2TX2MIX Input 4 Source */
-       [0x074F] = 0x0080,     /* R1871  - AIF2TX2MIX Input 4 Volume */
-       [0x0780] = 0x0000,     /* R1920  - AIF3TX1MIX Input 1 Source */
-       [0x0781] = 0x0080,     /* R1921  - AIF3TX1MIX Input 1 Volume */
-       [0x0782] = 0x0000,     /* R1922  - AIF3TX1MIX Input 2 Source */
-       [0x0783] = 0x0080,     /* R1923  - AIF3TX1MIX Input 2 Volume */
-       [0x0784] = 0x0000,     /* R1924  - AIF3TX1MIX Input 3 Source */
-       [0x0785] = 0x0080,     /* R1925  - AIF3TX1MIX Input 3 Volume */
-       [0x0786] = 0x0000,     /* R1926  - AIF3TX1MIX Input 4 Source */
-       [0x0787] = 0x0080,     /* R1927  - AIF3TX1MIX Input 4 Volume */
-       [0x0788] = 0x0000,     /* R1928  - AIF3TX2MIX Input 1 Source */
-       [0x0789] = 0x0080,     /* R1929  - AIF3TX2MIX Input 1 Volume */
-       [0x078A] = 0x0000,     /* R1930  - AIF3TX2MIX Input 2 Source */
-       [0x078B] = 0x0080,     /* R1931  - AIF3TX2MIX Input 2 Volume */
-       [0x078C] = 0x0000,     /* R1932  - AIF3TX2MIX Input 3 Source */
-       [0x078D] = 0x0080,     /* R1933  - AIF3TX2MIX Input 3 Volume */
-       [0x078E] = 0x0000,     /* R1934  - AIF3TX2MIX Input 4 Source */
-       [0x078F] = 0x0080,     /* R1935  - AIF3TX2MIX Input 4 Volume */
-       [0x0880] = 0x0000,     /* R2176  - EQ1MIX Input 1 Source */
-       [0x0881] = 0x0080,     /* R2177  - EQ1MIX Input 1 Volume */
-       [0x0882] = 0x0000,     /* R2178  - EQ1MIX Input 2 Source */
-       [0x0883] = 0x0080,     /* R2179  - EQ1MIX Input 2 Volume */
-       [0x0884] = 0x0000,     /* R2180  - EQ1MIX Input 3 Source */
-       [0x0885] = 0x0080,     /* R2181  - EQ1MIX Input 3 Volume */
-       [0x0886] = 0x0000,     /* R2182  - EQ1MIX Input 4 Source */
-       [0x0887] = 0x0080,     /* R2183  - EQ1MIX Input 4 Volume */
-       [0x0888] = 0x0000,     /* R2184  - EQ2MIX Input 1 Source */
-       [0x0889] = 0x0080,     /* R2185  - EQ2MIX Input 1 Volume */
-       [0x088A] = 0x0000,     /* R2186  - EQ2MIX Input 2 Source */
-       [0x088B] = 0x0080,     /* R2187  - EQ2MIX Input 2 Volume */
-       [0x088C] = 0x0000,     /* R2188  - EQ2MIX Input 3 Source */
-       [0x088D] = 0x0080,     /* R2189  - EQ2MIX Input 3 Volume */
-       [0x088E] = 0x0000,     /* R2190  - EQ2MIX Input 4 Source */
-       [0x088F] = 0x0080,     /* R2191  - EQ2MIX Input 4 Volume */
-       [0x0890] = 0x0000,     /* R2192  - EQ3MIX Input 1 Source */
-       [0x0891] = 0x0080,     /* R2193  - EQ3MIX Input 1 Volume */
-       [0x0892] = 0x0000,     /* R2194  - EQ3MIX Input 2 Source */
-       [0x0893] = 0x0080,     /* R2195  - EQ3MIX Input 2 Volume */
-       [0x0894] = 0x0000,     /* R2196  - EQ3MIX Input 3 Source */
-       [0x0895] = 0x0080,     /* R2197  - EQ3MIX Input 3 Volume */
-       [0x0896] = 0x0000,     /* R2198  - EQ3MIX Input 4 Source */
-       [0x0897] = 0x0080,     /* R2199  - EQ3MIX Input 4 Volume */
-       [0x0898] = 0x0000,     /* R2200  - EQ4MIX Input 1 Source */
-       [0x0899] = 0x0080,     /* R2201  - EQ4MIX Input 1 Volume */
-       [0x089A] = 0x0000,     /* R2202  - EQ4MIX Input 2 Source */
-       [0x089B] = 0x0080,     /* R2203  - EQ4MIX Input 2 Volume */
-       [0x089C] = 0x0000,     /* R2204  - EQ4MIX Input 3 Source */
-       [0x089D] = 0x0080,     /* R2205  - EQ4MIX Input 3 Volume */
-       [0x089E] = 0x0000,     /* R2206  - EQ4MIX Input 4 Source */
-       [0x089F] = 0x0080,     /* R2207  - EQ4MIX Input 4 Volume */
-       [0x08C0] = 0x0000,     /* R2240  - DRC1LMIX Input 1 Source */
-       [0x08C1] = 0x0080,     /* R2241  - DRC1LMIX Input 1 Volume */
-       [0x08C2] = 0x0000,     /* R2242  - DRC1LMIX Input 2 Source */
-       [0x08C3] = 0x0080,     /* R2243  - DRC1LMIX Input 2 Volume */
-       [0x08C4] = 0x0000,     /* R2244  - DRC1LMIX Input 3 Source */
-       [0x08C5] = 0x0080,     /* R2245  - DRC1LMIX Input 3 Volume */
-       [0x08C6] = 0x0000,     /* R2246  - DRC1LMIX Input 4 Source */
-       [0x08C7] = 0x0080,     /* R2247  - DRC1LMIX Input 4 Volume */
-       [0x08C8] = 0x0000,     /* R2248  - DRC1RMIX Input 1 Source */
-       [0x08C9] = 0x0080,     /* R2249  - DRC1RMIX Input 1 Volume */
-       [0x08CA] = 0x0000,     /* R2250  - DRC1RMIX Input 2 Source */
-       [0x08CB] = 0x0080,     /* R2251  - DRC1RMIX Input 2 Volume */
-       [0x08CC] = 0x0000,     /* R2252  - DRC1RMIX Input 3 Source */
-       [0x08CD] = 0x0080,     /* R2253  - DRC1RMIX Input 3 Volume */
-       [0x08CE] = 0x0000,     /* R2254  - DRC1RMIX Input 4 Source */
-       [0x08CF] = 0x0080,     /* R2255  - DRC1RMIX Input 4 Volume */
-       [0x0900] = 0x0000,     /* R2304  - HPLP1MIX Input 1 Source */
-       [0x0901] = 0x0080,     /* R2305  - HPLP1MIX Input 1 Volume */
-       [0x0902] = 0x0000,     /* R2306  - HPLP1MIX Input 2 Source */
-       [0x0903] = 0x0080,     /* R2307  - HPLP1MIX Input 2 Volume */
-       [0x0904] = 0x0000,     /* R2308  - HPLP1MIX Input 3 Source */
-       [0x0905] = 0x0080,     /* R2309  - HPLP1MIX Input 3 Volume */
-       [0x0906] = 0x0000,     /* R2310  - HPLP1MIX Input 4 Source */
-       [0x0907] = 0x0080,     /* R2311  - HPLP1MIX Input 4 Volume */
-       [0x0908] = 0x0000,     /* R2312  - HPLP2MIX Input 1 Source */
-       [0x0909] = 0x0080,     /* R2313  - HPLP2MIX Input 1 Volume */
-       [0x090A] = 0x0000,     /* R2314  - HPLP2MIX Input 2 Source */
-       [0x090B] = 0x0080,     /* R2315  - HPLP2MIX Input 2 Volume */
-       [0x090C] = 0x0000,     /* R2316  - HPLP2MIX Input 3 Source */
-       [0x090D] = 0x0080,     /* R2317  - HPLP2MIX Input 3 Volume */
-       [0x090E] = 0x0000,     /* R2318  - HPLP2MIX Input 4 Source */
-       [0x090F] = 0x0080,     /* R2319  - HPLP2MIX Input 4 Volume */
-       [0x0910] = 0x0000,     /* R2320  - HPLP3MIX Input 1 Source */
-       [0x0911] = 0x0080,     /* R2321  - HPLP3MIX Input 1 Volume */
-       [0x0912] = 0x0000,     /* R2322  - HPLP3MIX Input 2 Source */
-       [0x0913] = 0x0080,     /* R2323  - HPLP3MIX Input 2 Volume */
-       [0x0914] = 0x0000,     /* R2324  - HPLP3MIX Input 3 Source */
-       [0x0915] = 0x0080,     /* R2325  - HPLP3MIX Input 3 Volume */
-       [0x0916] = 0x0000,     /* R2326  - HPLP3MIX Input 4 Source */
-       [0x0917] = 0x0080,     /* R2327  - HPLP3MIX Input 4 Volume */
-       [0x0918] = 0x0000,     /* R2328  - HPLP4MIX Input 1 Source */
-       [0x0919] = 0x0080,     /* R2329  - HPLP4MIX Input 1 Volume */
-       [0x091A] = 0x0000,     /* R2330  - HPLP4MIX Input 2 Source */
-       [0x091B] = 0x0080,     /* R2331  - HPLP4MIX Input 2 Volume */
-       [0x091C] = 0x0000,     /* R2332  - HPLP4MIX Input 3 Source */
-       [0x091D] = 0x0080,     /* R2333  - HPLP4MIX Input 3 Volume */
-       [0x091E] = 0x0000,     /* R2334  - HPLP4MIX Input 4 Source */
-       [0x091F] = 0x0080,     /* R2335  - HPLP4MIX Input 4 Volume */
-       [0x0940] = 0x0000,     /* R2368  - DSP1LMIX Input 1 Source */
-       [0x0941] = 0x0080,     /* R2369  - DSP1LMIX Input 1 Volume */
-       [0x0942] = 0x0000,     /* R2370  - DSP1LMIX Input 2 Source */
-       [0x0943] = 0x0080,     /* R2371  - DSP1LMIX Input 2 Volume */
-       [0x0944] = 0x0000,     /* R2372  - DSP1LMIX Input 3 Source */
-       [0x0945] = 0x0080,     /* R2373  - DSP1LMIX Input 3 Volume */
-       [0x0946] = 0x0000,     /* R2374  - DSP1LMIX Input 4 Source */
-       [0x0947] = 0x0080,     /* R2375  - DSP1LMIX Input 4 Volume */
-       [0x0948] = 0x0000,     /* R2376  - DSP1RMIX Input 1 Source */
-       [0x0949] = 0x0080,     /* R2377  - DSP1RMIX Input 1 Volume */
-       [0x094A] = 0x0000,     /* R2378  - DSP1RMIX Input 2 Source */
-       [0x094B] = 0x0080,     /* R2379  - DSP1RMIX Input 2 Volume */
-       [0x094C] = 0x0000,     /* R2380  - DSP1RMIX Input 3 Source */
-       [0x094D] = 0x0080,     /* R2381  - DSP1RMIX Input 3 Volume */
-       [0x094E] = 0x0000,     /* R2382  - DSP1RMIX Input 4 Source */
-       [0x094F] = 0x0080,     /* R2383  - DSP1RMIX Input 4 Volume */
-       [0x0950] = 0x0000,     /* R2384  - DSP1AUX1MIX Input 1 Source */
-       [0x0958] = 0x0000,     /* R2392  - DSP1AUX2MIX Input 1 Source */
-       [0x0960] = 0x0000,     /* R2400  - DSP1AUX3MIX Input 1 Source */
-       [0x0968] = 0x0000,     /* R2408  - DSP1AUX4MIX Input 1 Source */
-       [0x0970] = 0x0000,     /* R2416  - DSP1AUX5MIX Input 1 Source */
-       [0x0978] = 0x0000,     /* R2424  - DSP1AUX6MIX Input 1 Source */
-       [0x0980] = 0x0000,     /* R2432  - DSP2LMIX Input 1 Source */
-       [0x0981] = 0x0080,     /* R2433  - DSP2LMIX Input 1 Volume */
-       [0x0982] = 0x0000,     /* R2434  - DSP2LMIX Input 2 Source */
-       [0x0983] = 0x0080,     /* R2435  - DSP2LMIX Input 2 Volume */
-       [0x0984] = 0x0000,     /* R2436  - DSP2LMIX Input 3 Source */
-       [0x0985] = 0x0080,     /* R2437  - DSP2LMIX Input 3 Volume */
-       [0x0986] = 0x0000,     /* R2438  - DSP2LMIX Input 4 Source */
-       [0x0987] = 0x0080,     /* R2439  - DSP2LMIX Input 4 Volume */
-       [0x0988] = 0x0000,     /* R2440  - DSP2RMIX Input 1 Source */
-       [0x0989] = 0x0080,     /* R2441  - DSP2RMIX Input 1 Volume */
-       [0x098A] = 0x0000,     /* R2442  - DSP2RMIX Input 2 Source */
-       [0x098B] = 0x0080,     /* R2443  - DSP2RMIX Input 2 Volume */
-       [0x098C] = 0x0000,     /* R2444  - DSP2RMIX Input 3 Source */
-       [0x098D] = 0x0080,     /* R2445  - DSP2RMIX Input 3 Volume */
-       [0x098E] = 0x0000,     /* R2446  - DSP2RMIX Input 4 Source */
-       [0x098F] = 0x0080,     /* R2447  - DSP2RMIX Input 4 Volume */
-       [0x0990] = 0x0000,     /* R2448  - DSP2AUX1MIX Input 1 Source */
-       [0x0998] = 0x0000,     /* R2456  - DSP2AUX2MIX Input 1 Source */
-       [0x09A0] = 0x0000,     /* R2464  - DSP2AUX3MIX Input 1 Source */
-       [0x09A8] = 0x0000,     /* R2472  - DSP2AUX4MIX Input 1 Source */
-       [0x09B0] = 0x0000,     /* R2480  - DSP2AUX5MIX Input 1 Source */
-       [0x09B8] = 0x0000,     /* R2488  - DSP2AUX6MIX Input 1 Source */
-       [0x09C0] = 0x0000,     /* R2496  - DSP3LMIX Input 1 Source */
-       [0x09C1] = 0x0080,     /* R2497  - DSP3LMIX Input 1 Volume */
-       [0x09C2] = 0x0000,     /* R2498  - DSP3LMIX Input 2 Source */
-       [0x09C3] = 0x0080,     /* R2499  - DSP3LMIX Input 2 Volume */
-       [0x09C4] = 0x0000,     /* R2500  - DSP3LMIX Input 3 Source */
-       [0x09C5] = 0x0080,     /* R2501  - DSP3LMIX Input 3 Volume */
-       [0x09C6] = 0x0000,     /* R2502  - DSP3LMIX Input 4 Source */
-       [0x09C7] = 0x0080,     /* R2503  - DSP3LMIX Input 4 Volume */
-       [0x09C8] = 0x0000,     /* R2504  - DSP3RMIX Input 1 Source */
-       [0x09C9] = 0x0080,     /* R2505  - DSP3RMIX Input 1 Volume */
-       [0x09CA] = 0x0000,     /* R2506  - DSP3RMIX Input 2 Source */
-       [0x09CB] = 0x0080,     /* R2507  - DSP3RMIX Input 2 Volume */
-       [0x09CC] = 0x0000,     /* R2508  - DSP3RMIX Input 3 Source */
-       [0x09CD] = 0x0080,     /* R2509  - DSP3RMIX Input 3 Volume */
-       [0x09CE] = 0x0000,     /* R2510  - DSP3RMIX Input 4 Source */
-       [0x09CF] = 0x0080,     /* R2511  - DSP3RMIX Input 4 Volume */
-       [0x09D0] = 0x0000,     /* R2512  - DSP3AUX1MIX Input 1 Source */
-       [0x09D8] = 0x0000,     /* R2520  - DSP3AUX2MIX Input 1 Source */
-       [0x09E0] = 0x0000,     /* R2528  - DSP3AUX3MIX Input 1 Source */
-       [0x09E8] = 0x0000,     /* R2536  - DSP3AUX4MIX Input 1 Source */
-       [0x09F0] = 0x0000,     /* R2544  - DSP3AUX5MIX Input 1 Source */
-       [0x09F8] = 0x0000,     /* R2552  - DSP3AUX6MIX Input 1 Source */
-       [0x0A80] = 0x0000,     /* R2688  - ASRC1LMIX Input 1 Source */
-       [0x0A88] = 0x0000,     /* R2696  - ASRC1RMIX Input 1 Source */
-       [0x0A90] = 0x0000,     /* R2704  - ASRC2LMIX Input 1 Source */
-       [0x0A98] = 0x0000,     /* R2712  - ASRC2RMIX Input 1 Source */
-       [0x0B00] = 0x0000,     /* R2816  - ISRC1DEC1MIX Input 1 Source */
-       [0x0B08] = 0x0000,     /* R2824  - ISRC1DEC2MIX Input 1 Source */
-       [0x0B10] = 0x0000,     /* R2832  - ISRC1DEC3MIX Input 1 Source */
-       [0x0B18] = 0x0000,     /* R2840  - ISRC1DEC4MIX Input 1 Source */
-       [0x0B20] = 0x0000,     /* R2848  - ISRC1INT1MIX Input 1 Source */
-       [0x0B28] = 0x0000,     /* R2856  - ISRC1INT2MIX Input 1 Source */
-       [0x0B30] = 0x0000,     /* R2864  - ISRC1INT3MIX Input 1 Source */
-       [0x0B38] = 0x0000,     /* R2872  - ISRC1INT4MIX Input 1 Source */
-       [0x0B40] = 0x0000,     /* R2880  - ISRC2DEC1MIX Input 1 Source */
-       [0x0B48] = 0x0000,     /* R2888  - ISRC2DEC2MIX Input 1 Source */
-       [0x0B50] = 0x0000,     /* R2896  - ISRC2DEC3MIX Input 1 Source */
-       [0x0B58] = 0x0000,     /* R2904  - ISRC2DEC4MIX Input 1 Source */
-       [0x0B60] = 0x0000,     /* R2912  - ISRC2INT1MIX Input 1 Source */
-       [0x0B68] = 0x0000,     /* R2920  - ISRC2INT2MIX Input 1 Source */
-       [0x0B70] = 0x0000,     /* R2928  - ISRC2INT3MIX Input 1 Source */
-       [0x0B78] = 0x0000,     /* R2936  - ISRC2INT4MIX Input 1 Source */
-       [0x0C00] = 0xA001,     /* R3072  - GPIO CTRL 1 */
-       [0x0C01] = 0xA001,     /* R3073  - GPIO CTRL 2 */
-       [0x0C02] = 0xA001,     /* R3074  - GPIO CTRL 3 */
-       [0x0C03] = 0xA001,     /* R3075  - GPIO CTRL 4 */
-       [0x0C04] = 0xA001,     /* R3076  - GPIO CTRL 5 */
-       [0x0C05] = 0xA001,     /* R3077  - GPIO CTRL 6 */
-       [0x0C23] = 0x4003,     /* R3107  - Misc Pad Ctrl 1 */
-       [0x0C24] = 0x0000,     /* R3108  - Misc Pad Ctrl 2 */
-       [0x0C25] = 0x0000,     /* R3109  - Misc Pad Ctrl 3 */
-       [0x0C26] = 0x0000,     /* R3110  - Misc Pad Ctrl 4 */
-       [0x0C27] = 0x0000,     /* R3111  - Misc Pad Ctrl 5 */
-       [0x0C28] = 0x0000,     /* R3112  - Misc GPIO 1 */
-       [0x0D00] = 0x0000,     /* R3328  - Interrupt Status 1 */
-       [0x0D01] = 0x0000,     /* R3329  - Interrupt Status 2 */
-       [0x0D02] = 0x0000,     /* R3330  - Interrupt Status 3 */
-       [0x0D03] = 0x0000,     /* R3331  - Interrupt Status 4 */
-       [0x0D04] = 0x0000,     /* R3332  - Interrupt Raw Status 2 */
-       [0x0D05] = 0x0000,     /* R3333  - Interrupt Raw Status 3 */
-       [0x0D06] = 0x0000,     /* R3334  - Interrupt Raw Status 4 */
-       [0x0D07] = 0xFFFF,     /* R3335  - Interrupt Status 1 Mask */
-       [0x0D08] = 0xFFFF,     /* R3336  - Interrupt Status 2 Mask */
-       [0x0D09] = 0xFFFF,     /* R3337  - Interrupt Status 3 Mask */
-       [0x0D0A] = 0xFFFF,     /* R3338  - Interrupt Status 4 Mask */
-       [0x0D1F] = 0x0000,     /* R3359  - Interrupt Control */
-       [0x0D20] = 0xFFFF,     /* R3360  - IRQ Debounce 1 */
-       [0x0D21] = 0xFFFF,     /* R3361  - IRQ Debounce 2 */
-       [0x0E00] = 0x0000,     /* R3584  - FX_Ctrl */
-       [0x0E10] = 0x6318,     /* R3600  - EQ1_1 */
-       [0x0E11] = 0x6300,     /* R3601  - EQ1_2 */
-       [0x0E12] = 0x0FC8,     /* R3602  - EQ1_3 */
-       [0x0E13] = 0x03FE,     /* R3603  - EQ1_4 */
-       [0x0E14] = 0x00E0,     /* R3604  - EQ1_5 */
-       [0x0E15] = 0x1EC4,     /* R3605  - EQ1_6 */
-       [0x0E16] = 0xF136,     /* R3606  - EQ1_7 */
-       [0x0E17] = 0x0409,     /* R3607  - EQ1_8 */
-       [0x0E18] = 0x04CC,     /* R3608  - EQ1_9 */
-       [0x0E19] = 0x1C9B,     /* R3609  - EQ1_10 */
-       [0x0E1A] = 0xF337,     /* R3610  - EQ1_11 */
-       [0x0E1B] = 0x040B,     /* R3611  - EQ1_12 */
-       [0x0E1C] = 0x0CBB,     /* R3612  - EQ1_13 */
-       [0x0E1D] = 0x16F8,     /* R3613  - EQ1_14 */
-       [0x0E1E] = 0xF7D9,     /* R3614  - EQ1_15 */
-       [0x0E1F] = 0x040A,     /* R3615  - EQ1_16 */
-       [0x0E20] = 0x1F14,     /* R3616  - EQ1_17 */
-       [0x0E21] = 0x058C,     /* R3617  - EQ1_18 */
-       [0x0E22] = 0x0563,     /* R3618  - EQ1_19 */
-       [0x0E23] = 0x4000,     /* R3619  - EQ1_20 */
-       [0x0E26] = 0x6318,     /* R3622  - EQ2_1 */
-       [0x0E27] = 0x6300,     /* R3623  - EQ2_2 */
-       [0x0E28] = 0x0FC8,     /* R3624  - EQ2_3 */
-       [0x0E29] = 0x03FE,     /* R3625  - EQ2_4 */
-       [0x0E2A] = 0x00E0,     /* R3626  - EQ2_5 */
-       [0x0E2B] = 0x1EC4,     /* R3627  - EQ2_6 */
-       [0x0E2C] = 0xF136,     /* R3628  - EQ2_7 */
-       [0x0E2D] = 0x0409,     /* R3629  - EQ2_8 */
-       [0x0E2E] = 0x04CC,     /* R3630  - EQ2_9 */
-       [0x0E2F] = 0x1C9B,     /* R3631  - EQ2_10 */
-       [0x0E30] = 0xF337,     /* R3632  - EQ2_11 */
-       [0x0E31] = 0x040B,     /* R3633  - EQ2_12 */
-       [0x0E32] = 0x0CBB,     /* R3634  - EQ2_13 */
-       [0x0E33] = 0x16F8,     /* R3635  - EQ2_14 */
-       [0x0E34] = 0xF7D9,     /* R3636  - EQ2_15 */
-       [0x0E35] = 0x040A,     /* R3637  - EQ2_16 */
-       [0x0E36] = 0x1F14,     /* R3638  - EQ2_17 */
-       [0x0E37] = 0x058C,     /* R3639  - EQ2_18 */
-       [0x0E38] = 0x0563,     /* R3640  - EQ2_19 */
-       [0x0E39] = 0x4000,     /* R3641  - EQ2_20 */
-       [0x0E3C] = 0x6318,     /* R3644  - EQ3_1 */
-       [0x0E3D] = 0x6300,     /* R3645  - EQ3_2 */
-       [0x0E3E] = 0x0FC8,     /* R3646  - EQ3_3 */
-       [0x0E3F] = 0x03FE,     /* R3647  - EQ3_4 */
-       [0x0E40] = 0x00E0,     /* R3648  - EQ3_5 */
-       [0x0E41] = 0x1EC4,     /* R3649  - EQ3_6 */
-       [0x0E42] = 0xF136,     /* R3650  - EQ3_7 */
-       [0x0E43] = 0x0409,     /* R3651  - EQ3_8 */
-       [0x0E44] = 0x04CC,     /* R3652  - EQ3_9 */
-       [0x0E45] = 0x1C9B,     /* R3653  - EQ3_10 */
-       [0x0E46] = 0xF337,     /* R3654  - EQ3_11 */
-       [0x0E47] = 0x040B,     /* R3655  - EQ3_12 */
-       [0x0E48] = 0x0CBB,     /* R3656  - EQ3_13 */
-       [0x0E49] = 0x16F8,     /* R3657  - EQ3_14 */
-       [0x0E4A] = 0xF7D9,     /* R3658  - EQ3_15 */
-       [0x0E4B] = 0x040A,     /* R3659  - EQ3_16 */
-       [0x0E4C] = 0x1F14,     /* R3660  - EQ3_17 */
-       [0x0E4D] = 0x058C,     /* R3661  - EQ3_18 */
-       [0x0E4E] = 0x0563,     /* R3662  - EQ3_19 */
-       [0x0E4F] = 0x4000,     /* R3663  - EQ3_20 */
-       [0x0E52] = 0x6318,     /* R3666  - EQ4_1 */
-       [0x0E53] = 0x6300,     /* R3667  - EQ4_2 */
-       [0x0E54] = 0x0FC8,     /* R3668  - EQ4_3 */
-       [0x0E55] = 0x03FE,     /* R3669  - EQ4_4 */
-       [0x0E56] = 0x00E0,     /* R3670  - EQ4_5 */
-       [0x0E57] = 0x1EC4,     /* R3671  - EQ4_6 */
-       [0x0E58] = 0xF136,     /* R3672  - EQ4_7 */
-       [0x0E59] = 0x0409,     /* R3673  - EQ4_8 */
-       [0x0E5A] = 0x04CC,     /* R3674  - EQ4_9 */
-       [0x0E5B] = 0x1C9B,     /* R3675  - EQ4_10 */
-       [0x0E5C] = 0xF337,     /* R3676  - EQ4_11 */
-       [0x0E5D] = 0x040B,     /* R3677  - EQ4_12 */
-       [0x0E5E] = 0x0CBB,     /* R3678  - EQ4_13 */
-       [0x0E5F] = 0x16F8,     /* R3679  - EQ4_14 */
-       [0x0E60] = 0xF7D9,     /* R3680  - EQ4_15 */
-       [0x0E61] = 0x040A,     /* R3681  - EQ4_16 */
-       [0x0E62] = 0x1F14,     /* R3682  - EQ4_17 */
-       [0x0E63] = 0x058C,     /* R3683  - EQ4_18 */
-       [0x0E64] = 0x0563,     /* R3684  - EQ4_19 */
-       [0x0E65] = 0x4000,     /* R3685  - EQ4_20 */
-       [0x0E80] = 0x0018,     /* R3712  - DRC1 ctrl1 */
-       [0x0E81] = 0x0933,     /* R3713  - DRC1 ctrl2 */
-       [0x0E82] = 0x0018,     /* R3714  - DRC1 ctrl3 */
-       [0x0E83] = 0x0000,     /* R3715  - DRC1 ctrl4 */
-       [0x0E84] = 0x0000,     /* R3716  - DRC1 ctrl5 */
-       [0x0EC0] = 0x0000,     /* R3776  - HPLPF1_1 */
-       [0x0EC1] = 0x0000,     /* R3777  - HPLPF1_2 */
-       [0x0EC4] = 0x0000,     /* R3780  - HPLPF2_1 */
-       [0x0EC5] = 0x0000,     /* R3781  - HPLPF2_2 */
-       [0x0EC8] = 0x0000,     /* R3784  - HPLPF3_1 */
-       [0x0EC9] = 0x0000,     /* R3785  - HPLPF3_2 */
-       [0x0ECC] = 0x0000,     /* R3788  - HPLPF4_1 */
-       [0x0ECD] = 0x0000,     /* R3789  - HPLPF4_2 */
-       [0x4000] = 0x0000,     /* R16384 - DSP1 DM 0 */
-       [0x4001] = 0x0000,     /* R16385 - DSP1 DM 1 */
-       [0x4002] = 0x0000,     /* R16386 - DSP1 DM 2 */
-       [0x4003] = 0x0000,     /* R16387 - DSP1 DM 3 */
-       [0x41FC] = 0x0000,     /* R16892 - DSP1 DM 508 */
-       [0x41FD] = 0x0000,     /* R16893 - DSP1 DM 509 */
-       [0x41FE] = 0x0000,     /* R16894 - DSP1 DM 510 */
-       [0x41FF] = 0x0000,     /* R16895 - DSP1 DM 511 */
-       [0x4800] = 0x0000,     /* R18432 - DSP1 PM 0 */
-       [0x4801] = 0x0000,     /* R18433 - DSP1 PM 1 */
-       [0x4802] = 0x0000,     /* R18434 - DSP1 PM 2 */
-       [0x4803] = 0x0000,     /* R18435 - DSP1 PM 3 */
-       [0x4804] = 0x0000,     /* R18436 - DSP1 PM 4 */
-       [0x4805] = 0x0000,     /* R18437 - DSP1 PM 5 */
-       [0x4DFA] = 0x0000,     /* R19962 - DSP1 PM 1530 */
-       [0x4DFB] = 0x0000,     /* R19963 - DSP1 PM 1531 */
-       [0x4DFC] = 0x0000,     /* R19964 - DSP1 PM 1532 */
-       [0x4DFD] = 0x0000,     /* R19965 - DSP1 PM 1533 */
-       [0x4DFE] = 0x0000,     /* R19966 - DSP1 PM 1534 */
-       [0x4DFF] = 0x0000,     /* R19967 - DSP1 PM 1535 */
-       [0x5000] = 0x0000,     /* R20480 - DSP1 ZM 0 */
-       [0x5001] = 0x0000,     /* R20481 - DSP1 ZM 1 */
-       [0x5002] = 0x0000,     /* R20482 - DSP1 ZM 2 */
-       [0x5003] = 0x0000,     /* R20483 - DSP1 ZM 3 */
-       [0x57FC] = 0x0000,     /* R22524 - DSP1 ZM 2044 */
-       [0x57FD] = 0x0000,     /* R22525 - DSP1 ZM 2045 */
-       [0x57FE] = 0x0000,     /* R22526 - DSP1 ZM 2046 */
-       [0x57FF] = 0x0000,     /* R22527 - DSP1 ZM 2047 */
-       [0x6000] = 0x0000,     /* R24576 - DSP2 DM 0 */
-       [0x6001] = 0x0000,     /* R24577 - DSP2 DM 1 */
-       [0x6002] = 0x0000,     /* R24578 - DSP2 DM 2 */
-       [0x6003] = 0x0000,     /* R24579 - DSP2 DM 3 */
-       [0x61FC] = 0x0000,     /* R25084 - DSP2 DM 508 */
-       [0x61FD] = 0x0000,     /* R25085 - DSP2 DM 509 */
-       [0x61FE] = 0x0000,     /* R25086 - DSP2 DM 510 */
-       [0x61FF] = 0x0000,     /* R25087 - DSP2 DM 511 */
-       [0x6800] = 0x0000,     /* R26624 - DSP2 PM 0 */
-       [0x6801] = 0x0000,     /* R26625 - DSP2 PM 1 */
-       [0x6802] = 0x0000,     /* R26626 - DSP2 PM 2 */
-       [0x6803] = 0x0000,     /* R26627 - DSP2 PM 3 */
-       [0x6804] = 0x0000,     /* R26628 - DSP2 PM 4 */
-       [0x6805] = 0x0000,     /* R26629 - DSP2 PM 5 */
-       [0x6DFA] = 0x0000,     /* R28154 - DSP2 PM 1530 */
-       [0x6DFB] = 0x0000,     /* R28155 - DSP2 PM 1531 */
-       [0x6DFC] = 0x0000,     /* R28156 - DSP2 PM 1532 */
-       [0x6DFD] = 0x0000,     /* R28157 - DSP2 PM 1533 */
-       [0x6DFE] = 0x0000,     /* R28158 - DSP2 PM 1534 */
-       [0x6DFF] = 0x0000,     /* R28159 - DSP2 PM 1535 */
-       [0x7000] = 0x0000,     /* R28672 - DSP2 ZM 0 */
-       [0x7001] = 0x0000,     /* R28673 - DSP2 ZM 1 */
-       [0x7002] = 0x0000,     /* R28674 - DSP2 ZM 2 */
-       [0x7003] = 0x0000,     /* R28675 - DSP2 ZM 3 */
-       [0x77FC] = 0x0000,     /* R30716 - DSP2 ZM 2044 */
-       [0x77FD] = 0x0000,     /* R30717 - DSP2 ZM 2045 */
-       [0x77FE] = 0x0000,     /* R30718 - DSP2 ZM 2046 */
-       [0x77FF] = 0x0000,     /* R30719 - DSP2 ZM 2047 */
-       [0x8000] = 0x0000,     /* R32768 - DSP3 DM 0 */
-       [0x8001] = 0x0000,     /* R32769 - DSP3 DM 1 */
-       [0x8002] = 0x0000,     /* R32770 - DSP3 DM 2 */
-       [0x8003] = 0x0000,     /* R32771 - DSP3 DM 3 */
-       [0x81FC] = 0x0000,     /* R33276 - DSP3 DM 508 */
-       [0x81FD] = 0x0000,     /* R33277 - DSP3 DM 509 */
-       [0x81FE] = 0x0000,     /* R33278 - DSP3 DM 510 */
-       [0x81FF] = 0x0000,     /* R33279 - DSP3 DM 511 */
-       [0x8800] = 0x0000,     /* R34816 - DSP3 PM 0 */
-       [0x8801] = 0x0000,     /* R34817 - DSP3 PM 1 */
-       [0x8802] = 0x0000,     /* R34818 - DSP3 PM 2 */
-       [0x8803] = 0x0000,     /* R34819 - DSP3 PM 3 */
-       [0x8804] = 0x0000,     /* R34820 - DSP3 PM 4 */
-       [0x8805] = 0x0000,     /* R34821 - DSP3 PM 5 */
-       [0x8DFA] = 0x0000,     /* R36346 - DSP3 PM 1530 */
-       [0x8DFB] = 0x0000,     /* R36347 - DSP3 PM 1531 */
-       [0x8DFC] = 0x0000,     /* R36348 - DSP3 PM 1532 */
-       [0x8DFD] = 0x0000,     /* R36349 - DSP3 PM 1533 */
-       [0x8DFE] = 0x0000,     /* R36350 - DSP3 PM 1534 */
-       [0x8DFF] = 0x0000,     /* R36351 - DSP3 PM 1535 */
-       [0x9000] = 0x0000,     /* R36864 - DSP3 ZM 0 */
-       [0x9001] = 0x0000,     /* R36865 - DSP3 ZM 1 */
-       [0x9002] = 0x0000,     /* R36866 - DSP3 ZM 2 */
-       [0x9003] = 0x0000,     /* R36867 - DSP3 ZM 3 */
-       [0x97FC] = 0x0000,     /* R38908 - DSP3 ZM 2044 */
-       [0x97FD] = 0x0000,     /* R38909 - DSP3 ZM 2045 */
-       [0x97FE] = 0x0000,     /* R38910 - DSP3 ZM 2046 */
-       [0x97FF] = 0x0000      /* R38911 - DSP3 ZM 2047 */
+struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT] = {
+       { 0x0000, 0x0000 },  /* R0     - software reset */
+       { 0x0001, 0x0000 },  /* R1     - Device Revision */
+       { 0x0010, 0x0801 },  /* R16    - Ctrl IF 1 */
+       { 0x0020, 0x0000 },  /* R32    - Tone Generator 1 */
+       { 0x0030, 0x0000 },  /* R48    - PWM Drive 1 */
+       { 0x0031, 0x0100 },  /* R49    - PWM Drive 2 */
+       { 0x0032, 0x0100 },  /* R50    - PWM Drive 3 */
+       { 0x0100, 0x0002 },  /* R256   - Clocking 1 */
+       { 0x0101, 0x0000 },  /* R257   - Clocking 3 */
+       { 0x0102, 0x0011 },  /* R258   - Clocking 4 */
+       { 0x0103, 0x0011 },  /* R259   - Clocking 5 */
+       { 0x0104, 0x0011 },  /* R260   - Clocking 6 */
+       { 0x0107, 0x0000 },  /* R263   - Clocking 7 */
+       { 0x0108, 0x0000 },  /* R264   - Clocking 8 */
+       { 0x0120, 0x0000 },  /* R288   - ASRC_ENABLE */
+       { 0x0121, 0x0000 },  /* R289   - ASRC_STATUS */
+       { 0x0122, 0x0000 },  /* R290   - ASRC_RATE1 */
+       { 0x0141, 0x8000 },  /* R321   - ISRC 1 CTRL 1 */
+       { 0x0142, 0x0000 },  /* R322   - ISRC 1 CTRL 2 */
+       { 0x0143, 0x8000 },  /* R323   - ISRC 2 CTRL1 */
+       { 0x0144, 0x0000 },  /* R324   - ISRC 2 CTRL 2 */
+       { 0x0182, 0x0000 },  /* R386   - FLL1 Control 1 */
+       { 0x0183, 0x0000 },  /* R387   - FLL1 Control 2 */
+       { 0x0184, 0x0000 },  /* R388   - FLL1 Control 3 */
+       { 0x0186, 0x0177 },  /* R390   - FLL1 Control 5 */
+       { 0x0187, 0x0001 },  /* R391   - FLL1 Control 6 */
+       { 0x0188, 0x0000 },  /* R392   - FLL1 EFS 1 */
+       { 0x01A2, 0x0000 },  /* R418   - FLL2 Control 1 */
+       { 0x01A3, 0x0000 },  /* R419   - FLL2 Control 2 */
+       { 0x01A4, 0x0000 },  /* R420   - FLL2 Control 3 */
+       { 0x01A6, 0x0177 },  /* R422   - FLL2 Control 5 */
+       { 0x01A7, 0x0001 },  /* R423   - FLL2 Control 6 */
+       { 0x01A8, 0x0000 },  /* R424   - FLL2 EFS 1 */
+       { 0x0200, 0x0020 },  /* R512   - Mic Charge Pump 1 */
+       { 0x0201, 0xB084 },  /* R513   - Mic Charge Pump 2 */
+       { 0x0202, 0xBBDE },  /* R514   - HP Charge Pump 1 */
+       { 0x0211, 0x20D4 },  /* R529   - LDO1 Control */
+       { 0x0215, 0x0062 },  /* R533   - Mic Bias Ctrl 1 */
+       { 0x0216, 0x0062 },  /* R534   - Mic Bias Ctrl 2 */
+       { 0x0217, 0x0062 },  /* R535   - Mic Bias Ctrl 3 */
+       { 0x0280, 0x0004 },  /* R640   - Accessory Detect Mode 1 */
+       { 0x0288, 0x0020 },  /* R648   - Headphone Detect 1 */
+       { 0x0289, 0x0000 },  /* R649   - Headphone Detect 2 */
+       { 0x0290, 0x1100 },  /* R656   - Mic Detect 1 */
+       { 0x0291, 0x009F },  /* R657   - Mic Detect 2 */
+       { 0x0292, 0x0000 },  /* R658   - Mic Detect 3 */
+       { 0x0301, 0x0000 },  /* R769   - Input Enables */
+       { 0x0302, 0x0000 },  /* R770   - Input Enables Status */
+       { 0x0310, 0x2280 },  /* R784   - Status */
+       { 0x0311, 0x0080 },  /* R785   - IN1R Control */
+       { 0x0312, 0x2280 },  /* R786   - IN2L Control */
+       { 0x0313, 0x0080 },  /* R787   - IN2R Control */
+       { 0x0314, 0x2280 },  /* R788   - IN3L Control */
+       { 0x0315, 0x0080 },  /* R789   - IN3R Control */
+       { 0x0316, 0x2280 },  /* R790   - IN4L Control */
+       { 0x0317, 0x0080 },  /* R791   - IN4R Control */
+       { 0x0318, 0x0000 },  /* R792   - RXANC_SRC */
+       { 0x0319, 0x0022 },  /* R793   - Input Volume Ramp */
+       { 0x0320, 0x0180 },  /* R800   - ADC Digital Volume 1L */
+       { 0x0321, 0x0180 },  /* R801   - ADC Digital Volume 1R */
+       { 0x0322, 0x0180 },  /* R802   - ADC Digital Volume 2L */
+       { 0x0323, 0x0180 },  /* R803   - ADC Digital Volume 2R */
+       { 0x0324, 0x0180 },  /* R804   - ADC Digital Volume 3L */
+       { 0x0325, 0x0180 },  /* R805   - ADC Digital Volume 3R */
+       { 0x0326, 0x0180 },  /* R806   - ADC Digital Volume 4L */
+       { 0x0327, 0x0180 },  /* R807   - ADC Digital Volume 4R */
+       { 0x0401, 0x0000 },  /* R1025  - Output Enables 2 */
+       { 0x0402, 0x0000 },  /* R1026  - Output Status 1 */
+       { 0x0403, 0x0000 },  /* R1027  - Output Status 2 */
+       { 0x0408, 0x0000 },  /* R1032  - Channel Enables 1 */
+       { 0x0410, 0x0080 },  /* R1040  - Out Volume 1L */
+       { 0x0411, 0x0080 },  /* R1041  - Out Volume 1R */
+       { 0x0412, 0x0080 },  /* R1042  - DAC Volume Limit 1L */
+       { 0x0413, 0x0080 },  /* R1043  - DAC Volume Limit 1R */
+       { 0x0414, 0x0080 },  /* R1044  - Out Volume 2L */
+       { 0x0415, 0x0080 },  /* R1045  - Out Volume 2R */
+       { 0x0416, 0x0080 },  /* R1046  - DAC Volume Limit 2L */
+       { 0x0417, 0x0080 },  /* R1047  - DAC Volume Limit 2R */
+       { 0x0418, 0x0080 },  /* R1048  - Out Volume 3L */
+       { 0x0419, 0x0080 },  /* R1049  - Out Volume 3R */
+       { 0x041A, 0x0080 },  /* R1050  - DAC Volume Limit 3L */
+       { 0x041B, 0x0080 },  /* R1051  - DAC Volume Limit 3R */
+       { 0x041C, 0x0080 },  /* R1052  - Out Volume 4L */
+       { 0x041D, 0x0080 },  /* R1053  - Out Volume 4R */
+       { 0x041E, 0x0080 },  /* R1054  - DAC Volume Limit 5L */
+       { 0x041F, 0x0080 },  /* R1055  - DAC Volume Limit 5R */
+       { 0x0420, 0x0080 },  /* R1056  - DAC Volume Limit 6L */
+       { 0x0421, 0x0080 },  /* R1057  - DAC Volume Limit 6R */
+       { 0x0440, 0x0000 },  /* R1088  - DAC AEC Control 1 */
+       { 0x0441, 0x0022 },  /* R1089  - Output Volume Ramp */
+       { 0x0480, 0x0180 },  /* R1152  - DAC Digital Volume 1L */
+       { 0x0481, 0x0180 },  /* R1153  - DAC Digital Volume 1R */
+       { 0x0482, 0x0180 },  /* R1154  - DAC Digital Volume 2L */
+       { 0x0483, 0x0180 },  /* R1155  - DAC Digital Volume 2R */
+       { 0x0484, 0x0180 },  /* R1156  - DAC Digital Volume 3L */
+       { 0x0485, 0x0180 },  /* R1157  - DAC Digital Volume 3R */
+       { 0x0486, 0x0180 },  /* R1158  - DAC Digital Volume 4L */
+       { 0x0487, 0x0180 },  /* R1159  - DAC Digital Volume 4R */
+       { 0x0488, 0x0180 },  /* R1160  - DAC Digital Volume 5L */
+       { 0x0489, 0x0180 },  /* R1161  - DAC Digital Volume 5R */
+       { 0x048A, 0x0180 },  /* R1162  - DAC Digital Volume 6L */
+       { 0x048B, 0x0180 },  /* R1163  - DAC Digital Volume 6R */
+       { 0x04C0, 0x0069 },  /* R1216  - PDM SPK1 CTRL 1 */
+       { 0x04C1, 0x0000 },  /* R1217  - PDM SPK1 CTRL 2 */
+       { 0x04C2, 0x0069 },  /* R1218  - PDM SPK2 CTRL 1 */
+       { 0x04C3, 0x0000 },  /* R1219  - PDM SPK2 CTRL 2 */
+       { 0x0500, 0x000C },  /* R1280  - Audio IF 1_1 */
+       { 0x0501, 0x0008 },  /* R1281  - Audio IF 1_2 */
+       { 0x0502, 0x0000 },  /* R1282  - Audio IF 1_3 */
+       { 0x0503, 0x0000 },  /* R1283  - Audio IF 1_4 */
+       { 0x0504, 0x0000 },  /* R1284  - Audio IF 1_5 */
+       { 0x0505, 0x0300 },  /* R1285  - Audio IF 1_6 */
+       { 0x0506, 0x0300 },  /* R1286  - Audio IF 1_7 */
+       { 0x0507, 0x1820 },  /* R1287  - Audio IF 1_8 */
+       { 0x0508, 0x1820 },  /* R1288  - Audio IF 1_9 */
+       { 0x0509, 0x0000 },  /* R1289  - Audio IF 1_10 */
+       { 0x050A, 0x0001 },  /* R1290  - Audio IF 1_11 */
+       { 0x050B, 0x0002 },  /* R1291  - Audio IF 1_12 */
+       { 0x050C, 0x0003 },  /* R1292  - Audio IF 1_13 */
+       { 0x050D, 0x0004 },  /* R1293  - Audio IF 1_14 */
+       { 0x050E, 0x0005 },  /* R1294  - Audio IF 1_15 */
+       { 0x050F, 0x0006 },  /* R1295  - Audio IF 1_16 */
+       { 0x0510, 0x0007 },  /* R1296  - Audio IF 1_17 */
+       { 0x0511, 0x0000 },  /* R1297  - Audio IF 1_18 */
+       { 0x0512, 0x0001 },  /* R1298  - Audio IF 1_19 */
+       { 0x0513, 0x0002 },  /* R1299  - Audio IF 1_20 */
+       { 0x0514, 0x0003 },  /* R1300  - Audio IF 1_21 */
+       { 0x0515, 0x0004 },  /* R1301  - Audio IF 1_22 */
+       { 0x0516, 0x0005 },  /* R1302  - Audio IF 1_23 */
+       { 0x0517, 0x0006 },  /* R1303  - Audio IF 1_24 */
+       { 0x0518, 0x0007 },  /* R1304  - Audio IF 1_25 */
+       { 0x0519, 0x0000 },  /* R1305  - Audio IF 1_26 */
+       { 0x051A, 0x0000 },  /* R1306  - Audio IF 1_27 */
+       { 0x0540, 0x000C },  /* R1344  - Audio IF 2_1 */
+       { 0x0541, 0x0008 },  /* R1345  - Audio IF 2_2 */
+       { 0x0542, 0x0000 },  /* R1346  - Audio IF 2_3 */
+       { 0x0543, 0x0000 },  /* R1347  - Audio IF 2_4 */
+       { 0x0544, 0x0000 },  /* R1348  - Audio IF 2_5 */
+       { 0x0545, 0x0300 },  /* R1349  - Audio IF 2_6 */
+       { 0x0546, 0x0300 },  /* R1350  - Audio IF 2_7 */
+       { 0x0547, 0x1820 },  /* R1351  - Audio IF 2_8 */
+       { 0x0548, 0x1820 },  /* R1352  - Audio IF 2_9 */
+       { 0x0549, 0x0000 },  /* R1353  - Audio IF 2_10 */
+       { 0x054A, 0x0001 },  /* R1354  - Audio IF 2_11 */
+       { 0x0551, 0x0000 },  /* R1361  - Audio IF 2_18 */
+       { 0x0552, 0x0001 },  /* R1362  - Audio IF 2_19 */
+       { 0x0559, 0x0000 },  /* R1369  - Audio IF 2_26 */
+       { 0x055A, 0x0000 },  /* R1370  - Audio IF 2_27 */
+       { 0x0580, 0x000C },  /* R1408  - Audio IF 3_1 */
+       { 0x0581, 0x0008 },  /* R1409  - Audio IF 3_2 */
+       { 0x0582, 0x0000 },  /* R1410  - Audio IF 3_3 */
+       { 0x0583, 0x0000 },  /* R1411  - Audio IF 3_4 */
+       { 0x0584, 0x0000 },  /* R1412  - Audio IF 3_5 */
+       { 0x0585, 0x0300 },  /* R1413  - Audio IF 3_6 */
+       { 0x0586, 0x0300 },  /* R1414  - Audio IF 3_7 */
+       { 0x0587, 0x1820 },  /* R1415  - Audio IF 3_8 */
+       { 0x0588, 0x1820 },  /* R1416  - Audio IF 3_9 */
+       { 0x0589, 0x0000 },  /* R1417  - Audio IF 3_10 */
+       { 0x058A, 0x0001 },  /* R1418  - Audio IF 3_11 */
+       { 0x0591, 0x0000 },  /* R1425  - Audio IF 3_18 */
+       { 0x0592, 0x0001 },  /* R1426  - Audio IF 3_19 */
+       { 0x0599, 0x0000 },  /* R1433  - Audio IF 3_26 */
+       { 0x059A, 0x0000 },  /* R1434  - Audio IF 3_27 */
+       { 0x0640, 0x0000 },  /* R1600  - PWM1MIX Input 1 Source */
+       { 0x0641, 0x0080 },  /* R1601  - PWM1MIX Input 1 Volume */
+       { 0x0642, 0x0000 },  /* R1602  - PWM1MIX Input 2 Source */
+       { 0x0643, 0x0080 },  /* R1603  - PWM1MIX Input 2 Volume */
+       { 0x0644, 0x0000 },  /* R1604  - PWM1MIX Input 3 Source */
+       { 0x0645, 0x0080 },  /* R1605  - PWM1MIX Input 3 Volume */
+       { 0x0646, 0x0000 },  /* R1606  - PWM1MIX Input 4 Source */
+       { 0x0647, 0x0080 },  /* R1607  - PWM1MIX Input 4 Volume */
+       { 0x0648, 0x0000 },  /* R1608  - PWM2MIX Input 1 Source */
+       { 0x0649, 0x0080 },  /* R1609  - PWM2MIX Input 1 Volume */
+       { 0x064A, 0x0000 },  /* R1610  - PWM2MIX Input 2 Source */
+       { 0x064B, 0x0080 },  /* R1611  - PWM2MIX Input 2 Volume */
+       { 0x064C, 0x0000 },  /* R1612  - PWM2MIX Input 3 Source */
+       { 0x064D, 0x0080 },  /* R1613  - PWM2MIX Input 3 Volume */
+       { 0x064E, 0x0000 },  /* R1614  - PWM2MIX Input 4 Source */
+       { 0x064F, 0x0080 },  /* R1615  - PWM2MIX Input 4 Volume */
+       { 0x0680, 0x0000 },  /* R1664  - OUT1LMIX Input 1 Source */
+       { 0x0681, 0x0080 },  /* R1665  - OUT1LMIX Input 1 Volume */
+       { 0x0682, 0x0000 },  /* R1666  - OUT1LMIX Input 2 Source */
+       { 0x0683, 0x0080 },  /* R1667  - OUT1LMIX Input 2 Volume */
+       { 0x0684, 0x0000 },  /* R1668  - OUT1LMIX Input 3 Source */
+       { 0x0685, 0x0080 },  /* R1669  - OUT1LMIX Input 3 Volume */
+       { 0x0686, 0x0000 },  /* R1670  - OUT1LMIX Input 4 Source */
+       { 0x0687, 0x0080 },  /* R1671  - OUT1LMIX Input 4 Volume */
+       { 0x0688, 0x0000 },  /* R1672  - OUT1RMIX Input 1 Source */
+       { 0x0689, 0x0080 },  /* R1673  - OUT1RMIX Input 1 Volume */
+       { 0x068A, 0x0000 },  /* R1674  - OUT1RMIX Input 2 Source */
+       { 0x068B, 0x0080 },  /* R1675  - OUT1RMIX Input 2 Volume */
+       { 0x068C, 0x0000 },  /* R1676  - OUT1RMIX Input 3 Source */
+       { 0x068D, 0x0080 },  /* R1677  - OUT1RMIX Input 3 Volume */
+       { 0x068E, 0x0000 },  /* R1678  - OUT1RMIX Input 4 Source */
+       { 0x068F, 0x0080 },  /* R1679  - OUT1RMIX Input 4 Volume */
+       { 0x0690, 0x0000 },  /* R1680  - OUT2LMIX Input 1 Source */
+       { 0x0691, 0x0080 },  /* R1681  - OUT2LMIX Input 1 Volume */
+       { 0x0692, 0x0000 },  /* R1682  - OUT2LMIX Input 2 Source */
+       { 0x0693, 0x0080 },  /* R1683  - OUT2LMIX Input 2 Volume */
+       { 0x0694, 0x0000 },  /* R1684  - OUT2LMIX Input 3 Source */
+       { 0x0695, 0x0080 },  /* R1685  - OUT2LMIX Input 3 Volume */
+       { 0x0696, 0x0000 },  /* R1686  - OUT2LMIX Input 4 Source */
+       { 0x0697, 0x0080 },  /* R1687  - OUT2LMIX Input 4 Volume */
+       { 0x0698, 0x0000 },  /* R1688  - OUT2RMIX Input 1 Source */
+       { 0x0699, 0x0080 },  /* R1689  - OUT2RMIX Input 1 Volume */
+       { 0x069A, 0x0000 },  /* R1690  - OUT2RMIX Input 2 Source */
+       { 0x069B, 0x0080 },  /* R1691  - OUT2RMIX Input 2 Volume */
+       { 0x069C, 0x0000 },  /* R1692  - OUT2RMIX Input 3 Source */
+       { 0x069D, 0x0080 },  /* R1693  - OUT2RMIX Input 3 Volume */
+       { 0x069E, 0x0000 },  /* R1694  - OUT2RMIX Input 4 Source */
+       { 0x069F, 0x0080 },  /* R1695  - OUT2RMIX Input 4 Volume */
+       { 0x06A0, 0x0000 },  /* R1696  - OUT3LMIX Input 1 Source */
+       { 0x06A1, 0x0080 },  /* R1697  - OUT3LMIX Input 1 Volume */
+       { 0x06A2, 0x0000 },  /* R1698  - OUT3LMIX Input 2 Source */
+       { 0x06A3, 0x0080 },  /* R1699  - OUT3LMIX Input 2 Volume */
+       { 0x06A4, 0x0000 },  /* R1700  - OUT3LMIX Input 3 Source */
+       { 0x06A5, 0x0080 },  /* R1701  - OUT3LMIX Input 3 Volume */
+       { 0x06A6, 0x0000 },  /* R1702  - OUT3LMIX Input 4 Source */
+       { 0x06A7, 0x0080 },  /* R1703  - OUT3LMIX Input 4 Volume */
+       { 0x06A8, 0x0000 },  /* R1704  - OUT3RMIX Input 1 Source */
+       { 0x06A9, 0x0080 },  /* R1705  - OUT3RMIX Input 1 Volume */
+       { 0x06AA, 0x0000 },  /* R1706  - OUT3RMIX Input 2 Source */
+       { 0x06AB, 0x0080 },  /* R1707  - OUT3RMIX Input 2 Volume */
+       { 0x06AC, 0x0000 },  /* R1708  - OUT3RMIX Input 3 Source */
+       { 0x06AD, 0x0080 },  /* R1709  - OUT3RMIX Input 3 Volume */
+       { 0x06AE, 0x0000 },  /* R1710  - OUT3RMIX Input 4 Source */
+       { 0x06AF, 0x0080 },  /* R1711  - OUT3RMIX Input 4 Volume */
+       { 0x06B0, 0x0000 },  /* R1712  - OUT4LMIX Input 1 Source */
+       { 0x06B1, 0x0080 },  /* R1713  - OUT4LMIX Input 1 Volume */
+       { 0x06B2, 0x0000 },  /* R1714  - OUT4LMIX Input 2 Source */
+       { 0x06B3, 0x0080 },  /* R1715  - OUT4LMIX Input 2 Volume */
+       { 0x06B4, 0x0000 },  /* R1716  - OUT4LMIX Input 3 Source */
+       { 0x06B5, 0x0080 },  /* R1717  - OUT4LMIX Input 3 Volume */
+       { 0x06B6, 0x0000 },  /* R1718  - OUT4LMIX Input 4 Source */
+       { 0x06B7, 0x0080 },  /* R1719  - OUT4LMIX Input 4 Volume */
+       { 0x06B8, 0x0000 },  /* R1720  - OUT4RMIX Input 1 Source */
+       { 0x06B9, 0x0080 },  /* R1721  - OUT4RMIX Input 1 Volume */
+       { 0x06BA, 0x0000 },  /* R1722  - OUT4RMIX Input 2 Source */
+       { 0x06BB, 0x0080 },  /* R1723  - OUT4RMIX Input 2 Volume */
+       { 0x06BC, 0x0000 },  /* R1724  - OUT4RMIX Input 3 Source */
+       { 0x06BD, 0x0080 },  /* R1725  - OUT4RMIX Input 3 Volume */
+       { 0x06BE, 0x0000 },  /* R1726  - OUT4RMIX Input 4 Source */
+       { 0x06BF, 0x0080 },  /* R1727  - OUT4RMIX Input 4 Volume */
+       { 0x06C0, 0x0000 },  /* R1728  - OUT5LMIX Input 1 Source */
+       { 0x06C1, 0x0080 },  /* R1729  - OUT5LMIX Input 1 Volume */
+       { 0x06C2, 0x0000 },  /* R1730  - OUT5LMIX Input 2 Source */
+       { 0x06C3, 0x0080 },  /* R1731  - OUT5LMIX Input 2 Volume */
+       { 0x06C4, 0x0000 },  /* R1732  - OUT5LMIX Input 3 Source */
+       { 0x06C5, 0x0080 },  /* R1733  - OUT5LMIX Input 3 Volume */
+       { 0x06C6, 0x0000 },  /* R1734  - OUT5LMIX Input 4 Source */
+       { 0x06C7, 0x0080 },  /* R1735  - OUT5LMIX Input 4 Volume */
+       { 0x06C8, 0x0000 },  /* R1736  - OUT5RMIX Input 1 Source */
+       { 0x06C9, 0x0080 },  /* R1737  - OUT5RMIX Input 1 Volume */
+       { 0x06CA, 0x0000 },  /* R1738  - OUT5RMIX Input 2 Source */
+       { 0x06CB, 0x0080 },  /* R1739  - OUT5RMIX Input 2 Volume */
+       { 0x06CC, 0x0000 },  /* R1740  - OUT5RMIX Input 3 Source */
+       { 0x06CD, 0x0080 },  /* R1741  - OUT5RMIX Input 3 Volume */
+       { 0x06CE, 0x0000 },  /* R1742  - OUT5RMIX Input 4 Source */
+       { 0x06CF, 0x0080 },  /* R1743  - OUT5RMIX Input 4 Volume */
+       { 0x06D0, 0x0000 },  /* R1744  - OUT6LMIX Input 1 Source */
+       { 0x06D1, 0x0080 },  /* R1745  - OUT6LMIX Input 1 Volume */
+       { 0x06D2, 0x0000 },  /* R1746  - OUT6LMIX Input 2 Source */
+       { 0x06D3, 0x0080 },  /* R1747  - OUT6LMIX Input 2 Volume */
+       { 0x06D4, 0x0000 },  /* R1748  - OUT6LMIX Input 3 Source */
+       { 0x06D5, 0x0080 },  /* R1749  - OUT6LMIX Input 3 Volume */
+       { 0x06D6, 0x0000 },  /* R1750  - OUT6LMIX Input 4 Source */
+       { 0x06D7, 0x0080 },  /* R1751  - OUT6LMIX Input 4 Volume */
+       { 0x06D8, 0x0000 },  /* R1752  - OUT6RMIX Input 1 Source */
+       { 0x06D9, 0x0080 },  /* R1753  - OUT6RMIX Input 1 Volume */
+       { 0x06DA, 0x0000 },  /* R1754  - OUT6RMIX Input 2 Source */
+       { 0x06DB, 0x0080 },  /* R1755  - OUT6RMIX Input 2 Volume */
+       { 0x06DC, 0x0000 },  /* R1756  - OUT6RMIX Input 3 Source */
+       { 0x06DD, 0x0080 },  /* R1757  - OUT6RMIX Input 3 Volume */
+       { 0x06DE, 0x0000 },  /* R1758  - OUT6RMIX Input 4 Source */
+       { 0x06DF, 0x0080 },  /* R1759  - OUT6RMIX Input 4 Volume */
+       { 0x0700, 0x0000 },  /* R1792  - AIF1TX1MIX Input 1 Source */
+       { 0x0701, 0x0080 },  /* R1793  - AIF1TX1MIX Input 1 Volume */
+       { 0x0702, 0x0000 },  /* R1794  - AIF1TX1MIX Input 2 Source */
+       { 0x0703, 0x0080 },  /* R1795  - AIF1TX1MIX Input 2 Volume */
+       { 0x0704, 0x0000 },  /* R1796  - AIF1TX1MIX Input 3 Source */
+       { 0x0705, 0x0080 },  /* R1797  - AIF1TX1MIX Input 3 Volume */
+       { 0x0706, 0x0000 },  /* R1798  - AIF1TX1MIX Input 4 Source */
+       { 0x0707, 0x0080 },  /* R1799  - AIF1TX1MIX Input 4 Volume */
+       { 0x0708, 0x0000 },  /* R1800  - AIF1TX2MIX Input 1 Source */
+       { 0x0709, 0x0080 },  /* R1801  - AIF1TX2MIX Input 1 Volume */
+       { 0x070A, 0x0000 },  /* R1802  - AIF1TX2MIX Input 2 Source */
+       { 0x070B, 0x0080 },  /* R1803  - AIF1TX2MIX Input 2 Volume */
+       { 0x070C, 0x0000 },  /* R1804  - AIF1TX2MIX Input 3 Source */
+       { 0x070D, 0x0080 },  /* R1805  - AIF1TX2MIX Input 3 Volume */
+       { 0x070E, 0x0000 },  /* R1806  - AIF1TX2MIX Input 4 Source */
+       { 0x070F, 0x0080 },  /* R1807  - AIF1TX2MIX Input 4 Volume */
+       { 0x0710, 0x0000 },  /* R1808  - AIF1TX3MIX Input 1 Source */
+       { 0x0711, 0x0080 },  /* R1809  - AIF1TX3MIX Input 1 Volume */
+       { 0x0712, 0x0000 },  /* R1810  - AIF1TX3MIX Input 2 Source */
+       { 0x0713, 0x0080 },  /* R1811  - AIF1TX3MIX Input 2 Volume */
+       { 0x0714, 0x0000 },  /* R1812  - AIF1TX3MIX Input 3 Source */
+       { 0x0715, 0x0080 },  /* R1813  - AIF1TX3MIX Input 3 Volume */
+       { 0x0716, 0x0000 },  /* R1814  - AIF1TX3MIX Input 4 Source */
+       { 0x0717, 0x0080 },  /* R1815  - AIF1TX3MIX Input 4 Volume */
+       { 0x0718, 0x0000 },  /* R1816  - AIF1TX4MIX Input 1 Source */
+       { 0x0719, 0x0080 },  /* R1817  - AIF1TX4MIX Input 1 Volume */
+       { 0x071A, 0x0000 },  /* R1818  - AIF1TX4MIX Input 2 Source */
+       { 0x071B, 0x0080 },  /* R1819  - AIF1TX4MIX Input 2 Volume */
+       { 0x071C, 0x0000 },  /* R1820  - AIF1TX4MIX Input 3 Source */
+       { 0x071D, 0x0080 },  /* R1821  - AIF1TX4MIX Input 3 Volume */
+       { 0x071E, 0x0000 },  /* R1822  - AIF1TX4MIX Input 4 Source */
+       { 0x071F, 0x0080 },  /* R1823  - AIF1TX4MIX Input 4 Volume */
+       { 0x0720, 0x0000 },  /* R1824  - AIF1TX5MIX Input 1 Source */
+       { 0x0721, 0x0080 },  /* R1825  - AIF1TX5MIX Input 1 Volume */
+       { 0x0722, 0x0000 },  /* R1826  - AIF1TX5MIX Input 2 Source */
+       { 0x0723, 0x0080 },  /* R1827  - AIF1TX5MIX Input 2 Volume */
+       { 0x0724, 0x0000 },  /* R1828  - AIF1TX5MIX Input 3 Source */
+       { 0x0725, 0x0080 },  /* R1829  - AIF1TX5MIX Input 3 Volume */
+       { 0x0726, 0x0000 },  /* R1830  - AIF1TX5MIX Input 4 Source */
+       { 0x0727, 0x0080 },  /* R1831  - AIF1TX5MIX Input 4 Volume */
+       { 0x0728, 0x0000 },  /* R1832  - AIF1TX6MIX Input 1 Source */
+       { 0x0729, 0x0080 },  /* R1833  - AIF1TX6MIX Input 1 Volume */
+       { 0x072A, 0x0000 },  /* R1834  - AIF1TX6MIX Input 2 Source */
+       { 0x072B, 0x0080 },  /* R1835  - AIF1TX6MIX Input 2 Volume */
+       { 0x072C, 0x0000 },  /* R1836  - AIF1TX6MIX Input 3 Source */
+       { 0x072D, 0x0080 },  /* R1837  - AIF1TX6MIX Input 3 Volume */
+       { 0x072E, 0x0000 },  /* R1838  - AIF1TX6MIX Input 4 Source */
+       { 0x072F, 0x0080 },  /* R1839  - AIF1TX6MIX Input 4 Volume */
+       { 0x0730, 0x0000 },  /* R1840  - AIF1TX7MIX Input 1 Source */
+       { 0x0731, 0x0080 },  /* R1841  - AIF1TX7MIX Input 1 Volume */
+       { 0x0732, 0x0000 },  /* R1842  - AIF1TX7MIX Input 2 Source */
+       { 0x0733, 0x0080 },  /* R1843  - AIF1TX7MIX Input 2 Volume */
+       { 0x0734, 0x0000 },  /* R1844  - AIF1TX7MIX Input 3 Source */
+       { 0x0735, 0x0080 },  /* R1845  - AIF1TX7MIX Input 3 Volume */
+       { 0x0736, 0x0000 },  /* R1846  - AIF1TX7MIX Input 4 Source */
+       { 0x0737, 0x0080 },  /* R1847  - AIF1TX7MIX Input 4 Volume */
+       { 0x0738, 0x0000 },  /* R1848  - AIF1TX8MIX Input 1 Source */
+       { 0x0739, 0x0080 },  /* R1849  - AIF1TX8MIX Input 1 Volume */
+       { 0x073A, 0x0000 },  /* R1850  - AIF1TX8MIX Input 2 Source */
+       { 0x073B, 0x0080 },  /* R1851  - AIF1TX8MIX Input 2 Volume */
+       { 0x073C, 0x0000 },  /* R1852  - AIF1TX8MIX Input 3 Source */
+       { 0x073D, 0x0080 },  /* R1853  - AIF1TX8MIX Input 3 Volume */
+       { 0x073E, 0x0000 },  /* R1854  - AIF1TX8MIX Input 4 Source */
+       { 0x073F, 0x0080 },  /* R1855  - AIF1TX8MIX Input 4 Volume */
+       { 0x0740, 0x0000 },  /* R1856  - AIF2TX1MIX Input 1 Source */
+       { 0x0741, 0x0080 },  /* R1857  - AIF2TX1MIX Input 1 Volume */
+       { 0x0742, 0x0000 },  /* R1858  - AIF2TX1MIX Input 2 Source */
+       { 0x0743, 0x0080 },  /* R1859  - AIF2TX1MIX Input 2 Volume */
+       { 0x0744, 0x0000 },  /* R1860  - AIF2TX1MIX Input 3 Source */
+       { 0x0745, 0x0080 },  /* R1861  - AIF2TX1MIX Input 3 Volume */
+       { 0x0746, 0x0000 },  /* R1862  - AIF2TX1MIX Input 4 Source */
+       { 0x0747, 0x0080 },  /* R1863  - AIF2TX1MIX Input 4 Volume */
+       { 0x0748, 0x0000 },  /* R1864  - AIF2TX2MIX Input 1 Source */
+       { 0x0749, 0x0080 },  /* R1865  - AIF2TX2MIX Input 1 Volume */
+       { 0x074A, 0x0000 },  /* R1866  - AIF2TX2MIX Input 2 Source */
+       { 0x074B, 0x0080 },  /* R1867  - AIF2TX2MIX Input 2 Volume */
+       { 0x074C, 0x0000 },  /* R1868  - AIF2TX2MIX Input 3 Source */
+       { 0x074D, 0x0080 },  /* R1869  - AIF2TX2MIX Input 3 Volume */
+       { 0x074E, 0x0000 },  /* R1870  - AIF2TX2MIX Input 4 Source */
+       { 0x074F, 0x0080 },  /* R1871  - AIF2TX2MIX Input 4 Volume */
+       { 0x0780, 0x0000 },  /* R1920  - AIF3TX1MIX Input 1 Source */
+       { 0x0781, 0x0080 },  /* R1921  - AIF3TX1MIX Input 1 Volume */
+       { 0x0782, 0x0000 },  /* R1922  - AIF3TX1MIX Input 2 Source */
+       { 0x0783, 0x0080 },  /* R1923  - AIF3TX1MIX Input 2 Volume */
+       { 0x0784, 0x0000 },  /* R1924  - AIF3TX1MIX Input 3 Source */
+       { 0x0785, 0x0080 },  /* R1925  - AIF3TX1MIX Input 3 Volume */
+       { 0x0786, 0x0000 },  /* R1926  - AIF3TX1MIX Input 4 Source */
+       { 0x0787, 0x0080 },  /* R1927  - AIF3TX1MIX Input 4 Volume */
+       { 0x0788, 0x0000 },  /* R1928  - AIF3TX2MIX Input 1 Source */
+       { 0x0789, 0x0080 },  /* R1929  - AIF3TX2MIX Input 1 Volume */
+       { 0x078A, 0x0000 },  /* R1930  - AIF3TX2MIX Input 2 Source */
+       { 0x078B, 0x0080 },  /* R1931  - AIF3TX2MIX Input 2 Volume */
+       { 0x078C, 0x0000 },  /* R1932  - AIF3TX2MIX Input 3 Source */
+       { 0x078D, 0x0080 },  /* R1933  - AIF3TX2MIX Input 3 Volume */
+       { 0x078E, 0x0000 },  /* R1934  - AIF3TX2MIX Input 4 Source */
+       { 0x078F, 0x0080 },  /* R1935  - AIF3TX2MIX Input 4 Volume */
+       { 0x0880, 0x0000 },  /* R2176  - EQ1MIX Input 1 Source */
+       { 0x0881, 0x0080 },  /* R2177  - EQ1MIX Input 1 Volume */
+       { 0x0882, 0x0000 },  /* R2178  - EQ1MIX Input 2 Source */
+       { 0x0883, 0x0080 },  /* R2179  - EQ1MIX Input 2 Volume */
+       { 0x0884, 0x0000 },  /* R2180  - EQ1MIX Input 3 Source */
+       { 0x0885, 0x0080 },  /* R2181  - EQ1MIX Input 3 Volume */
+       { 0x0886, 0x0000 },  /* R2182  - EQ1MIX Input 4 Source */
+       { 0x0887, 0x0080 },  /* R2183  - EQ1MIX Input 4 Volume */
+       { 0x0888, 0x0000 },  /* R2184  - EQ2MIX Input 1 Source */
+       { 0x0889, 0x0080 },  /* R2185  - EQ2MIX Input 1 Volume */
+       { 0x088A, 0x0000 },  /* R2186  - EQ2MIX Input 2 Source */
+       { 0x088B, 0x0080 },  /* R2187  - EQ2MIX Input 2 Volume */
+       { 0x088C, 0x0000 },  /* R2188  - EQ2MIX Input 3 Source */
+       { 0x088D, 0x0080 },  /* R2189  - EQ2MIX Input 3 Volume */
+       { 0x088E, 0x0000 },  /* R2190  - EQ2MIX Input 4 Source */
+       { 0x088F, 0x0080 },  /* R2191  - EQ2MIX Input 4 Volume */
+       { 0x0890, 0x0000 },  /* R2192  - EQ3MIX Input 1 Source */
+       { 0x0891, 0x0080 },  /* R2193  - EQ3MIX Input 1 Volume */
+       { 0x0892, 0x0000 },  /* R2194  - EQ3MIX Input 2 Source */
+       { 0x0893, 0x0080 },  /* R2195  - EQ3MIX Input 2 Volume */
+       { 0x0894, 0x0000 },  /* R2196  - EQ3MIX Input 3 Source */
+       { 0x0895, 0x0080 },  /* R2197  - EQ3MIX Input 3 Volume */
+       { 0x0896, 0x0000 },  /* R2198  - EQ3MIX Input 4 Source */
+       { 0x0897, 0x0080 },  /* R2199  - EQ3MIX Input 4 Volume */
+       { 0x0898, 0x0000 },  /* R2200  - EQ4MIX Input 1 Source */
+       { 0x0899, 0x0080 },  /* R2201  - EQ4MIX Input 1 Volume */
+       { 0x089A, 0x0000 },  /* R2202  - EQ4MIX Input 2 Source */
+       { 0x089B, 0x0080 },  /* R2203  - EQ4MIX Input 2 Volume */
+       { 0x089C, 0x0000 },  /* R2204  - EQ4MIX Input 3 Source */
+       { 0x089D, 0x0080 },  /* R2205  - EQ4MIX Input 3 Volume */
+       { 0x089E, 0x0000 },  /* R2206  - EQ4MIX Input 4 Source */
+       { 0x089F, 0x0080 },  /* R2207  - EQ4MIX Input 4 Volume */
+       { 0x08C0, 0x0000 },  /* R2240  - DRC1LMIX Input 1 Source */
+       { 0x08C1, 0x0080 },  /* R2241  - DRC1LMIX Input 1 Volume */
+       { 0x08C2, 0x0000 },  /* R2242  - DRC1LMIX Input 2 Source */
+       { 0x08C3, 0x0080 },  /* R2243  - DRC1LMIX Input 2 Volume */
+       { 0x08C4, 0x0000 },  /* R2244  - DRC1LMIX Input 3 Source */
+       { 0x08C5, 0x0080 },  /* R2245  - DRC1LMIX Input 3 Volume */
+       { 0x08C6, 0x0000 },  /* R2246  - DRC1LMIX Input 4 Source */
+       { 0x08C7, 0x0080 },  /* R2247  - DRC1LMIX Input 4 Volume */
+       { 0x08C8, 0x0000 },  /* R2248  - DRC1RMIX Input 1 Source */
+       { 0x08C9, 0x0080 },  /* R2249  - DRC1RMIX Input 1 Volume */
+       { 0x08CA, 0x0000 },  /* R2250  - DRC1RMIX Input 2 Source */
+       { 0x08CB, 0x0080 },  /* R2251  - DRC1RMIX Input 2 Volume */
+       { 0x08CC, 0x0000 },  /* R2252  - DRC1RMIX Input 3 Source */
+       { 0x08CD, 0x0080 },  /* R2253  - DRC1RMIX Input 3 Volume */
+       { 0x08CE, 0x0000 },  /* R2254  - DRC1RMIX Input 4 Source */
+       { 0x08CF, 0x0080 },  /* R2255  - DRC1RMIX Input 4 Volume */
+       { 0x0900, 0x0000 },  /* R2304  - HPLP1MIX Input 1 Source */
+       { 0x0901, 0x0080 },  /* R2305  - HPLP1MIX Input 1 Volume */
+       { 0x0902, 0x0000 },  /* R2306  - HPLP1MIX Input 2 Source */
+       { 0x0903, 0x0080 },  /* R2307  - HPLP1MIX Input 2 Volume */
+       { 0x0904, 0x0000 },  /* R2308  - HPLP1MIX Input 3 Source */
+       { 0x0905, 0x0080 },  /* R2309  - HPLP1MIX Input 3 Volume */
+       { 0x0906, 0x0000 },  /* R2310  - HPLP1MIX Input 4 Source */
+       { 0x0907, 0x0080 },  /* R2311  - HPLP1MIX Input 4 Volume */
+       { 0x0908, 0x0000 },  /* R2312  - HPLP2MIX Input 1 Source */
+       { 0x0909, 0x0080 },  /* R2313  - HPLP2MIX Input 1 Volume */
+       { 0x090A, 0x0000 },  /* R2314  - HPLP2MIX Input 2 Source */
+       { 0x090B, 0x0080 },  /* R2315  - HPLP2MIX Input 2 Volume */
+       { 0x090C, 0x0000 },  /* R2316  - HPLP2MIX Input 3 Source */
+       { 0x090D, 0x0080 },  /* R2317  - HPLP2MIX Input 3 Volume */
+       { 0x090E, 0x0000 },  /* R2318  - HPLP2MIX Input 4 Source */
+       { 0x090F, 0x0080 },  /* R2319  - HPLP2MIX Input 4 Volume */
+       { 0x0910, 0x0000 },  /* R2320  - HPLP3MIX Input 1 Source */
+       { 0x0911, 0x0080 },  /* R2321  - HPLP3MIX Input 1 Volume */
+       { 0x0912, 0x0000 },  /* R2322  - HPLP3MIX Input 2 Source */
+       { 0x0913, 0x0080 },  /* R2323  - HPLP3MIX Input 2 Volume */
+       { 0x0914, 0x0000 },  /* R2324  - HPLP3MIX Input 3 Source */
+       { 0x0915, 0x0080 },  /* R2325  - HPLP3MIX Input 3 Volume */
+       { 0x0916, 0x0000 },  /* R2326  - HPLP3MIX Input 4 Source */
+       { 0x0917, 0x0080 },  /* R2327  - HPLP3MIX Input 4 Volume */
+       { 0x0918, 0x0000 },  /* R2328  - HPLP4MIX Input 1 Source */
+       { 0x0919, 0x0080 },  /* R2329  - HPLP4MIX Input 1 Volume */
+       { 0x091A, 0x0000 },  /* R2330  - HPLP4MIX Input 2 Source */
+       { 0x091B, 0x0080 },  /* R2331  - HPLP4MIX Input 2 Volume */
+       { 0x091C, 0x0000 },  /* R2332  - HPLP4MIX Input 3 Source */
+       { 0x091D, 0x0080 },  /* R2333  - HPLP4MIX Input 3 Volume */
+       { 0x091E, 0x0000 },  /* R2334  - HPLP4MIX Input 4 Source */
+       { 0x091F, 0x0080 },  /* R2335  - HPLP4MIX Input 4 Volume */
+       { 0x0940, 0x0000 },  /* R2368  - DSP1LMIX Input 1 Source */
+       { 0x0941, 0x0080 },  /* R2369  - DSP1LMIX Input 1 Volume */
+       { 0x0942, 0x0000 },  /* R2370  - DSP1LMIX Input 2 Source */
+       { 0x0943, 0x0080 },  /* R2371  - DSP1LMIX Input 2 Volume */
+       { 0x0944, 0x0000 },  /* R2372  - DSP1LMIX Input 3 Source */
+       { 0x0945, 0x0080 },  /* R2373  - DSP1LMIX Input 3 Volume */
+       { 0x0946, 0x0000 },  /* R2374  - DSP1LMIX Input 4 Source */
+       { 0x0947, 0x0080 },  /* R2375  - DSP1LMIX Input 4 Volume */
+       { 0x0948, 0x0000 },  /* R2376  - DSP1RMIX Input 1 Source */
+       { 0x0949, 0x0080 },  /* R2377  - DSP1RMIX Input 1 Volume */
+       { 0x094A, 0x0000 },  /* R2378  - DSP1RMIX Input 2 Source */
+       { 0x094B, 0x0080 },  /* R2379  - DSP1RMIX Input 2 Volume */
+       { 0x094C, 0x0000 },  /* R2380  - DSP1RMIX Input 3 Source */
+       { 0x094D, 0x0080 },  /* R2381  - DSP1RMIX Input 3 Volume */
+       { 0x094E, 0x0000 },  /* R2382  - DSP1RMIX Input 4 Source */
+       { 0x094F, 0x0080 },  /* R2383  - DSP1RMIX Input 4 Volume */
+       { 0x0950, 0x0000 },  /* R2384  - DSP1AUX1MIX Input 1 Source */
+       { 0x0958, 0x0000 },  /* R2392  - DSP1AUX2MIX Input 1 Source */
+       { 0x0960, 0x0000 },  /* R2400  - DSP1AUX3MIX Input 1 Source */
+       { 0x0968, 0x0000 },  /* R2408  - DSP1AUX4MIX Input 1 Source */
+       { 0x0970, 0x0000 },  /* R2416  - DSP1AUX5MIX Input 1 Source */
+       { 0x0978, 0x0000 },  /* R2424  - DSP1AUX6MIX Input 1 Source */
+       { 0x0980, 0x0000 },  /* R2432  - DSP2LMIX Input 1 Source */
+       { 0x0981, 0x0080 },  /* R2433  - DSP2LMIX Input 1 Volume */
+       { 0x0982, 0x0000 },  /* R2434  - DSP2LMIX Input 2 Source */
+       { 0x0983, 0x0080 },  /* R2435  - DSP2LMIX Input 2 Volume */
+       { 0x0984, 0x0000 },  /* R2436  - DSP2LMIX Input 3 Source */
+       { 0x0985, 0x0080 },  /* R2437  - DSP2LMIX Input 3 Volume */
+       { 0x0986, 0x0000 },  /* R2438  - DSP2LMIX Input 4 Source */
+       { 0x0987, 0x0080 },  /* R2439  - DSP2LMIX Input 4 Volume */
+       { 0x0988, 0x0000 },  /* R2440  - DSP2RMIX Input 1 Source */
+       { 0x0989, 0x0080 },  /* R2441  - DSP2RMIX Input 1 Volume */
+       { 0x098A, 0x0000 },  /* R2442  - DSP2RMIX Input 2 Source */
+       { 0x098B, 0x0080 },  /* R2443  - DSP2RMIX Input 2 Volume */
+       { 0x098C, 0x0000 },  /* R2444  - DSP2RMIX Input 3 Source */
+       { 0x098D, 0x0080 },  /* R2445  - DSP2RMIX Input 3 Volume */
+       { 0x098E, 0x0000 },  /* R2446  - DSP2RMIX Input 4 Source */
+       { 0x098F, 0x0080 },  /* R2447  - DSP2RMIX Input 4 Volume */
+       { 0x0990, 0x0000 },  /* R2448  - DSP2AUX1MIX Input 1 Source */
+       { 0x0998, 0x0000 },  /* R2456  - DSP2AUX2MIX Input 1 Source */
+       { 0x09A0, 0x0000 },  /* R2464  - DSP2AUX3MIX Input 1 Source */
+       { 0x09A8, 0x0000 },  /* R2472  - DSP2AUX4MIX Input 1 Source */
+       { 0x09B0, 0x0000 },  /* R2480  - DSP2AUX5MIX Input 1 Source */
+       { 0x09B8, 0x0000 },  /* R2488  - DSP2AUX6MIX Input 1 Source */
+       { 0x09C0, 0x0000 },  /* R2496  - DSP3LMIX Input 1 Source */
+       { 0x09C1, 0x0080 },  /* R2497  - DSP3LMIX Input 1 Volume */
+       { 0x09C2, 0x0000 },  /* R2498  - DSP3LMIX Input 2 Source */
+       { 0x09C3, 0x0080 },  /* R2499  - DSP3LMIX Input 2 Volume */
+       { 0x09C4, 0x0000 },  /* R2500  - DSP3LMIX Input 3 Source */
+       { 0x09C5, 0x0080 },  /* R2501  - DSP3LMIX Input 3 Volume */
+       { 0x09C6, 0x0000 },  /* R2502  - DSP3LMIX Input 4 Source */
+       { 0x09C7, 0x0080 },  /* R2503  - DSP3LMIX Input 4 Volume */
+       { 0x09C8, 0x0000 },  /* R2504  - DSP3RMIX Input 1 Source */
+       { 0x09C9, 0x0080 },  /* R2505  - DSP3RMIX Input 1 Volume */
+       { 0x09CA, 0x0000 },  /* R2506  - DSP3RMIX Input 2 Source */
+       { 0x09CB, 0x0080 },  /* R2507  - DSP3RMIX Input 2 Volume */
+       { 0x09CC, 0x0000 },  /* R2508  - DSP3RMIX Input 3 Source */
+       { 0x09CD, 0x0080 },  /* R2509  - DSP3RMIX Input 3 Volume */
+       { 0x09CE, 0x0000 },  /* R2510  - DSP3RMIX Input 4 Source */
+       { 0x09CF, 0x0080 },  /* R2511  - DSP3RMIX Input 4 Volume */
+       { 0x09D0, 0x0000 },  /* R2512  - DSP3AUX1MIX Input 1 Source */
+       { 0x09D8, 0x0000 },  /* R2520  - DSP3AUX2MIX Input 1 Source */
+       { 0x09E0, 0x0000 },  /* R2528  - DSP3AUX3MIX Input 1 Source */
+       { 0x09E8, 0x0000 },  /* R2536  - DSP3AUX4MIX Input 1 Source */
+       { 0x09F0, 0x0000 },  /* R2544  - DSP3AUX5MIX Input 1 Source */
+       { 0x09F8, 0x0000 },  /* R2552  - DSP3AUX6MIX Input 1 Source */
+       { 0x0A80, 0x0000 },  /* R2688  - ASRC1LMIX Input 1 Source */
+       { 0x0A88, 0x0000 },  /* R2696  - ASRC1RMIX Input 1 Source */
+       { 0x0A90, 0x0000 },  /* R2704  - ASRC2LMIX Input 1 Source */
+       { 0x0A98, 0x0000 },  /* R2712  - ASRC2RMIX Input 1 Source */
+       { 0x0B00, 0x0000 },  /* R2816  - ISRC1DEC1MIX Input 1 Source */
+       { 0x0B08, 0x0000 },  /* R2824  - ISRC1DEC2MIX Input 1 Source */
+       { 0x0B10, 0x0000 },  /* R2832  - ISRC1DEC3MIX Input 1 Source */
+       { 0x0B18, 0x0000 },  /* R2840  - ISRC1DEC4MIX Input 1 Source */
+       { 0x0B20, 0x0000 },  /* R2848  - ISRC1INT1MIX Input 1 Source */
+       { 0x0B28, 0x0000 },  /* R2856  - ISRC1INT2MIX Input 1 Source */
+       { 0x0B30, 0x0000 },  /* R2864  - ISRC1INT3MIX Input 1 Source */
+       { 0x0B38, 0x0000 },  /* R2872  - ISRC1INT4MIX Input 1 Source */
+       { 0x0B40, 0x0000 },  /* R2880  - ISRC2DEC1MIX Input 1 Source */
+       { 0x0B48, 0x0000 },  /* R2888  - ISRC2DEC2MIX Input 1 Source */
+       { 0x0B50, 0x0000 },  /* R2896  - ISRC2DEC3MIX Input 1 Source */
+       { 0x0B58, 0x0000 },  /* R2904  - ISRC2DEC4MIX Input 1 Source */
+       { 0x0B60, 0x0000 },  /* R2912  - ISRC2INT1MIX Input 1 Source */
+       { 0x0B68, 0x0000 },  /* R2920  - ISRC2INT2MIX Input 1 Source */
+       { 0x0B70, 0x0000 },  /* R2928  - ISRC2INT3MIX Input 1 Source */
+       { 0x0B78, 0x0000 },  /* R2936  - ISRC2INT4MIX Input 1 Source */
+       { 0x0C00, 0xA001 },  /* R3072  - GPIO CTRL 1 */
+       { 0x0C01, 0xA001 },  /* R3073  - GPIO CTRL 2 */
+       { 0x0C02, 0xA001 },  /* R3074  - GPIO CTRL 3 */
+       { 0x0C03, 0xA001 },  /* R3075  - GPIO CTRL 4 */
+       { 0x0C04, 0xA001 },  /* R3076  - GPIO CTRL 5 */
+       { 0x0C05, 0xA001 },  /* R3077  - GPIO CTRL 6 */
+       { 0x0C23, 0x4003 },  /* R3107  - Misc Pad Ctrl 1 */
+       { 0x0C24, 0x0000 },  /* R3108  - Misc Pad Ctrl 2 */
+       { 0x0C25, 0x0000 },  /* R3109  - Misc Pad Ctrl 3 */
+       { 0x0C26, 0x0000 },  /* R3110  - Misc Pad Ctrl 4 */
+       { 0x0C27, 0x0000 },  /* R3111  - Misc Pad Ctrl 5 */
+       { 0x0C28, 0x0000 },  /* R3112  - Misc GPIO 1 */
+       { 0x0D00, 0x0000 },  /* R3328  - Interrupt Status 1 */
+       { 0x0D01, 0x0000 },  /* R3329  - Interrupt Status 2 */
+       { 0x0D02, 0x0000 },  /* R3330  - Interrupt Status 3 */
+       { 0x0D03, 0x0000 },  /* R3331  - Interrupt Status 4 */
+       { 0x0D04, 0x0000 },  /* R3332  - Interrupt Raw Status 2 */
+       { 0x0D05, 0x0000 },  /* R3333  - Interrupt Raw Status 3 */
+       { 0x0D06, 0x0000 },  /* R3334  - Interrupt Raw Status 4 */
+       { 0x0D07, 0xFFFF },  /* R3335  - Interrupt Status 1 Mask */
+       { 0x0D08, 0xFFFF },  /* R3336  - Interrupt Status 2 Mask */
+       { 0x0D09, 0xFFFF },  /* R3337  - Interrupt Status 3 Mask */
+       { 0x0D0A, 0xFFFF },  /* R3338  - Interrupt Status 4 Mask */
+       { 0x0D1F, 0x0000 },  /* R3359  - Interrupt Control */
+       { 0x0D20, 0xFFFF },  /* R3360  - IRQ Debounce 1 */
+       { 0x0D21, 0xFFFF },  /* R3361  - IRQ Debounce 2 */
+       { 0x0E00, 0x0000 },  /* R3584  - FX_Ctrl */
+       { 0x0E10, 0x6318 },  /* R3600  - EQ1_1 */
+       { 0x0E11, 0x6300 },  /* R3601  - EQ1_2 */
+       { 0x0E12, 0x0FC8 },  /* R3602  - EQ1_3 */
+       { 0x0E13, 0x03FE },  /* R3603  - EQ1_4 */
+       { 0x0E14, 0x00E0 },  /* R3604  - EQ1_5 */
+       { 0x0E15, 0x1EC4 },  /* R3605  - EQ1_6 */
+       { 0x0E16, 0xF136 },  /* R3606  - EQ1_7 */
+       { 0x0E17, 0x0409 },  /* R3607  - EQ1_8 */
+       { 0x0E18, 0x04CC },  /* R3608  - EQ1_9 */
+       { 0x0E19, 0x1C9B },  /* R3609  - EQ1_10 */
+       { 0x0E1A, 0xF337 },  /* R3610  - EQ1_11 */
+       { 0x0E1B, 0x040B },  /* R3611  - EQ1_12 */
+       { 0x0E1C, 0x0CBB },  /* R3612  - EQ1_13 */
+       { 0x0E1D, 0x16F8 },  /* R3613  - EQ1_14 */
+       { 0x0E1E, 0xF7D9 },  /* R3614  - EQ1_15 */
+       { 0x0E1F, 0x040A },  /* R3615  - EQ1_16 */
+       { 0x0E20, 0x1F14 },  /* R3616  - EQ1_17 */
+       { 0x0E21, 0x058C },  /* R3617  - EQ1_18 */
+       { 0x0E22, 0x0563 },  /* R3618  - EQ1_19 */
+       { 0x0E23, 0x4000 },  /* R3619  - EQ1_20 */
+       { 0x0E26, 0x6318 },  /* R3622  - EQ2_1 */
+       { 0x0E27, 0x6300 },  /* R3623  - EQ2_2 */
+       { 0x0E28, 0x0FC8 },  /* R3624  - EQ2_3 */
+       { 0x0E29, 0x03FE },  /* R3625  - EQ2_4 */
+       { 0x0E2A, 0x00E0 },  /* R3626  - EQ2_5 */
+       { 0x0E2B, 0x1EC4 },  /* R3627  - EQ2_6 */
+       { 0x0E2C, 0xF136 },  /* R3628  - EQ2_7 */
+       { 0x0E2D, 0x0409 },  /* R3629  - EQ2_8 */
+       { 0x0E2E, 0x04CC },  /* R3630  - EQ2_9 */
+       { 0x0E2F, 0x1C9B },  /* R3631  - EQ2_10 */
+       { 0x0E30, 0xF337 },  /* R3632  - EQ2_11 */
+       { 0x0E31, 0x040B },  /* R3633  - EQ2_12 */
+       { 0x0E32, 0x0CBB },  /* R3634  - EQ2_13 */
+       { 0x0E33, 0x16F8 },  /* R3635  - EQ2_14 */
+       { 0x0E34, 0xF7D9 },  /* R3636  - EQ2_15 */
+       { 0x0E35, 0x040A },  /* R3637  - EQ2_16 */
+       { 0x0E36, 0x1F14 },  /* R3638  - EQ2_17 */
+       { 0x0E37, 0x058C },  /* R3639  - EQ2_18 */
+       { 0x0E38, 0x0563 },  /* R3640  - EQ2_19 */
+       { 0x0E39, 0x4000 },  /* R3641  - EQ2_20 */
+       { 0x0E3C, 0x6318 },  /* R3644  - EQ3_1 */
+       { 0x0E3D, 0x6300 },  /* R3645  - EQ3_2 */
+       { 0x0E3E, 0x0FC8 },  /* R3646  - EQ3_3 */
+       { 0x0E3F, 0x03FE },  /* R3647  - EQ3_4 */
+       { 0x0E40, 0x00E0 },  /* R3648  - EQ3_5 */
+       { 0x0E41, 0x1EC4 },  /* R3649  - EQ3_6 */
+       { 0x0E42, 0xF136 },  /* R3650  - EQ3_7 */
+       { 0x0E43, 0x0409 },  /* R3651  - EQ3_8 */
+       { 0x0E44, 0x04CC },  /* R3652  - EQ3_9 */
+       { 0x0E45, 0x1C9B },  /* R3653  - EQ3_10 */
+       { 0x0E46, 0xF337 },  /* R3654  - EQ3_11 */
+       { 0x0E47, 0x040B },  /* R3655  - EQ3_12 */
+       { 0x0E48, 0x0CBB },  /* R3656  - EQ3_13 */
+       { 0x0E49, 0x16F8 },  /* R3657  - EQ3_14 */
+       { 0x0E4A, 0xF7D9 },  /* R3658  - EQ3_15 */
+       { 0x0E4B, 0x040A },  /* R3659  - EQ3_16 */
+       { 0x0E4C, 0x1F14 },  /* R3660  - EQ3_17 */
+       { 0x0E4D, 0x058C },  /* R3661  - EQ3_18 */
+       { 0x0E4E, 0x0563 },  /* R3662  - EQ3_19 */
+       { 0x0E4F, 0x4000 },  /* R3663  - EQ3_20 */
+       { 0x0E52, 0x6318 },  /* R3666  - EQ4_1 */
+       { 0x0E53, 0x6300 },  /* R3667  - EQ4_2 */
+       { 0x0E54, 0x0FC8 },  /* R3668  - EQ4_3 */
+       { 0x0E55, 0x03FE },  /* R3669  - EQ4_4 */
+       { 0x0E56, 0x00E0 },  /* R3670  - EQ4_5 */
+       { 0x0E57, 0x1EC4 },  /* R3671  - EQ4_6 */
+       { 0x0E58, 0xF136 },  /* R3672  - EQ4_7 */
+       { 0x0E59, 0x0409 },  /* R3673  - EQ4_8 */
+       { 0x0E5A, 0x04CC },  /* R3674  - EQ4_9 */
+       { 0x0E5B, 0x1C9B },  /* R3675  - EQ4_10 */
+       { 0x0E5C, 0xF337 },  /* R3676  - EQ4_11 */
+       { 0x0E5D, 0x040B },  /* R3677  - EQ4_12 */
+       { 0x0E5E, 0x0CBB },  /* R3678  - EQ4_13 */
+       { 0x0E5F, 0x16F8 },  /* R3679  - EQ4_14 */
+       { 0x0E60, 0xF7D9 },  /* R3680  - EQ4_15 */
+       { 0x0E61, 0x040A },  /* R3681  - EQ4_16 */
+       { 0x0E62, 0x1F14 },  /* R3682  - EQ4_17 */
+       { 0x0E63, 0x058C },  /* R3683  - EQ4_18 */
+       { 0x0E64, 0x0563 },  /* R3684  - EQ4_19 */
+       { 0x0E65, 0x4000 },  /* R3685  - EQ4_20 */
+       { 0x0E80, 0x0018 },  /* R3712  - DRC1 ctrl1 */
+       { 0x0E81, 0x0933 },  /* R3713  - DRC1 ctrl2 */
+       { 0x0E82, 0x0018 },  /* R3714  - DRC1 ctrl3 */
+       { 0x0E83, 0x0000 },  /* R3715  - DRC1 ctrl4 */
+       { 0x0E84, 0x0000 },  /* R3716  - DRC1 ctrl5 */
+       { 0x0EC0, 0x0000 },  /* R3776  - HPLPF1_1 */
+       { 0x0EC1, 0x0000 },  /* R3777  - HPLPF1_2 */
+       { 0x0EC4, 0x0000 },  /* R3780  - HPLPF2_1 */
+       { 0x0EC5, 0x0000 },  /* R3781  - HPLPF2_2 */
+       { 0x0EC8, 0x0000 },  /* R3784  - HPLPF3_1 */
+       { 0x0EC9, 0x0000 },  /* R3785  - HPLPF3_2 */
+       { 0x0ECC, 0x0000 },  /* R3788  - HPLPF4_1 */
+       { 0x0ECD, 0x0000 },  /* R3789  - HPLPF4_2 */
 };
index 42d9039a49e93863ba3adfb046a5b8d1f43a8515..8b24323d6b2c89ecb5a751b17e1e747cb2d35807 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/fixed.h>
 #include <linux/slab.h>
@@ -51,6 +50,7 @@ struct wm5100_fll {
 
 /* codec private data */
 struct wm5100_priv {
+       struct regmap *regmap;
        struct snd_soc_codec *codec;
 
        struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES];
@@ -204,17 +204,15 @@ static void wm5100_free_sr(struct snd_soc_codec *codec, int rate)
        }
 }
 
-static int wm5100_reset(struct snd_soc_codec *codec)
+static int wm5100_reset(struct wm5100_priv *wm5100)
 {
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
-
        if (wm5100->pdata.reset) {
                gpio_set_value_cansleep(wm5100->pdata.reset, 0);
                gpio_set_value_cansleep(wm5100->pdata.reset, 1);
 
                return 0;
        } else {
-               return snd_soc_write(codec, WM5100_SOFTWARE_RESET, 0);
+               return regmap_write(wm5100->regmap, WM5100_SOFTWARE_RESET, 0);
        }
 }
 
@@ -954,7 +952,7 @@ SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
-SND_SOC_DAPM_INPUT("TONE"),
+SND_SOC_DAPM_SIGGEN("TONE"),
 
 SND_SOC_DAPM_PGA_E("IN1L PGA", WM5100_INPUT_ENABLES, WM5100_IN1L_ENA_SHIFT, 0,
                   NULL, 0, wm5100_out_ev, SND_SOC_DAPM_POST_PMU),
@@ -1375,7 +1373,7 @@ static int wm5100_set_bias_level(struct snd_soc_codec *codec,
                                msleep(2);
                        }
 
-                       codec->cache_only = false;
+                       regcache_cache_only(wm5100->regmap, false);
 
                        switch (wm5100->rev) {
                        case 0:
@@ -1399,7 +1397,7 @@ static int wm5100_set_bias_level(struct snd_soc_codec *codec,
                                break;
                        }
 
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm5100->regmap);
                }
                break;
 
@@ -1662,7 +1660,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops wm5100_dai_ops = {
+static const struct snd_soc_dai_ops wm5100_dai_ops = {
        .set_fmt = wm5100_set_fmt,
        .hw_params = wm5100_hw_params,
 };
@@ -1993,6 +1991,9 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        else
                timeout = 50;
 
+       snd_soc_update_bits(codec, WM5100_CLOCKING_3, WM5100_SYSCLK_ENA,
+                           WM5100_SYSCLK_ENA);
+
        /* Poll for the lock; will use interrupt when we can test */
        for (i = 0; i < timeout; i++) {
                if (i2c->irq) {
@@ -2350,24 +2351,22 @@ static inline struct wm5100_priv *gpio_to_wm5100(struct gpio_chip *chip)
 static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
-       struct snd_soc_codec *codec = wm5100->codec;
 
-       snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
-                           WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
+       regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+                          WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
 }
 
 static int wm5100_gpio_direction_out(struct gpio_chip *chip,
                                     unsigned offset, int value)
 {
        struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
-       struct snd_soc_codec *codec = wm5100->codec;
        int val, ret;
 
        val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
 
-       ret = snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
-                                 WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
-                                 WM5100_GP1_LVL, val);
+       ret = regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+                                WM5100_GP1_FN_MASK | WM5100_GP1_DIR |
+                                WM5100_GP1_LVL, val);
        if (ret < 0)
                return ret;
        else
@@ -2377,25 +2376,24 @@ static int wm5100_gpio_direction_out(struct gpio_chip *chip,
 static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
-       struct snd_soc_codec *codec = wm5100->codec;
+       unsigned int reg;
        int ret;
 
-       ret = snd_soc_read(codec, WM5100_GPIO_CTRL_1 + offset);
+       ret = regmap_read(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset, &reg);
        if (ret < 0)
                return ret;
 
-       return (ret & WM5100_GP1_LVL) != 0;
+       return (reg & WM5100_GP1_LVL) != 0;
 }
 
 static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
-       struct snd_soc_codec *codec = wm5100->codec;
 
-       return snd_soc_update_bits(codec, WM5100_GPIO_CTRL_1 + offset,
-                                  WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
-                                  (1 << WM5100_GP1_FN_SHIFT) |
-                                  (1 << WM5100_GP1_DIR_SHIFT));
+       return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
+                                 WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
+                                 (1 << WM5100_GP1_FN_SHIFT) |
+                                 (1 << WM5100_GP1_DIR_SHIFT));
 }
 
 static struct gpio_chip wm5100_template_chip = {
@@ -2408,14 +2406,14 @@ static struct gpio_chip wm5100_template_chip = {
        .can_sleep              = 1,
 };
 
-static void wm5100_init_gpio(struct snd_soc_codec *codec)
+static void wm5100_init_gpio(struct i2c_client *i2c)
 {
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+       struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
        int ret;
 
        wm5100->gpio_chip = wm5100_template_chip;
        wm5100->gpio_chip.ngpio = 6;
-       wm5100->gpio_chip.dev = codec->dev;
+       wm5100->gpio_chip.dev = &i2c->dev;
 
        if (wm5100->pdata.gpio_base)
                wm5100->gpio_chip.base = wm5100->pdata.gpio_base;
@@ -2424,24 +2422,24 @@ static void wm5100_init_gpio(struct snd_soc_codec *codec)
 
        ret = gpiochip_add(&wm5100->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
 }
 
-static void wm5100_free_gpio(struct snd_soc_codec *codec)
+static void wm5100_free_gpio(struct i2c_client *i2c)
 {
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
+       struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
        int ret;
 
        ret = gpiochip_remove(&wm5100->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
 }
 #else
-static void wm5100_init_gpio(struct snd_soc_codec *codec)
+static void wm5100_init_gpio(struct i2c_client *i2c)
 {
 }
 
-static void wm5100_free_gpio(struct snd_soc_codec *codec)
+static void wm5100_free_gpio(struct i2c_client *i2c)
 {
 }
 #endif
@@ -2453,131 +2451,21 @@ static int wm5100_probe(struct snd_soc_codec *codec)
        int ret, i, irq_flags;
 
        wm5100->codec = codec;
+       codec->control_data = wm5100->regmap;
 
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
-               wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
-
-       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies),
-                                wm5100->core_supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request core supplies: %d\n",
-                       ret);
-               return ret;
-       }
-
-       wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD");
-       if (IS_ERR(wm5100->cpvdd)) {
-               ret = PTR_ERR(wm5100->cpvdd);
-               dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
-               goto err_core;
-       }
-
-       wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2");
-       if (IS_ERR(wm5100->dbvdd2)) {
-               ret = PTR_ERR(wm5100->dbvdd2);
-               dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
-               goto err_cpvdd;
-       }
+       regcache_cache_only(wm5100->regmap, true);
 
-       wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3");
-       if (IS_ERR(wm5100->dbvdd3)) {
-               ret = PTR_ERR(wm5100->dbvdd3);
-               dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
-               goto err_dbvdd2;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
-                                   wm5100->core_supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable core supplies: %d\n",
-                       ret);
-               goto err_dbvdd3;
-       }
-
-       if (wm5100->pdata.ldo_ena) {
-               ret = gpio_request_one(wm5100->pdata.ldo_ena,
-                                      GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
-               if (ret < 0) {
-                       dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
-                               wm5100->pdata.ldo_ena, ret);
-                       goto err_enable;
-               }
-               msleep(2);
-       }
-
-       if (wm5100->pdata.reset) {
-               ret = gpio_request_one(wm5100->pdata.reset,
-                                      GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
-               if (ret < 0) {
-                       dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
-                               wm5100->pdata.reset, ret);
-                       goto err_ldo;
-               }
-       }
-
-       ret = snd_soc_read(codec, WM5100_SOFTWARE_RESET);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read ID register\n");
-               goto err_reset;
-       }
-       switch (ret) {
-       case 0x8997:
-       case 0x5100:
-               break;
-
-       default:
-               dev_err(codec->dev, "Device is not a WM5100, ID is %x\n", ret);
-               ret = -EINVAL;
-               goto err_reset;
-       }
-
-       ret = snd_soc_read(codec, WM5100_DEVICE_REVISION);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read revision register\n");
-               goto err_reset;
-       }
-       wm5100->rev = ret & WM5100_DEVICE_REVISION_MASK;
-
-       dev_info(codec->dev, "revision %c\n", wm5100->rev + 'A');
-
-       ret = wm5100_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_reset;
-       }
-
-       codec->cache_only = true;
-
-       wm5100_init_gpio(codec);
 
        for (i = 0; i < ARRAY_SIZE(wm5100_dig_vu); i++)
                snd_soc_update_bits(codec, wm5100_dig_vu[i], WM5100_OUT_VU,
                                    WM5100_OUT_VU);
 
-       for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
-               snd_soc_update_bits(codec, WM5100_IN1L_CONTROL,
-                                   WM5100_IN1_MODE_MASK |
-                                   WM5100_IN1_DMIC_SUP_MASK,
-                                   (wm5100->pdata.in_mode[i] <<
-                                    WM5100_IN1_MODE_SHIFT) |
-                                   (wm5100->pdata.dmic_sup[i] <<
-                                    WM5100_IN1_DMIC_SUP_SHIFT));
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
-               if (!wm5100->pdata.gpio_defaults[i])
-                       continue;
-
-               snd_soc_write(codec, WM5100_GPIO_CTRL_1 + i,
-                             wm5100->pdata.gpio_defaults[i]);
-       }
-
        /* Don't debounce interrupts to support use of SYSCLK only */
        snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_1, 0);
        snd_soc_write(codec, WM5100_IRQ_DEBOUNCE_2, 0);
@@ -2662,29 +2550,6 @@ static int wm5100_probe(struct snd_soc_codec *codec)
 err_gpio:
        if (i2c->irq)
                free_irq(i2c->irq, codec);
-       wm5100_free_gpio(codec);
-err_reset:
-       if (wm5100->pdata.reset) {
-               gpio_set_value_cansleep(wm5100->pdata.reset, 1);
-               gpio_free(wm5100->pdata.reset);
-       }
-err_ldo:
-       if (wm5100->pdata.ldo_ena) {
-               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-               gpio_free(wm5100->pdata.ldo_ena);
-       }
-err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
-                              wm5100->core_supplies);
-err_dbvdd3:
-       regulator_put(wm5100->dbvdd3);
-err_dbvdd2:
-       regulator_put(wm5100->dbvdd2);
-err_cpvdd:
-       regulator_put(wm5100->cpvdd);
-err_core:
-       regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
-                           wm5100->core_supplies);
 
        return ret;
 }
@@ -2700,23 +2565,16 @@ static int wm5100_remove(struct snd_soc_codec *codec)
        }
        if (i2c->irq)
                free_irq(i2c->irq, codec);
-       wm5100_free_gpio(codec);
-       if (wm5100->pdata.reset) {
-               gpio_set_value_cansleep(wm5100->pdata.reset, 1);
-               gpio_free(wm5100->pdata.reset);
-       }
-       if (wm5100->pdata.ldo_ena) {
-               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
-               gpio_free(wm5100->pdata.ldo_ena);
-       }
-       regulator_put(wm5100->dbvdd3);
-       regulator_put(wm5100->dbvdd2);
-       regulator_put(wm5100->cpvdd);
-       regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
-                           wm5100->core_supplies);
        return 0;
 }
 
+static int wm5100_soc_volatile(struct snd_soc_codec *codec,
+                              unsigned int reg)
+{
+       return true;
+}
+
+
 static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
        .probe =        wm5100_probe,
        .remove =       wm5100_remove,
@@ -2725,6 +2583,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
        .set_pll = wm5100_set_fll,
        .set_bias_level = wm5100_set_bias_level,
        .idle_bias_off = 1,
+       .reg_cache_size = WM5100_MAX_REGISTER,
+       .volatile_register = wm5100_soc_volatile,
 
        .seq_notifier = wm5100_seq_notifier,
        .controls = wm5100_snd_controls,
@@ -2733,14 +2593,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = {
        .num_dapm_widgets = ARRAY_SIZE(wm5100_dapm_widgets),
        .dapm_routes = wm5100_dapm_routes,
        .num_dapm_routes = ARRAY_SIZE(wm5100_dapm_routes),
+};
 
-       .reg_cache_size = ARRAY_SIZE(wm5100_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .compress_type = SND_SOC_RBTREE_COMPRESSION,
-       .reg_cache_default = wm5100_reg_defaults,
+static const struct regmap_config wm5100_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
 
-       .volatile_register = wm5100_volatile_register,
-       .readable_register = wm5100_readable_register,
+       .max_register = WM5100_MAX_REGISTER,
+       .reg_defaults = wm5100_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm5100_reg_defaults),
+       .volatile_reg = wm5100_volatile_register,
+       .readable_reg = wm5100_readable_register,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
@@ -2748,12 +2612,22 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
 {
        struct wm5100_pdata *pdata = dev_get_platdata(&i2c->dev);
        struct wm5100_priv *wm5100;
+       unsigned int reg;
        int ret, i;
 
-       wm5100 = kzalloc(sizeof(struct wm5100_priv), GFP_KERNEL);
+       wm5100 = devm_kzalloc(&i2c->dev, sizeof(struct wm5100_priv),
+                             GFP_KERNEL);
        if (wm5100 == NULL)
                return -ENOMEM;
 
+       wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
+       if (IS_ERR(wm5100->regmap)) {
+               ret = PTR_ERR(wm5100->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               goto err;
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm5100->fll); i++)
                init_completion(&wm5100->fll[i].lock);
 
@@ -2762,21 +2636,178 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, wm5100);
 
+       for (i = 0; i < ARRAY_SIZE(wm5100->core_supplies); i++)
+               wm5100->core_supplies[i].supply = wm5100_core_supply_names[i];
+
+       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm5100->core_supplies),
+                                wm5100->core_supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
+                       ret);
+               goto err_regmap;
+       }
+
+       wm5100->cpvdd = regulator_get(&i2c->dev, "CPVDD");
+       if (IS_ERR(wm5100->cpvdd)) {
+               ret = PTR_ERR(wm5100->cpvdd);
+               dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
+               goto err_core;
+       }
+
+       wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2");
+       if (IS_ERR(wm5100->dbvdd2)) {
+               ret = PTR_ERR(wm5100->dbvdd2);
+               dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
+               goto err_cpvdd;
+       }
+
+       wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3");
+       if (IS_ERR(wm5100->dbvdd3)) {
+               ret = PTR_ERR(wm5100->dbvdd3);
+               dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret);
+               goto err_dbvdd2;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
+                                   wm5100->core_supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
+                       ret);
+               goto err_dbvdd3;
+       }
+
+       if (wm5100->pdata.ldo_ena) {
+               ret = gpio_request_one(wm5100->pdata.ldo_ena,
+                                      GPIOF_OUT_INIT_HIGH, "WM5100 LDOENA");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
+                               wm5100->pdata.ldo_ena, ret);
+                       goto err_enable;
+               }
+               msleep(2);
+       }
+
+       if (wm5100->pdata.reset) {
+               ret = gpio_request_one(wm5100->pdata.reset,
+                                      GPIOF_OUT_INIT_HIGH, "WM5100 /RESET");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
+                               wm5100->pdata.reset, ret);
+                       goto err_ldo;
+               }
+       }
+
+       ret = regmap_read(wm5100->regmap, WM5100_SOFTWARE_RESET, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read ID register\n");
+               goto err_reset;
+       }
+       switch (reg) {
+       case 0x8997:
+       case 0x5100:
+               break;
+
+       default:
+               dev_err(&i2c->dev, "Device is not a WM5100, ID is %x\n", reg);
+               ret = -EINVAL;
+               goto err_reset;
+       }
+
+       ret = regmap_read(wm5100->regmap, WM5100_DEVICE_REVISION, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read revision register\n");
+               goto err_reset;
+       }
+       wm5100->rev = reg & WM5100_DEVICE_REVISION_MASK;
+
+       dev_info(&i2c->dev, "revision %c\n", wm5100->rev + 'A');
+
+       ret = wm5100_reset(wm5100);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to issue reset\n");
+               goto err_reset;
+       }
+
+       wm5100_init_gpio(i2c);
+
+       for (i = 0; i < ARRAY_SIZE(wm5100->pdata.gpio_defaults); i++) {
+               if (!wm5100->pdata.gpio_defaults[i])
+                       continue;
+
+               regmap_write(wm5100->regmap, WM5100_GPIO_CTRL_1 + i,
+                            wm5100->pdata.gpio_defaults[i]);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm5100->pdata.in_mode); i++) {
+               regmap_update_bits(wm5100->regmap, WM5100_IN1L_CONTROL,
+                                  WM5100_IN1_MODE_MASK |
+                                  WM5100_IN1_DMIC_SUP_MASK,
+                                  (wm5100->pdata.in_mode[i] <<
+                                   WM5100_IN1_MODE_SHIFT) |
+                                  (wm5100->pdata.dmic_sup[i] <<
+                                   WM5100_IN1_DMIC_SUP_SHIFT));
+       }
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm5100, wm5100_dai,
                                     ARRAY_SIZE(wm5100_dai));
        if (ret < 0) {
                dev_err(&i2c->dev, "Failed to register WM5100: %d\n", ret);
-               kfree(wm5100);
+               goto err_reset;
        }
 
        return ret;
+
+err_reset:
+       wm5100_free_gpio(i2c);
+       if (wm5100->pdata.reset) {
+               gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+               gpio_free(wm5100->pdata.reset);
+       }
+err_ldo:
+       if (wm5100->pdata.ldo_ena) {
+               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+               gpio_free(wm5100->pdata.ldo_ena);
+       }
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+                              wm5100->core_supplies);
+err_dbvdd3:
+       regulator_put(wm5100->dbvdd3);
+err_dbvdd2:
+       regulator_put(wm5100->dbvdd2);
+err_cpvdd:
+       regulator_put(wm5100->cpvdd);
+err_core:
+       regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
+                           wm5100->core_supplies);
+err_regmap:
+       regmap_exit(wm5100->regmap);
+err:
+       return ret;
 }
 
 static __devexit int wm5100_i2c_remove(struct i2c_client *client)
 {
+       struct wm5100_priv *wm5100 = i2c_get_clientdata(client);
+
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+       wm5100_free_gpio(client);
+       if (wm5100->pdata.reset) {
+               gpio_set_value_cansleep(wm5100->pdata.reset, 1);
+               gpio_free(wm5100->pdata.reset);
+       }
+       if (wm5100->pdata.ldo_ena) {
+               gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
+               gpio_free(wm5100->pdata.ldo_ena);
+       }
+       regulator_put(wm5100->dbvdd3);
+       regulator_put(wm5100->dbvdd2);
+       regulator_put(wm5100->cpvdd);
+       regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies),
+                           wm5100->core_supplies);
+       regmap_exit(wm5100->regmap);
+
        return 0;
 }
 
index 970759636bdc508b10603aa7fd8da6765043ad7c..25cb6016f9d7f37ce7eb855c66930ba27f06bd90 100644 (file)
@@ -15,6 +15,7 @@
 #define WM5100_ASOC_H
 
 #include <sound/soc.h>
+#include <linux/regmap.h>
 
 int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 
@@ -5147,9 +5148,9 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
 #define WM5100_DSP3_ZM_END_SHIFT                     0  /* DSP3_ZM_END - [15:0] */
 #define WM5100_DSP3_ZM_END_WIDTH                    16  /* DSP3_ZM_END - [15:0] */
 
-int wm5100_readable_register(struct snd_soc_codec *codec, unsigned int reg);
-int wm5100_volatile_register(struct snd_soc_codec *codec, unsigned int reg);
+bool wm5100_readable_register(struct device *dev, unsigned int reg);
+bool wm5100_volatile_register(struct device *dev, unsigned int reg);
 
-extern u16 wm5100_reg_defaults[WM5100_MAX_REGISTER + 1];
+extern struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT];
 
 #endif
index 35f3ad83dfb6670013652772268385b75cda481a..8c4c9591ec055103eb1cf3381ae3e3d969abac85 100644 (file)
@@ -696,7 +696,7 @@ static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("IN3L"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8350_dapm_routes[] = {
 
        /* left playback mixer */
        {"Left Playback Mixer", "Playback Switch", "Left DAC"},
@@ -777,29 +777,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Beep", NULL, "IN3R PGA"},
 };
 
-static int wm8350_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       ret = snd_soc_dapm_new_controls(dapm,
-                                       wm8350_dapm_widgets,
-                                       ARRAY_SIZE(wm8350_dapm_widgets));
-       if (ret != 0) {
-               dev_err(codec->dev, "dapm control register failed\n");
-               return ret;
-       }
-
-       /* set up audio paths */
-       ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-       if (ret != 0) {
-               dev_err(codec->dev, "DAPM route register failed\n");
-               return ret;
-       }
-
-       return 0;
-}
-
 static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                                 int clk_id, unsigned int freq, int dir)
 {
@@ -1315,7 +1292,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8350_suspend(struct snd_soc_codec *codec)
 {
        wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1511,7 +1488,7 @@ EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
                        SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8350_dai_ops = {
+static const struct snd_soc_dai_ops wm8350_dai_ops = {
         .hw_params     = wm8350_pcm_hw_params,
         .digital_mute  = wm8350_mute,
         .trigger       = wm8350_pcm_trigger,
@@ -1553,7 +1530,8 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+       priv = devm_kzalloc(codec->dev, sizeof(struct wm8350_data),
+                           GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, priv);
@@ -1564,7 +1542,7 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
                                 priv->supplies);
        if (ret != 0)
-               goto err_priv;
+               return ret;
 
        wm8350->codec.codec = codec;
        codec->control_data = wm8350;
@@ -1633,17 +1611,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
                            wm8350_mic_handler, 0, "Microphone detect", priv);
 
 
-       snd_soc_add_controls(codec, wm8350_snd_controls,
-                               ARRAY_SIZE(wm8350_snd_controls));
-       wm8350_add_widgets(codec);
-
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
-
-err_priv:
-       kfree(priv);
-       return ret;
 }
 
 static int  wm8350_codec_remove(struct snd_soc_codec *codec)
@@ -1676,7 +1646,7 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
        regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-       kfree(priv);
+
        return 0;
 }
 
@@ -1688,6 +1658,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
        .read = wm8350_codec_read,
        .write = wm8350_codec_write,
        .set_bias_level = wm8350_set_bias_level,
+
+       .controls = wm8350_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8350_snd_controls),
+       .dapm_widgets = wm8350_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets),
+       .dapm_routes = wm8350_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes),
 };
 
 static int __devinit wm8350_probe(struct platform_device *pdev)
@@ -1711,17 +1688,7 @@ static struct platform_driver wm8350_codec_driver = {
        .remove = __devexit_p(wm8350_remove),
 };
 
-static __init int wm8350_init(void)
-{
-       return platform_driver_register(&wm8350_codec_driver);
-}
-module_init(wm8350_init);
-
-static __exit void wm8350_exit(void)
-{
-       platform_driver_unregister(&wm8350_codec_driver);
-}
-module_exit(wm8350_exit);
+module_platform_driver(wm8350_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM8350 driver");
 MODULE_AUTHOR("Liam Girdwood");
index dc13be2a09c52b64b95aee07eb9d4061485c8b56..898979d23010e3f5f50cc00070c4d6d56b92b58f 100644 (file)
@@ -353,13 +353,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
 
 };
 
-/* add non dapm controls */
-static int wm8400_add_controls(struct snd_soc_codec *codec)
-{
-       return snd_soc_add_controls(codec, wm8400_snd_controls,
-                               ARRAY_SIZE(wm8400_snd_controls));
-}
-
 /*
  * _DAPM_ Controls
  */
@@ -766,8 +759,8 @@ SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0,
        NULL, 0),
 
 /* MICBIAS */
-SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1,
-       WM8400_MIC1BIAS_ENA_SHIFT, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8400_POWER_MANAGEMENT_1,
+                   WM8400_MIC1BIAS_ENA_SHIFT, 0, NULL, 0),
 
 SND_SOC_DAPM_OUTPUT("LON"),
 SND_SOC_DAPM_OUTPUT("LOP"),
@@ -783,7 +776,7 @@ SND_SOC_DAPM_OUTPUT("RON"),
 SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
        /* Make DACs turn on when playing even if not mixed into any outputs */
        {"Internal DAC Sink", NULL, "Left DAC"},
        {"Internal DAC Sink", NULL, "Right DAC"},
@@ -909,17 +902,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"RON", NULL, "RONMIX"},
 };
 
-static int wm8400_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8400_dapm_widgets,
-                                 ARRAY_SIZE(wm8400_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /*
  * Clock after FLL and dividers
  */
@@ -1059,7 +1041,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
 
        reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
-       reg &= WM8400_FLL_OUTDIV_MASK;
+       reg &= ~WM8400_FLL_OUTDIV_MASK;
        reg |= factors.outdiv;
        wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
 
@@ -1316,7 +1298,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
 #define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8400_dai_ops = {
+static const struct snd_soc_dai_ops wm8400_dai_ops = {
        .hw_params = wm8400_hw_params,
        .digital_mute = wm8400_mute,
        .set_fmt = wm8400_set_dai_fmt,
@@ -1352,7 +1334,7 @@ static struct snd_soc_dai_driver wm8400_dai = {
        .ops = &wm8400_dai_ops,
 };
 
-static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8400_suspend(struct snd_soc_codec *codec)
 {
        wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1383,7 +1365,8 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
        int ret;
        u16 reg;
 
-       priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
+       priv = devm_kzalloc(codec->dev, sizeof(struct wm8400_priv),
+                           GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
 
@@ -1395,7 +1378,7 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
                                 ARRAY_SIZE(power), &power[0]);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        INIT_WORK(&priv->work, wm8400_probe_deferred);
@@ -1420,20 +1403,15 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
                ret = -EINVAL;
                goto err_regulator;
        }
-       wm8400_add_controls(codec);
-       wm8400_add_widgets(codec);
        return 0;
 
 err_regulator:
        regulator_bulk_free(ARRAY_SIZE(power), power);
-err:
-       kfree(priv);
        return ret;
 }
 
 static int  wm8400_codec_remove(struct snd_soc_codec *codec)
 {
-       struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
        u16 reg;
 
        reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
@@ -1441,7 +1419,6 @@ static int  wm8400_codec_remove(struct snd_soc_codec *codec)
                     reg & (~WM8400_CODEC_ENA));
 
        regulator_bulk_free(ARRAY_SIZE(power), power);
-       kfree(priv);
 
        return 0;
 }
@@ -1454,6 +1431,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
        .read = wm8400_read,
        .write = wm8400_write,
        .set_bias_level = wm8400_set_bias_level,
+
+       .controls = wm8400_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8400_snd_controls),
+       .dapm_widgets = wm8400_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8400_dapm_widgets),
+       .dapm_routes = wm8400_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8400_dapm_routes),
 };
 
 static int __devinit wm8400_probe(struct platform_device *pdev)
@@ -1477,17 +1461,7 @@ static struct platform_driver wm8400_codec_driver = {
        .remove = __devexit_p(wm8400_remove),
 };
 
-static __init int wm8400_init(void)
-{
-       return platform_driver_register(&wm8400_codec_driver);
-}
-module_init(wm8400_init);
-
-static __exit void wm8400_exit(void)
-{
-       platform_driver_unregister(&wm8400_codec_driver);
-}
-module_exit(wm8400_exit);
+module_platform_driver(wm8400_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM8400 driver");
 MODULE_AUTHOR("Mark Brown");
index 07c9cc759e97706a308d0489bac40a0f0482fdd1..9166126bd31259f10fa56c7b224029e7f7a7b0cc 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -182,7 +181,7 @@ SND_SOC_DAPM_OUTPUT("SPKOUTP"),
 SND_SOC_DAPM_OUTPUT("SPKOUTN"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8510_dapm_routes[] = {
        /* Mono output mixer */
        {"Mono Mixer", "PCM Playback Switch", "DAC"},
        {"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -214,17 +213,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"ADC", NULL, "Boost Mixer"},
 };
 
-static int wm8510_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8510_dapm_widgets,
-                                 ARRAY_SIZE(wm8510_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 struct pll_ {
        unsigned int pre_div:4; /* prescale - 1 */
        unsigned int n:4;
@@ -509,7 +497,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
 #define WM8510_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 wm8510_dai_ops = {
+static const struct snd_soc_dai_ops wm8510_dai_ops = {
        .hw_params      = wm8510_pcm_hw_params,
        .digital_mute   = wm8510_mute,
        .set_fmt        = wm8510_set_dai_fmt,
@@ -535,7 +523,7 @@ static struct snd_soc_dai_driver wm8510_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec)
 {
        wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -562,9 +550,6 @@ static int wm8510_probe(struct snd_soc_codec *codec)
 
        /* power on device */
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       snd_soc_add_controls(codec, wm8510_snd_controls,
-                               ARRAY_SIZE(wm8510_snd_controls));
-       wm8510_add_widgets(codec);
 
        return ret;
 }
@@ -588,6 +573,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
        .reg_cache_size = ARRAY_SIZE(wm8510_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default =wm8510_reg,
+
+       .controls = wm8510_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8510_snd_controls),
+       .dapm_widgets = wm8510_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8510_dapm_widgets),
+       .dapm_routes = wm8510_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8510_dapm_routes),
 };
 
 static const struct of_device_id wm8510_of_match[] = {
@@ -667,7 +659,7 @@ MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
 
 static struct i2c_driver wm8510_i2c_driver = {
        .driver = {
-               .name = "wm8510-codec",
+               .name = "wm8510",
                .owner = THIS_MODULE,
                .of_match_table = wm8510_of_match,
        },
index db7a6819499fa59a1597f5c93066149e08d3c2ac..7fea2c3bf7e77dbf16096709df41004cf88ffdbf 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -365,7 +364,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
 #define WM8523_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 wm8523_dai_ops = {
+static const struct snd_soc_dai_ops wm8523_dai_ops = {
        .startup        = wm8523_startup,
        .hw_params      = wm8523_hw_params,
        .set_sysclk     = wm8523_set_dai_sysclk,
@@ -385,7 +384,7 @@ static struct snd_soc_dai_driver wm8523_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8523_suspend(struct snd_soc_codec *codec)
 {
        wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
index 8212b3c8bfdd90da61cfe426344c13aa6deadae8..211285164d70eb1ddf6dc4f86e084a124e136729 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -273,7 +272,7 @@ SND_SOC_DAPM_INPUT("AINL"),
 SND_SOC_DAPM_INPUT("AINR"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8580_dapm_routes[] = {
        { "VOUT1L", NULL, "DAC1" },
        { "VOUT1R", NULL, "DAC1" },
 
@@ -287,17 +286,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "ADC", NULL, "AINR" },
 };
 
-static int wm8580_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets,
-                                 ARRAY_SIZE(wm8580_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /* PLL divisors */
 struct _pll_div {
        u32 prescale:1;
@@ -682,7 +670,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
-       int sel, sel_mask, sel_shift;
+       int ret, sel, sel_mask, sel_shift;
 
        switch (dai->driver->id) {
        case WM8580_DAI_PAIFRX:
@@ -723,7 +711,11 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        /* We really should validate PLL settings but not yet */
        wm8580->sysclk[dai->driver->id] = freq;
 
-       return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+       ret = snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
@@ -776,7 +768,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
 #define WM8580_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 wm8580_dai_ops_playback = {
+static const struct snd_soc_dai_ops wm8580_dai_ops_playback = {
        .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
@@ -785,7 +777,7 @@ static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
        .digital_mute   = wm8580_digital_mute,
 };
 
-static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+static const struct snd_soc_dai_ops wm8580_dai_ops_capture = {
        .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
@@ -857,10 +849,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)
 
        wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       snd_soc_add_controls(codec, wm8580_snd_controls,
-                            ARRAY_SIZE(wm8580_snd_controls));
-       wm8580_add_widgets(codec);
-
        return 0;
 
 err_regulator_enable:
@@ -890,6 +878,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
        .reg_cache_size = ARRAY_SIZE(wm8580_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8580_reg,
+
+       .controls = wm8580_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8580_snd_controls),
+       .dapm_widgets = wm8580_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8580_dapm_widgets),
+       .dapm_routes = wm8580_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8580_dapm_routes),
 };
 
 static const struct of_device_id wm8580_of_match[] = {
index 076bdb9930a15d6d50c4edd3d6009a7fad801089..0b76d1dca5eade12cfd3bfd640a665e1f0626b97 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -318,7 +317,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
 #define WM8711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8711_ops = {
+static const struct snd_soc_dai_ops wm8711_ops = {
        .prepare = wm8711_pcm_prepare,
        .hw_params = wm8711_hw_params,
        .shutdown = wm8711_shutdown,
@@ -339,7 +338,7 @@ static struct snd_soc_dai_driver wm8711_dai = {
        .ops = &wm8711_ops,
 };
 
-static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8711_suspend(struct snd_soc_codec *codec)
 {
        snd_soc_write(codec, WM8711_ACTIVE, 0x0);
        wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -375,9 +374,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100);
 
-       snd_soc_add_controls(codec, wm8711_snd_controls,
-                            ARRAY_SIZE(wm8711_snd_controls));
-
        return ret;
 
 }
@@ -398,6 +394,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
        .reg_cache_size = ARRAY_SIZE(wm8711_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8711_reg,
+       .controls = wm8711_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8711_snd_controls),
        .dapm_widgets = wm8711_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
        .dapm_routes = wm8711_intercon,
index 7488082851191ce120a8a66fd8704b53613b8189..e81705620718eacf785fc10ecab3d74a0adbebcb 100644 (file)
@@ -59,7 +59,7 @@ static int __devexit wm8727_remove(struct platform_device *pdev)
 
 static struct platform_driver wm8727_codec_driver = {
        .driver = {
-                       .name = "wm8727-codec",
+                       .name = "wm8727",
                        .owner = THIS_MODULE,
        },
 
@@ -67,17 +67,7 @@ static struct platform_driver wm8727_codec_driver = {
        .remove = __devexit_p(wm8727_remove),
 };
 
-static int __init wm8727_init(void)
-{
-       return platform_driver_register(&wm8727_codec_driver);
-}
-module_init(wm8727_init);
-
-static void __exit wm8727_exit(void)
-{
-       platform_driver_unregister(&wm8727_codec_driver);
-}
-module_exit(wm8727_exit);
+module_platform_driver(wm8727_codec_driver);
 
 MODULE_DESCRIPTION("ASoC wm8727 driver");
 MODULE_AUTHOR("Neil Jones");
index 04b027efd5c003df25769eb92e3ff7a74317a975..fc3d59e4908404491a1801765f29bbacabb3c15c 100644 (file)
@@ -196,7 +196,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8728_dai_ops = {
+static const struct snd_soc_dai_ops wm8728_dai_ops = {
        .hw_params      = wm8728_hw_params,
        .digital_mute   = wm8728_mute,
        .set_fmt        = wm8728_set_dai_fmt,
@@ -214,7 +214,7 @@ static struct snd_soc_dai_driver wm8728_dai = {
        .ops = &wm8728_dai_ops,
 };
 
-static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8728_suspend(struct snd_soc_codec *codec)
 {
        wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -243,9 +243,6 @@ static int wm8728_probe(struct snd_soc_codec *codec)
        /* power on device */
        wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       snd_soc_add_controls(codec, wm8728_snd_controls,
-                               ARRAY_SIZE(wm8728_snd_controls));
-
        return ret;
 }
 
@@ -264,6 +261,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
        .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8728_reg_defaults,
+       .controls = wm8728_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8728_snd_controls),
        .dapm_widgets = wm8728_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
        .dapm_routes = wm8728_intercon,
index a7c9ae17fc7eb0e743a8dbfb27db88fea58a456e..8821af70e660b354e4672a5aa7c32fa5fd7fd3f9 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/of_device.h>
@@ -465,7 +464,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8731_dai_ops = {
+static const struct snd_soc_dai_ops wm8731_dai_ops = {
        .hw_params      = wm8731_hw_params,
        .digital_mute   = wm8731_mute,
        .set_sysclk     = wm8731_set_dai_sysclk,
@@ -491,7 +490,7 @@ static struct snd_soc_dai_driver wm8731_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8731_suspend(struct snd_soc_codec *codec)
 {
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -554,9 +553,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
        /* Disable bypass path by default */
        snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0);
 
-       snd_soc_add_controls(codec, wm8731_snd_controls,
-                            ARRAY_SIZE(wm8731_snd_controls));
-
        /* Regulators will have been enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
@@ -596,6 +592,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
        .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
        .dapm_routes = wm8731_intercon,
        .num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
+       .controls =     wm8731_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8731_snd_controls),
 };
 
 static const struct of_device_id wm8731_of_match[] = {
index f6aef58845c2dc31880529cdaa9510a96735e334..ff95e62c56b9a7ae211c3f2d508d9cff94132931 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
@@ -521,7 +520,7 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
 #define WM8737_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 wm8737_dai_ops = {
+static const struct snd_soc_dai_ops wm8737_dai_ops = {
        .hw_params      = wm8737_hw_params,
        .set_sysclk     = wm8737_set_dai_sysclk,
        .set_fmt        = wm8737_set_dai_fmt,
@@ -540,7 +539,7 @@ static struct snd_soc_dai_driver wm8737_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8737_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8737_suspend(struct snd_soc_codec *codec)
 {
        wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
index 57ad22aacc516dc17e18042a98712266f761afa3..3941f50bf18787b57a9e99555c7f67a28b00eedc 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -86,24 +85,13 @@ SND_SOC_DAPM_OUTPUT("VOUTRP"),
 SND_SOC_DAPM_OUTPUT("VOUTRN"),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8741_dapm_routes[] = {
        { "VOUTLP", NULL, "DACL" },
        { "VOUTLN", NULL, "DACL" },
        { "VOUTRP", NULL, "DACR" },
        { "VOUTRN", NULL, "DACR" },
 };
 
-static int wm8741_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8741_dapm_widgets,
-                                 ARRAY_SIZE(wm8741_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
 static struct {
        int value;
        int ratio;
@@ -382,7 +370,7 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
 #define WM8741_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 wm8741_dai_ops = {
+static const struct snd_soc_dai_ops wm8741_dai_ops = {
        .startup        = wm8741_startup,
        .hw_params      = wm8741_hw_params,
        .set_sysclk     = wm8741_set_dai_sysclk,
@@ -457,10 +445,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
                            WM8741_UPDATERM, WM8741_UPDATERM);
 
-       snd_soc_add_controls(codec, wm8741_snd_controls,
-                            ARRAY_SIZE(wm8741_snd_controls));
-       wm8741_add_widgets(codec);
-
        dev_dbg(codec->dev, "Successful registration\n");
        return ret;
 
@@ -489,6 +473,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8741_reg_defaults,
+
+       .controls = wm8741_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8741_snd_controls),
+       .dapm_widgets = wm8741_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8741_dapm_widgets),
+       .dapm_routes = wm8741_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8741_dapm_routes),
 };
 
 static const struct of_device_id wm8741_of_match[] = {
@@ -504,7 +495,8 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
        struct wm8741_priv *wm8741;
        int ret;
 
-       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+       wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),
+                             GFP_KERNEL);
        if (wm8741 == NULL)
                return -ENOMEM;
 
@@ -513,20 +505,13 @@ static int wm8741_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8741, &wm8741_dai, 1);
-       if (ret != 0)
-               goto err;
 
        return ret;
-
-err:
-       kfree(wm8741);
-       return ret;
 }
 
 static int wm8741_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -554,7 +539,8 @@ static int __devinit wm8741_spi_probe(struct spi_device *spi)
        struct wm8741_priv *wm8741;
        int ret;
 
-       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+       wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),
+                            GFP_KERNEL);
        if (wm8741 == NULL)
                return -ENOMEM;
 
@@ -563,15 +549,12 @@ static int __devinit wm8741_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8741, &wm8741_dai, 1);
-       if (ret < 0)
-               kfree(wm8741);
        return ret;
 }
 
 static int __devexit wm8741_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
index ca75a818070804610d0b7c0d10554e48cbf2f1bd..e4c50ce7d9c0852bce267e0e13b41a759a810ae3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -302,7 +301,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("RINPUT3"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8750_dapm_routes[] = {
        /* left mixer */
        {"Left Mixer", "Playback Switch", "Left DAC"},
        {"Left Mixer", "Left Bypass Switch", "Left Line Mux"},
@@ -396,17 +395,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Right ADC", NULL, "Right ADC Mux"},
 };
 
-static int wm8750_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
-                                 ARRAY_SIZE(wm8750_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 struct _coeff_div {
        u32 mclk;
        u32 rate;
@@ -643,7 +631,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
 #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8750_dai_ops = {
+static const struct snd_soc_dai_ops wm8750_dai_ops = {
        .hw_params      = wm8750_pcm_hw_params,
        .digital_mute   = wm8750_mute,
        .set_fmt        = wm8750_set_dai_fmt,
@@ -667,7 +655,7 @@ static struct snd_soc_dai_driver wm8750_dai = {
        .ops = &wm8750_dai_ops,
 };
 
-static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8750_suspend(struct snd_soc_codec *codec)
 {
        wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -709,9 +697,6 @@ static int wm8750_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8750_LINVOL, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8750_RINVOL, 0x0100, 0x0100);
 
-       snd_soc_add_controls(codec, wm8750_snd_controls,
-                               ARRAY_SIZE(wm8750_snd_controls));
-       wm8750_add_widgets(codec);
        return ret;
 }
 
@@ -730,6 +715,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
        .reg_cache_size = ARRAY_SIZE(wm8750_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8750_reg,
+
+       .controls = wm8750_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8750_snd_controls),
+       .dapm_widgets = wm8750_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+       .dapm_routes = wm8750_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes),
 };
 
 static const struct of_device_id wm8750_of_match[] = {
@@ -745,7 +737,8 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi)
        struct wm8750_priv *wm8750;
        int ret;
 
-       wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
+       wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv),
+                             GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
@@ -754,15 +747,12 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8750, &wm8750_dai, 1);
-       if (ret < 0)
-               kfree(wm8750);
        return ret;
 }
 
 static int __devexit wm8750_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -792,7 +782,8 @@ static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
        struct wm8750_priv *wm8750;
        int ret;
 
-       wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
+       wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv),
+                             GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
@@ -801,15 +792,12 @@ static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8750, &wm8750_dai, 1);
-       if (ret < 0)
-               kfree(wm8750);
        return ret;
 }
 
 static __devexit int wm8750_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 3a629d0d690ed1fbe8129f096e0edf492faf9eb2..b114c19f530ab89c30ea9daa24cc2a0eef143f85 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -486,7 +485,7 @@ SND_SOC_DAPM_INPUT("MIC2"),
 SND_SOC_DAPM_VMID("VREF"),
 };
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8753_dapm_routes[] = {
        /* left mixer */
        {"Left Mixer", "Left Playback Switch", "Left DAC"},
        {"Left Mixer", "Voice Playback Switch", "Voice DAC"},
@@ -640,17 +639,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"ACOP", NULL, "ALC Mixer"},
 };
 
-static int wm8753_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
-                                 ARRAY_SIZE(wm8753_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 /* PLL divisors */
 struct _pll_div {
        u32 div2:1;
@@ -1326,7 +1314,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
  * 3. Voice disabled - HIFI over HIFI
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
-static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
+static const struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_hifi_set_dai_fmt,
@@ -1335,7 +1323,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
        .set_sysclk     = wm8753_set_dai_sysclk,
 };
 
-static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
+static const struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
        .hw_params      = wm8753_pcm_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_voice_set_dai_fmt,
@@ -1392,7 +1380,7 @@ static void wm8753_work(struct work_struct *work)
        wm8753_set_bias_level(codec, dapm->bias_level);
 }
 
-static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8753_suspend(struct snd_soc_codec *codec)
 {
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1467,10 +1455,6 @@ static int wm8753_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8753_LINVOL, 0x0100, 0x0100);
        snd_soc_update_bits(codec, WM8753_RINVOL, 0x0100, 0x0100);
 
-       snd_soc_add_controls(codec, wm8753_snd_controls,
-                            ARRAY_SIZE(wm8753_snd_controls));
-       wm8753_add_widgets(codec);
-
        return 0;
 }
 
@@ -1492,6 +1476,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
        .reg_cache_size = ARRAY_SIZE(wm8753_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8753_reg,
+
+       .controls = wm8753_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8753_snd_controls),
+       .dapm_widgets = wm8753_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8753_dapm_widgets),
+       .dapm_routes = wm8753_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8753_dapm_routes),
 };
 
 static const struct of_device_id wm8753_of_match[] = {
index aa05e6507f844a2ac90c970e939a92efc9de0ff7..19374a9e5ba6ce06fc721e768255fcdb1ea2d97b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/pm.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -528,7 +527,7 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
 #define WM8770_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 wm8770_dai_ops = {
+static const struct snd_soc_dai_ops wm8770_dai_ops = {
        .digital_mute = wm8770_mute,
        .hw_params = wm8770_hw_params,
        .set_fmt = wm8770_set_fmt,
@@ -556,7 +555,7 @@ static struct snd_soc_dai_driver wm8770_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8770_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8770_suspend(struct snd_soc_codec *codec)
 {
        wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -691,13 +690,13 @@ static const struct of_device_id wm8770_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8770_of_match);
 
-#if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8770_spi_probe(struct spi_device *spi)
 {
        struct wm8770_priv *wm8770;
        int ret;
 
-       wm8770 = kzalloc(sizeof(struct wm8770_priv), GFP_KERNEL);
+       wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv),
+                             GFP_KERNEL);
        if (!wm8770)
                return -ENOMEM;
 
@@ -706,15 +705,13 @@ static int __devinit wm8770_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                                     &soc_codec_dev_wm8770, &wm8770_dai, 1);
-       if (ret < 0)
-               kfree(wm8770);
+
        return ret;
 }
 
 static int __devexit wm8770_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -727,28 +724,23 @@ static struct spi_driver wm8770_spi_driver = {
        .probe = wm8770_spi_probe,
        .remove = __devexit_p(wm8770_spi_remove)
 };
-#endif
 
 static int __init wm8770_modinit(void)
 {
        int ret = 0;
 
-#if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8770_spi_driver);
        if (ret) {
                printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n",
                       ret);
        }
-#endif
        return ret;
 }
 module_init(wm8770_modinit);
 
 static void __exit wm8770_exit(void)
 {
-#if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8770_spi_driver);
-#endif
 }
 module_exit(wm8770_exit);
 
index d3b0a20744f1950ee2c0c882f77d72b6ab0a1959..33e97d1d8f4675a46aabdc452ee05122a19550f8 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -328,14 +327,14 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
 #define WM8776_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 wm8776_dac_ops = {
+static const struct snd_soc_dai_ops wm8776_dac_ops = {
        .digital_mute   = wm8776_mute,
        .hw_params      = wm8776_hw_params,
        .set_fmt        = wm8776_set_fmt,
        .set_sysclk     = wm8776_set_sysclk,
 };
 
-static struct snd_soc_dai_ops wm8776_adc_ops = {
+static const struct snd_soc_dai_ops wm8776_adc_ops = {
        .hw_params      = wm8776_hw_params,
        .set_fmt        = wm8776_set_fmt,
        .set_sysclk     = wm8776_set_sysclk,
@@ -373,7 +372,7 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec)
 {
        wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -393,7 +392,6 @@ static int wm8776_resume(struct snd_soc_codec *codec)
 static int wm8776_probe(struct snd_soc_codec *codec)
 {
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret = 0;
 
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
@@ -415,12 +413,6 @@ static int wm8776_probe(struct snd_soc_codec *codec)
        snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
        snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
 
-       snd_soc_add_controls(codec, wm8776_snd_controls,
-                            ARRAY_SIZE(wm8776_snd_controls));
-       snd_soc_dapm_new_controls(dapm, wm8776_dapm_widgets,
-                                 ARRAY_SIZE(wm8776_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
-
        return ret;
 }
 
@@ -440,6 +432,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .reg_cache_size = ARRAY_SIZE(wm8776_reg),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8776_reg,
+
+       .controls = wm8776_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8776_snd_controls),
+       .dapm_widgets = wm8776_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8776_dapm_widgets),
+       .dapm_routes = routes,
+       .num_dapm_routes = ARRAY_SIZE(routes),
 };
 
 static const struct of_device_id wm8776_of_match[] = {
@@ -454,7 +453,8 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi)
        struct wm8776_priv *wm8776;
        int ret;
 
-       wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
+       wm8776 = devm_kzalloc(&spi->dev, sizeof(struct wm8776_priv),
+                             GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
@@ -463,15 +463,13 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi)
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       if (ret < 0)
-               kfree(wm8776);
+
        return ret;
 }
 
 static int __devexit wm8776_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -493,7 +491,8 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
        struct wm8776_priv *wm8776;
        int ret;
 
-       wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
+       wm8776 = devm_kzalloc(&i2c->dev, sizeof(struct wm8776_priv),
+                             GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
@@ -502,15 +501,13 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       if (ret < 0)
-               kfree(wm8776);
+
        return ret;
 }
 
 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index f2ced71328b0a6cc7ee073a4099fd6fd6afe5b15..3fdea98f732ec3814dd96f2150ffa5fe4c6b4349 100644 (file)
@@ -63,17 +63,7 @@ static struct platform_driver wm8782_codec_driver = {
        .remove = __devexit_p(wm8782_remove),
 };
 
-static int __init wm8782_init(void)
-{
-       return platform_driver_register(&wm8782_codec_driver);
-}
-module_init(wm8782_init);
-
-static void __exit wm8782_exit(void)
-{
-       platform_driver_unregister(&wm8782_codec_driver);
-}
-module_exit(wm8782_exit);
+module_platform_driver(wm8782_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM8782 driver");
 MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
index 9ee072b859751ac16b3163c0f5a33833e5eb878a..d54a3ca5e19ee3c72550f464e0032d1caeca0bc3 100644 (file)
@@ -542,7 +542,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
 }
 
 #ifdef CONFIG_PM
-static int wm8804_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8804_suspend(struct snd_soc_codec *codec)
 {
        wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -659,8 +659,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
 
        wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       snd_soc_add_controls(codec, wm8804_snd_controls,
-                            ARRAY_SIZE(wm8804_snd_controls));
        return 0;
 
 err_reg_enable:
@@ -670,7 +668,7 @@ err_reg_get:
        return ret;
 }
 
-static struct snd_soc_dai_ops wm8804_dai_ops = {
+static const struct snd_soc_dai_ops wm8804_dai_ops = {
        .hw_params = wm8804_hw_params,
        .set_fmt = wm8804_set_fmt,
        .set_sysclk = wm8804_set_sysclk,
@@ -715,7 +713,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
        .reg_word_size = sizeof(u8),
        .reg_cache_default = wm8804_reg_defs,
-       .volatile_register = wm8804_volatile
+       .volatile_register = wm8804_volatile,
+
+       .controls = wm8804_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8804_snd_controls),
 };
 
 static const struct of_device_id wm8804_of_match[] = {
index 3d0dc1591eccda191057f2d957823ebb79f55b1e..f18c554efc984832ec6b538cf896cfce5ae2d925 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -513,7 +512,7 @@ SND_SOC_DAPM_MIXER("Right Input Mixer", WM8900_REG_POWER2, 4, 0,
                   wm8900_rinmix_controls,
                   ARRAY_SIZE(wm8900_rinmix_controls)),
 
-SND_SOC_DAPM_MICBIAS("Mic Bias", WM8900_REG_POWER1, 4, 0),
+SND_SOC_DAPM_SUPPLY("Mic Bias", WM8900_REG_POWER1, 4, 0, NULL, 0),
 
 SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8900_REG_POWER2, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8900_REG_POWER2, 0, 0),
@@ -543,7 +542,7 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8900_REG_POWER3, 2, 0,
 };
 
 /* Target, Path, Source */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8900_dapm_routes[] = {
 /* Inputs */
 {"Left Input PGA", "LINPUT1 Switch", "LINPUT1"},
 {"Left Input PGA", "LINPUT2 Switch", "LINPUT2"},
@@ -607,17 +606,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 {"HP_R", NULL, "Headphone Amplifier"},
 };
 
-static int wm8900_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, wm8900_dapm_widgets,
-                                 ARRAY_SIZE(wm8900_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       return 0;
-}
-
 static int wm8900_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
@@ -987,7 +975,7 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
        (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
         SNDRV_PCM_FORMAT_S24_LE)
 
-static struct snd_soc_dai_ops wm8900_dai_ops = {
+static const struct snd_soc_dai_ops wm8900_dai_ops = {
        .hw_params      = wm8900_hw_params,
        .set_clkdiv     = wm8900_set_dai_clkdiv,
        .set_pll        = wm8900_set_dai_pll,
@@ -1107,7 +1095,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8900_suspend(struct snd_soc_codec *codec)
 {
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        int fll_out = wm8900->fll_out;
@@ -1204,10 +1192,6 @@ static int wm8900_probe(struct snd_soc_codec *codec)
        /* Set the DAC and mixer output bias */
        snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
 
-       snd_soc_add_controls(codec, wm8900_snd_controls,
-                               ARRAY_SIZE(wm8900_snd_controls));
-       wm8900_add_widgets(codec);
-
        return 0;
 }
 
@@ -1228,6 +1212,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
        .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
        .reg_word_size = sizeof(u16),
        .reg_cache_default = wm8900_reg_defaults,
+
+       .controls = wm8900_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8900_snd_controls),
+       .dapm_widgets = wm8900_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8900_dapm_widgets),
+       .dapm_routes = wm8900_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes),
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -1259,7 +1250,7 @@ static int __devexit wm8900_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8900_spi_driver = {
        .driver = {
-               .name   = "wm8900-codec",
+               .name   = "wm8900",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8900_spi_probe,
@@ -1303,7 +1294,7 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
 
 static struct i2c_driver wm8900_i2c_driver = {
        .driver = {
-               .name = "wm8900-codec",
+               .name = "wm8900",
                .owner = THIS_MODULE,
        },
        .probe =    wm8900_i2c_probe,
index 4ad8ebd290e3decbe79f181bbbd1af2a3b014d4f..c91fb2f99c13b5ac978191ecff133302989ea5ce 100644 (file)
@@ -23,8 +23,9 @@
 #include <linux/gpio.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include "wm8903.h"
 
 /* Register defaults at reset */
-static u16 wm8903_reg_defaults[] = {
-       0x8903,     /* R0   - SW Reset and ID */
-       0x0000,     /* R1   - Revision Number */
-       0x0000,     /* R2 */
-       0x0000,     /* R3 */
-       0x0018,     /* R4   - Bias Control 0 */
-       0x0000,     /* R5   - VMID Control 0 */
-       0x0000,     /* R6   - Mic Bias Control 0 */
-       0x0000,     /* R7 */
-       0x0001,     /* R8   - Analogue DAC 0 */
-       0x0000,     /* R9 */
-       0x0001,     /* R10  - Analogue ADC 0 */
-       0x0000,     /* R11 */
-       0x0000,     /* R12  - Power Management 0 */
-       0x0000,     /* R13  - Power Management 1 */
-       0x0000,     /* R14  - Power Management 2 */
-       0x0000,     /* R15  - Power Management 3 */
-       0x0000,     /* R16  - Power Management 4 */
-       0x0000,     /* R17  - Power Management 5 */
-       0x0000,     /* R18  - Power Management 6 */
-       0x0000,     /* R19 */
-       0x0400,     /* R20  - Clock Rates 0 */
-       0x0D07,     /* R21  - Clock Rates 1 */
-       0x0000,     /* R22  - Clock Rates 2 */
-       0x0000,     /* R23 */
-       0x0050,     /* R24  - Audio Interface 0 */
-       0x0242,     /* R25  - Audio Interface 1 */
-       0x0008,     /* R26  - Audio Interface 2 */
-       0x0022,     /* 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 */
-       0x0000,     /* R33  - DAC Digital 1 */
-       0x0000,     /* R34 */
-       0x0000,     /* R35 */
-       0x00C0,     /* R36  - ADC Digital Volume Left */
-       0x00C0,     /* R37  - ADC Digital Volume Right */
-       0x0000,     /* R38  - ADC Digital 0 */
-       0x0073,     /* R39  - Digital Microphone 0 */
-       0x09BF,     /* R40  - DRC 0 */
-       0x3241,     /* R41  - DRC 1 */
-       0x0020,     /* 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 */
-       0x0008,     /* R50  - Analogue Left Mix 0 */
-       0x0004,     /* R51  - Analogue Right Mix 0 */
-       0x0000,     /* R52  - Analogue Spk Mix Left 0 */
-       0x0000,     /* R53  - Analogue Spk Mix Left 1 */
-       0x0000,     /* R54  - Analogue Spk Mix Right 0 */
-       0x0000,     /* R55  - Analogue Spk Mix Right 1 */
-       0x0000,     /* R56 */
-       0x002D,     /* R57  - Analogue OUT1 Left */
-       0x002D,     /* R58  - Analogue OUT1 Right */
-       0x0039,     /* R59  - Analogue OUT2 Left */
-       0x0039,     /* R60  - Analogue OUT2 Right */
-       0x0100,     /* R61 */
-       0x0139,     /* R62  - Analogue OUT3 Left */
-       0x0139,     /* R63  - Analogue OUT3 Right */
-       0x0000,     /* R64 */
-       0x0000,     /* R65  - Analogue SPK Output Control 0 */
-       0x0000,     /* R66 */
-       0x0010,     /* R67  - DC Servo 0 */
-       0x0100,     /* R68 */
-       0x00A4,     /* R69  - DC Servo 2 */
-       0x0807,     /* R70 */
-       0x0000,     /* R71 */
-       0x0000,     /* R72 */
-       0x0000,     /* R73 */
-       0x0000,     /* R74 */
-       0x0000,     /* R75 */
-       0x0000,     /* R76 */
-       0x0000,     /* R77 */
-       0x0000,     /* R78 */
-       0x000E,     /* R79 */
-       0x0000,     /* R80 */
-       0x0000,     /* R81 */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84 */
-       0x0000,     /* R85 */
-       0x0000,     /* R86 */
-       0x0006,     /* R87 */
-       0x0000,     /* R88 */
-       0x0000,     /* R89 */
-       0x0000,     /* R90  - Analogue HP 0 */
-       0x0060,     /* R91 */
-       0x0000,     /* R92 */
-       0x0000,     /* R93 */
-       0x0000,     /* R94  - Analogue Lineout 0 */
-       0x0060,     /* R95 */
-       0x0000,     /* R96 */
-       0x0000,     /* R97 */
-       0x0000,     /* R98  - Charge Pump 0 */
-       0x1F25,     /* R99 */
-       0x2B19,     /* R100 */
-       0x01C0,     /* R101 */
-       0x01EF,     /* R102 */
-       0x2B00,     /* R103 */
-       0x0000,     /* R104 - Class W 0 */
-       0x01C0,     /* R105 */
-       0x1C10,     /* 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 - Control Interface */
-       0x0000,     /* R115 */
-       0x00A8,     /* R116 - GPIO Control 1 */
-       0x00A8,     /* R117 - GPIO Control 2 */
-       0x00A8,     /* R118 - GPIO Control 3 */
-       0x0220,     /* R119 - GPIO Control 4 */
-       0x01A0,     /* R120 - GPIO Control 5 */
-       0x0000,     /* R121 - Interrupt Status 1 */
-       0xFFFF,     /* R122 - Interrupt Status 1 Mask */
-       0x0000,     /* R123 - Interrupt Polarity 1 */
-       0x0000,     /* R124 */
-       0x0003,     /* R125 */
-       0x0000,     /* R126 - Interrupt Control */
-       0x0000,     /* R127 */
-       0x0005,     /* R128 */
-       0x0000,     /* R129 - Control Interface Test 1 */
-       0x0000,     /* R130 */
-       0x0000,     /* R131 */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 */
-       0x0000,     /* R134 */
-       0x03FF,     /* R135 */
-       0x0007,     /* R136 */
-       0x0040,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0000,     /* R140 */
-       0x0000,     /* R141 */
-       0x0000,     /* R142 */
-       0x0000,     /* R143 */
-       0x0000,     /* R144 */
-       0x0000,     /* R145 */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x4000,     /* R148 */
-       0x6810,     /* R149 - Charge Pump Test 1 */
-       0x0004,     /* R150 */
-       0x0000,     /* R151 */
-       0x0000,     /* R152 */
-       0x0000,     /* R153 */
-       0x0000,     /* R154 */
-       0x0000,     /* R155 */
-       0x0000,     /* R156 */
-       0x0000,     /* R157 */
-       0x0000,     /* R158 */
-       0x0000,     /* R159 */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 */
-       0x0028,     /* R164 - Clock Rate Test 4 */
-       0x0004,     /* R165 */
-       0x0000,     /* R166 */
-       0x0060,     /* R167 */
-       0x0000,     /* R168 */
-       0x0000,     /* R169 */
-       0x0000,     /* R170 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 - Analogue Output Bias 0 */
+static const struct reg_default wm8903_reg_defaults[] = {
+       { 4,  0x0018 },     /* R4   - Bias Control 0 */
+       { 5,  0x0000 },     /* R5   - VMID Control 0 */
+       { 6,  0x0000 },     /* R6   - Mic Bias Control 0 */
+       { 8,  0x0001 },     /* R8   - Analogue DAC 0 */
+       { 10, 0x0001 },     /* R10  - Analogue ADC 0 */
+       { 12, 0x0000 },     /* R12  - Power Management 0 */
+       { 13, 0x0000 },     /* R13  - Power Management 1 */
+       { 14, 0x0000 },     /* R14  - Power Management 2 */
+       { 15, 0x0000 },     /* R15  - Power Management 3 */
+       { 16, 0x0000 },     /* R16  - Power Management 4 */
+       { 17, 0x0000 },     /* R17  - Power Management 5 */
+       { 18, 0x0000 },     /* R18  - Power Management 6 */
+       { 20, 0x0400 },     /* R20  - Clock Rates 0 */
+       { 21, 0x0D07 },     /* R21  - Clock Rates 1 */
+       { 22, 0x0000 },     /* R22  - Clock Rates 2 */
+       { 24, 0x0050 },     /* R24  - Audio Interface 0 */
+       { 25, 0x0242 },     /* R25  - Audio Interface 1 */
+       { 26, 0x0008 },     /* R26  - Audio Interface 2 */
+       { 27, 0x0022 },     /* R27  - Audio Interface 3 */
+       { 30, 0x00C0 },     /* R30  - DAC Digital Volume Left */
+       { 31, 0x00C0 },     /* R31  - DAC Digital Volume Right */
+       { 32, 0x0000 },     /* R32  - DAC Digital 0 */
+       { 33, 0x0000 },     /* R33  - DAC Digital 1 */
+       { 36, 0x00C0 },     /* R36  - ADC Digital Volume Left */
+       { 37, 0x00C0 },     /* R37  - ADC Digital Volume Right */
+       { 38, 0x0000 },     /* R38  - ADC Digital 0 */
+       { 39, 0x0073 },     /* R39  - Digital Microphone 0 */
+       { 40, 0x09BF },     /* R40  - DRC 0 */
+       { 41, 0x3241 },     /* R41  - DRC 1 */
+       { 42, 0x0020 },     /* R42  - DRC 2 */
+       { 43, 0x0000 },     /* R43  - DRC 3 */
+       { 44, 0x0085 },     /* R44  - Analogue Left Input 0 */
+       { 45, 0x0085 },     /* R45  - Analogue Right Input 0 */
+       { 46, 0x0044 },     /* R46  - Analogue Left Input 1 */
+       { 47, 0x0044 },     /* R47  - Analogue Right Input 1 */
+       { 50, 0x0008 },     /* R50  - Analogue Left Mix 0 */
+       { 51, 0x0004 },     /* R51  - Analogue Right Mix 0 */
+       { 52, 0x0000 },     /* R52  - Analogue Spk Mix Left 0 */
+       { 53, 0x0000 },     /* R53  - Analogue Spk Mix Left 1 */
+       { 54, 0x0000 },     /* R54  - Analogue Spk Mix Right 0 */
+       { 55, 0x0000 },     /* R55  - Analogue Spk Mix Right 1 */
+       { 57, 0x002D },     /* R57  - Analogue OUT1 Left */
+       { 58, 0x002D },     /* R58  - Analogue OUT1 Right */
+       { 59, 0x0039 },     /* R59  - Analogue OUT2 Left */
+       { 60, 0x0039 },     /* R60  - Analogue OUT2 Right */
+       { 62, 0x0139 },     /* R62  - Analogue OUT3 Left */
+       { 63, 0x0139 },     /* R63  - Analogue OUT3 Right */
+       { 64, 0x0000 },     /* R65  - Analogue SPK Output Control 0 */
+       { 67, 0x0010 },     /* R67  - DC Servo 0 */
+       { 69, 0x00A4 },     /* R69  - DC Servo 2 */
+       { 90, 0x0000 },     /* R90  - Analogue HP 0 */
+       { 94, 0x0000 },     /* R94  - Analogue Lineout 0 */
+       { 98, 0x0000 },     /* R98  - Charge Pump 0 */
+       { 104, 0x0000 },    /* R104 - Class W 0 */
+       { 108, 0x0000 },    /* R108 - Write Sequencer 0 */
+       { 109, 0x0000 },    /* R109 - Write Sequencer 1 */
+       { 110, 0x0000 },    /* R110 - Write Sequencer 2 */
+       { 111, 0x0000 },    /* R111 - Write Sequencer 3 */
+       { 112, 0x0000 },    /* R112 - Write Sequencer 4 */
+       { 114, 0x0000 },    /* R114 - Control Interface */
+       { 116, 0x00A8 },    /* R116 - GPIO Control 1 */
+       { 117, 0x00A8 },    /* R117 - GPIO Control 2 */
+       { 118, 0x00A8 },    /* R118 - GPIO Control 3 */
+       { 119, 0x0220 },    /* R119 - GPIO Control 4 */
+       { 120, 0x01A0 },    /* R120 - GPIO Control 5 */
+       { 122, 0xFFFF },    /* R122 - Interrupt Status 1 Mask */
+       { 123, 0x0000 },    /* R123 - Interrupt Polarity 1 */
+       { 126, 0x0000 },    /* R126 - Interrupt Control */
+       { 129, 0x0000 },    /* R129 - Control Interface Test 1 */
+       { 149, 0x6810 },    /* R149 - Charge Pump Test 1 */
+       { 164, 0x0028 },    /* R164 - Clock Rate Test 4 */
+       { 172, 0x0000 },    /* R172 - Analogue Output Bias 0 */
 };
 
 struct wm8903_priv {
+       struct wm8903_platform_data *pdata;
        struct snd_soc_codec *codec;
+       struct regmap *regmap;
 
        int sysclk;
        int irq;
@@ -240,7 +142,93 @@ struct wm8903_priv {
 #endif
 };
 
-static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8903_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8903_SW_RESET_AND_ID:
+       case WM8903_REVISION_NUMBER:
+       case WM8903_BIAS_CONTROL_0:
+       case WM8903_VMID_CONTROL_0:
+       case WM8903_MIC_BIAS_CONTROL_0:
+       case WM8903_ANALOGUE_DAC_0:
+       case WM8903_ANALOGUE_ADC_0:
+       case WM8903_POWER_MANAGEMENT_0:
+       case WM8903_POWER_MANAGEMENT_1:
+       case WM8903_POWER_MANAGEMENT_2:
+       case WM8903_POWER_MANAGEMENT_3:
+       case WM8903_POWER_MANAGEMENT_4:
+       case WM8903_POWER_MANAGEMENT_5:
+       case WM8903_POWER_MANAGEMENT_6:
+       case WM8903_CLOCK_RATES_0:
+       case WM8903_CLOCK_RATES_1:
+       case WM8903_CLOCK_RATES_2:
+       case WM8903_AUDIO_INTERFACE_0:
+       case WM8903_AUDIO_INTERFACE_1:
+       case WM8903_AUDIO_INTERFACE_2:
+       case WM8903_AUDIO_INTERFACE_3:
+       case WM8903_DAC_DIGITAL_VOLUME_LEFT:
+       case WM8903_DAC_DIGITAL_VOLUME_RIGHT:
+       case WM8903_DAC_DIGITAL_0:
+       case WM8903_DAC_DIGITAL_1:
+       case WM8903_ADC_DIGITAL_VOLUME_LEFT:
+       case WM8903_ADC_DIGITAL_VOLUME_RIGHT:
+       case WM8903_ADC_DIGITAL_0:
+       case WM8903_DIGITAL_MICROPHONE_0:
+       case WM8903_DRC_0:
+       case WM8903_DRC_1:
+       case WM8903_DRC_2:
+       case WM8903_DRC_3:
+       case WM8903_ANALOGUE_LEFT_INPUT_0:
+       case WM8903_ANALOGUE_RIGHT_INPUT_0:
+       case WM8903_ANALOGUE_LEFT_INPUT_1:
+       case WM8903_ANALOGUE_RIGHT_INPUT_1:
+       case WM8903_ANALOGUE_LEFT_MIX_0:
+       case WM8903_ANALOGUE_RIGHT_MIX_0:
+       case WM8903_ANALOGUE_SPK_MIX_LEFT_0:
+       case WM8903_ANALOGUE_SPK_MIX_LEFT_1:
+       case WM8903_ANALOGUE_SPK_MIX_RIGHT_0:
+       case WM8903_ANALOGUE_SPK_MIX_RIGHT_1:
+       case WM8903_ANALOGUE_OUT1_LEFT:
+       case WM8903_ANALOGUE_OUT1_RIGHT:
+       case WM8903_ANALOGUE_OUT2_LEFT:
+       case WM8903_ANALOGUE_OUT2_RIGHT:
+       case WM8903_ANALOGUE_OUT3_LEFT:
+       case WM8903_ANALOGUE_OUT3_RIGHT:
+       case WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0:
+       case WM8903_DC_SERVO_0:
+       case WM8903_DC_SERVO_2:
+       case WM8903_DC_SERVO_READBACK_1:
+       case WM8903_DC_SERVO_READBACK_2:
+       case WM8903_DC_SERVO_READBACK_3:
+       case WM8903_DC_SERVO_READBACK_4:
+       case WM8903_ANALOGUE_HP_0:
+       case WM8903_ANALOGUE_LINEOUT_0:
+       case WM8903_CHARGE_PUMP_0:
+       case WM8903_CLASS_W_0:
+       case WM8903_WRITE_SEQUENCER_0:
+       case WM8903_WRITE_SEQUENCER_1:
+       case WM8903_WRITE_SEQUENCER_2:
+       case WM8903_WRITE_SEQUENCER_3:
+       case WM8903_WRITE_SEQUENCER_4:
+       case WM8903_CONTROL_INTERFACE:
+       case WM8903_GPIO_CONTROL_1:
+       case WM8903_GPIO_CONTROL_2:
+       case WM8903_GPIO_CONTROL_3:
+       case WM8903_GPIO_CONTROL_4:
+       case WM8903_GPIO_CONTROL_5:
+       case WM8903_INTERRUPT_STATUS_1:
+       case WM8903_INTERRUPT_STATUS_1_MASK:
+       case WM8903_INTERRUPT_POLARITY_1:
+       case WM8903_INTERRUPT_CONTROL:
+       case WM8903_CLOCK_RATE_TEST_4:
+       case WM8903_ANALOGUE_OUTPUT_BIAS_0:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8903_SW_RESET_AND_ID:
@@ -258,13 +246,6 @@ static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int re
        }
 }
 
-static void wm8903_reset(struct snd_soc_codec *codec)
-{
-       snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0);
-       memcpy(codec->reg_cache, wm8903_reg_defaults,
-              sizeof(wm8903_reg_defaults));
-}
-
 static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
@@ -839,7 +820,7 @@ SND_SOC_DAPM_OUTPUT("LON"),
 SND_SOC_DAPM_OUTPUT("ROP"),
 SND_SOC_DAPM_OUTPUT("RON"),
 
-SND_SOC_DAPM_MICBIAS("Mic Bias", WM8903_MIC_BIAS_CONTROL_0, 0, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8903_MIC_BIAS_CONTROL_0, 0, 0, NULL, 0),
 
 SND_SOC_DAPM_MUX("Left Input Mux", SND_SOC_NOPM, 0, 0, &linput_mux),
 SND_SOC_DAPM_MUX("Left Input Inverting Mux", SND_SOC_NOPM, 0, 0,
@@ -948,7 +929,7 @@ SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 static const struct snd_soc_dapm_route wm8903_intercon[] = {
 
        { "CLK_DSP", NULL, "CLK_SYS" },
-       { "Mic Bias", NULL, "CLK_SYS" },
+       { "MICBIAS", NULL, "CLK_SYS" },
        { "HPL_DCS", NULL, "CLK_SYS" },
        { "HPR_DCS", NULL, "CLK_SYS" },
        { "LINEOUTL_DCS", NULL, "CLK_SYS" },
@@ -1732,7 +1713,7 @@ static irqreturn_t wm8903_irq(int irq, void *data)
                        SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8903_dai_ops = {
+static const struct snd_soc_dai_ops wm8903_dai_ops = {
        .hw_params      = wm8903_hw_params,
        .digital_mute   = wm8903_digital_mute,
        .set_fmt        = wm8903_set_dai_fmt,
@@ -1759,7 +1740,7 @@ static struct snd_soc_dai_driver wm8903_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec)
 {
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1768,23 +1749,11 @@ static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8903_resume(struct snd_soc_codec *codec)
 {
-       int i;
-       u16 *reg_cache = codec->reg_cache;
-       u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
-                                GFP_KERNEL);
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
-       /* Bring the codec back up to standby first to minimise pop/clicks */
-       wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       regcache_sync(wm8903->regmap);
 
-       /* Sync back everything else */
-       if (tmp_cache) {
-               for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
-                       if (tmp_cache[i] != reg_cache[i])
-                               snd_soc_write(codec, i, tmp_cache[i]);
-               kfree(tmp_cache);
-       } else {
-               dev_err(codec->dev, "Failed to allocate temporary cache\n");
-       }
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
@@ -1808,13 +1777,18 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
        struct snd_soc_codec *codec = wm8903->codec;
        unsigned int mask, val;
+       int ret;
 
        mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK;
        val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
                WM8903_GP1_DIR;
 
-       return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-                                  mask, val);
+       ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
+                                 mask, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -1834,13 +1808,18 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
        struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
        struct snd_soc_codec *codec = wm8903->codec;
        unsigned int mask, val;
+       int ret;
 
        mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK;
        val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
                (value << WM8903_GP2_LVL_SHIFT);
 
-       return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
-                                  mask, val);
+       ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
+                                 mask, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -1867,14 +1846,14 @@ static struct gpio_chip wm8903_template_chip = {
 static void wm8903_init_gpio(struct snd_soc_codec *codec)
 {
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+       struct wm8903_platform_data *pdata = wm8903->pdata;
        int ret;
 
        wm8903->gpio_chip = wm8903_template_chip;
        wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
        wm8903->gpio_chip.dev = codec->dev;
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                wm8903->gpio_chip.base = pdata->gpio_base;
        else
                wm8903->gpio_chip.base = -1;
@@ -1905,78 +1884,65 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec)
 
 static int wm8903_probe(struct snd_soc_codec *codec)
 {
-       struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+       struct wm8903_platform_data *pdata = wm8903->pdata;
        int ret, i;
        int trigger, irq_pol;
        u16 val;
+       bool mic_gpio = false;
 
        wm8903->codec = codec;
+       codec->control_data = wm8903->regmap;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
-       if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
-               dev_err(codec->dev,
-                       "Device with ID register %x is not a WM8903\n", val);
-               return -ENODEV;
-       }
-
-       val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
-       dev_info(codec->dev, "WM8903 revision %c\n",
-                (val & WM8903_CHIP_REV_MASK) + 'A');
+       /* Set up GPIOs, detect if any are MIC detect outputs */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+               if ((!pdata->gpio_cfg[i]) ||
+                   (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO))
+                       continue;
 
-       wm8903_reset(codec);
+               snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
+                               pdata->gpio_cfg[i] & 0x7fff);
 
-       /* Set up GPIOs and microphone detection */
-       if (pdata) {
-               bool mic_gpio = false;
+               val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+                       >> WM8903_GP1_FN_SHIFT;
 
-               for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
-                       if (pdata->gpio_cfg[i] == WM8903_GPIO_NO_CONFIG)
-                               continue;
-
-                       snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
-                                     pdata->gpio_cfg[i] & 0xffff);
-
-                       val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
-                               >> WM8903_GP1_FN_SHIFT;
-
-                       switch (val) {
-                       case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
-                       case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
-                               mic_gpio = true;
-                               break;
-                       default:
-                               break;
-                       }
+               switch (val) {
+               case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+               case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+                       mic_gpio = true;
+                       break;
+               default:
+                       break;
                }
+       }
+
+       /* Set up microphone detection */
+       snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
+                       pdata->micdet_cfg);
 
-               snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
-                             pdata->micdet_cfg);
+       /* Microphone detection needs the WSEQ clock */
+       if (pdata->micdet_cfg)
+               snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
+                                   WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
 
-               /* Microphone detection needs the WSEQ clock */
-               if (pdata->micdet_cfg)
-                       snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
-                                           WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+       /* If microphone detection is enabled by pdata but
+           * detected via IRQ then interrupts can be lost before
+           * the machine driver has set up microphone detection
+           * IRQs as the IRQs are clear on read.  The detection
+           * will be enabled when the machine driver configures.
+           */
+       WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
 
-               /* If microphone detection is enabled by pdata but
-                * detected via IRQ then interrupts can be lost before
-                * the machine driver has set up microphone detection
-                * IRQs as the IRQs are clear on read.  The detection
-                * will be enabled when the machine driver configures.
-                */
-               WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+       wm8903->mic_delay = pdata->micdet_delay;
 
-               wm8903->mic_delay = pdata->micdet_delay;
-       }
-       
        if (wm8903->irq) {
-               if (pdata && pdata->irq_active_low) {
+               if (pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8903_IRQ_POL;
                } else {
@@ -2035,9 +2001,6 @@ static int wm8903_probe(struct snd_soc_codec *codec)
                            WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
                            WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
 
-       snd_soc_add_controls(codec, wm8903_snd_controls,
-                               ARRAY_SIZE(wm8903_snd_controls));
-
        wm8903_init_gpio(codec);
 
        return ret;
@@ -2062,45 +2025,198 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
        .suspend =      wm8903_suspend,
        .resume =       wm8903_resume,
        .set_bias_level = wm8903_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8903_reg_defaults,
-       .volatile_register = wm8903_volatile_register,
        .seq_notifier = wm8903_seq_notifier,
+       .controls = wm8903_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8903_snd_controls),
        .dapm_widgets = wm8903_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
        .dapm_routes = wm8903_intercon,
        .num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct regmap_config wm8903_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = WM8903_MAX_REGISTER,
+       .volatile_reg = wm8903_volatile_register,
+       .readable_reg = wm8903_readable_register,
+
+       .cache_type = REGCACHE_RBTREE,
+       .reg_defaults = wm8903_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8903_reg_defaults),
+};
+
+static int wm8903_set_pdata_irq_trigger(struct i2c_client *i2c,
+                                       struct wm8903_platform_data *pdata)
+{
+       struct irq_data *irq_data = irq_get_irq_data(i2c->irq);
+       if (!irq_data) {
+               dev_err(&i2c->dev, "Invalid IRQ: %d\n",
+                       i2c->irq);
+               return -EINVAL;
+       }
+
+       switch (irqd_get_trigger_type(irq_data)) {
+       case IRQ_TYPE_NONE:
+       default:
+               /*
+               * We assume the controller imposes no restrictions,
+               * so we are able to select active-high
+               */
+               /* Fall-through */
+       case IRQ_TYPE_LEVEL_HIGH:
+               pdata->irq_active_low = false;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               pdata->irq_active_low = true;
+               break;
+       }
+
+       return 0;
+}
+
+static int wm8903_set_pdata_from_of(struct i2c_client *i2c,
+                                   struct wm8903_platform_data *pdata)
+{
+       const struct device_node *np = i2c->dev.of_node;
+       u32 val32;
+       int i;
+
+       if (of_property_read_u32(np, "micdet-cfg", &val32) >= 0)
+               pdata->micdet_cfg = val32;
+
+       if (of_property_read_u32(np, "micdet-delay", &val32) >= 0)
+               pdata->micdet_delay = val32;
+
+       if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_cfg,
+                                      ARRAY_SIZE(pdata->gpio_cfg)) >= 0) {
+               /*
+                * In device tree: 0 means "write 0",
+                * 0xffffffff means "don't touch".
+                *
+                * In platform data: 0 means "don't touch",
+                * 0x8000 means "write 0".
+                *
+                * Note: WM8903_GPIO_CONFIG_ZERO == 0x8000.
+                *
+                *  Convert from DT to pdata representation here,
+                * so no other code needs to change.
+                */
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
+                       if (pdata->gpio_cfg[i] == 0) {
+                               pdata->gpio_cfg[i] = WM8903_GPIO_CONFIG_ZERO;
+                       } else if (pdata->gpio_cfg[i] == 0xffffffff) {
+                               pdata->gpio_cfg[i] = 0;
+                       } else if (pdata->gpio_cfg[i] > 0x7fff) {
+                               dev_err(&i2c->dev, "Invalid gpio-cfg[%d] %x\n",
+                                       i, pdata->gpio_cfg[i]);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
+       struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct wm8903_priv *wm8903;
+       unsigned int val;
        int ret;
 
-       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+       wm8903 = devm_kzalloc(&i2c->dev,  sizeof(struct wm8903_priv),
+                             GFP_KERNEL);
        if (wm8903 == NULL)
                return -ENOMEM;
 
+       wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap);
+       if (IS_ERR(wm8903->regmap)) {
+               ret = PTR_ERR(wm8903->regmap);
+               dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8903);
        wm8903->irq = i2c->irq;
 
+       /* If no platform data was supplied, create storage for defaults */
+       if (pdata) {
+               wm8903->pdata = pdata;
+       } else {
+               wm8903->pdata = devm_kzalloc(&i2c->dev,
+                                       sizeof(struct wm8903_platform_data),
+                                       GFP_KERNEL);
+               if (wm8903->pdata == NULL) {
+                       dev_err(&i2c->dev, "Failed to allocate pdata\n");
+                       return -ENOMEM;
+               }
+
+               if (i2c->irq) {
+                       ret = wm8903_set_pdata_irq_trigger(i2c, wm8903->pdata);
+                       if (ret != 0)
+                               return ret;
+               }
+
+               if (i2c->dev.of_node) {
+                       ret = wm8903_set_pdata_from_of(i2c, wm8903->pdata);
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+               goto err;
+       }
+       if (val != 0x8903) {
+               dev_err(&i2c->dev, "Device with ID %x is not a WM8903\n", val);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       ret = regmap_read(wm8903->regmap, WM8903_REVISION_NUMBER, &val);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+               goto err;
+       }
+       dev_info(&i2c->dev, "WM8903 revision %c\n",
+                (val & WM8903_CHIP_REV_MASK) + 'A');
+
+       /* Reset the device */
+       regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903);
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8903, &wm8903_dai, 1);
-       if (ret < 0)
-               kfree(wm8903);
+       if (ret != 0)
+               goto err;
+
+       return 0;
+err:
+       regmap_exit(wm8903->regmap);
        return ret;
 }
 
 static __devexit int wm8903_i2c_remove(struct i2c_client *client)
 {
+       struct wm8903_priv *wm8903 = i2c_get_clientdata(client);
+
+       regmap_exit(wm8903->regmap);
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+
        return 0;
 }
 
+static const struct of_device_id wm8903_of_match[] = {
+       { .compatible = "wlf,wm8903", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, wm8903_of_match);
+
 static const struct i2c_device_id wm8903_i2c_id[] = {
        { "wm8903", 0 },
        { }
@@ -2111,32 +2227,28 @@ static struct i2c_driver wm8903_i2c_driver = {
        .driver = {
                .name = "wm8903",
                .owner = THIS_MODULE,
+               .of_match_table = wm8903_of_match,
        },
        .probe =    wm8903_i2c_probe,
        .remove =   __devexit_p(wm8903_i2c_remove),
        .id_table = wm8903_i2c_id,
 };
-#endif
 
 static int __init wm8903_modinit(void)
 {
        int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8903_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
                       ret);
        }
-#endif
        return ret;
 }
 module_init(wm8903_modinit);
 
 static void __exit wm8903_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8903_i2c_driver);
-#endif
 }
 module_exit(wm8903_exit);
 
index 285ef87e6704fd655d89170ce5e5307e25a36983..f31c754c8865abd5b21ee61c3e47b810f73721a6 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -1196,7 +1195,7 @@ 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_SUPPLY("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0, NULL, 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,
@@ -2205,7 +2204,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
 #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 = {
+static const 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,
@@ -2235,7 +2234,7 @@ static struct snd_soc_dai_driver wm8904_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8904_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8904_suspend(struct snd_soc_codec *codec)
 {
        wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -2565,7 +2564,7 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
 
 static struct i2c_driver wm8904_i2c_driver = {
        .driver = {
-               .name = "wm8904-codec",
+               .name = "wm8904",
                .owner = THIS_MODULE,
        },
        .probe =    wm8904_i2c_probe,
index de9ec9b8b7d9ae06e98bd58f01e28ff67b08f0e1..14039ea2f3e4a13d9e882fefe3c2dd4f387bb670 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -629,8 +628,8 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5));
                break;
        case WM8940_OPCLKDIV:
-               reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF;
-               ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4));
+               reg = snd_soc_read(codec, WM8940_GPIO) & 0xFFCF;
+               ret = snd_soc_write(codec, WM8940_GPIO, reg | (div << 4));
                break;
        }
        return ret;
@@ -644,7 +643,7 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                        SNDRV_PCM_FMTBIT_S24_LE |                       \
                        SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops wm8940_dai_ops = {
+static const struct snd_soc_dai_ops wm8940_dai_ops = {
        .hw_params = wm8940_i2s_hw_params,
        .set_sysclk = wm8940_set_dai_sysclk,
        .digital_mute = wm8940_mute,
@@ -673,7 +672,7 @@ static struct snd_soc_dai_driver wm8940_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8940_suspend(struct snd_soc_codec *codec)
 {
        return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
@@ -780,7 +779,7 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
 
 static struct i2c_driver wm8940_i2c_driver = {
        .driver = {
-               .name = "wm8940-codec",
+               .name = "wm8940",
                .owner = THIS_MODULE,
        },
        .probe =    wm8940_i2c_probe,
index 3c7198779c3173e1408daf2403dc794a5bf4e157..924548182d58f86257e1a4a2d9fde8125e67a8af 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -859,7 +858,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
 #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 = {
+static const struct snd_soc_dai_ops wm8955_dai_ops = {
        .set_sysclk = wm8955_set_sysclk,
        .set_fmt = wm8955_set_fmt,
        .hw_params = wm8955_hw_params,
@@ -879,7 +878,7 @@ static struct snd_soc_dai_driver wm8955_dai = {
 };
 
 #ifdef CONFIG_PM
-static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8955_suspend(struct snd_soc_codec *codec)
 {
        wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1038,7 +1037,7 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
 
 static struct i2c_driver wm8955_i2c_driver = {
        .driver = {
-               .name = "wm8955-codec",
+               .name = "wm8955",
                .owner = THIS_MODULE,
        },
        .probe =    wm8955_i2c_probe,
index 5a14d5c0e0e1b6dc98fb39140a4ca47f6bd18294..8d4ea43d40a383298023165e517ed1c9de510063 100644 (file)
@@ -55,7 +55,8 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
                return 0;
 
        if (fw->size < 32) {
-               dev_err(codec->dev, "%s: firmware too short\n", name);
+               dev_err(codec->dev, "%s: firmware too short (%d bytes)\n",
+                       name, fw->size);
                goto err;
        }
 
index 2df253c185683cb0001b05e6d7c7ecd21c759147..e5caae32e5419a695f0533b833fb3d719ccbbf4c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -26,8 +25,6 @@
 
 #include "wm8960.h"
 
-#define AUDIO_NAME "wm8960"
-
 /* R25 - Power 1 */
 #define WM8960_VMID_MASK 0x180
 #define WM8960_VREF      0x40
@@ -265,7 +262,7 @@ SND_SOC_DAPM_INPUT("RINPUT2"),
 SND_SOC_DAPM_INPUT("LINPUT3"),
 SND_SOC_DAPM_INPUT("RINPUT3"),
 
-SND_SOC_DAPM_MICBIAS("MICB", WM8960_POWER1, 1, 0),
+SND_SOC_DAPM_SUPPLY("MICB", WM8960_POWER1, 1, 0, NULL, 0),
 
 SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,
                   wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),
@@ -546,30 +543,24 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
 static int wm8960_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7;
 
        if (mute)
-               snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8);
+               snd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0x8);
        else
-               snd_soc_write(codec, WM8960_DACCTL1, mute_reg);
+               snd_soc_update_bits(codec, WM8960_DACCTL1, 0x8, 0);
        return 0;
 }
 
 static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                                      enum snd_soc_bias_level level)
 {
-       u16 reg;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
                /* Set VMID to 2x50k */
-               reg = snd_soc_read(codec, WM8960_POWER1);
-               reg &= ~0x180;
-               reg |= 0x80;
-               snd_soc_write(codec, WM8960_POWER1, reg);
+               snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -582,23 +573,19 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                                      WM8960_BUFDCOPEN | WM8960_BUFIOEN);
 
                        /* Enable & ramp VMID at 2x50k */
-                       reg = snd_soc_read(codec, WM8960_POWER1);
-                       reg |= 0x80;
-                       snd_soc_write(codec, WM8960_POWER1, reg);
+                       snd_soc_update_bits(codec, WM8960_POWER1, 0x80, 0x80);
                        msleep(100);
 
                        /* Enable VREF */
-                       snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF);
+                       snd_soc_update_bits(codec, WM8960_POWER1, WM8960_VREF,
+                                           WM8960_VREF);
 
                        /* Disable anti-pop features */
                        snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
                }
 
                /* Set VMID to 2x250k */
-               reg = snd_soc_read(codec, WM8960_POWER1);
-               reg &= ~0x180;
-               reg |= 0x100;
-               snd_soc_write(codec, WM8960_POWER1, reg);
+               snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x100);
                break;
 
        case SND_SOC_BIAS_OFF:
@@ -790,10 +777,8 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 
        /* Disable the PLL: even if we are changing the frequency the
         * PLL needs to be disabled while we do so. */
-       snd_soc_write(codec, WM8960_CLOCK1,
-                    snd_soc_read(codec, WM8960_CLOCK1) & ~1);
-       snd_soc_write(codec, WM8960_POWER2,
-                    snd_soc_read(codec, WM8960_POWER2) & ~1);
+       snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, 0);
+       snd_soc_update_bits(codec, WM8960_POWER2, 0x1, 0);
 
        if (!freq_in || !freq_out)
                return 0;
@@ -812,11 +797,9 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        snd_soc_write(codec, WM8960_PLL1, reg);
 
        /* Turn it on */
-       snd_soc_write(codec, WM8960_POWER2,
-                    snd_soc_read(codec, WM8960_POWER2) | 1);
+       snd_soc_update_bits(codec, WM8960_POWER2, 0x1, 0x1);
        msleep(250);
-       snd_soc_write(codec, WM8960_CLOCK1,
-                    snd_soc_read(codec, WM8960_CLOCK1) | 1);
+       snd_soc_update_bits(codec, WM8960_CLOCK1, 0x1, 0x1);
 
        return 0;
 }
@@ -869,7 +852,7 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8960_dai_ops = {
+static const struct snd_soc_dai_ops wm8960_dai_ops = {
        .hw_params = wm8960_hw_params,
        .digital_mute = wm8960_mute,
        .set_fmt = wm8960_set_dai_fmt,
@@ -895,7 +878,7 @@ static struct snd_soc_dai_driver wm8960_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8960_suspend(struct snd_soc_codec *codec)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
@@ -916,7 +899,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        struct wm8960_data *pdata = dev_get_platdata(codec->dev);
        int ret;
-       u16 reg;
 
        wm8960->set_bias_level = wm8960_set_bias_level_out3;
 
@@ -947,26 +929,16 @@ static int wm8960_probe(struct snd_soc_codec *codec)
        wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
-       reg = snd_soc_read(codec, WM8960_LINVOL);
-       snd_soc_write(codec, WM8960_LINVOL, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_RINVOL);
-       snd_soc_write(codec, WM8960_RINVOL, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_LADC);
-       snd_soc_write(codec, WM8960_LADC, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_RADC);
-       snd_soc_write(codec, WM8960_RADC, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_LDAC);
-       snd_soc_write(codec, WM8960_LDAC, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_RDAC);
-       snd_soc_write(codec, WM8960_RDAC, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_LOUT1);
-       snd_soc_write(codec, WM8960_LOUT1, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_ROUT1);
-       snd_soc_write(codec, WM8960_ROUT1, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_LOUT2);
-       snd_soc_write(codec, WM8960_LOUT2, reg | 0x100);
-       reg = snd_soc_read(codec, WM8960_ROUT2);
-       snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
+       snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100);
 
        snd_soc_add_controls(codec, wm8960_snd_controls,
                                     ARRAY_SIZE(wm8960_snd_controls));
@@ -995,14 +967,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
        .reg_cache_default = wm8960_reg,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8960_priv *wm8960;
        int ret;
 
-       wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
+       wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv),
+                             GFP_KERNEL);
        if (wm8960 == NULL)
                return -ENOMEM;
 
@@ -1011,15 +983,13 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8960, &wm8960_dai, 1);
-       if (ret < 0)
-               kfree(wm8960);
+
        return ret;
 }
 
 static __devexit int wm8960_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1031,34 +1001,29 @@ MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
 
 static struct i2c_driver wm8960_i2c_driver = {
        .driver = {
-               .name = "wm8960-codec",
+               .name = "wm8960",
                .owner = THIS_MODULE,
        },
        .probe =    wm8960_i2c_probe,
        .remove =   __devexit_p(wm8960_i2c_remove),
        .id_table = wm8960_i2c_id,
 };
-#endif
 
 static int __init wm8960_modinit(void)
 {
        int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8960_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
                       ret);
        }
-#endif
        return ret;
 }
 module_init(wm8960_modinit);
 
 static void __exit wm8960_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8960_i2c_driver);
-#endif
 }
 module_exit(wm8960_exit);
 
index 9568c8a49f962da10d62a11ad58a8143cfd8619d..4f20c72a0f1d329a824ee2255f6003ef741c07da 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -423,11 +422,11 @@ static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
        }
 
        if (event & SND_SOC_DAPM_PRE_PMD) {
-               /* Enable the amplifier */
+               /* Disable the amplifier */
                spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA);
                snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg);
 
-               /* Enable the PGA */
+               /* Disable the PGA */
                pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA);
                snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg);
        }
@@ -531,7 +530,7 @@ SND_SOC_DAPM_PGA("Right Input", WM8961_PWR_MGMT_1, 4, 0, NULL, 0),
 SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", WM8961_PWR_MGMT_1, 3, 0),
 SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", WM8961_PWR_MGMT_1, 2, 0),
 
-SND_SOC_DAPM_MICBIAS("MICBIAS", WM8961_PWR_MGMT_1, 1, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8961_PWR_MGMT_1, 1, 0, NULL, 0),
 
 SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &dacl_mux),
 SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &dacr_mux),
@@ -929,7 +928,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8961_dai_ops = {
+static const struct snd_soc_dai_ops wm8961_dai_ops = {
        .hw_params = wm8961_hw_params,
        .set_sysclk = wm8961_set_sysclk,
        .set_fmt = wm8961_set_fmt,
@@ -1039,7 +1038,7 @@ static int wm8961_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8961_suspend(struct snd_soc_codec *codec)
 {
        wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1048,18 +1047,7 @@ static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm8961_resume(struct snd_soc_codec *codec)
 {
-       u16 *reg_cache = codec->reg_cache;
-       int i;
-
-       for (i = 0; i < codec->driver->reg_cache_size; i++) {
-               if (reg_cache[i] == wm8961_reg_defaults[i])
-                       continue;
-
-               if (i == WM8961_SOFTWARE_RESET)
-                       continue;
-
-               snd_soc_write(codec, i, reg_cache[i]);
-       }
+       snd_soc_cache_sync(codec);
 
        wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1082,14 +1070,14 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
        .volatile_register = wm8961_volatile_register,
 };
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8961_priv *wm8961;
        int ret;
 
-       wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
+       wm8961 = devm_kzalloc(&i2c->dev, sizeof(struct wm8961_priv),
+                             GFP_KERNEL);
        if (wm8961 == NULL)
                return -ENOMEM;
 
@@ -1097,15 +1085,14 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8961, &wm8961_dai, 1);
-       if (ret < 0)
-               kfree(wm8961);
+
        return ret;
 }
 
 static __devexit int wm8961_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+
        return 0;
 }
 
@@ -1117,34 +1104,29 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
 
 static struct i2c_driver wm8961_i2c_driver = {
        .driver = {
-               .name = "wm8961-codec",
+               .name = "wm8961",
                .owner = THIS_MODULE,
        },
        .probe =    wm8961_i2c_probe,
        .remove =   __devexit_p(wm8961_i2c_remove),
        .id_table = wm8961_i2c_id,
 };
-#endif
 
 static int __init wm8961_modinit(void)
 {
        int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8961_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
                       ret);
        }
-#endif
        return ret;
 }
 module_init(wm8961_modinit);
 
 static void __exit wm8961_exit(void)
 {
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8961_i2c_driver);
-#endif
 }
 module_exit(wm8961_exit);
 
index 53edd9a8c758f24943de1219b37cb45602fc11ef..296de4e30d26f49729cd25bc4c22134b01fb90aa 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
-#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -50,6 +50,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8962_priv {
+       struct regmap *regmap;
        struct snd_soc_codec *codec;
 
        int sysclk;
@@ -95,7 +96,7 @@ static int wm8962_regulator_event_##n(struct notifier_block *nb, \
        struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
                                                  disable_nb[n]); \
        if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8962->codec->cache_sync = 1; \
+               regcache_cache_only(wm8962->regmap, true);      \
        } \
        return 0; \
 }
@@ -109,691 +110,691 @@ WM8962_REGULATOR_EVENT(5)
 WM8962_REGULATOR_EVENT(6)
 WM8962_REGULATOR_EVENT(7)
 
-static const u16 wm8962_reg[WM8962_MAX_REGISTER + 1] = {
-       [0] = 0x009F,     /* R0     - Left Input volume */
-       [1] = 0x049F,     /* R1     - Right Input volume */
-       [2] = 0x0000,     /* R2     - HPOUTL volume */
-       [3] = 0x0000,     /* R3     - HPOUTR volume */
-       [4] = 0x0020,     /* R4     - Clocking1 */
-       [5] = 0x0018,     /* R5     - ADC & DAC Control 1 */
-       [6] = 0x2008,     /* R6     - ADC & DAC Control 2 */
-       [7] = 0x000A,     /* R7     - Audio Interface 0 */
-       [8] = 0x01E4,     /* R8     - Clocking2 */
-       [9] = 0x0300,     /* R9     - Audio Interface 1 */
-       [10] = 0x00C0,    /* R10    - Left DAC volume */
-       [11] = 0x00C0,    /* R11    - Right DAC volume */
-
-       [14] = 0x0040,     /* R14    - Audio Interface 2 */
-       [15] = 0x6243,     /* R15    - Software Reset */
-
-       [17] = 0x007B,     /* R17    - ALC1 */
-       [18] = 0x0000,     /* R18    - ALC2 */
-       [19] = 0x1C32,     /* R19    - ALC3 */
-       [20] = 0x3200,     /* R20    - Noise Gate */
-       [21] = 0x00C0,     /* R21    - Left ADC volume */
-       [22] = 0x00C0,     /* R22    - Right ADC volume */
-       [23] = 0x0160,     /* R23    - Additional control(1) */
-       [24] = 0x0000,     /* R24    - Additional control(2) */
-       [25] = 0x0000,     /* R25    - Pwr Mgmt (1) */
-       [26] = 0x0000,     /* R26    - Pwr Mgmt (2) */
-       [27] = 0x0010,     /* R27    - Additional Control (3) */
-       [28] = 0x0000,     /* R28    - Anti-pop */
-
-       [30] = 0x005E,     /* R30    - Clocking 3 */
-       [31] = 0x0000,     /* R31    - Input mixer control (1) */
-       [32] = 0x0145,     /* R32    - Left input mixer volume */
-       [33] = 0x0145,     /* R33    - Right input mixer volume */
-       [34] = 0x0009,     /* R34    - Input mixer control (2) */
-       [35] = 0x0003,     /* R35    - Input bias control */
-       [37] = 0x0008,     /* R37    - Left input PGA control */
-       [38] = 0x0008,     /* R38    - Right input PGA control */
-
-       [40] = 0x0000,     /* R40    - SPKOUTL volume */
-       [41] = 0x0000,     /* R41    - SPKOUTR volume */
-
-       [47] = 0x0000,     /* R47    - Thermal Shutdown Status */
-       [48] = 0x8027,     /* R48    - Additional Control (4) */
-       [49] = 0x0010,     /* R49    - Class D Control 1 */
-
-       [51] = 0x0003,     /* R51    - Class D Control 2 */
-
-       [56] = 0x0506,     /* R56    - Clocking 4 */
-       [57] = 0x0000,     /* R57    - DAC DSP Mixing (1) */
-       [58] = 0x0000,     /* R58    - DAC DSP Mixing (2) */
-
-       [60] = 0x0300,     /* R60    - DC Servo 0 */
-       [61] = 0x0300,     /* R61    - DC Servo 1 */
-
-       [64] = 0x0810,     /* R64    - DC Servo 4 */
-
-       [66] = 0x0000,     /* R66    - DC Servo 6 */
-
-       [68] = 0x001B,     /* R68    - Analogue PGA Bias */
-       [69] = 0x0000,     /* R69    - Analogue HP 0 */
-
-       [71] = 0x01FB,     /* R71    - Analogue HP 2 */
-       [72] = 0x0000,     /* R72    - Charge Pump 1 */
-
-       [82] = 0x0004,     /* R82    - Charge Pump B */
-
-       [87] = 0x0000,     /* R87    - Write Sequencer Control 1 */
-
-       [90] = 0x0000,     /* R90    - Write Sequencer Control 2 */
-
-       [93] = 0x0000,     /* R93    - Write Sequencer Control 3 */
-       [94] = 0x0000,     /* R94    - Control Interface */
-
-       [99] = 0x0000,     /* R99    - Mixer Enables */
-       [100] = 0x0000,     /* R100   - Headphone Mixer (1) */
-       [101] = 0x0000,     /* R101   - Headphone Mixer (2) */
-       [102] = 0x013F,     /* R102   - Headphone Mixer (3) */
-       [103] = 0x013F,     /* R103   - Headphone Mixer (4) */
-
-       [105] = 0x0000,     /* R105   - Speaker Mixer (1) */
-       [106] = 0x0000,     /* R106   - Speaker Mixer (2) */
-       [107] = 0x013F,     /* R107   - Speaker Mixer (3) */
-       [108] = 0x013F,     /* R108   - Speaker Mixer (4) */
-       [109] = 0x0003,     /* R109   - Speaker Mixer (5) */
-       [110] = 0x0002,     /* R110   - Beep Generator (1) */
-
-       [115] = 0x0006,     /* R115   - Oscillator Trim (3) */
-       [116] = 0x0026,     /* R116   - Oscillator Trim (4) */
-
-       [119] = 0x0000,     /* R119   - Oscillator Trim (7) */
-
-       [124] = 0x0011,     /* R124   - Analogue Clocking1 */
-       [125] = 0x004B,     /* R125   - Analogue Clocking2 */
-       [126] = 0x000D,     /* R126   - Analogue Clocking3 */
-       [127] = 0x0000,     /* R127   - PLL Software Reset */
-
-       [129] = 0x0000,     /* R129   - PLL2 */
-
-       [131] = 0x0000,     /* R131   - PLL 4 */
-
-       [136] = 0x0067,     /* R136   - PLL 9 */
-       [137] = 0x001C,     /* R137   - PLL 10 */
-       [138] = 0x0071,     /* R138   - PLL 11 */
-       [139] = 0x00C7,     /* R139   - PLL 12 */
-       [140] = 0x0067,     /* R140   - PLL 13 */
-       [141] = 0x0048,     /* R141   - PLL 14 */
-       [142] = 0x0022,     /* R142   - PLL 15 */
-       [143] = 0x0097,     /* R143   - PLL 16 */
-
-       [155] = 0x000C,     /* R155   - FLL Control (1) */
-       [156] = 0x0039,     /* R156   - FLL Control (2) */
-       [157] = 0x0180,     /* R157   - FLL Control (3) */
-
-       [159] = 0x0032,     /* R159   - FLL Control (5) */
-       [160] = 0x0018,     /* R160   - FLL Control (6) */
-       [161] = 0x007D,     /* R161   - FLL Control (7) */
-       [162] = 0x0008,     /* R162   - FLL Control (8) */
-
-       [252] = 0x0005,     /* R252   - General test 1 */
-
-       [256] = 0x0000,     /* R256   - DF1 */
-       [257] = 0x0000,     /* R257   - DF2 */
-       [258] = 0x0000,     /* R258   - DF3 */
-       [259] = 0x0000,     /* R259   - DF4 */
-       [260] = 0x0000,     /* R260   - DF5 */
-       [261] = 0x0000,     /* R261   - DF6 */
-       [262] = 0x0000,     /* R262   - DF7 */
-
-       [264] = 0x0000,     /* R264   - LHPF1 */
-       [265] = 0x0000,     /* R265   - LHPF2 */
-
-       [268] = 0x0000,     /* R268   - THREED1 */
-       [269] = 0x0000,     /* R269   - THREED2 */
-       [270] = 0x0000,     /* R270   - THREED3 */
-       [271] = 0x0000,     /* R271   - THREED4 */
-
-       [276] = 0x000C,     /* R276   - DRC 1 */
-       [277] = 0x0925,     /* R277   - DRC 2 */
-       [278] = 0x0000,     /* R278   - DRC 3 */
-       [279] = 0x0000,     /* R279   - DRC 4 */
-       [280] = 0x0000,     /* R280   - DRC 5 */
-
-       [285] = 0x0000,     /* R285   - Tloopback */
-
-       [335] = 0x0004,     /* R335   - EQ1 */
-       [336] = 0x6318,     /* R336   - EQ2 */
-       [337] = 0x6300,     /* R337   - EQ3 */
-       [338] = 0x0FCA,     /* R338   - EQ4 */
-       [339] = 0x0400,     /* R339   - EQ5 */
-       [340] = 0x00D8,     /* R340   - EQ6 */
-       [341] = 0x1EB5,     /* R341   - EQ7 */
-       [342] = 0xF145,     /* R342   - EQ8 */
-       [343] = 0x0B75,     /* R343   - EQ9 */
-       [344] = 0x01C5,     /* R344   - EQ10 */
-       [345] = 0x1C58,     /* R345   - EQ11 */
-       [346] = 0xF373,     /* R346   - EQ12 */
-       [347] = 0x0A54,     /* R347   - EQ13 */
-       [348] = 0x0558,     /* R348   - EQ14 */
-       [349] = 0x168E,     /* R349   - EQ15 */
-       [350] = 0xF829,     /* R350   - EQ16 */
-       [351] = 0x07AD,     /* R351   - EQ17 */
-       [352] = 0x1103,     /* R352   - EQ18 */
-       [353] = 0x0564,     /* R353   - EQ19 */
-       [354] = 0x0559,     /* R354   - EQ20 */
-       [355] = 0x4000,     /* R355   - EQ21 */
-       [356] = 0x6318,     /* R356   - EQ22 */
-       [357] = 0x6300,     /* R357   - EQ23 */
-       [358] = 0x0FCA,     /* R358   - EQ24 */
-       [359] = 0x0400,     /* R359   - EQ25 */
-       [360] = 0x00D8,     /* R360   - EQ26 */
-       [361] = 0x1EB5,     /* R361   - EQ27 */
-       [362] = 0xF145,     /* R362   - EQ28 */
-       [363] = 0x0B75,     /* R363   - EQ29 */
-       [364] = 0x01C5,     /* R364   - EQ30 */
-       [365] = 0x1C58,     /* R365   - EQ31 */
-       [366] = 0xF373,     /* R366   - EQ32 */
-       [367] = 0x0A54,     /* R367   - EQ33 */
-       [368] = 0x0558,     /* R368   - EQ34 */
-       [369] = 0x168E,     /* R369   - EQ35 */
-       [370] = 0xF829,     /* R370   - EQ36 */
-       [371] = 0x07AD,     /* R371   - EQ37 */
-       [372] = 0x1103,     /* R372   - EQ38 */
-       [373] = 0x0564,     /* R373   - EQ39 */
-       [374] = 0x0559,     /* R374   - EQ40 */
-       [375] = 0x4000,     /* R375   - EQ41 */
-
-       [513] = 0x0000,     /* R513   - GPIO 2 */
-       [514] = 0x0000,     /* R514   - GPIO 3 */
-
-       [516] = 0x8100,     /* R516   - GPIO 5 */
-       [517] = 0x8100,     /* R517   - GPIO 6 */
-
-       [560] = 0x0000,     /* R560   - Interrupt Status 1 */
-       [561] = 0x0000,     /* R561   - Interrupt Status 2 */
-
-       [568] = 0x0030,     /* R568   - Interrupt Status 1 Mask */
-       [569] = 0xFFED,     /* R569   - Interrupt Status 2 Mask */
-
-       [576] = 0x0000,     /* R576   - Interrupt Control */
-
-       [584] = 0x002D,     /* R584   - IRQ Debounce */
-
-       [586] = 0x0000,     /* R586   -  MICINT Source Pol */
-
-       [768] = 0x1C00,     /* R768   - DSP2 Power Management */
-
-       [1037] = 0x0000,     /* R1037  - DSP2_ExecControl */
-
-       [8192] = 0x0000,     /* R8192  - DSP2 Instruction RAM 0 */
-
-       [9216] = 0x0030,     /* R9216  - DSP2 Address RAM 2 */
-       [9217] = 0x0000,     /* R9217  - DSP2 Address RAM 1 */
-       [9218] = 0x0000,     /* R9218  - DSP2 Address RAM 0 */
-
-       [12288] = 0x0000,     /* R12288 - DSP2 Data1 RAM 1 */
-       [12289] = 0x0000,     /* R12289 - DSP2 Data1 RAM 0 */
-
-       [13312] = 0x0000,     /* R13312 - DSP2 Data2 RAM 1 */
-       [13313] = 0x0000,     /* R13313 - DSP2 Data2 RAM 0 */
-
-       [14336] = 0x0000,     /* R14336 - DSP2 Data3 RAM 1 */
-       [14337] = 0x0000,     /* R14337 - DSP2 Data3 RAM 0 */
-
-       [15360] = 0x000A,     /* R15360 - DSP2 Coeff RAM 0 */
-
-       [16384] = 0x0000,     /* R16384 - RETUNEADC_SHARED_COEFF_1 */
-       [16385] = 0x0000,     /* R16385 - RETUNEADC_SHARED_COEFF_0 */
-       [16386] = 0x0000,     /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
-       [16387] = 0x0000,     /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
-       [16388] = 0x0000,     /* R16388 - SOUNDSTAGE_ENABLES_1 */
-       [16389] = 0x0000,     /* R16389 - SOUNDSTAGE_ENABLES_0 */
-
-       [16896] = 0x0002,     /* R16896 - HDBASS_AI_1 */
-       [16897] = 0xBD12,     /* R16897 - HDBASS_AI_0 */
-       [16898] = 0x007C,     /* R16898 - HDBASS_AR_1 */
-       [16899] = 0x586C,     /* R16899 - HDBASS_AR_0 */
-       [16900] = 0x0053,     /* R16900 - HDBASS_B_1 */
-       [16901] = 0x8121,     /* R16901 - HDBASS_B_0 */
-       [16902] = 0x003F,     /* R16902 - HDBASS_K_1 */
-       [16903] = 0x8BD8,     /* R16903 - HDBASS_K_0 */
-       [16904] = 0x0032,     /* R16904 - HDBASS_N1_1 */
-       [16905] = 0xF52D,     /* R16905 - HDBASS_N1_0 */
-       [16906] = 0x0065,     /* R16906 - HDBASS_N2_1 */
-       [16907] = 0xAC8C,     /* R16907 - HDBASS_N2_0 */
-       [16908] = 0x006B,     /* R16908 - HDBASS_N3_1 */
-       [16909] = 0xE087,     /* R16909 - HDBASS_N3_0 */
-       [16910] = 0x0072,     /* R16910 - HDBASS_N4_1 */
-       [16911] = 0x1483,     /* R16911 - HDBASS_N4_0 */
-       [16912] = 0x0072,     /* R16912 - HDBASS_N5_1 */
-       [16913] = 0x1483,     /* R16913 - HDBASS_N5_0 */
-       [16914] = 0x0043,     /* R16914 - HDBASS_X1_1 */
-       [16915] = 0x3525,     /* R16915 - HDBASS_X1_0 */
-       [16916] = 0x0006,     /* R16916 - HDBASS_X2_1 */
-       [16917] = 0x6A4A,     /* R16917 - HDBASS_X2_0 */
-       [16918] = 0x0043,     /* R16918 - HDBASS_X3_1 */
-       [16919] = 0x6079,     /* R16919 - HDBASS_X3_0 */
-       [16920] = 0x0008,     /* R16920 - HDBASS_ATK_1 */
-       [16921] = 0x0000,     /* R16921 - HDBASS_ATK_0 */
-       [16922] = 0x0001,     /* R16922 - HDBASS_DCY_1 */
-       [16923] = 0x0000,     /* R16923 - HDBASS_DCY_0 */
-       [16924] = 0x0059,     /* R16924 - HDBASS_PG_1 */
-       [16925] = 0x999A,     /* R16925 - HDBASS_PG_0 */
-
-       [17048] = 0x0083,     /* R17408 - HPF_C_1 */
-       [17049] = 0x98AD,     /* R17409 - HPF_C_0 */
-
-       [17920] = 0x007F,     /* R17920 - ADCL_RETUNE_C1_1 */
-       [17921] = 0xFFFF,     /* R17921 - ADCL_RETUNE_C1_0 */
-       [17922] = 0x0000,     /* R17922 - ADCL_RETUNE_C2_1 */
-       [17923] = 0x0000,     /* R17923 - ADCL_RETUNE_C2_0 */
-       [17924] = 0x0000,     /* R17924 - ADCL_RETUNE_C3_1 */
-       [17925] = 0x0000,     /* R17925 - ADCL_RETUNE_C3_0 */
-       [17926] = 0x0000,     /* R17926 - ADCL_RETUNE_C4_1 */
-       [17927] = 0x0000,     /* R17927 - ADCL_RETUNE_C4_0 */
-       [17928] = 0x0000,     /* R17928 - ADCL_RETUNE_C5_1 */
-       [17929] = 0x0000,     /* R17929 - ADCL_RETUNE_C5_0 */
-       [17930] = 0x0000,     /* R17930 - ADCL_RETUNE_C6_1 */
-       [17931] = 0x0000,     /* R17931 - ADCL_RETUNE_C6_0 */
-       [17932] = 0x0000,     /* R17932 - ADCL_RETUNE_C7_1 */
-       [17933] = 0x0000,     /* R17933 - ADCL_RETUNE_C7_0 */
-       [17934] = 0x0000,     /* R17934 - ADCL_RETUNE_C8_1 */
-       [17935] = 0x0000,     /* R17935 - ADCL_RETUNE_C8_0 */
-       [17936] = 0x0000,     /* R17936 - ADCL_RETUNE_C9_1 */
-       [17937] = 0x0000,     /* R17937 - ADCL_RETUNE_C9_0 */
-       [17938] = 0x0000,     /* R17938 - ADCL_RETUNE_C10_1 */
-       [17939] = 0x0000,     /* R17939 - ADCL_RETUNE_C10_0 */
-       [17940] = 0x0000,     /* R17940 - ADCL_RETUNE_C11_1 */
-       [17941] = 0x0000,     /* R17941 - ADCL_RETUNE_C11_0 */
-       [17942] = 0x0000,     /* R17942 - ADCL_RETUNE_C12_1 */
-       [17943] = 0x0000,     /* R17943 - ADCL_RETUNE_C12_0 */
-       [17944] = 0x0000,     /* R17944 - ADCL_RETUNE_C13_1 */
-       [17945] = 0x0000,     /* R17945 - ADCL_RETUNE_C13_0 */
-       [17946] = 0x0000,     /* R17946 - ADCL_RETUNE_C14_1 */
-       [17947] = 0x0000,     /* R17947 - ADCL_RETUNE_C14_0 */
-       [17948] = 0x0000,     /* R17948 - ADCL_RETUNE_C15_1 */
-       [17949] = 0x0000,     /* R17949 - ADCL_RETUNE_C15_0 */
-       [17950] = 0x0000,     /* R17950 - ADCL_RETUNE_C16_1 */
-       [17951] = 0x0000,     /* R17951 - ADCL_RETUNE_C16_0 */
-       [17952] = 0x0000,     /* R17952 - ADCL_RETUNE_C17_1 */
-       [17953] = 0x0000,     /* R17953 - ADCL_RETUNE_C17_0 */
-       [17954] = 0x0000,     /* R17954 - ADCL_RETUNE_C18_1 */
-       [17955] = 0x0000,     /* R17955 - ADCL_RETUNE_C18_0 */
-       [17956] = 0x0000,     /* R17956 - ADCL_RETUNE_C19_1 */
-       [17957] = 0x0000,     /* R17957 - ADCL_RETUNE_C19_0 */
-       [17958] = 0x0000,     /* R17958 - ADCL_RETUNE_C20_1 */
-       [17959] = 0x0000,     /* R17959 - ADCL_RETUNE_C20_0 */
-       [17960] = 0x0000,     /* R17960 - ADCL_RETUNE_C21_1 */
-       [17961] = 0x0000,     /* R17961 - ADCL_RETUNE_C21_0 */
-       [17962] = 0x0000,     /* R17962 - ADCL_RETUNE_C22_1 */
-       [17963] = 0x0000,     /* R17963 - ADCL_RETUNE_C22_0 */
-       [17964] = 0x0000,     /* R17964 - ADCL_RETUNE_C23_1 */
-       [17965] = 0x0000,     /* R17965 - ADCL_RETUNE_C23_0 */
-       [17966] = 0x0000,     /* R17966 - ADCL_RETUNE_C24_1 */
-       [17967] = 0x0000,     /* R17967 - ADCL_RETUNE_C24_0 */
-       [17968] = 0x0000,     /* R17968 - ADCL_RETUNE_C25_1 */
-       [17969] = 0x0000,     /* R17969 - ADCL_RETUNE_C25_0 */
-       [17970] = 0x0000,     /* R17970 - ADCL_RETUNE_C26_1 */
-       [17971] = 0x0000,     /* R17971 - ADCL_RETUNE_C26_0 */
-       [17972] = 0x0000,     /* R17972 - ADCL_RETUNE_C27_1 */
-       [17973] = 0x0000,     /* R17973 - ADCL_RETUNE_C27_0 */
-       [17974] = 0x0000,     /* R17974 - ADCL_RETUNE_C28_1 */
-       [17975] = 0x0000,     /* R17975 - ADCL_RETUNE_C28_0 */
-       [17976] = 0x0000,     /* R17976 - ADCL_RETUNE_C29_1 */
-       [17977] = 0x0000,     /* R17977 - ADCL_RETUNE_C29_0 */
-       [17978] = 0x0000,     /* R17978 - ADCL_RETUNE_C30_1 */
-       [17979] = 0x0000,     /* R17979 - ADCL_RETUNE_C30_0 */
-       [17980] = 0x0000,     /* R17980 - ADCL_RETUNE_C31_1 */
-       [17981] = 0x0000,     /* R17981 - ADCL_RETUNE_C31_0 */
-       [17982] = 0x0000,     /* R17982 - ADCL_RETUNE_C32_1 */
-       [17983] = 0x0000,     /* R17983 - ADCL_RETUNE_C32_0 */
-
-       [18432] = 0x0020,     /* R18432 - RETUNEADC_PG2_1 */
-       [18433] = 0x0000,     /* R18433 - RETUNEADC_PG2_0 */
-       [18434] = 0x0040,     /* R18434 - RETUNEADC_PG_1 */
-       [18435] = 0x0000,     /* R18435 - RETUNEADC_PG_0 */
-
-       [18944] = 0x007F,     /* R18944 - ADCR_RETUNE_C1_1 */
-       [18945] = 0xFFFF,     /* R18945 - ADCR_RETUNE_C1_0 */
-       [18946] = 0x0000,     /* R18946 - ADCR_RETUNE_C2_1 */
-       [18947] = 0x0000,     /* R18947 - ADCR_RETUNE_C2_0 */
-       [18948] = 0x0000,     /* R18948 - ADCR_RETUNE_C3_1 */
-       [18949] = 0x0000,     /* R18949 - ADCR_RETUNE_C3_0 */
-       [18950] = 0x0000,     /* R18950 - ADCR_RETUNE_C4_1 */
-       [18951] = 0x0000,     /* R18951 - ADCR_RETUNE_C4_0 */
-       [18952] = 0x0000,     /* R18952 - ADCR_RETUNE_C5_1 */
-       [18953] = 0x0000,     /* R18953 - ADCR_RETUNE_C5_0 */
-       [18954] = 0x0000,     /* R18954 - ADCR_RETUNE_C6_1 */
-       [18955] = 0x0000,     /* R18955 - ADCR_RETUNE_C6_0 */
-       [18956] = 0x0000,     /* R18956 - ADCR_RETUNE_C7_1 */
-       [18957] = 0x0000,     /* R18957 - ADCR_RETUNE_C7_0 */
-       [18958] = 0x0000,     /* R18958 - ADCR_RETUNE_C8_1 */
-       [18959] = 0x0000,     /* R18959 - ADCR_RETUNE_C8_0 */
-       [18960] = 0x0000,     /* R18960 - ADCR_RETUNE_C9_1 */
-       [18961] = 0x0000,     /* R18961 - ADCR_RETUNE_C9_0 */
-       [18962] = 0x0000,     /* R18962 - ADCR_RETUNE_C10_1 */
-       [18963] = 0x0000,     /* R18963 - ADCR_RETUNE_C10_0 */
-       [18964] = 0x0000,     /* R18964 - ADCR_RETUNE_C11_1 */
-       [18965] = 0x0000,     /* R18965 - ADCR_RETUNE_C11_0 */
-       [18966] = 0x0000,     /* R18966 - ADCR_RETUNE_C12_1 */
-       [18967] = 0x0000,     /* R18967 - ADCR_RETUNE_C12_0 */
-       [18968] = 0x0000,     /* R18968 - ADCR_RETUNE_C13_1 */
-       [18969] = 0x0000,     /* R18969 - ADCR_RETUNE_C13_0 */
-       [18970] = 0x0000,     /* R18970 - ADCR_RETUNE_C14_1 */
-       [18971] = 0x0000,     /* R18971 - ADCR_RETUNE_C14_0 */
-       [18972] = 0x0000,     /* R18972 - ADCR_RETUNE_C15_1 */
-       [18973] = 0x0000,     /* R18973 - ADCR_RETUNE_C15_0 */
-       [18974] = 0x0000,     /* R18974 - ADCR_RETUNE_C16_1 */
-       [18975] = 0x0000,     /* R18975 - ADCR_RETUNE_C16_0 */
-       [18976] = 0x0000,     /* R18976 - ADCR_RETUNE_C17_1 */
-       [18977] = 0x0000,     /* R18977 - ADCR_RETUNE_C17_0 */
-       [18978] = 0x0000,     /* R18978 - ADCR_RETUNE_C18_1 */
-       [18979] = 0x0000,     /* R18979 - ADCR_RETUNE_C18_0 */
-       [18980] = 0x0000,     /* R18980 - ADCR_RETUNE_C19_1 */
-       [18981] = 0x0000,     /* R18981 - ADCR_RETUNE_C19_0 */
-       [18982] = 0x0000,     /* R18982 - ADCR_RETUNE_C20_1 */
-       [18983] = 0x0000,     /* R18983 - ADCR_RETUNE_C20_0 */
-       [18984] = 0x0000,     /* R18984 - ADCR_RETUNE_C21_1 */
-       [18985] = 0x0000,     /* R18985 - ADCR_RETUNE_C21_0 */
-       [18986] = 0x0000,     /* R18986 - ADCR_RETUNE_C22_1 */
-       [18987] = 0x0000,     /* R18987 - ADCR_RETUNE_C22_0 */
-       [18988] = 0x0000,     /* R18988 - ADCR_RETUNE_C23_1 */
-       [18989] = 0x0000,     /* R18989 - ADCR_RETUNE_C23_0 */
-       [18990] = 0x0000,     /* R18990 - ADCR_RETUNE_C24_1 */
-       [18991] = 0x0000,     /* R18991 - ADCR_RETUNE_C24_0 */
-       [18992] = 0x0000,     /* R18992 - ADCR_RETUNE_C25_1 */
-       [18993] = 0x0000,     /* R18993 - ADCR_RETUNE_C25_0 */
-       [18994] = 0x0000,     /* R18994 - ADCR_RETUNE_C26_1 */
-       [18995] = 0x0000,     /* R18995 - ADCR_RETUNE_C26_0 */
-       [18996] = 0x0000,     /* R18996 - ADCR_RETUNE_C27_1 */
-       [18997] = 0x0000,     /* R18997 - ADCR_RETUNE_C27_0 */
-       [18998] = 0x0000,     /* R18998 - ADCR_RETUNE_C28_1 */
-       [18999] = 0x0000,     /* R18999 - ADCR_RETUNE_C28_0 */
-       [19000] = 0x0000,     /* R19000 - ADCR_RETUNE_C29_1 */
-       [19001] = 0x0000,     /* R19001 - ADCR_RETUNE_C29_0 */
-       [19002] = 0x0000,     /* R19002 - ADCR_RETUNE_C30_1 */
-       [19003] = 0x0000,     /* R19003 - ADCR_RETUNE_C30_0 */
-       [19004] = 0x0000,     /* R19004 - ADCR_RETUNE_C31_1 */
-       [19005] = 0x0000,     /* R19005 - ADCR_RETUNE_C31_0 */
-       [19006] = 0x0000,     /* R19006 - ADCR_RETUNE_C32_1 */
-       [19007] = 0x0000,     /* R19007 - ADCR_RETUNE_C32_0 */
-
-       [19456] = 0x007F,     /* R19456 - DACL_RETUNE_C1_1 */
-       [19457] = 0xFFFF,     /* R19457 - DACL_RETUNE_C1_0 */
-       [19458] = 0x0000,     /* R19458 - DACL_RETUNE_C2_1 */
-       [19459] = 0x0000,     /* R19459 - DACL_RETUNE_C2_0 */
-       [19460] = 0x0000,     /* R19460 - DACL_RETUNE_C3_1 */
-       [19461] = 0x0000,     /* R19461 - DACL_RETUNE_C3_0 */
-       [19462] = 0x0000,     /* R19462 - DACL_RETUNE_C4_1 */
-       [19463] = 0x0000,     /* R19463 - DACL_RETUNE_C4_0 */
-       [19464] = 0x0000,     /* R19464 - DACL_RETUNE_C5_1 */
-       [19465] = 0x0000,     /* R19465 - DACL_RETUNE_C5_0 */
-       [19466] = 0x0000,     /* R19466 - DACL_RETUNE_C6_1 */
-       [19467] = 0x0000,     /* R19467 - DACL_RETUNE_C6_0 */
-       [19468] = 0x0000,     /* R19468 - DACL_RETUNE_C7_1 */
-       [19469] = 0x0000,     /* R19469 - DACL_RETUNE_C7_0 */
-       [19470] = 0x0000,     /* R19470 - DACL_RETUNE_C8_1 */
-       [19471] = 0x0000,     /* R19471 - DACL_RETUNE_C8_0 */
-       [19472] = 0x0000,     /* R19472 - DACL_RETUNE_C9_1 */
-       [19473] = 0x0000,     /* R19473 - DACL_RETUNE_C9_0 */
-       [19474] = 0x0000,     /* R19474 - DACL_RETUNE_C10_1 */
-       [19475] = 0x0000,     /* R19475 - DACL_RETUNE_C10_0 */
-       [19476] = 0x0000,     /* R19476 - DACL_RETUNE_C11_1 */
-       [19477] = 0x0000,     /* R19477 - DACL_RETUNE_C11_0 */
-       [19478] = 0x0000,     /* R19478 - DACL_RETUNE_C12_1 */
-       [19479] = 0x0000,     /* R19479 - DACL_RETUNE_C12_0 */
-       [19480] = 0x0000,     /* R19480 - DACL_RETUNE_C13_1 */
-       [19481] = 0x0000,     /* R19481 - DACL_RETUNE_C13_0 */
-       [19482] = 0x0000,     /* R19482 - DACL_RETUNE_C14_1 */
-       [19483] = 0x0000,     /* R19483 - DACL_RETUNE_C14_0 */
-       [19484] = 0x0000,     /* R19484 - DACL_RETUNE_C15_1 */
-       [19485] = 0x0000,     /* R19485 - DACL_RETUNE_C15_0 */
-       [19486] = 0x0000,     /* R19486 - DACL_RETUNE_C16_1 */
-       [19487] = 0x0000,     /* R19487 - DACL_RETUNE_C16_0 */
-       [19488] = 0x0000,     /* R19488 - DACL_RETUNE_C17_1 */
-       [19489] = 0x0000,     /* R19489 - DACL_RETUNE_C17_0 */
-       [19490] = 0x0000,     /* R19490 - DACL_RETUNE_C18_1 */
-       [19491] = 0x0000,     /* R19491 - DACL_RETUNE_C18_0 */
-       [19492] = 0x0000,     /* R19492 - DACL_RETUNE_C19_1 */
-       [19493] = 0x0000,     /* R19493 - DACL_RETUNE_C19_0 */
-       [19494] = 0x0000,     /* R19494 - DACL_RETUNE_C20_1 */
-       [19495] = 0x0000,     /* R19495 - DACL_RETUNE_C20_0 */
-       [19496] = 0x0000,     /* R19496 - DACL_RETUNE_C21_1 */
-       [19497] = 0x0000,     /* R19497 - DACL_RETUNE_C21_0 */
-       [19498] = 0x0000,     /* R19498 - DACL_RETUNE_C22_1 */
-       [19499] = 0x0000,     /* R19499 - DACL_RETUNE_C22_0 */
-       [19500] = 0x0000,     /* R19500 - DACL_RETUNE_C23_1 */
-       [19501] = 0x0000,     /* R19501 - DACL_RETUNE_C23_0 */
-       [19502] = 0x0000,     /* R19502 - DACL_RETUNE_C24_1 */
-       [19503] = 0x0000,     /* R19503 - DACL_RETUNE_C24_0 */
-       [19504] = 0x0000,     /* R19504 - DACL_RETUNE_C25_1 */
-       [19505] = 0x0000,     /* R19505 - DACL_RETUNE_C25_0 */
-       [19506] = 0x0000,     /* R19506 - DACL_RETUNE_C26_1 */
-       [19507] = 0x0000,     /* R19507 - DACL_RETUNE_C26_0 */
-       [19508] = 0x0000,     /* R19508 - DACL_RETUNE_C27_1 */
-       [19509] = 0x0000,     /* R19509 - DACL_RETUNE_C27_0 */
-       [19510] = 0x0000,     /* R19510 - DACL_RETUNE_C28_1 */
-       [19511] = 0x0000,     /* R19511 - DACL_RETUNE_C28_0 */
-       [19512] = 0x0000,     /* R19512 - DACL_RETUNE_C29_1 */
-       [19513] = 0x0000,     /* R19513 - DACL_RETUNE_C29_0 */
-       [19514] = 0x0000,     /* R19514 - DACL_RETUNE_C30_1 */
-       [19515] = 0x0000,     /* R19515 - DACL_RETUNE_C30_0 */
-       [19516] = 0x0000,     /* R19516 - DACL_RETUNE_C31_1 */
-       [19517] = 0x0000,     /* R19517 - DACL_RETUNE_C31_0 */
-       [19518] = 0x0000,     /* R19518 - DACL_RETUNE_C32_1 */
-       [19519] = 0x0000,     /* R19519 - DACL_RETUNE_C32_0 */
-
-       [19968] = 0x0020,     /* R19968 - RETUNEDAC_PG2_1 */
-       [19969] = 0x0000,     /* R19969 - RETUNEDAC_PG2_0 */
-       [19970] = 0x0040,     /* R19970 - RETUNEDAC_PG_1 */
-       [19971] = 0x0000,     /* R19971 - RETUNEDAC_PG_0 */
-
-       [20480] = 0x007F,     /* R20480 - DACR_RETUNE_C1_1 */
-       [20481] = 0xFFFF,     /* R20481 - DACR_RETUNE_C1_0 */
-       [20482] = 0x0000,     /* R20482 - DACR_RETUNE_C2_1 */
-       [20483] = 0x0000,     /* R20483 - DACR_RETUNE_C2_0 */
-       [20484] = 0x0000,     /* R20484 - DACR_RETUNE_C3_1 */
-       [20485] = 0x0000,     /* R20485 - DACR_RETUNE_C3_0 */
-       [20486] = 0x0000,     /* R20486 - DACR_RETUNE_C4_1 */
-       [20487] = 0x0000,     /* R20487 - DACR_RETUNE_C4_0 */
-       [20488] = 0x0000,     /* R20488 - DACR_RETUNE_C5_1 */
-       [20489] = 0x0000,     /* R20489 - DACR_RETUNE_C5_0 */
-       [20490] = 0x0000,     /* R20490 - DACR_RETUNE_C6_1 */
-       [20491] = 0x0000,     /* R20491 - DACR_RETUNE_C6_0 */
-       [20492] = 0x0000,     /* R20492 - DACR_RETUNE_C7_1 */
-       [20493] = 0x0000,     /* R20493 - DACR_RETUNE_C7_0 */
-       [20494] = 0x0000,     /* R20494 - DACR_RETUNE_C8_1 */
-       [20495] = 0x0000,     /* R20495 - DACR_RETUNE_C8_0 */
-       [20496] = 0x0000,     /* R20496 - DACR_RETUNE_C9_1 */
-       [20497] = 0x0000,     /* R20497 - DACR_RETUNE_C9_0 */
-       [20498] = 0x0000,     /* R20498 - DACR_RETUNE_C10_1 */
-       [20499] = 0x0000,     /* R20499 - DACR_RETUNE_C10_0 */
-       [20500] = 0x0000,     /* R20500 - DACR_RETUNE_C11_1 */
-       [20501] = 0x0000,     /* R20501 - DACR_RETUNE_C11_0 */
-       [20502] = 0x0000,     /* R20502 - DACR_RETUNE_C12_1 */
-       [20503] = 0x0000,     /* R20503 - DACR_RETUNE_C12_0 */
-       [20504] = 0x0000,     /* R20504 - DACR_RETUNE_C13_1 */
-       [20505] = 0x0000,     /* R20505 - DACR_RETUNE_C13_0 */
-       [20506] = 0x0000,     /* R20506 - DACR_RETUNE_C14_1 */
-       [20507] = 0x0000,     /* R20507 - DACR_RETUNE_C14_0 */
-       [20508] = 0x0000,     /* R20508 - DACR_RETUNE_C15_1 */
-       [20509] = 0x0000,     /* R20509 - DACR_RETUNE_C15_0 */
-       [20510] = 0x0000,     /* R20510 - DACR_RETUNE_C16_1 */
-       [20511] = 0x0000,     /* R20511 - DACR_RETUNE_C16_0 */
-       [20512] = 0x0000,     /* R20512 - DACR_RETUNE_C17_1 */
-       [20513] = 0x0000,     /* R20513 - DACR_RETUNE_C17_0 */
-       [20514] = 0x0000,     /* R20514 - DACR_RETUNE_C18_1 */
-       [20515] = 0x0000,     /* R20515 - DACR_RETUNE_C18_0 */
-       [20516] = 0x0000,     /* R20516 - DACR_RETUNE_C19_1 */
-       [20517] = 0x0000,     /* R20517 - DACR_RETUNE_C19_0 */
-       [20518] = 0x0000,     /* R20518 - DACR_RETUNE_C20_1 */
-       [20519] = 0x0000,     /* R20519 - DACR_RETUNE_C20_0 */
-       [20520] = 0x0000,     /* R20520 - DACR_RETUNE_C21_1 */
-       [20521] = 0x0000,     /* R20521 - DACR_RETUNE_C21_0 */
-       [20522] = 0x0000,     /* R20522 - DACR_RETUNE_C22_1 */
-       [20523] = 0x0000,     /* R20523 - DACR_RETUNE_C22_0 */
-       [20524] = 0x0000,     /* R20524 - DACR_RETUNE_C23_1 */
-       [20525] = 0x0000,     /* R20525 - DACR_RETUNE_C23_0 */
-       [20526] = 0x0000,     /* R20526 - DACR_RETUNE_C24_1 */
-       [20527] = 0x0000,     /* R20527 - DACR_RETUNE_C24_0 */
-       [20528] = 0x0000,     /* R20528 - DACR_RETUNE_C25_1 */
-       [20529] = 0x0000,     /* R20529 - DACR_RETUNE_C25_0 */
-       [20530] = 0x0000,     /* R20530 - DACR_RETUNE_C26_1 */
-       [20531] = 0x0000,     /* R20531 - DACR_RETUNE_C26_0 */
-       [20532] = 0x0000,     /* R20532 - DACR_RETUNE_C27_1 */
-       [20533] = 0x0000,     /* R20533 - DACR_RETUNE_C27_0 */
-       [20534] = 0x0000,     /* R20534 - DACR_RETUNE_C28_1 */
-       [20535] = 0x0000,     /* R20535 - DACR_RETUNE_C28_0 */
-       [20536] = 0x0000,     /* R20536 - DACR_RETUNE_C29_1 */
-       [20537] = 0x0000,     /* R20537 - DACR_RETUNE_C29_0 */
-       [20538] = 0x0000,     /* R20538 - DACR_RETUNE_C30_1 */
-       [20539] = 0x0000,     /* R20539 - DACR_RETUNE_C30_0 */
-       [20540] = 0x0000,     /* R20540 - DACR_RETUNE_C31_1 */
-       [20541] = 0x0000,     /* R20541 - DACR_RETUNE_C31_0 */
-       [20542] = 0x0000,     /* R20542 - DACR_RETUNE_C32_1 */
-       [20543] = 0x0000,     /* R20543 - DACR_RETUNE_C32_0 */
-
-       [20992] = 0x008C,     /* R20992 - VSS_XHD2_1 */
-       [20993] = 0x0200,     /* R20993 - VSS_XHD2_0 */
-       [20994] = 0x0035,     /* R20994 - VSS_XHD3_1 */
-       [20995] = 0x0700,     /* R20995 - VSS_XHD3_0 */
-       [20996] = 0x003A,     /* R20996 - VSS_XHN1_1 */
-       [20997] = 0x4100,     /* R20997 - VSS_XHN1_0 */
-       [20998] = 0x008B,     /* R20998 - VSS_XHN2_1 */
-       [20999] = 0x7D00,     /* R20999 - VSS_XHN2_0 */
-       [21000] = 0x003A,     /* R21000 - VSS_XHN3_1 */
-       [21001] = 0x4100,     /* R21001 - VSS_XHN3_0 */
-       [21002] = 0x008C,     /* R21002 - VSS_XLA_1 */
-       [21003] = 0xFEE8,     /* R21003 - VSS_XLA_0 */
-       [21004] = 0x0078,     /* R21004 - VSS_XLB_1 */
-       [21005] = 0x0000,     /* R21005 - VSS_XLB_0 */
-       [21006] = 0x003F,     /* R21006 - VSS_XLG_1 */
-       [21007] = 0xB260,     /* R21007 - VSS_XLG_0 */
-       [21008] = 0x002D,     /* R21008 - VSS_PG2_1 */
-       [21009] = 0x1818,     /* R21009 - VSS_PG2_0 */
-       [21010] = 0x0020,     /* R21010 - VSS_PG_1 */
-       [21011] = 0x0000,     /* R21011 - VSS_PG_0 */
-       [21012] = 0x00F1,     /* R21012 - VSS_XTD1_1 */
-       [21013] = 0x8340,     /* R21013 - VSS_XTD1_0 */
-       [21014] = 0x00FB,     /* R21014 - VSS_XTD2_1 */
-       [21015] = 0x8300,     /* R21015 - VSS_XTD2_0 */
-       [21016] = 0x00EE,     /* R21016 - VSS_XTD3_1 */
-       [21017] = 0xAEC0,     /* R21017 - VSS_XTD3_0 */
-       [21018] = 0x00FB,     /* R21018 - VSS_XTD4_1 */
-       [21019] = 0xAC40,     /* R21019 - VSS_XTD4_0 */
-       [21020] = 0x00F1,     /* R21020 - VSS_XTD5_1 */
-       [21021] = 0x7F80,     /* R21021 - VSS_XTD5_0 */
-       [21022] = 0x00F4,     /* R21022 - VSS_XTD6_1 */
-       [21023] = 0x3B40,     /* R21023 - VSS_XTD6_0 */
-       [21024] = 0x00F5,     /* R21024 - VSS_XTD7_1 */
-       [21025] = 0xFB00,     /* R21025 - VSS_XTD7_0 */
-       [21026] = 0x00EA,     /* R21026 - VSS_XTD8_1 */
-       [21027] = 0x10C0,     /* R21027 - VSS_XTD8_0 */
-       [21028] = 0x00FC,     /* R21028 - VSS_XTD9_1 */
-       [21029] = 0xC580,     /* R21029 - VSS_XTD9_0 */
-       [21030] = 0x00E2,     /* R21030 - VSS_XTD10_1 */
-       [21031] = 0x75C0,     /* R21031 - VSS_XTD10_0 */
-       [21032] = 0x0004,     /* R21032 - VSS_XTD11_1 */
-       [21033] = 0xB480,     /* R21033 - VSS_XTD11_0 */
-       [21034] = 0x00D4,     /* R21034 - VSS_XTD12_1 */
-       [21035] = 0xF980,     /* R21035 - VSS_XTD12_0 */
-       [21036] = 0x0004,     /* R21036 - VSS_XTD13_1 */
-       [21037] = 0x9140,     /* R21037 - VSS_XTD13_0 */
-       [21038] = 0x00D8,     /* R21038 - VSS_XTD14_1 */
-       [21039] = 0xA480,     /* R21039 - VSS_XTD14_0 */
-       [21040] = 0x0002,     /* R21040 - VSS_XTD15_1 */
-       [21041] = 0x3DC0,     /* R21041 - VSS_XTD15_0 */
-       [21042] = 0x00CF,     /* R21042 - VSS_XTD16_1 */
-       [21043] = 0x7A80,     /* R21043 - VSS_XTD16_0 */
-       [21044] = 0x00DC,     /* R21044 - VSS_XTD17_1 */
-       [21045] = 0x0600,     /* R21045 - VSS_XTD17_0 */
-       [21046] = 0x00F2,     /* R21046 - VSS_XTD18_1 */
-       [21047] = 0xDAC0,     /* R21047 - VSS_XTD18_0 */
-       [21048] = 0x00BA,     /* R21048 - VSS_XTD19_1 */
-       [21049] = 0xF340,     /* R21049 - VSS_XTD19_0 */
-       [21050] = 0x000A,     /* R21050 - VSS_XTD20_1 */
-       [21051] = 0x7940,     /* R21051 - VSS_XTD20_0 */
-       [21052] = 0x001C,     /* R21052 - VSS_XTD21_1 */
-       [21053] = 0x0680,     /* R21053 - VSS_XTD21_0 */
-       [21054] = 0x00FD,     /* R21054 - VSS_XTD22_1 */
-       [21055] = 0x2D00,     /* R21055 - VSS_XTD22_0 */
-       [21056] = 0x001C,     /* R21056 - VSS_XTD23_1 */
-       [21057] = 0xE840,     /* R21057 - VSS_XTD23_0 */
-       [21058] = 0x000D,     /* R21058 - VSS_XTD24_1 */
-       [21059] = 0xDC40,     /* R21059 - VSS_XTD24_0 */
-       [21060] = 0x00FC,     /* R21060 - VSS_XTD25_1 */
-       [21061] = 0x9D00,     /* R21061 - VSS_XTD25_0 */
-       [21062] = 0x0009,     /* R21062 - VSS_XTD26_1 */
-       [21063] = 0x5580,     /* R21063 - VSS_XTD26_0 */
-       [21064] = 0x00FE,     /* R21064 - VSS_XTD27_1 */
-       [21065] = 0x7E80,     /* R21065 - VSS_XTD27_0 */
-       [21066] = 0x000E,     /* R21066 - VSS_XTD28_1 */
-       [21067] = 0xAB40,     /* R21067 - VSS_XTD28_0 */
-       [21068] = 0x00F9,     /* R21068 - VSS_XTD29_1 */
-       [21069] = 0x9880,     /* R21069 - VSS_XTD29_0 */
-       [21070] = 0x0009,     /* R21070 - VSS_XTD30_1 */
-       [21071] = 0x87C0,     /* R21071 - VSS_XTD30_0 */
-       [21072] = 0x00FD,     /* R21072 - VSS_XTD31_1 */
-       [21073] = 0x2C40,     /* R21073 - VSS_XTD31_0 */
-       [21074] = 0x0009,     /* R21074 - VSS_XTD32_1 */
-       [21075] = 0x4800,     /* R21075 - VSS_XTD32_0 */
-       [21076] = 0x0003,     /* R21076 - VSS_XTS1_1 */
-       [21077] = 0x5F40,     /* R21077 - VSS_XTS1_0 */
-       [21078] = 0x0000,     /* R21078 - VSS_XTS2_1 */
-       [21079] = 0x8700,     /* R21079 - VSS_XTS2_0 */
-       [21080] = 0x00FA,     /* R21080 - VSS_XTS3_1 */
-       [21081] = 0xE4C0,     /* R21081 - VSS_XTS3_0 */
-       [21082] = 0x0000,     /* R21082 - VSS_XTS4_1 */
-       [21083] = 0x0B40,     /* R21083 - VSS_XTS4_0 */
-       [21084] = 0x0004,     /* R21084 - VSS_XTS5_1 */
-       [21085] = 0xE180,     /* R21085 - VSS_XTS5_0 */
-       [21086] = 0x0001,     /* R21086 - VSS_XTS6_1 */
-       [21087] = 0x1F40,     /* R21087 - VSS_XTS6_0 */
-       [21088] = 0x00F8,     /* R21088 - VSS_XTS7_1 */
-       [21089] = 0xB000,     /* R21089 - VSS_XTS7_0 */
-       [21090] = 0x00FB,     /* R21090 - VSS_XTS8_1 */
-       [21091] = 0xCBC0,     /* R21091 - VSS_XTS8_0 */
-       [21092] = 0x0004,     /* R21092 - VSS_XTS9_1 */
-       [21093] = 0xF380,     /* R21093 - VSS_XTS9_0 */
-       [21094] = 0x0007,     /* R21094 - VSS_XTS10_1 */
-       [21095] = 0xDF40,     /* R21095 - VSS_XTS10_0 */
-       [21096] = 0x00FF,     /* R21096 - VSS_XTS11_1 */
-       [21097] = 0x0700,     /* R21097 - VSS_XTS11_0 */
-       [21098] = 0x00EF,     /* R21098 - VSS_XTS12_1 */
-       [21099] = 0xD700,     /* R21099 - VSS_XTS12_0 */
-       [21100] = 0x00FB,     /* R21100 - VSS_XTS13_1 */
-       [21101] = 0xAF40,     /* R21101 - VSS_XTS13_0 */
-       [21102] = 0x0010,     /* R21102 - VSS_XTS14_1 */
-       [21103] = 0x8A80,     /* R21103 - VSS_XTS14_0 */
-       [21104] = 0x0011,     /* R21104 - VSS_XTS15_1 */
-       [21105] = 0x07C0,     /* R21105 - VSS_XTS15_0 */
-       [21106] = 0x00E0,     /* R21106 - VSS_XTS16_1 */
-       [21107] = 0x0800,     /* R21107 - VSS_XTS16_0 */
-       [21108] = 0x00D2,     /* R21108 - VSS_XTS17_1 */
-       [21109] = 0x7600,     /* R21109 - VSS_XTS17_0 */
-       [21110] = 0x0020,     /* R21110 - VSS_XTS18_1 */
-       [21111] = 0xCF40,     /* R21111 - VSS_XTS18_0 */
-       [21112] = 0x0030,     /* R21112 - VSS_XTS19_1 */
-       [21113] = 0x2340,     /* R21113 - VSS_XTS19_0 */
-       [21114] = 0x00FD,     /* R21114 - VSS_XTS20_1 */
-       [21115] = 0x69C0,     /* R21115 - VSS_XTS20_0 */
-       [21116] = 0x0028,     /* R21116 - VSS_XTS21_1 */
-       [21117] = 0x3500,     /* R21117 - VSS_XTS21_0 */
-       [21118] = 0x0006,     /* R21118 - VSS_XTS22_1 */
-       [21119] = 0x3300,     /* R21119 - VSS_XTS22_0 */
-       [21120] = 0x00D9,     /* R21120 - VSS_XTS23_1 */
-       [21121] = 0xF6C0,     /* R21121 - VSS_XTS23_0 */
-       [21122] = 0x00F3,     /* R21122 - VSS_XTS24_1 */
-       [21123] = 0x3340,     /* R21123 - VSS_XTS24_0 */
-       [21124] = 0x000F,     /* R21124 - VSS_XTS25_1 */
-       [21125] = 0x4200,     /* R21125 - VSS_XTS25_0 */
-       [21126] = 0x0004,     /* R21126 - VSS_XTS26_1 */
-       [21127] = 0x0C80,     /* R21127 - VSS_XTS26_0 */
-       [21128] = 0x00FB,     /* R21128 - VSS_XTS27_1 */
-       [21129] = 0x3F80,     /* R21129 - VSS_XTS27_0 */
-       [21130] = 0x00F7,     /* R21130 - VSS_XTS28_1 */
-       [21131] = 0x57C0,     /* R21131 - VSS_XTS28_0 */
-       [21132] = 0x0003,     /* R21132 - VSS_XTS29_1 */
-       [21133] = 0x5400,     /* R21133 - VSS_XTS29_0 */
-       [21134] = 0x0000,     /* R21134 - VSS_XTS30_1 */
-       [21135] = 0xC6C0,     /* R21135 - VSS_XTS30_0 */
-       [21136] = 0x0003,     /* R21136 - VSS_XTS31_1 */
-       [21137] = 0x12C0,     /* R21137 - VSS_XTS31_0 */
-       [21138] = 0x00FD,     /* R21138 - VSS_XTS32_1 */
-       [21139] = 0x8580,     /* R21139 - VSS_XTS32_0 */
+static struct reg_default wm8962_reg[] = {
+       { 0, 0x009F },   /* R0     - Left Input volume */
+       { 1, 0x049F },   /* R1     - Right Input volume */
+       { 2, 0x0000 },   /* R2     - HPOUTL volume */
+       { 3, 0x0000 },   /* R3     - HPOUTR volume */
+       { 4, 0x0020 },   /* R4     - Clocking1 */
+       { 5, 0x0018 },   /* R5     - ADC & DAC Control 1 */
+       { 6, 0x2008 },   /* R6     - ADC & DAC Control 2 */
+       { 7, 0x000A },   /* R7     - Audio Interface 0 */
+       { 8, 0x01E4 },   /* R8     - Clocking2 */
+       { 9, 0x0300 },   /* R9     - Audio Interface 1 */
+       { 10, 0x00C0 },  /* R10    - Left DAC volume */
+       { 11, 0x00C0 },  /* R11    - Right DAC volume */
+
+       { 14, 0x0040 },   /* R14    - Audio Interface 2 */
+       { 15, 0x6243 },   /* R15    - Software Reset */
+
+       { 17, 0x007B },   /* R17    - ALC1 */
+       { 18, 0x0000 },   /* R18    - ALC2 */
+       { 19, 0x1C32 },   /* R19    - ALC3 */
+       { 20, 0x3200 },   /* R20    - Noise Gate */
+       { 21, 0x00C0 },   /* R21    - Left ADC volume */
+       { 22, 0x00C0 },   /* R22    - Right ADC volume */
+       { 23, 0x0160 },   /* R23    - Additional control(1) */
+       { 24, 0x0000 },   /* R24    - Additional control(2) */
+       { 25, 0x0000 },   /* R25    - Pwr Mgmt (1) */
+       { 26, 0x0000 },   /* R26    - Pwr Mgmt (2) */
+       { 27, 0x0010 },   /* R27    - Additional Control (3) */
+       { 28, 0x0000 },   /* R28    - Anti-pop */
+
+       { 30, 0x005E },   /* R30    - Clocking 3 */
+       { 31, 0x0000 },   /* R31    - Input mixer control (1) */
+       { 32, 0x0145 },   /* R32    - Left input mixer volume */
+       { 33, 0x0145 },   /* R33    - Right input mixer volume */
+       { 34, 0x0009 },   /* R34    - Input mixer control (2) */
+       { 35, 0x0003 },   /* R35    - Input bias control */
+       { 37, 0x0008 },   /* R37    - Left input PGA control */
+       { 38, 0x0008 },   /* R38    - Right input PGA control */
+
+       { 40, 0x0000 },   /* R40    - SPKOUTL volume */
+       { 41, 0x0000 },   /* R41    - SPKOUTR volume */
+
+       { 47, 0x0000 },   /* R47    - Thermal Shutdown Status */
+       { 48, 0x8027 },   /* R48    - Additional Control (4) */
+       { 49, 0x0010 },   /* R49    - Class D Control 1 */
+
+       { 51, 0x0003 },   /* R51    - Class D Control 2 */
+
+       { 56, 0x0506 },   /* R56    - Clocking 4 */
+       { 57, 0x0000 },   /* R57    - DAC DSP Mixing (1) */
+       { 58, 0x0000 },   /* R58    - DAC DSP Mixing (2) */
+
+       { 60, 0x0300 },   /* R60    - DC Servo 0 */
+       { 61, 0x0300 },   /* R61    - DC Servo 1 */
+
+       { 64, 0x0810 },   /* R64    - DC Servo 4 */
+
+       { 66, 0x0000 },   /* R66    - DC Servo 6 */
+
+       { 68, 0x001B },   /* R68    - Analogue PGA Bias */
+       { 69, 0x0000 },   /* R69    - Analogue HP 0 */
+
+       { 71, 0x01FB },   /* R71    - Analogue HP 2 */
+       { 72, 0x0000 },   /* R72    - Charge Pump 1 */
+
+       { 82, 0x0004 },   /* R82    - Charge Pump B */
+
+       { 87, 0x0000 },   /* R87    - Write Sequencer Control 1 */
+
+       { 90, 0x0000 },   /* R90    - Write Sequencer Control 2 */
+
+       { 93, 0x0000 },   /* R93    - Write Sequencer Control 3 */
+       { 94, 0x0000 },   /* R94    - Control Interface */
+
+       { 99, 0x0000 },   /* R99    - Mixer Enables */
+       { 100, 0x0000 },   /* R100   - Headphone Mixer (1) */
+       { 101, 0x0000 },   /* R101   - Headphone Mixer (2) */
+       { 102, 0x013F },   /* R102   - Headphone Mixer (3) */
+       { 103, 0x013F },   /* R103   - Headphone Mixer (4) */
+
+       { 105, 0x0000 },   /* R105   - Speaker Mixer (1) */
+       { 106, 0x0000 },   /* R106   - Speaker Mixer (2) */
+       { 107, 0x013F },   /* R107   - Speaker Mixer (3) */
+       { 108, 0x013F },   /* R108   - Speaker Mixer (4) */
+       { 109, 0x0003 },   /* R109   - Speaker Mixer (5) */
+       { 110, 0x0002 },   /* R110   - Beep Generator (1) */
+
+       { 115, 0x0006 },   /* R115   - Oscillator Trim (3) */
+       { 116, 0x0026 },   /* R116   - Oscillator Trim (4) */
+
+       { 119, 0x0000 },   /* R119   - Oscillator Trim (7) */
+
+       { 124, 0x0011 },   /* R124   - Analogue Clocking1 */
+       { 125, 0x004B },   /* R125   - Analogue Clocking2 */
+       { 126, 0x000D },   /* R126   - Analogue Clocking3 */
+       { 127, 0x0000 },   /* R127   - PLL Software Reset */
+
+       { 129, 0x0000 },   /* R129   - PLL2 */
+
+       { 131, 0x0000 },   /* R131   - PLL 4 */
+
+       { 136, 0x0067 },   /* R136   - PLL 9 */
+       { 137, 0x001C },   /* R137   - PLL 10 */
+       { 138, 0x0071 },   /* R138   - PLL 11 */
+       { 139, 0x00C7 },   /* R139   - PLL 12 */
+       { 140, 0x0067 },   /* R140   - PLL 13 */
+       { 141, 0x0048 },   /* R141   - PLL 14 */
+       { 142, 0x0022 },   /* R142   - PLL 15 */
+       { 143, 0x0097 },   /* R143   - PLL 16 */
+
+       { 155, 0x000C },   /* R155   - FLL Control (1) */
+       { 156, 0x0039 },   /* R156   - FLL Control (2) */
+       { 157, 0x0180 },   /* R157   - FLL Control (3) */
+
+       { 159, 0x0032 },   /* R159   - FLL Control (5) */
+       { 160, 0x0018 },   /* R160   - FLL Control (6) */
+       { 161, 0x007D },   /* R161   - FLL Control (7) */
+       { 162, 0x0008 },   /* R162   - FLL Control (8) */
+
+       { 252, 0x0005 },   /* R252   - General test 1 */
+
+       { 256, 0x0000 },   /* R256   - DF1 */
+       { 257, 0x0000 },   /* R257   - DF2 */
+       { 258, 0x0000 },   /* R258   - DF3 */
+       { 259, 0x0000 },   /* R259   - DF4 */
+       { 260, 0x0000 },   /* R260   - DF5 */
+       { 261, 0x0000 },   /* R261   - DF6 */
+       { 262, 0x0000 },   /* R262   - DF7 */
+
+       { 264, 0x0000 },   /* R264   - LHPF1 */
+       { 265, 0x0000 },   /* R265   - LHPF2 */
+
+       { 268, 0x0000 },   /* R268   - THREED1 */
+       { 269, 0x0000 },   /* R269   - THREED2 */
+       { 270, 0x0000 },   /* R270   - THREED3 */
+       { 271, 0x0000 },   /* R271   - THREED4 */
+
+       { 276, 0x000C },   /* R276   - DRC 1 */
+       { 277, 0x0925 },   /* R277   - DRC 2 */
+       { 278, 0x0000 },   /* R278   - DRC 3 */
+       { 279, 0x0000 },   /* R279   - DRC 4 */
+       { 280, 0x0000 },   /* R280   - DRC 5 */
+
+       { 285, 0x0000 },   /* R285   - Tloopback */
+
+       { 335, 0x0004 },   /* R335   - EQ1 */
+       { 336, 0x6318 },   /* R336   - EQ2 */
+       { 337, 0x6300 },   /* R337   - EQ3 */
+       { 338, 0x0FCA },   /* R338   - EQ4 */
+       { 339, 0x0400 },   /* R339   - EQ5 */
+       { 340, 0x00D8 },   /* R340   - EQ6 */
+       { 341, 0x1EB5 },   /* R341   - EQ7 */
+       { 342, 0xF145 },   /* R342   - EQ8 */
+       { 343, 0x0B75 },   /* R343   - EQ9 */
+       { 344, 0x01C5 },   /* R344   - EQ10 */
+       { 345, 0x1C58 },   /* R345   - EQ11 */
+       { 346, 0xF373 },   /* R346   - EQ12 */
+       { 347, 0x0A54 },   /* R347   - EQ13 */
+       { 348, 0x0558 },   /* R348   - EQ14 */
+       { 349, 0x168E },   /* R349   - EQ15 */
+       { 350, 0xF829 },   /* R350   - EQ16 */
+       { 351, 0x07AD },   /* R351   - EQ17 */
+       { 352, 0x1103 },   /* R352   - EQ18 */
+       { 353, 0x0564 },   /* R353   - EQ19 */
+       { 354, 0x0559 },   /* R354   - EQ20 */
+       { 355, 0x4000 },   /* R355   - EQ21 */
+       { 356, 0x6318 },   /* R356   - EQ22 */
+       { 357, 0x6300 },   /* R357   - EQ23 */
+       { 358, 0x0FCA },   /* R358   - EQ24 */
+       { 359, 0x0400 },   /* R359   - EQ25 */
+       { 360, 0x00D8 },   /* R360   - EQ26 */
+       { 361, 0x1EB5 },   /* R361   - EQ27 */
+       { 362, 0xF145 },   /* R362   - EQ28 */
+       { 363, 0x0B75 },   /* R363   - EQ29 */
+       { 364, 0x01C5 },   /* R364   - EQ30 */
+       { 365, 0x1C58 },   /* R365   - EQ31 */
+       { 366, 0xF373 },   /* R366   - EQ32 */
+       { 367, 0x0A54 },   /* R367   - EQ33 */
+       { 368, 0x0558 },   /* R368   - EQ34 */
+       { 369, 0x168E },   /* R369   - EQ35 */
+       { 370, 0xF829 },   /* R370   - EQ36 */
+       { 371, 0x07AD },   /* R371   - EQ37 */
+       { 372, 0x1103 },   /* R372   - EQ38 */
+       { 373, 0x0564 },   /* R373   - EQ39 */
+       { 374, 0x0559 },   /* R374   - EQ40 */
+       { 375, 0x4000 },   /* R375   - EQ41 */
+
+       { 513, 0x0000 },   /* R513   - GPIO 2 */
+       { 514, 0x0000 },   /* R514   - GPIO 3 */
+
+       { 516, 0x8100 },   /* R516   - GPIO 5 */
+       { 517, 0x8100 },   /* R517   - GPIO 6 */
+
+       { 560, 0x0000 },   /* R560   - Interrupt Status 1 */
+       { 561, 0x0000 },   /* R561   - Interrupt Status 2 */
+
+       { 568, 0x0030 },   /* R568   - Interrupt Status 1 Mask */
+       { 569, 0xFFED },   /* R569   - Interrupt Status 2 Mask */
+
+       { 576, 0x0000 },   /* R576   - Interrupt Control */
+
+       { 584, 0x002D },   /* R584   - IRQ Debounce */
+
+       { 586, 0x0000 },   /* R586   -  MICINT Source Pol */
+
+       { 768, 0x1C00 },   /* R768   - DSP2 Power Management */
+
+       { 1037, 0x0000 },   /* R1037  - DSP2_ExecControl */
+
+       { 8192, 0x0000 },   /* R8192  - DSP2 Instruction RAM 0 */
+
+       { 9216, 0x0030 },   /* R9216  - DSP2 Address RAM 2 */
+       { 9217, 0x0000 },   /* R9217  - DSP2 Address RAM 1 */
+       { 9218, 0x0000 },   /* R9218  - DSP2 Address RAM 0 */
+
+       { 12288, 0x0000 },   /* R12288 - DSP2 Data1 RAM 1 */
+       { 12289, 0x0000 },   /* R12289 - DSP2 Data1 RAM 0 */
+
+       { 13312, 0x0000 },   /* R13312 - DSP2 Data2 RAM 1 */
+       { 13313, 0x0000 },   /* R13313 - DSP2 Data2 RAM 0 */
+
+       { 14336, 0x0000 },   /* R14336 - DSP2 Data3 RAM 1 */
+       { 14337, 0x0000 },   /* R14337 - DSP2 Data3 RAM 0 */
+
+       { 15360, 0x000A },   /* R15360 - DSP2 Coeff RAM 0 */
+
+       { 16384, 0x0000 },   /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+       { 16385, 0x0000 },   /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+       { 16386, 0x0000 },   /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+       { 16387, 0x0000 },   /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+       { 16388, 0x0000 },   /* R16388 - SOUNDSTAGE_ENABLES_1 */
+       { 16389, 0x0000 },   /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+       { 16896, 0x0002 },   /* R16896 - HDBASS_AI_1 */
+       { 16897, 0xBD12 },   /* R16897 - HDBASS_AI_0 */
+       { 16898, 0x007C },   /* R16898 - HDBASS_AR_1 */
+       { 16899, 0x586C },   /* R16899 - HDBASS_AR_0 */
+       { 16900, 0x0053 },   /* R16900 - HDBASS_B_1 */
+       { 16901, 0x8121 },   /* R16901 - HDBASS_B_0 */
+       { 16902, 0x003F },   /* R16902 - HDBASS_K_1 */
+       { 16903, 0x8BD8 },   /* R16903 - HDBASS_K_0 */
+       { 16904, 0x0032 },   /* R16904 - HDBASS_N1_1 */
+       { 16905, 0xF52D },   /* R16905 - HDBASS_N1_0 */
+       { 16906, 0x0065 },   /* R16906 - HDBASS_N2_1 */
+       { 16907, 0xAC8C },   /* R16907 - HDBASS_N2_0 */
+       { 16908, 0x006B },   /* R16908 - HDBASS_N3_1 */
+       { 16909, 0xE087 },   /* R16909 - HDBASS_N3_0 */
+       { 16910, 0x0072 },   /* R16910 - HDBASS_N4_1 */
+       { 16911, 0x1483 },   /* R16911 - HDBASS_N4_0 */
+       { 16912, 0x0072 },   /* R16912 - HDBASS_N5_1 */
+       { 16913, 0x1483 },   /* R16913 - HDBASS_N5_0 */
+       { 16914, 0x0043 },   /* R16914 - HDBASS_X1_1 */
+       { 16915, 0x3525 },   /* R16915 - HDBASS_X1_0 */
+       { 16916, 0x0006 },   /* R16916 - HDBASS_X2_1 */
+       { 16917, 0x6A4A },   /* R16917 - HDBASS_X2_0 */
+       { 16918, 0x0043 },   /* R16918 - HDBASS_X3_1 */
+       { 16919, 0x6079 },   /* R16919 - HDBASS_X3_0 */
+       { 16920, 0x0008 },   /* R16920 - HDBASS_ATK_1 */
+       { 16921, 0x0000 },   /* R16921 - HDBASS_ATK_0 */
+       { 16922, 0x0001 },   /* R16922 - HDBASS_DCY_1 */
+       { 16923, 0x0000 },   /* R16923 - HDBASS_DCY_0 */
+       { 16924, 0x0059 },   /* R16924 - HDBASS_PG_1 */
+       { 16925, 0x999A },   /* R16925 - HDBASS_PG_0 */
+
+       { 17048, 0x0083 },   /* R17408 - HPF_C_1 */
+       { 17049, 0x98AD },   /* R17409 - HPF_C_0 */
+
+       { 17920, 0x007F },   /* R17920 - ADCL_RETUNE_C1_1 */
+       { 17921, 0xFFFF },   /* R17921 - ADCL_RETUNE_C1_0 */
+       { 17922, 0x0000 },   /* R17922 - ADCL_RETUNE_C2_1 */
+       { 17923, 0x0000 },   /* R17923 - ADCL_RETUNE_C2_0 */
+       { 17924, 0x0000 },   /* R17924 - ADCL_RETUNE_C3_1 */
+       { 17925, 0x0000 },   /* R17925 - ADCL_RETUNE_C3_0 */
+       { 17926, 0x0000 },   /* R17926 - ADCL_RETUNE_C4_1 */
+       { 17927, 0x0000 },   /* R17927 - ADCL_RETUNE_C4_0 */
+       { 17928, 0x0000 },   /* R17928 - ADCL_RETUNE_C5_1 */
+       { 17929, 0x0000 },   /* R17929 - ADCL_RETUNE_C5_0 */
+       { 17930, 0x0000 },   /* R17930 - ADCL_RETUNE_C6_1 */
+       { 17931, 0x0000 },   /* R17931 - ADCL_RETUNE_C6_0 */
+       { 17932, 0x0000 },   /* R17932 - ADCL_RETUNE_C7_1 */
+       { 17933, 0x0000 },   /* R17933 - ADCL_RETUNE_C7_0 */
+       { 17934, 0x0000 },   /* R17934 - ADCL_RETUNE_C8_1 */
+       { 17935, 0x0000 },   /* R17935 - ADCL_RETUNE_C8_0 */
+       { 17936, 0x0000 },   /* R17936 - ADCL_RETUNE_C9_1 */
+       { 17937, 0x0000 },   /* R17937 - ADCL_RETUNE_C9_0 */
+       { 17938, 0x0000 },   /* R17938 - ADCL_RETUNE_C10_1 */
+       { 17939, 0x0000 },   /* R17939 - ADCL_RETUNE_C10_0 */
+       { 17940, 0x0000 },   /* R17940 - ADCL_RETUNE_C11_1 */
+       { 17941, 0x0000 },   /* R17941 - ADCL_RETUNE_C11_0 */
+       { 17942, 0x0000 },   /* R17942 - ADCL_RETUNE_C12_1 */
+       { 17943, 0x0000 },   /* R17943 - ADCL_RETUNE_C12_0 */
+       { 17944, 0x0000 },   /* R17944 - ADCL_RETUNE_C13_1 */
+       { 17945, 0x0000 },   /* R17945 - ADCL_RETUNE_C13_0 */
+       { 17946, 0x0000 },   /* R17946 - ADCL_RETUNE_C14_1 */
+       { 17947, 0x0000 },   /* R17947 - ADCL_RETUNE_C14_0 */
+       { 17948, 0x0000 },   /* R17948 - ADCL_RETUNE_C15_1 */
+       { 17949, 0x0000 },   /* R17949 - ADCL_RETUNE_C15_0 */
+       { 17950, 0x0000 },   /* R17950 - ADCL_RETUNE_C16_1 */
+       { 17951, 0x0000 },   /* R17951 - ADCL_RETUNE_C16_0 */
+       { 17952, 0x0000 },   /* R17952 - ADCL_RETUNE_C17_1 */
+       { 17953, 0x0000 },   /* R17953 - ADCL_RETUNE_C17_0 */
+       { 17954, 0x0000 },   /* R17954 - ADCL_RETUNE_C18_1 */
+       { 17955, 0x0000 },   /* R17955 - ADCL_RETUNE_C18_0 */
+       { 17956, 0x0000 },   /* R17956 - ADCL_RETUNE_C19_1 */
+       { 17957, 0x0000 },   /* R17957 - ADCL_RETUNE_C19_0 */
+       { 17958, 0x0000 },   /* R17958 - ADCL_RETUNE_C20_1 */
+       { 17959, 0x0000 },   /* R17959 - ADCL_RETUNE_C20_0 */
+       { 17960, 0x0000 },   /* R17960 - ADCL_RETUNE_C21_1 */
+       { 17961, 0x0000 },   /* R17961 - ADCL_RETUNE_C21_0 */
+       { 17962, 0x0000 },   /* R17962 - ADCL_RETUNE_C22_1 */
+       { 17963, 0x0000 },   /* R17963 - ADCL_RETUNE_C22_0 */
+       { 17964, 0x0000 },   /* R17964 - ADCL_RETUNE_C23_1 */
+       { 17965, 0x0000 },   /* R17965 - ADCL_RETUNE_C23_0 */
+       { 17966, 0x0000 },   /* R17966 - ADCL_RETUNE_C24_1 */
+       { 17967, 0x0000 },   /* R17967 - ADCL_RETUNE_C24_0 */
+       { 17968, 0x0000 },   /* R17968 - ADCL_RETUNE_C25_1 */
+       { 17969, 0x0000 },   /* R17969 - ADCL_RETUNE_C25_0 */
+       { 17970, 0x0000 },   /* R17970 - ADCL_RETUNE_C26_1 */
+       { 17971, 0x0000 },   /* R17971 - ADCL_RETUNE_C26_0 */
+       { 17972, 0x0000 },   /* R17972 - ADCL_RETUNE_C27_1 */
+       { 17973, 0x0000 },   /* R17973 - ADCL_RETUNE_C27_0 */
+       { 17974, 0x0000 },   /* R17974 - ADCL_RETUNE_C28_1 */
+       { 17975, 0x0000 },   /* R17975 - ADCL_RETUNE_C28_0 */
+       { 17976, 0x0000 },   /* R17976 - ADCL_RETUNE_C29_1 */
+       { 17977, 0x0000 },   /* R17977 - ADCL_RETUNE_C29_0 */
+       { 17978, 0x0000 },   /* R17978 - ADCL_RETUNE_C30_1 */
+       { 17979, 0x0000 },   /* R17979 - ADCL_RETUNE_C30_0 */
+       { 17980, 0x0000 },   /* R17980 - ADCL_RETUNE_C31_1 */
+       { 17981, 0x0000 },   /* R17981 - ADCL_RETUNE_C31_0 */
+       { 17982, 0x0000 },   /* R17982 - ADCL_RETUNE_C32_1 */
+       { 17983, 0x0000 },   /* R17983 - ADCL_RETUNE_C32_0 */
+
+       { 18432, 0x0020 },   /* R18432 - RETUNEADC_PG2_1 */
+       { 18433, 0x0000 },   /* R18433 - RETUNEADC_PG2_0 */
+       { 18434, 0x0040 },   /* R18434 - RETUNEADC_PG_1 */
+       { 18435, 0x0000 },   /* R18435 - RETUNEADC_PG_0 */
+
+       { 18944, 0x007F },   /* R18944 - ADCR_RETUNE_C1_1 */
+       { 18945, 0xFFFF },   /* R18945 - ADCR_RETUNE_C1_0 */
+       { 18946, 0x0000 },   /* R18946 - ADCR_RETUNE_C2_1 */
+       { 18947, 0x0000 },   /* R18947 - ADCR_RETUNE_C2_0 */
+       { 18948, 0x0000 },   /* R18948 - ADCR_RETUNE_C3_1 */
+       { 18949, 0x0000 },   /* R18949 - ADCR_RETUNE_C3_0 */
+       { 18950, 0x0000 },   /* R18950 - ADCR_RETUNE_C4_1 */
+       { 18951, 0x0000 },   /* R18951 - ADCR_RETUNE_C4_0 */
+       { 18952, 0x0000 },   /* R18952 - ADCR_RETUNE_C5_1 */
+       { 18953, 0x0000 },   /* R18953 - ADCR_RETUNE_C5_0 */
+       { 18954, 0x0000 },   /* R18954 - ADCR_RETUNE_C6_1 */
+       { 18955, 0x0000 },   /* R18955 - ADCR_RETUNE_C6_0 */
+       { 18956, 0x0000 },   /* R18956 - ADCR_RETUNE_C7_1 */
+       { 18957, 0x0000 },   /* R18957 - ADCR_RETUNE_C7_0 */
+       { 18958, 0x0000 },   /* R18958 - ADCR_RETUNE_C8_1 */
+       { 18959, 0x0000 },   /* R18959 - ADCR_RETUNE_C8_0 */
+       { 18960, 0x0000 },   /* R18960 - ADCR_RETUNE_C9_1 */
+       { 18961, 0x0000 },   /* R18961 - ADCR_RETUNE_C9_0 */
+       { 18962, 0x0000 },   /* R18962 - ADCR_RETUNE_C10_1 */
+       { 18963, 0x0000 },   /* R18963 - ADCR_RETUNE_C10_0 */
+       { 18964, 0x0000 },   /* R18964 - ADCR_RETUNE_C11_1 */
+       { 18965, 0x0000 },   /* R18965 - ADCR_RETUNE_C11_0 */
+       { 18966, 0x0000 },   /* R18966 - ADCR_RETUNE_C12_1 */
+       { 18967, 0x0000 },   /* R18967 - ADCR_RETUNE_C12_0 */
+       { 18968, 0x0000 },   /* R18968 - ADCR_RETUNE_C13_1 */
+       { 18969, 0x0000 },   /* R18969 - ADCR_RETUNE_C13_0 */
+       { 18970, 0x0000 },   /* R18970 - ADCR_RETUNE_C14_1 */
+       { 18971, 0x0000 },   /* R18971 - ADCR_RETUNE_C14_0 */
+       { 18972, 0x0000 },   /* R18972 - ADCR_RETUNE_C15_1 */
+       { 18973, 0x0000 },   /* R18973 - ADCR_RETUNE_C15_0 */
+       { 18974, 0x0000 },   /* R18974 - ADCR_RETUNE_C16_1 */
+       { 18975, 0x0000 },   /* R18975 - ADCR_RETUNE_C16_0 */
+       { 18976, 0x0000 },   /* R18976 - ADCR_RETUNE_C17_1 */
+       { 18977, 0x0000 },   /* R18977 - ADCR_RETUNE_C17_0 */
+       { 18978, 0x0000 },   /* R18978 - ADCR_RETUNE_C18_1 */
+       { 18979, 0x0000 },   /* R18979 - ADCR_RETUNE_C18_0 */
+       { 18980, 0x0000 },   /* R18980 - ADCR_RETUNE_C19_1 */
+       { 18981, 0x0000 },   /* R18981 - ADCR_RETUNE_C19_0 */
+       { 18982, 0x0000 },   /* R18982 - ADCR_RETUNE_C20_1 */
+       { 18983, 0x0000 },   /* R18983 - ADCR_RETUNE_C20_0 */
+       { 18984, 0x0000 },   /* R18984 - ADCR_RETUNE_C21_1 */
+       { 18985, 0x0000 },   /* R18985 - ADCR_RETUNE_C21_0 */
+       { 18986, 0x0000 },   /* R18986 - ADCR_RETUNE_C22_1 */
+       { 18987, 0x0000 },   /* R18987 - ADCR_RETUNE_C22_0 */
+       { 18988, 0x0000 },   /* R18988 - ADCR_RETUNE_C23_1 */
+       { 18989, 0x0000 },   /* R18989 - ADCR_RETUNE_C23_0 */
+       { 18990, 0x0000 },   /* R18990 - ADCR_RETUNE_C24_1 */
+       { 18991, 0x0000 },   /* R18991 - ADCR_RETUNE_C24_0 */
+       { 18992, 0x0000 },   /* R18992 - ADCR_RETUNE_C25_1 */
+       { 18993, 0x0000 },   /* R18993 - ADCR_RETUNE_C25_0 */
+       { 18994, 0x0000 },   /* R18994 - ADCR_RETUNE_C26_1 */
+       { 18995, 0x0000 },   /* R18995 - ADCR_RETUNE_C26_0 */
+       { 18996, 0x0000 },   /* R18996 - ADCR_RETUNE_C27_1 */
+       { 18997, 0x0000 },   /* R18997 - ADCR_RETUNE_C27_0 */
+       { 18998, 0x0000 },   /* R18998 - ADCR_RETUNE_C28_1 */
+       { 18999, 0x0000 },   /* R18999 - ADCR_RETUNE_C28_0 */
+       { 19000, 0x0000 },   /* R19000 - ADCR_RETUNE_C29_1 */
+       { 19001, 0x0000 },   /* R19001 - ADCR_RETUNE_C29_0 */
+       { 19002, 0x0000 },   /* R19002 - ADCR_RETUNE_C30_1 */
+       { 19003, 0x0000 },   /* R19003 - ADCR_RETUNE_C30_0 */
+       { 19004, 0x0000 },   /* R19004 - ADCR_RETUNE_C31_1 */
+       { 19005, 0x0000 },   /* R19005 - ADCR_RETUNE_C31_0 */
+       { 19006, 0x0000 },   /* R19006 - ADCR_RETUNE_C32_1 */
+       { 19007, 0x0000 },   /* R19007 - ADCR_RETUNE_C32_0 */
+
+       { 19456, 0x007F },   /* R19456 - DACL_RETUNE_C1_1 */
+       { 19457, 0xFFFF },   /* R19457 - DACL_RETUNE_C1_0 */
+       { 19458, 0x0000 },   /* R19458 - DACL_RETUNE_C2_1 */
+       { 19459, 0x0000 },   /* R19459 - DACL_RETUNE_C2_0 */
+       { 19460, 0x0000 },   /* R19460 - DACL_RETUNE_C3_1 */
+       { 19461, 0x0000 },   /* R19461 - DACL_RETUNE_C3_0 */
+       { 19462, 0x0000 },   /* R19462 - DACL_RETUNE_C4_1 */
+       { 19463, 0x0000 },   /* R19463 - DACL_RETUNE_C4_0 */
+       { 19464, 0x0000 },   /* R19464 - DACL_RETUNE_C5_1 */
+       { 19465, 0x0000 },   /* R19465 - DACL_RETUNE_C5_0 */
+       { 19466, 0x0000 },   /* R19466 - DACL_RETUNE_C6_1 */
+       { 19467, 0x0000 },   /* R19467 - DACL_RETUNE_C6_0 */
+       { 19468, 0x0000 },   /* R19468 - DACL_RETUNE_C7_1 */
+       { 19469, 0x0000 },   /* R19469 - DACL_RETUNE_C7_0 */
+       { 19470, 0x0000 },   /* R19470 - DACL_RETUNE_C8_1 */
+       { 19471, 0x0000 },   /* R19471 - DACL_RETUNE_C8_0 */
+       { 19472, 0x0000 },   /* R19472 - DACL_RETUNE_C9_1 */
+       { 19473, 0x0000 },   /* R19473 - DACL_RETUNE_C9_0 */
+       { 19474, 0x0000 },   /* R19474 - DACL_RETUNE_C10_1 */
+       { 19475, 0x0000 },   /* R19475 - DACL_RETUNE_C10_0 */
+       { 19476, 0x0000 },   /* R19476 - DACL_RETUNE_C11_1 */
+       { 19477, 0x0000 },   /* R19477 - DACL_RETUNE_C11_0 */
+       { 19478, 0x0000 },   /* R19478 - DACL_RETUNE_C12_1 */
+       { 19479, 0x0000 },   /* R19479 - DACL_RETUNE_C12_0 */
+       { 19480, 0x0000 },   /* R19480 - DACL_RETUNE_C13_1 */
+       { 19481, 0x0000 },   /* R19481 - DACL_RETUNE_C13_0 */
+       { 19482, 0x0000 },   /* R19482 - DACL_RETUNE_C14_1 */
+       { 19483, 0x0000 },   /* R19483 - DACL_RETUNE_C14_0 */
+       { 19484, 0x0000 },   /* R19484 - DACL_RETUNE_C15_1 */
+       { 19485, 0x0000 },   /* R19485 - DACL_RETUNE_C15_0 */
+       { 19486, 0x0000 },   /* R19486 - DACL_RETUNE_C16_1 */
+       { 19487, 0x0000 },   /* R19487 - DACL_RETUNE_C16_0 */
+       { 19488, 0x0000 },   /* R19488 - DACL_RETUNE_C17_1 */
+       { 19489, 0x0000 },   /* R19489 - DACL_RETUNE_C17_0 */
+       { 19490, 0x0000 },   /* R19490 - DACL_RETUNE_C18_1 */
+       { 19491, 0x0000 },   /* R19491 - DACL_RETUNE_C18_0 */
+       { 19492, 0x0000 },   /* R19492 - DACL_RETUNE_C19_1 */
+       { 19493, 0x0000 },   /* R19493 - DACL_RETUNE_C19_0 */
+       { 19494, 0x0000 },   /* R19494 - DACL_RETUNE_C20_1 */
+       { 19495, 0x0000 },   /* R19495 - DACL_RETUNE_C20_0 */
+       { 19496, 0x0000 },   /* R19496 - DACL_RETUNE_C21_1 */
+       { 19497, 0x0000 },   /* R19497 - DACL_RETUNE_C21_0 */
+       { 19498, 0x0000 },   /* R19498 - DACL_RETUNE_C22_1 */
+       { 19499, 0x0000 },   /* R19499 - DACL_RETUNE_C22_0 */
+       { 19500, 0x0000 },   /* R19500 - DACL_RETUNE_C23_1 */
+       { 19501, 0x0000 },   /* R19501 - DACL_RETUNE_C23_0 */
+       { 19502, 0x0000 },   /* R19502 - DACL_RETUNE_C24_1 */
+       { 19503, 0x0000 },   /* R19503 - DACL_RETUNE_C24_0 */
+       { 19504, 0x0000 },   /* R19504 - DACL_RETUNE_C25_1 */
+       { 19505, 0x0000 },   /* R19505 - DACL_RETUNE_C25_0 */
+       { 19506, 0x0000 },   /* R19506 - DACL_RETUNE_C26_1 */
+       { 19507, 0x0000 },   /* R19507 - DACL_RETUNE_C26_0 */
+       { 19508, 0x0000 },   /* R19508 - DACL_RETUNE_C27_1 */
+       { 19509, 0x0000 },   /* R19509 - DACL_RETUNE_C27_0 */
+       { 19510, 0x0000 },   /* R19510 - DACL_RETUNE_C28_1 */
+       { 19511, 0x0000 },   /* R19511 - DACL_RETUNE_C28_0 */
+       { 19512, 0x0000 },   /* R19512 - DACL_RETUNE_C29_1 */
+       { 19513, 0x0000 },   /* R19513 - DACL_RETUNE_C29_0 */
+       { 19514, 0x0000 },   /* R19514 - DACL_RETUNE_C30_1 */
+       { 19515, 0x0000 },   /* R19515 - DACL_RETUNE_C30_0 */
+       { 19516, 0x0000 },   /* R19516 - DACL_RETUNE_C31_1 */
+       { 19517, 0x0000 },   /* R19517 - DACL_RETUNE_C31_0 */
+       { 19518, 0x0000 },   /* R19518 - DACL_RETUNE_C32_1 */
+       { 19519, 0x0000 },   /* R19519 - DACL_RETUNE_C32_0 */
+
+       { 19968, 0x0020 },   /* R19968 - RETUNEDAC_PG2_1 */
+       { 19969, 0x0000 },   /* R19969 - RETUNEDAC_PG2_0 */
+       { 19970, 0x0040 },   /* R19970 - RETUNEDAC_PG_1 */
+       { 19971, 0x0000 },   /* R19971 - RETUNEDAC_PG_0 */
+
+       { 20480, 0x007F },   /* R20480 - DACR_RETUNE_C1_1 */
+       { 20481, 0xFFFF },   /* R20481 - DACR_RETUNE_C1_0 */
+       { 20482, 0x0000 },   /* R20482 - DACR_RETUNE_C2_1 */
+       { 20483, 0x0000 },   /* R20483 - DACR_RETUNE_C2_0 */
+       { 20484, 0x0000 },   /* R20484 - DACR_RETUNE_C3_1 */
+       { 20485, 0x0000 },   /* R20485 - DACR_RETUNE_C3_0 */
+       { 20486, 0x0000 },   /* R20486 - DACR_RETUNE_C4_1 */
+       { 20487, 0x0000 },   /* R20487 - DACR_RETUNE_C4_0 */
+       { 20488, 0x0000 },   /* R20488 - DACR_RETUNE_C5_1 */
+       { 20489, 0x0000 },   /* R20489 - DACR_RETUNE_C5_0 */
+       { 20490, 0x0000 },   /* R20490 - DACR_RETUNE_C6_1 */
+       { 20491, 0x0000 },   /* R20491 - DACR_RETUNE_C6_0 */
+       { 20492, 0x0000 },   /* R20492 - DACR_RETUNE_C7_1 */
+       { 20493, 0x0000 },   /* R20493 - DACR_RETUNE_C7_0 */
+       { 20494, 0x0000 },   /* R20494 - DACR_RETUNE_C8_1 */
+       { 20495, 0x0000 },   /* R20495 - DACR_RETUNE_C8_0 */
+       { 20496, 0x0000 },   /* R20496 - DACR_RETUNE_C9_1 */
+       { 20497, 0x0000 },   /* R20497 - DACR_RETUNE_C9_0 */
+       { 20498, 0x0000 },   /* R20498 - DACR_RETUNE_C10_1 */
+       { 20499, 0x0000 },   /* R20499 - DACR_RETUNE_C10_0 */
+       { 20500, 0x0000 },   /* R20500 - DACR_RETUNE_C11_1 */
+       { 20501, 0x0000 },   /* R20501 - DACR_RETUNE_C11_0 */
+       { 20502, 0x0000 },   /* R20502 - DACR_RETUNE_C12_1 */
+       { 20503, 0x0000 },   /* R20503 - DACR_RETUNE_C12_0 */
+       { 20504, 0x0000 },   /* R20504 - DACR_RETUNE_C13_1 */
+       { 20505, 0x0000 },   /* R20505 - DACR_RETUNE_C13_0 */
+       { 20506, 0x0000 },   /* R20506 - DACR_RETUNE_C14_1 */
+       { 20507, 0x0000 },   /* R20507 - DACR_RETUNE_C14_0 */
+       { 20508, 0x0000 },   /* R20508 - DACR_RETUNE_C15_1 */
+       { 20509, 0x0000 },   /* R20509 - DACR_RETUNE_C15_0 */
+       { 20510, 0x0000 },   /* R20510 - DACR_RETUNE_C16_1 */
+       { 20511, 0x0000 },   /* R20511 - DACR_RETUNE_C16_0 */
+       { 20512, 0x0000 },   /* R20512 - DACR_RETUNE_C17_1 */
+       { 20513, 0x0000 },   /* R20513 - DACR_RETUNE_C17_0 */
+       { 20514, 0x0000 },   /* R20514 - DACR_RETUNE_C18_1 */
+       { 20515, 0x0000 },   /* R20515 - DACR_RETUNE_C18_0 */
+       { 20516, 0x0000 },   /* R20516 - DACR_RETUNE_C19_1 */
+       { 20517, 0x0000 },   /* R20517 - DACR_RETUNE_C19_0 */
+       { 20518, 0x0000 },   /* R20518 - DACR_RETUNE_C20_1 */
+       { 20519, 0x0000 },   /* R20519 - DACR_RETUNE_C20_0 */
+       { 20520, 0x0000 },   /* R20520 - DACR_RETUNE_C21_1 */
+       { 20521, 0x0000 },   /* R20521 - DACR_RETUNE_C21_0 */
+       { 20522, 0x0000 },   /* R20522 - DACR_RETUNE_C22_1 */
+       { 20523, 0x0000 },   /* R20523 - DACR_RETUNE_C22_0 */
+       { 20524, 0x0000 },   /* R20524 - DACR_RETUNE_C23_1 */
+       { 20525, 0x0000 },   /* R20525 - DACR_RETUNE_C23_0 */
+       { 20526, 0x0000 },   /* R20526 - DACR_RETUNE_C24_1 */
+       { 20527, 0x0000 },   /* R20527 - DACR_RETUNE_C24_0 */
+       { 20528, 0x0000 },   /* R20528 - DACR_RETUNE_C25_1 */
+       { 20529, 0x0000 },   /* R20529 - DACR_RETUNE_C25_0 */
+       { 20530, 0x0000 },   /* R20530 - DACR_RETUNE_C26_1 */
+       { 20531, 0x0000 },   /* R20531 - DACR_RETUNE_C26_0 */
+       { 20532, 0x0000 },   /* R20532 - DACR_RETUNE_C27_1 */
+       { 20533, 0x0000 },   /* R20533 - DACR_RETUNE_C27_0 */
+       { 20534, 0x0000 },   /* R20534 - DACR_RETUNE_C28_1 */
+       { 20535, 0x0000 },   /* R20535 - DACR_RETUNE_C28_0 */
+       { 20536, 0x0000 },   /* R20536 - DACR_RETUNE_C29_1 */
+       { 20537, 0x0000 },   /* R20537 - DACR_RETUNE_C29_0 */
+       { 20538, 0x0000 },   /* R20538 - DACR_RETUNE_C30_1 */
+       { 20539, 0x0000 },   /* R20539 - DACR_RETUNE_C30_0 */
+       { 20540, 0x0000 },   /* R20540 - DACR_RETUNE_C31_1 */
+       { 20541, 0x0000 },   /* R20541 - DACR_RETUNE_C31_0 */
+       { 20542, 0x0000 },   /* R20542 - DACR_RETUNE_C32_1 */
+       { 20543, 0x0000 },   /* R20543 - DACR_RETUNE_C32_0 */
+
+       { 20992, 0x008C },   /* R20992 - VSS_XHD2_1 */
+       { 20993, 0x0200 },   /* R20993 - VSS_XHD2_0 */
+       { 20994, 0x0035 },   /* R20994 - VSS_XHD3_1 */
+       { 20995, 0x0700 },   /* R20995 - VSS_XHD3_0 */
+       { 20996, 0x003A },   /* R20996 - VSS_XHN1_1 */
+       { 20997, 0x4100 },   /* R20997 - VSS_XHN1_0 */
+       { 20998, 0x008B },   /* R20998 - VSS_XHN2_1 */
+       { 20999, 0x7D00 },   /* R20999 - VSS_XHN2_0 */
+       { 21000, 0x003A },   /* R21000 - VSS_XHN3_1 */
+       { 21001, 0x4100 },   /* R21001 - VSS_XHN3_0 */
+       { 21002, 0x008C },   /* R21002 - VSS_XLA_1 */
+       { 21003, 0xFEE8 },   /* R21003 - VSS_XLA_0 */
+       { 21004, 0x0078 },   /* R21004 - VSS_XLB_1 */
+       { 21005, 0x0000 },   /* R21005 - VSS_XLB_0 */
+       { 21006, 0x003F },   /* R21006 - VSS_XLG_1 */
+       { 21007, 0xB260 },   /* R21007 - VSS_XLG_0 */
+       { 21008, 0x002D },   /* R21008 - VSS_PG2_1 */
+       { 21009, 0x1818 },   /* R21009 - VSS_PG2_0 */
+       { 21010, 0x0020 },   /* R21010 - VSS_PG_1 */
+       { 21011, 0x0000 },   /* R21011 - VSS_PG_0 */
+       { 21012, 0x00F1 },   /* R21012 - VSS_XTD1_1 */
+       { 21013, 0x8340 },   /* R21013 - VSS_XTD1_0 */
+       { 21014, 0x00FB },   /* R21014 - VSS_XTD2_1 */
+       { 21015, 0x8300 },   /* R21015 - VSS_XTD2_0 */
+       { 21016, 0x00EE },   /* R21016 - VSS_XTD3_1 */
+       { 21017, 0xAEC0 },   /* R21017 - VSS_XTD3_0 */
+       { 21018, 0x00FB },   /* R21018 - VSS_XTD4_1 */
+       { 21019, 0xAC40 },   /* R21019 - VSS_XTD4_0 */
+       { 21020, 0x00F1 },   /* R21020 - VSS_XTD5_1 */
+       { 21021, 0x7F80 },   /* R21021 - VSS_XTD5_0 */
+       { 21022, 0x00F4 },   /* R21022 - VSS_XTD6_1 */
+       { 21023, 0x3B40 },   /* R21023 - VSS_XTD6_0 */
+       { 21024, 0x00F5 },   /* R21024 - VSS_XTD7_1 */
+       { 21025, 0xFB00 },   /* R21025 - VSS_XTD7_0 */
+       { 21026, 0x00EA },   /* R21026 - VSS_XTD8_1 */
+       { 21027, 0x10C0 },   /* R21027 - VSS_XTD8_0 */
+       { 21028, 0x00FC },   /* R21028 - VSS_XTD9_1 */
+       { 21029, 0xC580 },   /* R21029 - VSS_XTD9_0 */
+       { 21030, 0x00E2 },   /* R21030 - VSS_XTD10_1 */
+       { 21031, 0x75C0 },   /* R21031 - VSS_XTD10_0 */
+       { 21032, 0x0004 },   /* R21032 - VSS_XTD11_1 */
+       { 21033, 0xB480 },   /* R21033 - VSS_XTD11_0 */
+       { 21034, 0x00D4 },   /* R21034 - VSS_XTD12_1 */
+       { 21035, 0xF980 },   /* R21035 - VSS_XTD12_0 */
+       { 21036, 0x0004 },   /* R21036 - VSS_XTD13_1 */
+       { 21037, 0x9140 },   /* R21037 - VSS_XTD13_0 */
+       { 21038, 0x00D8 },   /* R21038 - VSS_XTD14_1 */
+       { 21039, 0xA480 },   /* R21039 - VSS_XTD14_0 */
+       { 21040, 0x0002 },   /* R21040 - VSS_XTD15_1 */
+       { 21041, 0x3DC0 },   /* R21041 - VSS_XTD15_0 */
+       { 21042, 0x00CF },   /* R21042 - VSS_XTD16_1 */
+       { 21043, 0x7A80 },   /* R21043 - VSS_XTD16_0 */
+       { 21044, 0x00DC },   /* R21044 - VSS_XTD17_1 */
+       { 21045, 0x0600 },   /* R21045 - VSS_XTD17_0 */
+       { 21046, 0x00F2 },   /* R21046 - VSS_XTD18_1 */
+       { 21047, 0xDAC0 },   /* R21047 - VSS_XTD18_0 */
+       { 21048, 0x00BA },   /* R21048 - VSS_XTD19_1 */
+       { 21049, 0xF340 },   /* R21049 - VSS_XTD19_0 */
+       { 21050, 0x000A },   /* R21050 - VSS_XTD20_1 */
+       { 21051, 0x7940 },   /* R21051 - VSS_XTD20_0 */
+       { 21052, 0x001C },   /* R21052 - VSS_XTD21_1 */
+       { 21053, 0x0680 },   /* R21053 - VSS_XTD21_0 */
+       { 21054, 0x00FD },   /* R21054 - VSS_XTD22_1 */
+       { 21055, 0x2D00 },   /* R21055 - VSS_XTD22_0 */
+       { 21056, 0x001C },   /* R21056 - VSS_XTD23_1 */
+       { 21057, 0xE840 },   /* R21057 - VSS_XTD23_0 */
+       { 21058, 0x000D },   /* R21058 - VSS_XTD24_1 */
+       { 21059, 0xDC40 },   /* R21059 - VSS_XTD24_0 */
+       { 21060, 0x00FC },   /* R21060 - VSS_XTD25_1 */
+       { 21061, 0x9D00 },   /* R21061 - VSS_XTD25_0 */
+       { 21062, 0x0009 },   /* R21062 - VSS_XTD26_1 */
+       { 21063, 0x5580 },   /* R21063 - VSS_XTD26_0 */
+       { 21064, 0x00FE },   /* R21064 - VSS_XTD27_1 */
+       { 21065, 0x7E80 },   /* R21065 - VSS_XTD27_0 */
+       { 21066, 0x000E },   /* R21066 - VSS_XTD28_1 */
+       { 21067, 0xAB40 },   /* R21067 - VSS_XTD28_0 */
+       { 21068, 0x00F9 },   /* R21068 - VSS_XTD29_1 */
+       { 21069, 0x9880 },   /* R21069 - VSS_XTD29_0 */
+       { 21070, 0x0009 },   /* R21070 - VSS_XTD30_1 */
+       { 21071, 0x87C0 },   /* R21071 - VSS_XTD30_0 */
+       { 21072, 0x00FD },   /* R21072 - VSS_XTD31_1 */
+       { 21073, 0x2C40 },   /* R21073 - VSS_XTD31_0 */
+       { 21074, 0x0009 },   /* R21074 - VSS_XTD32_1 */
+       { 21075, 0x4800 },   /* R21075 - VSS_XTD32_0 */
+       { 21076, 0x0003 },   /* R21076 - VSS_XTS1_1 */
+       { 21077, 0x5F40 },   /* R21077 - VSS_XTS1_0 */
+       { 21078, 0x0000 },   /* R21078 - VSS_XTS2_1 */
+       { 21079, 0x8700 },   /* R21079 - VSS_XTS2_0 */
+       { 21080, 0x00FA },   /* R21080 - VSS_XTS3_1 */
+       { 21081, 0xE4C0 },   /* R21081 - VSS_XTS3_0 */
+       { 21082, 0x0000 },   /* R21082 - VSS_XTS4_1 */
+       { 21083, 0x0B40 },   /* R21083 - VSS_XTS4_0 */
+       { 21084, 0x0004 },   /* R21084 - VSS_XTS5_1 */
+       { 21085, 0xE180 },   /* R21085 - VSS_XTS5_0 */
+       { 21086, 0x0001 },   /* R21086 - VSS_XTS6_1 */
+       { 21087, 0x1F40 },   /* R21087 - VSS_XTS6_0 */
+       { 21088, 0x00F8 },   /* R21088 - VSS_XTS7_1 */
+       { 21089, 0xB000 },   /* R21089 - VSS_XTS7_0 */
+       { 21090, 0x00FB },   /* R21090 - VSS_XTS8_1 */
+       { 21091, 0xCBC0 },   /* R21091 - VSS_XTS8_0 */
+       { 21092, 0x0004 },   /* R21092 - VSS_XTS9_1 */
+       { 21093, 0xF380 },   /* R21093 - VSS_XTS9_0 */
+       { 21094, 0x0007 },   /* R21094 - VSS_XTS10_1 */
+       { 21095, 0xDF40 },   /* R21095 - VSS_XTS10_0 */
+       { 21096, 0x00FF },   /* R21096 - VSS_XTS11_1 */
+       { 21097, 0x0700 },   /* R21097 - VSS_XTS11_0 */
+       { 21098, 0x00EF },   /* R21098 - VSS_XTS12_1 */
+       { 21099, 0xD700 },   /* R21099 - VSS_XTS12_0 */
+       { 21100, 0x00FB },   /* R21100 - VSS_XTS13_1 */
+       { 21101, 0xAF40 },   /* R21101 - VSS_XTS13_0 */
+       { 21102, 0x0010 },   /* R21102 - VSS_XTS14_1 */
+       { 21103, 0x8A80 },   /* R21103 - VSS_XTS14_0 */
+       { 21104, 0x0011 },   /* R21104 - VSS_XTS15_1 */
+       { 21105, 0x07C0 },   /* R21105 - VSS_XTS15_0 */
+       { 21106, 0x00E0 },   /* R21106 - VSS_XTS16_1 */
+       { 21107, 0x0800 },   /* R21107 - VSS_XTS16_0 */
+       { 21108, 0x00D2 },   /* R21108 - VSS_XTS17_1 */
+       { 21109, 0x7600 },   /* R21109 - VSS_XTS17_0 */
+       { 21110, 0x0020 },   /* R21110 - VSS_XTS18_1 */
+       { 21111, 0xCF40 },   /* R21111 - VSS_XTS18_0 */
+       { 21112, 0x0030 },   /* R21112 - VSS_XTS19_1 */
+       { 21113, 0x2340 },   /* R21113 - VSS_XTS19_0 */
+       { 21114, 0x00FD },   /* R21114 - VSS_XTS20_1 */
+       { 21115, 0x69C0 },   /* R21115 - VSS_XTS20_0 */
+       { 21116, 0x0028 },   /* R21116 - VSS_XTS21_1 */
+       { 21117, 0x3500 },   /* R21117 - VSS_XTS21_0 */
+       { 21118, 0x0006 },   /* R21118 - VSS_XTS22_1 */
+       { 21119, 0x3300 },   /* R21119 - VSS_XTS22_0 */
+       { 21120, 0x00D9 },   /* R21120 - VSS_XTS23_1 */
+       { 21121, 0xF6C0 },   /* R21121 - VSS_XTS23_0 */
+       { 21122, 0x00F3 },   /* R21122 - VSS_XTS24_1 */
+       { 21123, 0x3340 },   /* R21123 - VSS_XTS24_0 */
+       { 21124, 0x000F },   /* R21124 - VSS_XTS25_1 */
+       { 21125, 0x4200 },   /* R21125 - VSS_XTS25_0 */
+       { 21126, 0x0004 },   /* R21126 - VSS_XTS26_1 */
+       { 21127, 0x0C80 },   /* R21127 - VSS_XTS26_0 */
+       { 21128, 0x00FB },   /* R21128 - VSS_XTS27_1 */
+       { 21129, 0x3F80 },   /* R21129 - VSS_XTS27_0 */
+       { 21130, 0x00F7 },   /* R21130 - VSS_XTS28_1 */
+       { 21131, 0x57C0 },   /* R21131 - VSS_XTS28_0 */
+       { 21132, 0x0003 },   /* R21132 - VSS_XTS29_1 */
+       { 21133, 0x5400 },   /* R21133 - VSS_XTS29_0 */
+       { 21134, 0x0000 },   /* R21134 - VSS_XTS30_1 */
+       { 21135, 0xC6C0 },   /* R21135 - VSS_XTS30_0 */
+       { 21136, 0x0003 },   /* R21136 - VSS_XTS31_1 */
+       { 21137, 0x12C0 },   /* R21137 - VSS_XTS31_0 */
+       { 21138, 0x00FD },   /* R21138 - VSS_XTS32_1 */
+       { 21139, 0x8580 },   /* R21139 - VSS_XTS32_0 */
 };
 
 static const struct wm8962_reg_access {
@@ -802,7 +803,7 @@ static const struct wm8962_reg_access {
        u16 vol;
 } wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
        [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0     - Left Input volume */
-       [1] = { 0xFEFF, 0x01FF, 0xFFFF }, /* R1     - Right Input volume */
+       [1] = { 0xFEFF, 0x01FF, 0x0000 }, /* R1     - Right Input volume */
        [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2     - HPOUTL volume */
        [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3     - HPOUTR volume */
        [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4     - Clocking1 */
@@ -1943,7 +1944,7 @@ static const struct wm8962_reg_access {
        [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
 };
 
-static int wm8962_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8962_volatile_register(struct device *dev, unsigned int reg)
 {
        if (wm8962_reg_access[reg].vol)
                return 1;
@@ -1951,7 +1952,7 @@ static int wm8962_volatile_register(struct snd_soc_codec *codec, unsigned int re
                return 0;
 }
 
-static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8962_readable_register(struct device *dev, unsigned int reg)
 {
        if (wm8962_reg_access[reg].read)
                return 1;
@@ -1959,15 +1960,15 @@ static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int re
                return 0;
 }
 
-static int wm8962_reset(struct snd_soc_codec *codec)
+static int wm8962_reset(struct wm8962_priv *wm8962)
 {
        int ret;
 
-       ret = snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
+       ret = regmap_write(wm8962->regmap, WM8962_SOFTWARE_RESET, 0x6243);
        if (ret != 0)
                return ret;
 
-       return snd_soc_write(codec, WM8962_PLL_SOFTWARE_RESET, 0);
+       return regmap_write(wm8962->regmap, WM8962_PLL_SOFTWARE_RESET, 0);
 }
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
@@ -2345,6 +2346,10 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
        int src;
        int fll;
 
+       /* Ignore attempts to run the event during startup */
+       if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               return 0;
+
        src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
 
        switch (src) {
@@ -2670,7 +2675,7 @@ SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
-SND_SOC_DAPM_INPUT("Beep"),
+SND_SOC_DAPM_SIGGEN("Beep"),
 SND_SOC_DAPM_INPUT("DMICDAT"),
 
 SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0),
@@ -2684,6 +2689,8 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
                      WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
                      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
 
 SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
                   inpgal, ARRAY_SIZE(inpgal)),
@@ -2839,6 +2846,9 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
 
        { "HPOUTL", NULL, "HPOUT" },
        { "HPOUTR", NULL, "HPOUT" },
+
+       { "HPOUTL", NULL, "TEMP_HP" },
+       { "HPOUTR", NULL, "TEMP_HP" },
 };
 
 static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
@@ -2855,6 +2865,7 @@ static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
        { "Speaker Output", NULL, "Speaker PGA" },
        { "Speaker Output", NULL, "SYSCLK" },
        { "Speaker Output", NULL, "TOCLK" },
+       { "Speaker Output", NULL, "TEMP_SPK" },
 
        { "SPKOUT", NULL, "Speaker Output" },
 };
@@ -2883,10 +2894,12 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
        { "SPKOUTL Output", NULL, "SPKOUTL PGA" },
        { "SPKOUTL Output", NULL, "SYSCLK" },
        { "SPKOUTL Output", NULL, "TOCLK" },
+       { "SPKOUTL Output", NULL, "TEMP_SPK" },
 
        { "SPKOUTR Output", NULL, "SPKOUTR PGA" },
        { "SPKOUTR Output", NULL, "SYSCLK" },
        { "SPKOUTR Output", NULL, "TOCLK" },
+       { "SPKOUTR Output", NULL, "TEMP_SPK" },
 
        { "SPKOUTL", NULL, "SPKOUTL Output" },
        { "SPKOUTR", NULL, "SPKOUTR Output" },
@@ -2931,33 +2944,6 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
        return 0;
 }
 
-static void wm8962_sync_cache(struct snd_soc_codec *codec)
-{
-       u16 *reg_cache = codec->reg_cache;
-       int i;
-
-       if (!codec->cache_sync)
-               return;
-
-       dev_dbg(codec->dev, "Syncing cache\n");
-
-       codec->cache_only = 0;
-
-       /* Sync back cached values if they're different from the
-        * hardware default.
-        */
-       for (i = 1; i < codec->driver->reg_cache_size; i++) {
-               if (i == WM8962_SOFTWARE_RESET)
-                       continue;
-               if (reg_cache[i] == wm8962_reg[i])
-                       continue;
-
-               snd_soc_write(codec, i, reg_cache[i]);
-       }
-
-       codec->cache_sync = 0;
-}
-
 /* -1 for reserved values */
 static const int bclk_divs[] = {
        1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
@@ -3085,7 +3071,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
-                       wm8962_sync_cache(codec);
+                       regcache_cache_only(wm8962->regmap, false);
+                       regcache_sync(wm8962->regmap);
 
                        snd_soc_update_bits(codec, WM8962_ANTI_POP,
                                            WM8962_STARTUP_BIAS_ENA |
@@ -3399,6 +3386,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
        unsigned long timeout;
        int ret;
        int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
+       int sysclk = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_ENA;
 
        /* Any change? */
        if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
@@ -3459,6 +3447,9 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 
        try_wait_for_completion(&wm8962->fll_lock);
 
+       if (sysclk)
+               fll1 |= WM8962_FLL_ENA;
+
        snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
                            WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
                            WM8962_FLL_ENA, fll1);
@@ -3511,7 +3502,7 @@ static int wm8962_mute(struct snd_soc_dai *dai, int mute)
 #define WM8962_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops wm8962_dai_ops = {
+static const struct snd_soc_dai_ops wm8962_dai_ops = {
        .hw_params = wm8962_hw_params,
        .set_sysclk = wm8962_set_dai_sysclk,
        .set_fmt = wm8962_set_dai_fmt,
@@ -3662,6 +3653,14 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
        snd_soc_jack_report(wm8962->jack, 0,
                            SND_JACK_MICROPHONE | SND_JACK_BTN_0);
 
+       if (jack) {
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS");
+       } else {
+               snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK");
+               snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS");
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(wm8962_mic_detect);
@@ -3879,13 +3878,17 @@ static int wm8962_gpio_direction_out(struct gpio_chip *chip,
 {
        struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
        struct snd_soc_codec *codec = wm8962->codec;
-       int val;
+       int ret, val;
 
        /* Force function 1 (logic output) */
        val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
 
-       return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
-                                  WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+       ret = snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+                                 WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static struct gpio_chip wm8962_template_chip = {
@@ -3946,26 +3949,12 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        bool dmicclk, dmicdat;
 
        wm8962->codec = codec;
-       INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
-       init_completion(&wm8962->fll_lock);
-
-       codec->cache_sync = 1;
-       codec->dapm.idle_bias_off = 1;
+       codec->control_data = wm8962->regmap;
 
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
-               wm8962->supplies[i].supply = wm8962_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8962->supplies),
-                                wm8962->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
@@ -3988,43 +3977,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                }
        }
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
-                                   wm8962->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       ret = snd_soc_read(codec, WM8962_SOFTWARE_RESET);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read ID register\n");
-               goto err_enable;
-       }
-       if (ret != wm8962_reg[WM8962_SOFTWARE_RESET]) {
-               dev_err(codec->dev, "Device is not a WM8962, ID %x != %x\n",
-                       ret, wm8962_reg[WM8962_SOFTWARE_RESET]);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8962_RIGHT_INPUT_VOLUME);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read device revision: %d\n",
-                       ret);
-               goto err_enable;
-       }
-       
-       dev_info(codec->dev, "customer id %x revision %c\n",
-                (ret & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
-                ((ret & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
-                + 'A');
-
-       ret = wm8962_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_enable;
-       }
-
        /* SYSCLK defaults to on; make sure it is off so we can safely
         * write to registers if the device is declocked.
         */
@@ -4039,8 +3991,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                            WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
                            0);
 
-       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
-
        if (pdata) {
                /* Apply static configuration for GPIOs */
                for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
@@ -4091,6 +4041,12 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        /* Stereo control for EQ */
        snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0);
 
+       /* Don't debouce interrupts so we don't need SYSCLK */
+       snd_soc_update_bits(codec, WM8962_IRQ_DEBOUNCE,
+                           WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
+                           WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
+                           0);
+
        wm8962_add_widgets(codec);
 
        /* Save boards having to disable DMIC when not in use */
@@ -4150,13 +4106,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        }
 
        return 0;
-
-err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
-err:
-       return ret;
 }
 
 static int wm8962_remove(struct snd_soc_codec *codec)
@@ -4174,21 +4123,36 @@ static int wm8962_remove(struct snd_soc_codec *codec)
        for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
                regulator_unregister_notifier(wm8962->supplies[i].consumer,
                                              &wm8962->disable_nb[i]);
-       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
 
        return 0;
 }
 
+static int wm8962_soc_volatile(struct snd_soc_codec *codec,
+                              unsigned int reg)
+{
+       return true;
+}
+
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
        .probe =        wm8962_probe,
        .remove =       wm8962_remove,
        .set_bias_level = wm8962_set_bias_level,
-       .reg_cache_size = WM8962_MAX_REGISTER + 1,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8962_reg,
-       .volatile_register = wm8962_volatile_register,
-       .readable_register = wm8962_readable_register,
        .set_pll = wm8962_set_fll,
+       .reg_cache_size = WM8962_MAX_REGISTER,
+       .volatile_register = wm8962_soc_volatile,
+};
+
+static const struct regmap_config wm8962_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .max_register = WM8962_MAX_REGISTER,
+       .reg_defaults = wm8962_reg,
+       .num_reg_defaults = ARRAY_SIZE(wm8962_reg),
+       .volatile_reg = wm8962_volatile_register,
+       .readable_reg = wm8962_readable_register,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -4196,28 +4160,112 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8962_priv *wm8962;
-       int ret;
+       unsigned int reg;
+       int ret, i;
 
-       wm8962 = kzalloc(sizeof(struct wm8962_priv), GFP_KERNEL);
+       wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv),
+                             GFP_KERNEL);
        if (wm8962 == NULL)
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, wm8962);
 
+       INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+       init_completion(&wm8962->fll_lock);
        wm8962->irq = i2c->irq;
 
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+               wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8962->supplies),
+                                wm8962->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                   wm8962->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       wm8962->regmap = regmap_init_i2c(i2c, &wm8962_regmap);
+       if (IS_ERR(wm8962->regmap)) {
+               ret = PTR_ERR(wm8962->regmap);
+               dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+               goto err_enable;
+       }
+
+       /*
+        * We haven't marked the chip revision as volatile due to
+        * sharing a register with the right input volume; explicitly
+        * bypass the cache to read it.
+        */
+       regcache_cache_bypass(wm8962->regmap, true);
+
+       ret = regmap_read(wm8962->regmap, WM8962_SOFTWARE_RESET, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read ID register\n");
+               goto err_regmap;
+       }
+       if (reg != 0x6243) {
+               dev_err(&i2c->dev,
+                       "Device is not a WM8962, ID %x != 0x6243\n", ret);
+               ret = -EINVAL;
+               goto err_regmap;
+       }
+
+       ret = regmap_read(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_regmap;
+       }
+
+       dev_info(&i2c->dev, "customer id %x revision %c\n",
+                (reg & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+                ((reg & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+                + 'A');
+
+       regcache_cache_bypass(wm8962->regmap, false);
+
+       ret = wm8962_reset(wm8962);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to issue reset\n");
+               goto err_regmap;
+       }
+
+       regcache_cache_only(wm8962->regmap, true);
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8962, &wm8962_dai, 1);
        if (ret < 0)
-               kfree(wm8962);
+               goto err_regmap;
+
+       /* The drivers should power up as needed */
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+       return 0;
 
+err_regmap:
+       regmap_exit(wm8962->regmap);
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
        return ret;
 }
 
 static __devexit int wm8962_i2c_remove(struct i2c_client *client)
 {
+       struct wm8962_priv *wm8962 = dev_get_drvdata(&client->dev);
+
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+       regmap_exit(wm8962->regmap);
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
        return 0;
 }
 
index b444b297d0b2f442d9f5d1d1e1014227ce42128d..4af893601f00e2da9c33101de59ed42ff949904b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -224,7 +223,7 @@ static const struct snd_soc_dapm_widget wm8971_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8971_PWR2, 8, 0),
        SND_SOC_DAPM_PGA("Mono Out 1", WM8971_PWR2, 2, 0, NULL, 0),
 
-       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8971_PWR1, 1, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias", WM8971_PWR1, 1, 0, NULL, 0),
        SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8971_PWR1, 2, 0),
        SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8971_PWR1, 3, 0),
 
@@ -567,7 +566,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
 #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8971_dai_ops = {
+static const struct snd_soc_dai_ops wm8971_dai_ops = {
        .hw_params      = wm8971_pcm_hw_params,
        .digital_mute   = wm8971_mute,
        .set_fmt        = wm8971_set_dai_fmt,
@@ -600,7 +599,7 @@ static void wm8971_work(struct work_struct *work)
        wm8971_set_bias_level(codec, codec->dapm.bias_level);
 }
 
-static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8971_suspend(struct snd_soc_codec *codec)
 {
        wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -725,7 +724,7 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
 
 static struct i2c_driver wm8971_i2c_driver = {
        .driver = {
-               .name = "wm8971-codec",
+               .name = "wm8971",
                .owner = THIS_MODULE,
        },
        .probe =    wm8971_i2c_probe,
index 9352f1e088d27fd4053ce7b6e6796081c1daee92..4a6a7b5a61ba442583cce6d1d6e6338836130f70 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -226,7 +225,7 @@ SND_SOC_DAPM_MIXER("Input PGA", WM8974_POWER2, 2, 0, wm8974_inpga,
 SND_SOC_DAPM_MIXER("Boost Mixer", WM8974_POWER2, 4, 0,
                   wm8974_boost_mixer, ARRAY_SIZE(wm8974_boost_mixer)),
 
-SND_SOC_DAPM_MICBIAS("Mic Bias", WM8974_POWER1, 4, 0),
+SND_SOC_DAPM_SUPPLY("Mic Bias", WM8974_POWER1, 4, 0, NULL, 0),
 
 SND_SOC_DAPM_INPUT("MICN"),
 SND_SOC_DAPM_INPUT("MICP"),
@@ -557,7 +556,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
 #define WM8974_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8974_ops = {
+static const struct snd_soc_dai_ops wm8974_ops = {
        .hw_params = wm8974_pcm_hw_params,
        .digital_mute = wm8974_mute,
        .set_fmt = wm8974_set_dai_fmt,
@@ -583,7 +582,7 @@ static struct snd_soc_dai_driver wm8974_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8974_suspend(struct snd_soc_codec *codec)
 {
        wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -672,7 +671,7 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
 
 static struct i2c_driver wm8974_i2c_driver = {
        .driver = {
-               .name = "wm8974-codec",
+               .name = "wm8974",
                .owner = THIS_MODULE,
        },
        .probe =    wm8974_i2c_probe,
index 41ca4d9ac20c0dff5aeb5d2666cae916237a0144..85d514d63a4c8862e9be6f7c4a751f1aa749a6ab 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -865,7 +864,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
 #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 = {
+static const struct snd_soc_dai_ops wm8978_dai_ops = {
        .hw_params      = wm8978_hw_params,
        .digital_mute   = wm8978_mute,
        .set_fmt        = wm8978_set_dai_fmt,
@@ -893,7 +892,7 @@ static struct snd_soc_dai_driver wm8978_dai = {
        .ops = &wm8978_dai_ops,
 };
 
-static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8978_suspend(struct snd_soc_codec *codec)
 {
        wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
        /* Also switch PLL off */
index 93ee28439be56f70dbdaec4a4689209df94f3243..cebde568d1919a0e961601b1e308be8ebb1accc8 100644 (file)
@@ -481,7 +481,8 @@ static const struct snd_soc_dapm_widget wm8983_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("OUT4 Out", WM8983_POWER_MANAGEMENT_3,
                         8, 0, NULL, 0),
 
-       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias", WM8983_POWER_MANAGEMENT_1, 4, 0,
+                           NULL, 0),
 
        SND_SOC_DAPM_INPUT("LIN"),
        SND_SOC_DAPM_INPUT("LIP"),
@@ -973,7 +974,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
 }
 
 #ifdef CONFIG_PM
-static int wm8983_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8983_suspend(struct snd_soc_codec *codec)
 {
        wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1034,7 +1035,7 @@ static int wm8983_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_dai_ops wm8983_dai_ops = {
+static const struct snd_soc_dai_ops wm8983_dai_ops = {
        .digital_mute = wm8983_dac_mute,
        .hw_params = wm8983_hw_params,
        .set_fmt = wm8983_set_fmt,
index bae510acdec8facfa985a966173c0512a92e8783..c0c86b3c6adf69076be221308d0fe0fcc48a1c08 100644 (file)
@@ -411,7 +411,8 @@ static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
                6, 0, NULL, 0),
 
-       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0,
+                           NULL, 0),
 
        SND_SOC_DAPM_INPUT("LIN"),
        SND_SOC_DAPM_INPUT("LIP"),
@@ -944,7 +945,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
 }
 
 #ifdef CONFIG_PM
-static int wm8985_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8985_suspend(struct snd_soc_codec *codec)
 {
        wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1030,7 +1031,7 @@ err_reg_get:
        return ret;
 }
 
-static struct snd_soc_dai_ops wm8985_dai_ops = {
+static const struct snd_soc_dai_ops wm8985_dai_ops = {
        .digital_mute = wm8985_dac_mute,
        .hw_params = wm8985_hw_params,
        .set_fmt = wm8985_set_fmt,
index 2e9eba717d1a9adb1f15fe345276699c67c26fca..ab52963dd04c976a21fab1badfffb6f775f30de7 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -267,7 +266,7 @@ static const struct snd_kcontrol_new wm8988_monomux_controls =
        SOC_DAPM_ENUM("Route", monomux);
 
 static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {
-       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8988_PWR1, 1, 0),
+       SND_SOC_DAPM_SUPPLY("Mic Bias", WM8988_PWR1, 1, 0, NULL, 0),
 
        SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,
                &wm8988_diffmux_controls),
@@ -701,7 +700,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
 #define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8988_ops = {
+static const struct snd_soc_dai_ops wm8988_ops = {
        .startup = wm8988_pcm_startup,
        .hw_params = wm8988_pcm_hw_params,
        .set_fmt = wm8988_set_dai_fmt,
@@ -729,7 +728,7 @@ static struct snd_soc_dai_driver wm8988_dai = {
        .symmetric_rates = 1,
 };
 
-static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8988_suspend(struct snd_soc_codec *codec)
 {
        wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -823,7 +822,7 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8988_spi_driver = {
        .driver = {
-               .name   = "wm8988-codec",
+               .name   = "wm8988",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8988_spi_probe,
index d29a9622964c20d32850c6f5c0ced435af22a1a7..e538edaae1f0dbd6d9cdd82f34bb8bc232b7b549 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -776,8 +775,8 @@ SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0,
        NULL, 0),
 
 /* MICBIAS */
-SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1,
-       WM8990_MICBIAS_ENA_BIT, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS", WM8990_POWER_MANAGEMENT_1,
+                   WM8990_MICBIAS_ENA_BIT, 0, NULL, 0),
 
 SND_SOC_DAPM_OUTPUT("LON"),
 SND_SOC_DAPM_OUTPUT("LOP"),
@@ -1287,7 +1286,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
-static struct snd_soc_dai_ops wm8990_dai_ops = {
+static const struct snd_soc_dai_ops wm8990_dai_ops = {
        .hw_params      = wm8990_hw_params,
        .digital_mute   = wm8990_mute,
        .set_fmt        = wm8990_set_dai_fmt,
@@ -1314,7 +1313,7 @@ static struct snd_soc_dai_driver wm8990_dai = {
        .ops = &wm8990_dai_ops,
 };
 
-static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8990_suspend(struct snd_soc_codec *codec)
 {
        wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1418,7 +1417,7 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
        .driver = {
-               .name = "wm8990-codec",
+               .name = "wm8990",
                .owner = THIS_MODULE,
        },
        .probe =    wm8990_i2c_probe,
index c9ab3ba9bcedf4269f3b9d9f00a146d0a7d4a8c8..7ee40da8dbb52021db9427ec84f7b2751236b7d5 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -770,8 +769,8 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
                NULL, 0),
 
        /* MICBIAS */
-       SND_SOC_DAPM_MICBIAS("MICBIAS", WM8991_POWER_MANAGEMENT_1,
-               WM8991_MICBIAS_ENA_BIT, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS", WM8991_POWER_MANAGEMENT_1,
+                           WM8991_MICBIAS_ENA_BIT, 0, NULL, 0),
 
        SND_SOC_DAPM_OUTPUT("LON"),
        SND_SOC_DAPM_OUTPUT("LOP"),
@@ -1241,7 +1240,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8991_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8991_suspend(struct snd_soc_codec *codec)
 {
        wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1311,7 +1310,7 @@ static int wm8991_probe(struct snd_soc_codec *codec)
 #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
                        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops wm8991_ops = {
+static const struct snd_soc_dai_ops wm8991_ops = {
        .hw_params = wm8991_hw_params,
        .digital_mute = wm8991_mute,
        .set_fmt = wm8991_set_dai_fmt,
index d1a142f48b09f03fb565a5c4a6419842a854c6f6..2b40c93601ed493a11bf0222dd5ba0c09754355b 100644 (file)
@@ -934,28 +934,6 @@ 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)
 {
@@ -979,7 +957,7 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                        if (ret != 0)
                                return ret;
 
-                       wm8993_cache_restore(codec);
+                       snd_soc_cache_sync(codec);
 
                        /* Tune DC servo configuration */
                        snd_soc_write(codec, 0x44, 3);
@@ -1394,7 +1372,7 @@ out:
        return 0;
 }
 
-static struct snd_soc_dai_ops wm8993_ops = {
+static const struct snd_soc_dai_ops wm8993_ops = {
        .set_sysclk = wm8993_set_sysclk,
        .set_fmt = wm8993_set_dai_fmt,
        .hw_params = wm8993_hw_params,
@@ -1544,7 +1522,7 @@ static int wm8993_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm8993_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8993_suspend(struct snd_soc_codec *codec)
 {
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int fll_fout = wm8993->fll_fout;
@@ -1613,7 +1591,8 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
        struct wm8993_priv *wm8993;
        int ret;
 
-       wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
+       wm8993 = devm_kzalloc(&i2c->dev, sizeof(struct wm8993_priv),
+                             GFP_KERNEL);
        if (wm8993 == NULL)
                return -ENOMEM;
 
@@ -1621,8 +1600,6 @@ static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8993, &wm8993_dai, 1);
-       if (ret < 0)
-               kfree(wm8993);
        return ret;
 }
 
@@ -1641,7 +1618,7 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
 
 static struct i2c_driver wm8993_i2c_driver = {
        .driver = {
-               .name = "wm8993-codec",
+               .name = "wm8993",
                .owner = THIS_MODULE,
        },
        .probe =    wm8993_i2c_probe,
diff --git a/sound/soc/codecs/wm8994-tables.c b/sound/soc/codecs/wm8994-tables.c
deleted file mode 100644 (file)
index df5a8b9..0000000
+++ /dev/null
@@ -1,3147 +0,0 @@
-#include "wm8994.h"
-
-const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
-       { 0xFFFF, 0xFFFF }, /* R0     - Software Reset */
-       { 0x3B37, 0x3B37 }, /* R1     - Power Management (1) */
-       { 0x6BF0, 0x6BF0 }, /* R2     - Power Management (2) */
-       { 0x3FF0, 0x3FF0 }, /* R3     - Power Management (3) */
-       { 0x3F3F, 0x3F3F }, /* R4     - Power Management (4) */
-       { 0x3F0F, 0x3F0F }, /* R5     - Power Management (5) */
-       { 0x003F, 0x003F }, /* R6     - Power Management (6) */
-       { 0x0000, 0x0000 }, /* R7 */
-       { 0x0000, 0x0000 }, /* R8 */
-       { 0x0000, 0x0000 }, /* R9 */
-       { 0x0000, 0x0000 }, /* R10 */
-       { 0x0000, 0x0000 }, /* R11 */
-       { 0x0000, 0x0000 }, /* R12 */
-       { 0x0000, 0x0000 }, /* R13 */
-       { 0x0000, 0x0000 }, /* R14 */
-       { 0x0000, 0x0000 }, /* R15 */
-       { 0x0000, 0x0000 }, /* R16 */
-       { 0x0000, 0x0000 }, /* R17 */
-       { 0x0000, 0x0000 }, /* R18 */
-       { 0x0000, 0x0000 }, /* R19 */
-       { 0x0000, 0x0000 }, /* R20 */
-       { 0x01C0, 0x01C0 }, /* R21    - Input Mixer (1) */
-       { 0x0000, 0x0000 }, /* R22 */
-       { 0x0000, 0x0000 }, /* R23 */
-       { 0x00DF, 0x01DF }, /* R24    - Left Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF }, /* R25    - Left Line Input 3&4 Volume */
-       { 0x00DF, 0x01DF }, /* R26    - Right Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF }, /* R27    - Right Line Input 3&4 Volume */
-       { 0x00FF, 0x01FF }, /* R28    - Left Output Volume */
-       { 0x00FF, 0x01FF }, /* R29    - Right Output Volume */
-       { 0x0077, 0x0077 }, /* R30    - Line Outputs Volume */
-       { 0x0030, 0x0030 }, /* R31    - HPOUT2 Volume */
-       { 0x00FF, 0x01FF }, /* R32    - Left OPGA Volume */
-       { 0x00FF, 0x01FF }, /* R33    - Right OPGA Volume */
-       { 0x007F, 0x007F }, /* R34    - SPKMIXL Attenuation */
-       { 0x017F, 0x017F }, /* R35    - SPKMIXR Attenuation */
-       { 0x003F, 0x003F }, /* R36    - SPKOUT Mixers */
-       { 0x003F, 0x003F }, /* R37    - ClassD */
-       { 0x00FF, 0x01FF }, /* R38    - Speaker Volume Left */
-       { 0x00FF, 0x01FF }, /* R39    - Speaker Volume Right */
-       { 0x00FF, 0x00FF }, /* R40    - Input Mixer (2) */
-       { 0x01B7, 0x01B7 }, /* R41    - Input Mixer (3) */
-       { 0x01B7, 0x01B7 }, /* R42    - Input Mixer (4) */
-       { 0x01C7, 0x01C7 }, /* R43    - Input Mixer (5) */
-       { 0x01C7, 0x01C7 }, /* R44    - Input Mixer (6) */
-       { 0x01FF, 0x01FF }, /* R45    - Output Mixer (1) */
-       { 0x01FF, 0x01FF }, /* R46    - Output Mixer (2) */
-       { 0x0FFF, 0x0FFF }, /* R47    - Output Mixer (3) */
-       { 0x0FFF, 0x0FFF }, /* R48    - Output Mixer (4) */
-       { 0x0FFF, 0x0FFF }, /* R49    - Output Mixer (5) */
-       { 0x0FFF, 0x0FFF }, /* R50    - Output Mixer (6) */
-       { 0x0038, 0x0038 }, /* R51    - HPOUT2 Mixer */
-       { 0x0077, 0x0077 }, /* R52    - Line Mixer (1) */
-       { 0x0077, 0x0077 }, /* R53    - Line Mixer (2) */
-       { 0x03FF, 0x03FF }, /* R54    - Speaker Mixer */
-       { 0x00C1, 0x00C1 }, /* R55    - Additional Control */
-       { 0x00F0, 0x00F0 }, /* R56    - AntiPOP (1) */
-       { 0x01EF, 0x01EF }, /* R57    - AntiPOP (2) */
-       { 0x00FF, 0x00FF }, /* R58    - MICBIAS */
-       { 0x000F, 0x000F }, /* R59    - LDO 1 */
-       { 0x0007, 0x0007 }, /* R60    - LDO 2 */
-       { 0xFFFF, 0xFFFF }, /* R61 */
-       { 0xFFFF, 0xFFFF }, /* R62 */
-       { 0x0000, 0x0000 }, /* R63 */
-       { 0x0000, 0x0000 }, /* R64 */
-       { 0x0000, 0x0000 }, /* R65 */
-       { 0x0000, 0x0000 }, /* R66 */
-       { 0x0000, 0x0000 }, /* R67 */
-       { 0x0000, 0x0000 }, /* R68 */
-       { 0x0000, 0x0000 }, /* R69 */
-       { 0x0000, 0x0000 }, /* R70 */
-       { 0x0000, 0x0000 }, /* R71 */
-       { 0x0000, 0x0000 }, /* R72 */
-       { 0x0000, 0x0000 }, /* R73 */
-       { 0x0000, 0x0000 }, /* R74 */
-       { 0x0000, 0x0000 }, /* R75 */
-       { 0x8000, 0x8000 }, /* R76    - Charge Pump (1) */
-       { 0x0000, 0x0000 }, /* R77 */
-       { 0x0000, 0x0000 }, /* R78 */
-       { 0x0000, 0x0000 }, /* R79 */
-       { 0x0000, 0x0000 }, /* R80 */
-       { 0x0301, 0x0301 }, /* R81    - Class W (1) */
-       { 0x0000, 0x0000 }, /* R82 */
-       { 0x0000, 0x0000 }, /* R83 */
-       { 0x333F, 0x333F }, /* R84    - DC Servo (1) */
-       { 0x0FEF, 0x0FEF }, /* R85    - DC Servo (2) */
-       { 0x0000, 0x0000 }, /* R86 */
-       { 0xFFFF, 0xFFFF }, /* R87    - DC Servo (4) */
-       { 0x0333, 0x0000 }, /* R88    - DC Servo Readback */
-       { 0x0000, 0x0000 }, /* R89 */
-       { 0x0000, 0x0000 }, /* R90 */
-       { 0x0000, 0x0000 }, /* R91 */
-       { 0x0000, 0x0000 }, /* R92 */
-       { 0x0000, 0x0000 }, /* R93 */
-       { 0x0000, 0x0000 }, /* R94 */
-       { 0x0000, 0x0000 }, /* R95 */
-       { 0x00EE, 0x00EE }, /* R96    - Analogue HP (1) */
-       { 0x0000, 0x0000 }, /* R97 */
-       { 0x0000, 0x0000 }, /* R98 */
-       { 0x0000, 0x0000 }, /* R99 */
-       { 0x0000, 0x0000 }, /* R100 */
-       { 0x0000, 0x0000 }, /* R101 */
-       { 0x0000, 0x0000 }, /* R102 */
-       { 0x0000, 0x0000 }, /* R103 */
-       { 0x0000, 0x0000 }, /* R104 */
-       { 0x0000, 0x0000 }, /* R105 */
-       { 0x0000, 0x0000 }, /* R106 */
-       { 0x0000, 0x0000 }, /* R107 */
-       { 0x0000, 0x0000 }, /* R108 */
-       { 0x0000, 0x0000 }, /* R109 */
-       { 0x0000, 0x0000 }, /* R110 */
-       { 0x0000, 0x0000 }, /* R111 */
-       { 0x0000, 0x0000 }, /* R112 */
-       { 0x0000, 0x0000 }, /* R113 */
-       { 0x0000, 0x0000 }, /* R114 */
-       { 0x0000, 0x0000 }, /* R115 */
-       { 0x0000, 0x0000 }, /* R116 */
-       { 0x0000, 0x0000 }, /* R117 */
-       { 0x0000, 0x0000 }, /* R118 */
-       { 0x0000, 0x0000 }, /* R119 */
-       { 0x0000, 0x0000 }, /* R120 */
-       { 0x0000, 0x0000 }, /* R121 */
-       { 0x0000, 0x0000 }, /* R122 */
-       { 0x0000, 0x0000 }, /* R123 */
-       { 0x0000, 0x0000 }, /* R124 */
-       { 0x0000, 0x0000 }, /* R125 */
-       { 0x0000, 0x0000 }, /* R126 */
-       { 0x0000, 0x0000 }, /* R127 */
-       { 0x0000, 0x0000 }, /* R128 */
-       { 0x0000, 0x0000 }, /* R129 */
-       { 0x0000, 0x0000 }, /* R130 */
-       { 0x0000, 0x0000 }, /* R131 */
-       { 0x0000, 0x0000 }, /* R132 */
-       { 0x0000, 0x0000 }, /* R133 */
-       { 0x0000, 0x0000 }, /* R134 */
-       { 0x0000, 0x0000 }, /* R135 */
-       { 0x0000, 0x0000 }, /* R136 */
-       { 0x0000, 0x0000 }, /* R137 */
-       { 0x0000, 0x0000 }, /* R138 */
-       { 0x0000, 0x0000 }, /* R139 */
-       { 0x0000, 0x0000 }, /* R140 */
-       { 0x0000, 0x0000 }, /* R141 */
-       { 0x0000, 0x0000 }, /* R142 */
-       { 0x0000, 0x0000 }, /* R143 */
-       { 0x0000, 0x0000 }, /* R144 */
-       { 0x0000, 0x0000 }, /* R145 */
-       { 0x0000, 0x0000 }, /* R146 */
-       { 0x0000, 0x0000 }, /* R147 */
-       { 0x0000, 0x0000 }, /* R148 */
-       { 0x0000, 0x0000 }, /* R149 */
-       { 0x0000, 0x0000 }, /* R150 */
-       { 0x0000, 0x0000 }, /* R151 */
-       { 0x0000, 0x0000 }, /* R152 */
-       { 0x0000, 0x0000 }, /* R153 */
-       { 0x0000, 0x0000 }, /* R154 */
-       { 0x0000, 0x0000 }, /* R155 */
-       { 0x0000, 0x0000 }, /* R156 */
-       { 0x0000, 0x0000 }, /* R157 */
-       { 0x0000, 0x0000 }, /* R158 */
-       { 0x0000, 0x0000 }, /* R159 */
-       { 0x0000, 0x0000 }, /* R160 */
-       { 0x0000, 0x0000 }, /* R161 */
-       { 0x0000, 0x0000 }, /* R162 */
-       { 0x0000, 0x0000 }, /* R163 */
-       { 0x0000, 0x0000 }, /* R164 */
-       { 0x0000, 0x0000 }, /* R165 */
-       { 0x0000, 0x0000 }, /* R166 */
-       { 0x0000, 0x0000 }, /* R167 */
-       { 0x0000, 0x0000 }, /* R168 */
-       { 0x0000, 0x0000 }, /* R169 */
-       { 0x0000, 0x0000 }, /* R170 */
-       { 0x0000, 0x0000 }, /* R171 */
-       { 0x0000, 0x0000 }, /* R172 */
-       { 0x0000, 0x0000 }, /* R173 */
-       { 0x0000, 0x0000 }, /* R174 */
-       { 0x0000, 0x0000 }, /* R175 */
-       { 0x0000, 0x0000 }, /* R176 */
-       { 0x0000, 0x0000 }, /* R177 */
-       { 0x0000, 0x0000 }, /* R178 */
-       { 0x0000, 0x0000 }, /* R179 */
-       { 0x0000, 0x0000 }, /* R180 */
-       { 0x0000, 0x0000 }, /* R181 */
-       { 0x0000, 0x0000 }, /* R182 */
-       { 0x0000, 0x0000 }, /* R183 */
-       { 0x0000, 0x0000 }, /* R184 */
-       { 0x0000, 0x0000 }, /* R185 */
-       { 0x0000, 0x0000 }, /* R186 */
-       { 0x0000, 0x0000 }, /* R187 */
-       { 0x0000, 0x0000 }, /* R188 */
-       { 0x0000, 0x0000 }, /* R189 */
-       { 0x0000, 0x0000 }, /* R190 */
-       { 0x0000, 0x0000 }, /* R191 */
-       { 0x0000, 0x0000 }, /* R192 */
-       { 0x0000, 0x0000 }, /* R193 */
-       { 0x0000, 0x0000 }, /* R194 */
-       { 0x0000, 0x0000 }, /* R195 */
-       { 0x0000, 0x0000 }, /* R196 */
-       { 0x0000, 0x0000 }, /* R197 */
-       { 0x0000, 0x0000 }, /* R198 */
-       { 0x0000, 0x0000 }, /* R199 */
-       { 0x0000, 0x0000 }, /* R200 */
-       { 0x0000, 0x0000 }, /* R201 */
-       { 0x0000, 0x0000 }, /* R202 */
-       { 0x0000, 0x0000 }, /* R203 */
-       { 0x0000, 0x0000 }, /* R204 */
-       { 0x0000, 0x0000 }, /* R205 */
-       { 0x0000, 0x0000 }, /* R206 */
-       { 0x0000, 0x0000 }, /* R207 */
-       { 0xFFFF, 0xFFFF }, /* R208 */
-       { 0xFFFF, 0xFFFF }, /* R209 */
-       { 0xFFFF, 0xFFFF }, /* R210 */
-       { 0x0000, 0x0000 }, /* R211 */
-       { 0x0000, 0x0000 }, /* R212 */
-       { 0x0000, 0x0000 }, /* R213 */
-       { 0x0000, 0x0000 }, /* R214 */
-       { 0x0000, 0x0000 }, /* R215 */
-       { 0x0000, 0x0000 }, /* R216 */
-       { 0x0000, 0x0000 }, /* R217 */
-       { 0x0000, 0x0000 }, /* R218 */
-       { 0x0000, 0x0000 }, /* R219 */
-       { 0x0000, 0x0000 }, /* R220 */
-       { 0x0000, 0x0000 }, /* R221 */
-       { 0x0000, 0x0000 }, /* R222 */
-       { 0x0000, 0x0000 }, /* R223 */
-       { 0x0000, 0x0000 }, /* R224 */
-       { 0x0000, 0x0000 }, /* R225 */
-       { 0x0000, 0x0000 }, /* R226 */
-       { 0x0000, 0x0000 }, /* R227 */
-       { 0x0000, 0x0000 }, /* R228 */
-       { 0x0000, 0x0000 }, /* R229 */
-       { 0x0000, 0x0000 }, /* R230 */
-       { 0x0000, 0x0000 }, /* R231 */
-       { 0x0000, 0x0000 }, /* R232 */
-       { 0x0000, 0x0000 }, /* R233 */
-       { 0x0000, 0x0000 }, /* R234 */
-       { 0x0000, 0x0000 }, /* R235 */
-       { 0x0000, 0x0000 }, /* R236 */
-       { 0x0000, 0x0000 }, /* R237 */
-       { 0x0000, 0x0000 }, /* R238 */
-       { 0x0000, 0x0000 }, /* R239 */
-       { 0x0000, 0x0000 }, /* R240 */
-       { 0x0000, 0x0000 }, /* R241 */
-       { 0x0000, 0x0000 }, /* R242 */
-       { 0x0000, 0x0000 }, /* R243 */
-       { 0x0000, 0x0000 }, /* R244 */
-       { 0x0000, 0x0000 }, /* R245 */
-       { 0x0000, 0x0000 }, /* R246 */
-       { 0x0000, 0x0000 }, /* R247 */
-       { 0x0000, 0x0000 }, /* R248 */
-       { 0x0000, 0x0000 }, /* R249 */
-       { 0x0000, 0x0000 }, /* R250 */
-       { 0x0000, 0x0000 }, /* R251 */
-       { 0x0000, 0x0000 }, /* R252 */
-       { 0x0000, 0x0000 }, /* R253 */
-       { 0x0000, 0x0000 }, /* R254 */
-       { 0x0000, 0x0000 }, /* R255 */
-       { 0x000F, 0x0000 }, /* R256   - Chip Revision */
-       { 0x0074, 0x0074 }, /* R257   - Control Interface */
-       { 0x0000, 0x0000 }, /* R258 */
-       { 0x0000, 0x0000 }, /* R259 */
-       { 0x0000, 0x0000 }, /* R260 */
-       { 0x0000, 0x0000 }, /* R261 */
-       { 0x0000, 0x0000 }, /* R262 */
-       { 0x0000, 0x0000 }, /* R263 */
-       { 0x0000, 0x0000 }, /* R264 */
-       { 0x0000, 0x0000 }, /* R265 */
-       { 0x0000, 0x0000 }, /* R266 */
-       { 0x0000, 0x0000 }, /* R267 */
-       { 0x0000, 0x0000 }, /* R268 */
-       { 0x0000, 0x0000 }, /* R269 */
-       { 0x0000, 0x0000 }, /* R270 */
-       { 0x0000, 0x0000 }, /* R271 */
-       { 0x807F, 0x837F }, /* R272   - Write Sequencer Ctrl (1) */
-       { 0x017F, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
-       { 0x0000, 0x0000 }, /* R274 */
-       { 0x0000, 0x0000 }, /* R275 */
-       { 0x0000, 0x0000 }, /* R276 */
-       { 0x0000, 0x0000 }, /* R277 */
-       { 0x0000, 0x0000 }, /* R278 */
-       { 0x0000, 0x0000 }, /* R279 */
-       { 0x0000, 0x0000 }, /* R280 */
-       { 0x0000, 0x0000 }, /* R281 */
-       { 0x0000, 0x0000 }, /* R282 */
-       { 0x0000, 0x0000 }, /* R283 */
-       { 0x0000, 0x0000 }, /* R284 */
-       { 0x0000, 0x0000 }, /* R285 */
-       { 0x0000, 0x0000 }, /* R286 */
-       { 0x0000, 0x0000 }, /* R287 */
-       { 0x0000, 0x0000 }, /* R288 */
-       { 0x0000, 0x0000 }, /* R289 */
-       { 0x0000, 0x0000 }, /* R290 */
-       { 0x0000, 0x0000 }, /* R291 */
-       { 0x0000, 0x0000 }, /* R292 */
-       { 0x0000, 0x0000 }, /* R293 */
-       { 0x0000, 0x0000 }, /* R294 */
-       { 0x0000, 0x0000 }, /* R295 */
-       { 0x0000, 0x0000 }, /* R296 */
-       { 0x0000, 0x0000 }, /* R297 */
-       { 0x0000, 0x0000 }, /* R298 */
-       { 0x0000, 0x0000 }, /* R299 */
-       { 0x0000, 0x0000 }, /* R300 */
-       { 0x0000, 0x0000 }, /* R301 */
-       { 0x0000, 0x0000 }, /* R302 */
-       { 0x0000, 0x0000 }, /* R303 */
-       { 0x0000, 0x0000 }, /* R304 */
-       { 0x0000, 0x0000 }, /* R305 */
-       { 0x0000, 0x0000 }, /* R306 */
-       { 0x0000, 0x0000 }, /* R307 */
-       { 0x0000, 0x0000 }, /* R308 */
-       { 0x0000, 0x0000 }, /* R309 */
-       { 0x0000, 0x0000 }, /* R310 */
-       { 0x0000, 0x0000 }, /* R311 */
-       { 0x0000, 0x0000 }, /* R312 */
-       { 0x0000, 0x0000 }, /* R313 */
-       { 0x0000, 0x0000 }, /* R314 */
-       { 0x0000, 0x0000 }, /* R315 */
-       { 0x0000, 0x0000 }, /* R316 */
-       { 0x0000, 0x0000 }, /* R317 */
-       { 0x0000, 0x0000 }, /* R318 */
-       { 0x0000, 0x0000 }, /* R319 */
-       { 0x0000, 0x0000 }, /* R320 */
-       { 0x0000, 0x0000 }, /* R321 */
-       { 0x0000, 0x0000 }, /* R322 */
-       { 0x0000, 0x0000 }, /* R323 */
-       { 0x0000, 0x0000 }, /* R324 */
-       { 0x0000, 0x0000 }, /* R325 */
-       { 0x0000, 0x0000 }, /* R326 */
-       { 0x0000, 0x0000 }, /* R327 */
-       { 0x0000, 0x0000 }, /* R328 */
-       { 0x0000, 0x0000 }, /* R329 */
-       { 0x0000, 0x0000 }, /* R330 */
-       { 0x0000, 0x0000 }, /* R331 */
-       { 0x0000, 0x0000 }, /* R332 */
-       { 0x0000, 0x0000 }, /* R333 */
-       { 0x0000, 0x0000 }, /* R334 */
-       { 0x0000, 0x0000 }, /* R335 */
-       { 0x0000, 0x0000 }, /* R336 */
-       { 0x0000, 0x0000 }, /* R337 */
-       { 0x0000, 0x0000 }, /* R338 */
-       { 0x0000, 0x0000 }, /* R339 */
-       { 0x0000, 0x0000 }, /* R340 */
-       { 0x0000, 0x0000 }, /* R341 */
-       { 0x0000, 0x0000 }, /* R342 */
-       { 0x0000, 0x0000 }, /* R343 */
-       { 0x0000, 0x0000 }, /* R344 */
-       { 0x0000, 0x0000 }, /* R345 */
-       { 0x0000, 0x0000 }, /* R346 */
-       { 0x0000, 0x0000 }, /* R347 */
-       { 0x0000, 0x0000 }, /* R348 */
-       { 0x0000, 0x0000 }, /* R349 */
-       { 0x0000, 0x0000 }, /* R350 */
-       { 0x0000, 0x0000 }, /* R351 */
-       { 0x0000, 0x0000 }, /* R352 */
-       { 0x0000, 0x0000 }, /* R353 */
-       { 0x0000, 0x0000 }, /* R354 */
-       { 0x0000, 0x0000 }, /* R355 */
-       { 0x0000, 0x0000 }, /* R356 */
-       { 0x0000, 0x0000 }, /* R357 */
-       { 0x0000, 0x0000 }, /* R358 */
-       { 0x0000, 0x0000 }, /* R359 */
-       { 0x0000, 0x0000 }, /* R360 */
-       { 0x0000, 0x0000 }, /* R361 */
-       { 0x0000, 0x0000 }, /* R362 */
-       { 0x0000, 0x0000 }, /* R363 */
-       { 0x0000, 0x0000 }, /* R364 */
-       { 0x0000, 0x0000 }, /* R365 */
-       { 0x0000, 0x0000 }, /* R366 */
-       { 0x0000, 0x0000 }, /* R367 */
-       { 0x0000, 0x0000 }, /* R368 */
-       { 0x0000, 0x0000 }, /* R369 */
-       { 0x0000, 0x0000 }, /* R370 */
-       { 0x0000, 0x0000 }, /* R371 */
-       { 0x0000, 0x0000 }, /* R372 */
-       { 0x0000, 0x0000 }, /* R373 */
-       { 0x0000, 0x0000 }, /* R374 */
-       { 0x0000, 0x0000 }, /* R375 */
-       { 0x0000, 0x0000 }, /* R376 */
-       { 0x0000, 0x0000 }, /* R377 */
-       { 0x0000, 0x0000 }, /* R378 */
-       { 0x0000, 0x0000 }, /* R379 */
-       { 0x0000, 0x0000 }, /* R380 */
-       { 0x0000, 0x0000 }, /* R381 */
-       { 0x0000, 0x0000 }, /* R382 */
-       { 0x0000, 0x0000 }, /* R383 */
-       { 0x0000, 0x0000 }, /* R384 */
-       { 0x0000, 0x0000 }, /* R385 */
-       { 0x0000, 0x0000 }, /* R386 */
-       { 0x0000, 0x0000 }, /* R387 */
-       { 0x0000, 0x0000 }, /* R388 */
-       { 0x0000, 0x0000 }, /* R389 */
-       { 0x0000, 0x0000 }, /* R390 */
-       { 0x0000, 0x0000 }, /* R391 */
-       { 0x0000, 0x0000 }, /* R392 */
-       { 0x0000, 0x0000 }, /* R393 */
-       { 0x0000, 0x0000 }, /* R394 */
-       { 0x0000, 0x0000 }, /* R395 */
-       { 0x0000, 0x0000 }, /* R396 */
-       { 0x0000, 0x0000 }, /* R397 */
-       { 0x0000, 0x0000 }, /* R398 */
-       { 0x0000, 0x0000 }, /* R399 */
-       { 0x0000, 0x0000 }, /* R400 */
-       { 0x0000, 0x0000 }, /* R401 */
-       { 0x0000, 0x0000 }, /* R402 */
-       { 0x0000, 0x0000 }, /* R403 */
-       { 0x0000, 0x0000 }, /* R404 */
-       { 0x0000, 0x0000 }, /* R405 */
-       { 0x0000, 0x0000 }, /* R406 */
-       { 0x0000, 0x0000 }, /* R407 */
-       { 0x0000, 0x0000 }, /* R408 */
-       { 0x0000, 0x0000 }, /* R409 */
-       { 0x0000, 0x0000 }, /* R410 */
-       { 0x0000, 0x0000 }, /* R411 */
-       { 0x0000, 0x0000 }, /* R412 */
-       { 0x0000, 0x0000 }, /* R413 */
-       { 0x0000, 0x0000 }, /* R414 */
-       { 0x0000, 0x0000 }, /* R415 */
-       { 0x0000, 0x0000 }, /* R416 */
-       { 0x0000, 0x0000 }, /* R417 */
-       { 0x0000, 0x0000 }, /* R418 */
-       { 0x0000, 0x0000 }, /* R419 */
-       { 0x0000, 0x0000 }, /* R420 */
-       { 0x0000, 0x0000 }, /* R421 */
-       { 0x0000, 0x0000 }, /* R422 */
-       { 0x0000, 0x0000 }, /* R423 */
-       { 0x0000, 0x0000 }, /* R424 */
-       { 0x0000, 0x0000 }, /* R425 */
-       { 0x0000, 0x0000 }, /* R426 */
-       { 0x0000, 0x0000 }, /* R427 */
-       { 0x0000, 0x0000 }, /* R428 */
-       { 0x0000, 0x0000 }, /* R429 */
-       { 0x0000, 0x0000 }, /* R430 */
-       { 0x0000, 0x0000 }, /* R431 */
-       { 0x0000, 0x0000 }, /* R432 */
-       { 0x0000, 0x0000 }, /* R433 */
-       { 0x0000, 0x0000 }, /* R434 */
-       { 0x0000, 0x0000 }, /* R435 */
-       { 0x0000, 0x0000 }, /* R436 */
-       { 0x0000, 0x0000 }, /* R437 */
-       { 0x0000, 0x0000 }, /* R438 */
-       { 0x0000, 0x0000 }, /* R439 */
-       { 0x0000, 0x0000 }, /* R440 */
-       { 0x0000, 0x0000 }, /* R441 */
-       { 0x0000, 0x0000 }, /* R442 */
-       { 0x0000, 0x0000 }, /* R443 */
-       { 0x0000, 0x0000 }, /* R444 */
-       { 0x0000, 0x0000 }, /* R445 */
-       { 0x0000, 0x0000 }, /* R446 */
-       { 0x0000, 0x0000 }, /* R447 */
-       { 0x0000, 0x0000 }, /* R448 */
-       { 0x0000, 0x0000 }, /* R449 */
-       { 0x0000, 0x0000 }, /* R450 */
-       { 0x0000, 0x0000 }, /* R451 */
-       { 0x0000, 0x0000 }, /* R452 */
-       { 0x0000, 0x0000 }, /* R453 */
-       { 0x0000, 0x0000 }, /* R454 */
-       { 0x0000, 0x0000 }, /* R455 */
-       { 0x0000, 0x0000 }, /* R456 */
-       { 0x0000, 0x0000 }, /* R457 */
-       { 0x0000, 0x0000 }, /* R458 */
-       { 0x0000, 0x0000 }, /* R459 */
-       { 0x0000, 0x0000 }, /* R460 */
-       { 0x0000, 0x0000 }, /* R461 */
-       { 0x0000, 0x0000 }, /* R462 */
-       { 0x0000, 0x0000 }, /* R463 */
-       { 0x0000, 0x0000 }, /* R464 */
-       { 0x0000, 0x0000 }, /* R465 */
-       { 0x0000, 0x0000 }, /* R466 */
-       { 0x0000, 0x0000 }, /* R467 */
-       { 0x0000, 0x0000 }, /* R468 */
-       { 0x0000, 0x0000 }, /* R469 */
-       { 0x0000, 0x0000 }, /* R470 */
-       { 0x0000, 0x0000 }, /* R471 */
-       { 0x0000, 0x0000 }, /* R472 */
-       { 0x0000, 0x0000 }, /* R473 */
-       { 0x0000, 0x0000 }, /* R474 */
-       { 0x0000, 0x0000 }, /* R475 */
-       { 0x0000, 0x0000 }, /* R476 */
-       { 0x0000, 0x0000 }, /* R477 */
-       { 0x0000, 0x0000 }, /* R478 */
-       { 0x0000, 0x0000 }, /* R479 */
-       { 0x0000, 0x0000 }, /* R480 */
-       { 0x0000, 0x0000 }, /* R481 */
-       { 0x0000, 0x0000 }, /* R482 */
-       { 0x0000, 0x0000 }, /* R483 */
-       { 0x0000, 0x0000 }, /* R484 */
-       { 0x0000, 0x0000 }, /* R485 */
-       { 0x0000, 0x0000 }, /* R486 */
-       { 0x0000, 0x0000 }, /* R487 */
-       { 0x0000, 0x0000 }, /* R488 */
-       { 0x0000, 0x0000 }, /* R489 */
-       { 0x0000, 0x0000 }, /* R490 */
-       { 0x0000, 0x0000 }, /* R491 */
-       { 0x0000, 0x0000 }, /* R492 */
-       { 0x0000, 0x0000 }, /* R493 */
-       { 0x0000, 0x0000 }, /* R494 */
-       { 0x0000, 0x0000 }, /* R495 */
-       { 0x0000, 0x0000 }, /* R496 */
-       { 0x0000, 0x0000 }, /* R497 */
-       { 0x0000, 0x0000 }, /* R498 */
-       { 0x0000, 0x0000 }, /* R499 */
-       { 0x0000, 0x0000 }, /* R500 */
-       { 0x0000, 0x0000 }, /* R501 */
-       { 0x0000, 0x0000 }, /* R502 */
-       { 0x0000, 0x0000 }, /* R503 */
-       { 0x0000, 0x0000 }, /* R504 */
-       { 0x0000, 0x0000 }, /* R505 */
-       { 0x0000, 0x0000 }, /* R506 */
-       { 0x0000, 0x0000 }, /* R507 */
-       { 0x0000, 0x0000 }, /* R508 */
-       { 0x0000, 0x0000 }, /* R509 */
-       { 0x0000, 0x0000 }, /* R510 */
-       { 0x0000, 0x0000 }, /* R511 */
-       { 0x001F, 0x001F }, /* R512   - AIF1 Clocking (1) */
-       { 0x003F, 0x003F }, /* R513   - AIF1 Clocking (2) */
-       { 0x0000, 0x0000 }, /* R514 */
-       { 0x0000, 0x0000 }, /* R515 */
-       { 0x001F, 0x001F }, /* R516   - AIF2 Clocking (1) */
-       { 0x003F, 0x003F }, /* R517   - AIF2 Clocking (2) */
-       { 0x0000, 0x0000 }, /* R518 */
-       { 0x0000, 0x0000 }, /* R519 */
-       { 0x001F, 0x001F }, /* R520   - Clocking (1) */
-       { 0x0777, 0x0777 }, /* R521   - Clocking (2) */
-       { 0x0000, 0x0000 }, /* R522 */
-       { 0x0000, 0x0000 }, /* R523 */
-       { 0x0000, 0x0000 }, /* R524 */
-       { 0x0000, 0x0000 }, /* R525 */
-       { 0x0000, 0x0000 }, /* R526 */
-       { 0x0000, 0x0000 }, /* R527 */
-       { 0x00FF, 0x00FF }, /* R528   - AIF1 Rate */
-       { 0x00FF, 0x00FF }, /* R529   - AIF2 Rate */
-       { 0x000F, 0x0000 }, /* R530   - Rate Status */
-       { 0x0000, 0x0000 }, /* R531 */
-       { 0x0000, 0x0000 }, /* R532 */
-       { 0x0000, 0x0000 }, /* R533 */
-       { 0x0000, 0x0000 }, /* R534 */
-       { 0x0000, 0x0000 }, /* R535 */
-       { 0x0000, 0x0000 }, /* R536 */
-       { 0x0000, 0x0000 }, /* R537 */
-       { 0x0000, 0x0000 }, /* R538 */
-       { 0x0000, 0x0000 }, /* R539 */
-       { 0x0000, 0x0000 }, /* R540 */
-       { 0x0000, 0x0000 }, /* R541 */
-       { 0x0000, 0x0000 }, /* R542 */
-       { 0x0000, 0x0000 }, /* R543 */
-       { 0x0007, 0x0007 }, /* R544   - FLL1 Control (1) */
-       { 0x3F77, 0x3F77 }, /* R545   - FLL1 Control (2) */
-       { 0xFFFF, 0xFFFF }, /* R546   - FLL1 Control (3) */
-       { 0x7FEF, 0x7FEF }, /* R547   - FLL1 Control (4) */
-       { 0x1FDB, 0x1FDB }, /* R548   - FLL1 Control (5) */
-       { 0x0000, 0x0000 }, /* R549 */
-       { 0x0000, 0x0000 }, /* R550 */
-       { 0x0000, 0x0000 }, /* R551 */
-       { 0x0000, 0x0000 }, /* R552 */
-       { 0x0000, 0x0000 }, /* R553 */
-       { 0x0000, 0x0000 }, /* R554 */
-       { 0x0000, 0x0000 }, /* R555 */
-       { 0x0000, 0x0000 }, /* R556 */
-       { 0x0000, 0x0000 }, /* R557 */
-       { 0x0000, 0x0000 }, /* R558 */
-       { 0x0000, 0x0000 }, /* R559 */
-       { 0x0000, 0x0000 }, /* R560 */
-       { 0x0000, 0x0000 }, /* R561 */
-       { 0x0000, 0x0000 }, /* R562 */
-       { 0x0000, 0x0000 }, /* R563 */
-       { 0x0000, 0x0000 }, /* R564 */
-       { 0x0000, 0x0000 }, /* R565 */
-       { 0x0000, 0x0000 }, /* R566 */
-       { 0x0000, 0x0000 }, /* R567 */
-       { 0x0000, 0x0000 }, /* R568 */
-       { 0x0000, 0x0000 }, /* R569 */
-       { 0x0000, 0x0000 }, /* R570 */
-       { 0x0000, 0x0000 }, /* R571 */
-       { 0x0000, 0x0000 }, /* R572 */
-       { 0x0000, 0x0000 }, /* R573 */
-       { 0x0000, 0x0000 }, /* R574 */
-       { 0x0000, 0x0000 }, /* R575 */
-       { 0x0007, 0x0007 }, /* R576   - FLL2 Control (1) */
-       { 0x3F77, 0x3F77 }, /* R577   - FLL2 Control (2) */
-       { 0xFFFF, 0xFFFF }, /* R578   - FLL2 Control (3) */
-       { 0x7FEF, 0x7FEF }, /* R579   - FLL2 Control (4) */
-       { 0x1FDB, 0x1FDB }, /* R580   - FLL2 Control (5) */
-       { 0x0000, 0x0000 }, /* R581 */
-       { 0x0000, 0x0000 }, /* R582 */
-       { 0x0000, 0x0000 }, /* R583 */
-       { 0x0000, 0x0000 }, /* R584 */
-       { 0x0000, 0x0000 }, /* R585 */
-       { 0x0000, 0x0000 }, /* R586 */
-       { 0x0000, 0x0000 }, /* R587 */
-       { 0x0000, 0x0000 }, /* R588 */
-       { 0x0000, 0x0000 }, /* R589 */
-       { 0x0000, 0x0000 }, /* R590 */
-       { 0x0000, 0x0000 }, /* R591 */
-       { 0x0000, 0x0000 }, /* R592 */
-       { 0x0000, 0x0000 }, /* R593 */
-       { 0x0000, 0x0000 }, /* R594 */
-       { 0x0000, 0x0000 }, /* R595 */
-       { 0x0000, 0x0000 }, /* R596 */
-       { 0x0000, 0x0000 }, /* R597 */
-       { 0x0000, 0x0000 }, /* R598 */
-       { 0x0000, 0x0000 }, /* R599 */
-       { 0x0000, 0x0000 }, /* R600 */
-       { 0x0000, 0x0000 }, /* R601 */
-       { 0x0000, 0x0000 }, /* R602 */
-       { 0x0000, 0x0000 }, /* R603 */
-       { 0x0000, 0x0000 }, /* R604 */
-       { 0x0000, 0x0000 }, /* R605 */
-       { 0x0000, 0x0000 }, /* R606 */
-       { 0x0000, 0x0000 }, /* R607 */
-       { 0x0000, 0x0000 }, /* R608 */
-       { 0x0000, 0x0000 }, /* R609 */
-       { 0x0000, 0x0000 }, /* R610 */
-       { 0x0000, 0x0000 }, /* R611 */
-       { 0x0000, 0x0000 }, /* R612 */
-       { 0x0000, 0x0000 }, /* R613 */
-       { 0x0000, 0x0000 }, /* R614 */
-       { 0x0000, 0x0000 }, /* R615 */
-       { 0x0000, 0x0000 }, /* R616 */
-       { 0x0000, 0x0000 }, /* R617 */
-       { 0x0000, 0x0000 }, /* R618 */
-       { 0x0000, 0x0000 }, /* R619 */
-       { 0x0000, 0x0000 }, /* R620 */
-       { 0x0000, 0x0000 }, /* R621 */
-       { 0x0000, 0x0000 }, /* R622 */
-       { 0x0000, 0x0000 }, /* R623 */
-       { 0x0000, 0x0000 }, /* R624 */
-       { 0x0000, 0x0000 }, /* R625 */
-       { 0x0000, 0x0000 }, /* R626 */
-       { 0x0000, 0x0000 }, /* R627 */
-       { 0x0000, 0x0000 }, /* R628 */
-       { 0x0000, 0x0000 }, /* R629 */
-       { 0x0000, 0x0000 }, /* R630 */
-       { 0x0000, 0x0000 }, /* R631 */
-       { 0x0000, 0x0000 }, /* R632 */
-       { 0x0000, 0x0000 }, /* R633 */
-       { 0x0000, 0x0000 }, /* R634 */
-       { 0x0000, 0x0000 }, /* R635 */
-       { 0x0000, 0x0000 }, /* R636 */
-       { 0x0000, 0x0000 }, /* R637 */
-       { 0x0000, 0x0000 }, /* R638 */
-       { 0x0000, 0x0000 }, /* R639 */
-       { 0x0000, 0x0000 }, /* R640 */
-       { 0x0000, 0x0000 }, /* R641 */
-       { 0x0000, 0x0000 }, /* R642 */
-       { 0x0000, 0x0000 }, /* R643 */
-       { 0x0000, 0x0000 }, /* R644 */
-       { 0x0000, 0x0000 }, /* R645 */
-       { 0x0000, 0x0000 }, /* R646 */
-       { 0x0000, 0x0000 }, /* R647 */
-       { 0x0000, 0x0000 }, /* R648 */
-       { 0x0000, 0x0000 }, /* R649 */
-       { 0x0000, 0x0000 }, /* R650 */
-       { 0x0000, 0x0000 }, /* R651 */
-       { 0x0000, 0x0000 }, /* R652 */
-       { 0x0000, 0x0000 }, /* R653 */
-       { 0x0000, 0x0000 }, /* R654 */
-       { 0x0000, 0x0000 }, /* R655 */
-       { 0x0000, 0x0000 }, /* R656 */
-       { 0x0000, 0x0000 }, /* R657 */
-       { 0x0000, 0x0000 }, /* R658 */
-       { 0x0000, 0x0000 }, /* R659 */
-       { 0x0000, 0x0000 }, /* R660 */
-       { 0x0000, 0x0000 }, /* R661 */
-       { 0x0000, 0x0000 }, /* R662 */
-       { 0x0000, 0x0000 }, /* R663 */
-       { 0x0000, 0x0000 }, /* R664 */
-       { 0x0000, 0x0000 }, /* R665 */
-       { 0x0000, 0x0000 }, /* R666 */
-       { 0x0000, 0x0000 }, /* R667 */
-       { 0x0000, 0x0000 }, /* R668 */
-       { 0x0000, 0x0000 }, /* R669 */
-       { 0x0000, 0x0000 }, /* R670 */
-       { 0x0000, 0x0000 }, /* R671 */
-       { 0x0000, 0x0000 }, /* R672 */
-       { 0x0000, 0x0000 }, /* R673 */
-       { 0x0000, 0x0000 }, /* R674 */
-       { 0x0000, 0x0000 }, /* R675 */
-       { 0x0000, 0x0000 }, /* R676 */
-       { 0x0000, 0x0000 }, /* R677 */
-       { 0x0000, 0x0000 }, /* R678 */
-       { 0x0000, 0x0000 }, /* R679 */
-       { 0x0000, 0x0000 }, /* R680 */
-       { 0x0000, 0x0000 }, /* R681 */
-       { 0x0000, 0x0000 }, /* R682 */
-       { 0x0000, 0x0000 }, /* R683 */
-       { 0x0000, 0x0000 }, /* R684 */
-       { 0x0000, 0x0000 }, /* R685 */
-       { 0x0000, 0x0000 }, /* R686 */
-       { 0x0000, 0x0000 }, /* R687 */
-       { 0x0000, 0x0000 }, /* R688 */
-       { 0x0000, 0x0000 }, /* R689 */
-       { 0x0000, 0x0000 }, /* R690 */
-       { 0x0000, 0x0000 }, /* R691 */
-       { 0x0000, 0x0000 }, /* R692 */
-       { 0x0000, 0x0000 }, /* R693 */
-       { 0x0000, 0x0000 }, /* R694 */
-       { 0x0000, 0x0000 }, /* R695 */
-       { 0x0000, 0x0000 }, /* R696 */
-       { 0x0000, 0x0000 }, /* R697 */
-       { 0x0000, 0x0000 }, /* R698 */
-       { 0x0000, 0x0000 }, /* R699 */
-       { 0x0000, 0x0000 }, /* R700 */
-       { 0x0000, 0x0000 }, /* R701 */
-       { 0x0000, 0x0000 }, /* R702 */
-       { 0x0000, 0x0000 }, /* R703 */
-       { 0x0000, 0x0000 }, /* R704 */
-       { 0x0000, 0x0000 }, /* R705 */
-       { 0x0000, 0x0000 }, /* R706 */
-       { 0x0000, 0x0000 }, /* R707 */
-       { 0x0000, 0x0000 }, /* R708 */
-       { 0x0000, 0x0000 }, /* R709 */
-       { 0x0000, 0x0000 }, /* R710 */
-       { 0x0000, 0x0000 }, /* R711 */
-       { 0x0000, 0x0000 }, /* R712 */
-       { 0x0000, 0x0000 }, /* R713 */
-       { 0x0000, 0x0000 }, /* R714 */
-       { 0x0000, 0x0000 }, /* R715 */
-       { 0x0000, 0x0000 }, /* R716 */
-       { 0x0000, 0x0000 }, /* R717 */
-       { 0x0000, 0x0000 }, /* R718 */
-       { 0x0000, 0x0000 }, /* R719 */
-       { 0x0000, 0x0000 }, /* R720 */
-       { 0x0000, 0x0000 }, /* R721 */
-       { 0x0000, 0x0000 }, /* R722 */
-       { 0x0000, 0x0000 }, /* R723 */
-       { 0x0000, 0x0000 }, /* R724 */
-       { 0x0000, 0x0000 }, /* R725 */
-       { 0x0000, 0x0000 }, /* R726 */
-       { 0x0000, 0x0000 }, /* R727 */
-       { 0x0000, 0x0000 }, /* R728 */
-       { 0x0000, 0x0000 }, /* R729 */
-       { 0x0000, 0x0000 }, /* R730 */
-       { 0x0000, 0x0000 }, /* R731 */
-       { 0x0000, 0x0000 }, /* R732 */
-       { 0x0000, 0x0000 }, /* R733 */
-       { 0x0000, 0x0000 }, /* R734 */
-       { 0x0000, 0x0000 }, /* R735 */
-       { 0x0000, 0x0000 }, /* R736 */
-       { 0x0000, 0x0000 }, /* R737 */
-       { 0x0000, 0x0000 }, /* R738 */
-       { 0x0000, 0x0000 }, /* R739 */
-       { 0x0000, 0x0000 }, /* R740 */
-       { 0x0000, 0x0000 }, /* R741 */
-       { 0x0000, 0x0000 }, /* R742 */
-       { 0x0000, 0x0000 }, /* R743 */
-       { 0x0000, 0x0000 }, /* R744 */
-       { 0x0000, 0x0000 }, /* R745 */
-       { 0x0000, 0x0000 }, /* R746 */
-       { 0x0000, 0x0000 }, /* R747 */
-       { 0x0000, 0x0000 }, /* R748 */
-       { 0x0000, 0x0000 }, /* R749 */
-       { 0x0000, 0x0000 }, /* R750 */
-       { 0x0000, 0x0000 }, /* R751 */
-       { 0x0000, 0x0000 }, /* R752 */
-       { 0x0000, 0x0000 }, /* R753 */
-       { 0x0000, 0x0000 }, /* R754 */
-       { 0x0000, 0x0000 }, /* R755 */
-       { 0x0000, 0x0000 }, /* R756 */
-       { 0x0000, 0x0000 }, /* R757 */
-       { 0x0000, 0x0000 }, /* R758 */
-       { 0x0000, 0x0000 }, /* R759 */
-       { 0x0000, 0x0000 }, /* R760 */
-       { 0x0000, 0x0000 }, /* R761 */
-       { 0x0000, 0x0000 }, /* R762 */
-       { 0x0000, 0x0000 }, /* R763 */
-       { 0x0000, 0x0000 }, /* R764 */
-       { 0x0000, 0x0000 }, /* R765 */
-       { 0x0000, 0x0000 }, /* R766 */
-       { 0x0000, 0x0000 }, /* R767 */
-       { 0xE1F8, 0xE1F8 }, /* R768   - AIF1 Control (1) */
-       { 0xCD1F, 0xCD1F }, /* R769   - AIF1 Control (2) */
-       { 0xF000, 0xF000 }, /* R770   - AIF1 Master/Slave */
-       { 0x01F0, 0x01F0 }, /* R771   - AIF1 BCLK */
-       { 0x0FFF, 0x0FFF }, /* R772   - AIF1ADC LRCLK */
-       { 0x0FFF, 0x0FFF }, /* R773   - AIF1DAC LRCLK */
-       { 0x0003, 0x0003 }, /* R774   - AIF1DAC Data */
-       { 0x0003, 0x0003 }, /* R775   - AIF1ADC Data */
-       { 0x0000, 0x0000 }, /* R776 */
-       { 0x0000, 0x0000 }, /* R777 */
-       { 0x0000, 0x0000 }, /* R778 */
-       { 0x0000, 0x0000 }, /* R779 */
-       { 0x0000, 0x0000 }, /* R780 */
-       { 0x0000, 0x0000 }, /* R781 */
-       { 0x0000, 0x0000 }, /* R782 */
-       { 0x0000, 0x0000 }, /* R783 */
-       { 0xF1F8, 0xF1F8 }, /* R784   - AIF2 Control (1) */
-       { 0xFD1F, 0xFD1F }, /* R785   - AIF2 Control (2) */
-       { 0xF000, 0xF000 }, /* R786   - AIF2 Master/Slave */
-       { 0x01F0, 0x01F0 }, /* R787   - AIF2 BCLK */
-       { 0x0FFF, 0x0FFF }, /* R788   - AIF2ADC LRCLK */
-       { 0x0FFF, 0x0FFF }, /* R789   - AIF2DAC LRCLK */
-       { 0x0003, 0x0003 }, /* R790   - AIF2DAC Data */
-       { 0x0003, 0x0003 }, /* R791   - AIF2ADC Data */
-       { 0x0000, 0x0000 }, /* R792 */
-       { 0x0000, 0x0000 }, /* R793 */
-       { 0x0000, 0x0000 }, /* R794 */
-       { 0x0000, 0x0000 }, /* R795 */
-       { 0x0000, 0x0000 }, /* R796 */
-       { 0x0000, 0x0000 }, /* R797 */
-       { 0x0000, 0x0000 }, /* R798 */
-       { 0x0000, 0x0000 }, /* R799 */
-       { 0x0000, 0x0000 }, /* R800 */
-       { 0x0000, 0x0000 }, /* R801 */
-       { 0x0000, 0x0000 }, /* R802 */
-       { 0x0000, 0x0000 }, /* R803 */
-       { 0x0000, 0x0000 }, /* R804 */
-       { 0x0000, 0x0000 }, /* R805 */
-       { 0x0000, 0x0000 }, /* R806 */
-       { 0x0000, 0x0000 }, /* R807 */
-       { 0x0000, 0x0000 }, /* R808 */
-       { 0x0000, 0x0000 }, /* R809 */
-       { 0x0000, 0x0000 }, /* R810 */
-       { 0x0000, 0x0000 }, /* R811 */
-       { 0x0000, 0x0000 }, /* R812 */
-       { 0x0000, 0x0000 }, /* R813 */
-       { 0x0000, 0x0000 }, /* R814 */
-       { 0x0000, 0x0000 }, /* R815 */
-       { 0x0000, 0x0000 }, /* R816 */
-       { 0x0000, 0x0000 }, /* R817 */
-       { 0x0000, 0x0000 }, /* R818 */
-       { 0x0000, 0x0000 }, /* R819 */
-       { 0x0000, 0x0000 }, /* R820 */
-       { 0x0000, 0x0000 }, /* R821 */
-       { 0x0000, 0x0000 }, /* R822 */
-       { 0x0000, 0x0000 }, /* R823 */
-       { 0x0000, 0x0000 }, /* R824 */
-       { 0x0000, 0x0000 }, /* R825 */
-       { 0x0000, 0x0000 }, /* R826 */
-       { 0x0000, 0x0000 }, /* R827 */
-       { 0x0000, 0x0000 }, /* R828 */
-       { 0x0000, 0x0000 }, /* R829 */
-       { 0x0000, 0x0000 }, /* R830 */
-       { 0x0000, 0x0000 }, /* R831 */
-       { 0x0000, 0x0000 }, /* R832 */
-       { 0x0000, 0x0000 }, /* R833 */
-       { 0x0000, 0x0000 }, /* R834 */
-       { 0x0000, 0x0000 }, /* R835 */
-       { 0x0000, 0x0000 }, /* R836 */
-       { 0x0000, 0x0000 }, /* R837 */
-       { 0x0000, 0x0000 }, /* R838 */
-       { 0x0000, 0x0000 }, /* R839 */
-       { 0x0000, 0x0000 }, /* R840 */
-       { 0x0000, 0x0000 }, /* R841 */
-       { 0x0000, 0x0000 }, /* R842 */
-       { 0x0000, 0x0000 }, /* R843 */
-       { 0x0000, 0x0000 }, /* R844 */
-       { 0x0000, 0x0000 }, /* R845 */
-       { 0x0000, 0x0000 }, /* R846 */
-       { 0x0000, 0x0000 }, /* R847 */
-       { 0x0000, 0x0000 }, /* R848 */
-       { 0x0000, 0x0000 }, /* R849 */
-       { 0x0000, 0x0000 }, /* R850 */
-       { 0x0000, 0x0000 }, /* R851 */
-       { 0x0000, 0x0000 }, /* R852 */
-       { 0x0000, 0x0000 }, /* R853 */
-       { 0x0000, 0x0000 }, /* R854 */
-       { 0x0000, 0x0000 }, /* R855 */
-       { 0x0000, 0x0000 }, /* R856 */
-       { 0x0000, 0x0000 }, /* R857 */
-       { 0x0000, 0x0000 }, /* R858 */
-       { 0x0000, 0x0000 }, /* R859 */
-       { 0x0000, 0x0000 }, /* R860 */
-       { 0x0000, 0x0000 }, /* R861 */
-       { 0x0000, 0x0000 }, /* R862 */
-       { 0x0000, 0x0000 }, /* R863 */
-       { 0x0000, 0x0000 }, /* R864 */
-       { 0x0000, 0x0000 }, /* R865 */
-       { 0x0000, 0x0000 }, /* R866 */
-       { 0x0000, 0x0000 }, /* R867 */
-       { 0x0000, 0x0000 }, /* R868 */
-       { 0x0000, 0x0000 }, /* R869 */
-       { 0x0000, 0x0000 }, /* R870 */
-       { 0x0000, 0x0000 }, /* R871 */
-       { 0x0000, 0x0000 }, /* R872 */
-       { 0x0000, 0x0000 }, /* R873 */
-       { 0x0000, 0x0000 }, /* R874 */
-       { 0x0000, 0x0000 }, /* R875 */
-       { 0x0000, 0x0000 }, /* R876 */
-       { 0x0000, 0x0000 }, /* R877 */
-       { 0x0000, 0x0000 }, /* R878 */
-       { 0x0000, 0x0000 }, /* R879 */
-       { 0x0000, 0x0000 }, /* R880 */
-       { 0x0000, 0x0000 }, /* R881 */
-       { 0x0000, 0x0000 }, /* R882 */
-       { 0x0000, 0x0000 }, /* R883 */
-       { 0x0000, 0x0000 }, /* R884 */
-       { 0x0000, 0x0000 }, /* R885 */
-       { 0x0000, 0x0000 }, /* R886 */
-       { 0x0000, 0x0000 }, /* R887 */
-       { 0x0000, 0x0000 }, /* R888 */
-       { 0x0000, 0x0000 }, /* R889 */
-       { 0x0000, 0x0000 }, /* R890 */
-       { 0x0000, 0x0000 }, /* R891 */
-       { 0x0000, 0x0000 }, /* R892 */
-       { 0x0000, 0x0000 }, /* R893 */
-       { 0x0000, 0x0000 }, /* R894 */
-       { 0x0000, 0x0000 }, /* R895 */
-       { 0x0000, 0x0000 }, /* R896 */
-       { 0x0000, 0x0000 }, /* R897 */
-       { 0x0000, 0x0000 }, /* R898 */
-       { 0x0000, 0x0000 }, /* R899 */
-       { 0x0000, 0x0000 }, /* R900 */
-       { 0x0000, 0x0000 }, /* R901 */
-       { 0x0000, 0x0000 }, /* R902 */
-       { 0x0000, 0x0000 }, /* R903 */
-       { 0x0000, 0x0000 }, /* R904 */
-       { 0x0000, 0x0000 }, /* R905 */
-       { 0x0000, 0x0000 }, /* R906 */
-       { 0x0000, 0x0000 }, /* R907 */
-       { 0x0000, 0x0000 }, /* R908 */
-       { 0x0000, 0x0000 }, /* R909 */
-       { 0x0000, 0x0000 }, /* R910 */
-       { 0x0000, 0x0000 }, /* R911 */
-       { 0x0000, 0x0000 }, /* R912 */
-       { 0x0000, 0x0000 }, /* R913 */
-       { 0x0000, 0x0000 }, /* R914 */
-       { 0x0000, 0x0000 }, /* R915 */
-       { 0x0000, 0x0000 }, /* R916 */
-       { 0x0000, 0x0000 }, /* R917 */
-       { 0x0000, 0x0000 }, /* R918 */
-       { 0x0000, 0x0000 }, /* R919 */
-       { 0x0000, 0x0000 }, /* R920 */
-       { 0x0000, 0x0000 }, /* R921 */
-       { 0x0000, 0x0000 }, /* R922 */
-       { 0x0000, 0x0000 }, /* R923 */
-       { 0x0000, 0x0000 }, /* R924 */
-       { 0x0000, 0x0000 }, /* R925 */
-       { 0x0000, 0x0000 }, /* R926 */
-       { 0x0000, 0x0000 }, /* R927 */
-       { 0x0000, 0x0000 }, /* R928 */
-       { 0x0000, 0x0000 }, /* R929 */
-       { 0x0000, 0x0000 }, /* R930 */
-       { 0x0000, 0x0000 }, /* R931 */
-       { 0x0000, 0x0000 }, /* R932 */
-       { 0x0000, 0x0000 }, /* R933 */
-       { 0x0000, 0x0000 }, /* R934 */
-       { 0x0000, 0x0000 }, /* R935 */
-       { 0x0000, 0x0000 }, /* R936 */
-       { 0x0000, 0x0000 }, /* R937 */
-       { 0x0000, 0x0000 }, /* R938 */
-       { 0x0000, 0x0000 }, /* R939 */
-       { 0x0000, 0x0000 }, /* R940 */
-       { 0x0000, 0x0000 }, /* R941 */
-       { 0x0000, 0x0000 }, /* R942 */
-       { 0x0000, 0x0000 }, /* R943 */
-       { 0x0000, 0x0000 }, /* R944 */
-       { 0x0000, 0x0000 }, /* R945 */
-       { 0x0000, 0x0000 }, /* R946 */
-       { 0x0000, 0x0000 }, /* R947 */
-       { 0x0000, 0x0000 }, /* R948 */
-       { 0x0000, 0x0000 }, /* R949 */
-       { 0x0000, 0x0000 }, /* R950 */
-       { 0x0000, 0x0000 }, /* R951 */
-       { 0x0000, 0x0000 }, /* R952 */
-       { 0x0000, 0x0000 }, /* R953 */
-       { 0x0000, 0x0000 }, /* R954 */
-       { 0x0000, 0x0000 }, /* R955 */
-       { 0x0000, 0x0000 }, /* R956 */
-       { 0x0000, 0x0000 }, /* R957 */
-       { 0x0000, 0x0000 }, /* R958 */
-       { 0x0000, 0x0000 }, /* R959 */
-       { 0x0000, 0x0000 }, /* R960 */
-       { 0x0000, 0x0000 }, /* R961 */
-       { 0x0000, 0x0000 }, /* R962 */
-       { 0x0000, 0x0000 }, /* R963 */
-       { 0x0000, 0x0000 }, /* R964 */
-       { 0x0000, 0x0000 }, /* R965 */
-       { 0x0000, 0x0000 }, /* R966 */
-       { 0x0000, 0x0000 }, /* R967 */
-       { 0x0000, 0x0000 }, /* R968 */
-       { 0x0000, 0x0000 }, /* R969 */
-       { 0x0000, 0x0000 }, /* R970 */
-       { 0x0000, 0x0000 }, /* R971 */
-       { 0x0000, 0x0000 }, /* R972 */
-       { 0x0000, 0x0000 }, /* R973 */
-       { 0x0000, 0x0000 }, /* R974 */
-       { 0x0000, 0x0000 }, /* R975 */
-       { 0x0000, 0x0000 }, /* R976 */
-       { 0x0000, 0x0000 }, /* R977 */
-       { 0x0000, 0x0000 }, /* R978 */
-       { 0x0000, 0x0000 }, /* R979 */
-       { 0x0000, 0x0000 }, /* R980 */
-       { 0x0000, 0x0000 }, /* R981 */
-       { 0x0000, 0x0000 }, /* R982 */
-       { 0x0000, 0x0000 }, /* R983 */
-       { 0x0000, 0x0000 }, /* R984 */
-       { 0x0000, 0x0000 }, /* R985 */
-       { 0x0000, 0x0000 }, /* R986 */
-       { 0x0000, 0x0000 }, /* R987 */
-       { 0x0000, 0x0000 }, /* R988 */
-       { 0x0000, 0x0000 }, /* R989 */
-       { 0x0000, 0x0000 }, /* R990 */
-       { 0x0000, 0x0000 }, /* R991 */
-       { 0x0000, 0x0000 }, /* R992 */
-       { 0x0000, 0x0000 }, /* R993 */
-       { 0x0000, 0x0000 }, /* R994 */
-       { 0x0000, 0x0000 }, /* R995 */
-       { 0x0000, 0x0000 }, /* R996 */
-       { 0x0000, 0x0000 }, /* R997 */
-       { 0x0000, 0x0000 }, /* R998 */
-       { 0x0000, 0x0000 }, /* R999 */
-       { 0x0000, 0x0000 }, /* R1000 */
-       { 0x0000, 0x0000 }, /* R1001 */
-       { 0x0000, 0x0000 }, /* R1002 */
-       { 0x0000, 0x0000 }, /* R1003 */
-       { 0x0000, 0x0000 }, /* R1004 */
-       { 0x0000, 0x0000 }, /* R1005 */
-       { 0x0000, 0x0000 }, /* R1006 */
-       { 0x0000, 0x0000 }, /* R1007 */
-       { 0x0000, 0x0000 }, /* R1008 */
-       { 0x0000, 0x0000 }, /* R1009 */
-       { 0x0000, 0x0000 }, /* R1010 */
-       { 0x0000, 0x0000 }, /* R1011 */
-       { 0x0000, 0x0000 }, /* R1012 */
-       { 0x0000, 0x0000 }, /* R1013 */
-       { 0x0000, 0x0000 }, /* R1014 */
-       { 0x0000, 0x0000 }, /* R1015 */
-       { 0x0000, 0x0000 }, /* R1016 */
-       { 0x0000, 0x0000 }, /* R1017 */
-       { 0x0000, 0x0000 }, /* R1018 */
-       { 0x0000, 0x0000 }, /* R1019 */
-       { 0x0000, 0x0000 }, /* R1020 */
-       { 0x0000, 0x0000 }, /* R1021 */
-       { 0x0000, 0x0000 }, /* R1022 */
-       { 0x0000, 0x0000 }, /* R1023 */
-       { 0x00FF, 0x01FF }, /* R1024  - AIF1 ADC1 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1025  - AIF1 ADC1 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1026  - AIF1 DAC1 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1027  - AIF1 DAC1 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1028  - AIF1 ADC2 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1029  - AIF1 ADC2 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1030  - AIF1 DAC2 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1031  - AIF1 DAC2 Right Volume */
-       { 0x0000, 0x0000 }, /* R1032 */
-       { 0x0000, 0x0000 }, /* R1033 */
-       { 0x0000, 0x0000 }, /* R1034 */
-       { 0x0000, 0x0000 }, /* R1035 */
-       { 0x0000, 0x0000 }, /* R1036 */
-       { 0x0000, 0x0000 }, /* R1037 */
-       { 0x0000, 0x0000 }, /* R1038 */
-       { 0x0000, 0x0000 }, /* R1039 */
-       { 0xF800, 0xF800 }, /* R1040  - AIF1 ADC1 Filters */
-       { 0x7800, 0x7800 }, /* R1041  - AIF1 ADC2 Filters */
-       { 0x0000, 0x0000 }, /* R1042 */
-       { 0x0000, 0x0000 }, /* R1043 */
-       { 0x0000, 0x0000 }, /* R1044 */
-       { 0x0000, 0x0000 }, /* R1045 */
-       { 0x0000, 0x0000 }, /* R1046 */
-       { 0x0000, 0x0000 }, /* R1047 */
-       { 0x0000, 0x0000 }, /* R1048 */
-       { 0x0000, 0x0000 }, /* R1049 */
-       { 0x0000, 0x0000 }, /* R1050 */
-       { 0x0000, 0x0000 }, /* R1051 */
-       { 0x0000, 0x0000 }, /* R1052 */
-       { 0x0000, 0x0000 }, /* R1053 */
-       { 0x0000, 0x0000 }, /* R1054 */
-       { 0x0000, 0x0000 }, /* R1055 */
-       { 0x02B6, 0x02B6 }, /* R1056  - AIF1 DAC1 Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1057  - AIF1 DAC1 Filters (2) */
-       { 0x02B6, 0x02B6 }, /* R1058  - AIF1 DAC2 Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1059  - AIF1 DAC2 Filters (2) */
-       { 0x0000, 0x0000 }, /* R1060 */
-       { 0x0000, 0x0000 }, /* R1061 */
-       { 0x0000, 0x0000 }, /* R1062 */
-       { 0x0000, 0x0000 }, /* R1063 */
-       { 0x0000, 0x0000 }, /* R1064 */
-       { 0x0000, 0x0000 }, /* R1065 */
-       { 0x0000, 0x0000 }, /* R1066 */
-       { 0x0000, 0x0000 }, /* R1067 */
-       { 0x0000, 0x0000 }, /* R1068 */
-       { 0x0000, 0x0000 }, /* R1069 */
-       { 0x0000, 0x0000 }, /* R1070 */
-       { 0x0000, 0x0000 }, /* R1071 */
-       { 0x006F, 0x006F }, /* R1072  - AIF1 DAC1 Noise Gate */
-       { 0x006F, 0x006F }, /* R1073  - AIF1 DAC2 Noise Gate */
-       { 0x0000, 0x0000 }, /* R1074 */
-       { 0x0000, 0x0000 }, /* R1075 */
-       { 0x0000, 0x0000 }, /* R1076 */
-       { 0x0000, 0x0000 }, /* R1077 */
-       { 0x0000, 0x0000 }, /* R1078 */
-       { 0x0000, 0x0000 }, /* R1079 */
-       { 0x0000, 0x0000 }, /* R1080 */
-       { 0x0000, 0x0000 }, /* R1081 */
-       { 0x0000, 0x0000 }, /* R1082 */
-       { 0x0000, 0x0000 }, /* R1083 */
-       { 0x0000, 0x0000 }, /* R1084 */
-       { 0x0000, 0x0000 }, /* R1085 */
-       { 0x0000, 0x0000 }, /* R1086 */
-       { 0x0000, 0x0000 }, /* R1087 */
-       { 0xFFFF, 0xFFFF }, /* R1088  - AIF1 DRC1 (1) */
-       { 0x1FFF, 0x1FFF }, /* R1089  - AIF1 DRC1 (2) */
-       { 0xFFFF, 0xFFFF }, /* R1090  - AIF1 DRC1 (3) */
-       { 0x07FF, 0x07FF }, /* R1091  - AIF1 DRC1 (4) */
-       { 0x03FF, 0x03FF }, /* R1092  - AIF1 DRC1 (5) */
-       { 0x0000, 0x0000 }, /* R1093 */
-       { 0x0000, 0x0000 }, /* R1094 */
-       { 0x0000, 0x0000 }, /* R1095 */
-       { 0x0000, 0x0000 }, /* R1096 */
-       { 0x0000, 0x0000 }, /* R1097 */
-       { 0x0000, 0x0000 }, /* R1098 */
-       { 0x0000, 0x0000 }, /* R1099 */
-       { 0x0000, 0x0000 }, /* R1100 */
-       { 0x0000, 0x0000 }, /* R1101 */
-       { 0x0000, 0x0000 }, /* R1102 */
-       { 0x0000, 0x0000 }, /* R1103 */
-       { 0xFFFF, 0xFFFF }, /* R1104  - AIF1 DRC2 (1) */
-       { 0x1FFF, 0x1FFF }, /* R1105  - AIF1 DRC2 (2) */
-       { 0xFFFF, 0xFFFF }, /* R1106  - AIF1 DRC2 (3) */
-       { 0x07FF, 0x07FF }, /* R1107  - AIF1 DRC2 (4) */
-       { 0x03FF, 0x03FF }, /* R1108  - AIF1 DRC2 (5) */
-       { 0x0000, 0x0000 }, /* R1109 */
-       { 0x0000, 0x0000 }, /* R1110 */
-       { 0x0000, 0x0000 }, /* R1111 */
-       { 0x0000, 0x0000 }, /* R1112 */
-       { 0x0000, 0x0000 }, /* R1113 */
-       { 0x0000, 0x0000 }, /* R1114 */
-       { 0x0000, 0x0000 }, /* R1115 */
-       { 0x0000, 0x0000 }, /* R1116 */
-       { 0x0000, 0x0000 }, /* R1117 */
-       { 0x0000, 0x0000 }, /* R1118 */
-       { 0x0000, 0x0000 }, /* R1119 */
-       { 0x0000, 0x0000 }, /* R1120 */
-       { 0x0000, 0x0000 }, /* R1121 */
-       { 0x0000, 0x0000 }, /* R1122 */
-       { 0x0000, 0x0000 }, /* R1123 */
-       { 0x0000, 0x0000 }, /* R1124 */
-       { 0x0000, 0x0000 }, /* R1125 */
-       { 0x0000, 0x0000 }, /* R1126 */
-       { 0x0000, 0x0000 }, /* R1127 */
-       { 0x0000, 0x0000 }, /* R1128 */
-       { 0x0000, 0x0000 }, /* R1129 */
-       { 0x0000, 0x0000 }, /* R1130 */
-       { 0x0000, 0x0000 }, /* R1131 */
-       { 0x0000, 0x0000 }, /* R1132 */
-       { 0x0000, 0x0000 }, /* R1133 */
-       { 0x0000, 0x0000 }, /* R1134 */
-       { 0x0000, 0x0000 }, /* R1135 */
-       { 0x0000, 0x0000 }, /* R1136 */
-       { 0x0000, 0x0000 }, /* R1137 */
-       { 0x0000, 0x0000 }, /* R1138 */
-       { 0x0000, 0x0000 }, /* R1139 */
-       { 0x0000, 0x0000 }, /* R1140 */
-       { 0x0000, 0x0000 }, /* R1141 */
-       { 0x0000, 0x0000 }, /* R1142 */
-       { 0x0000, 0x0000 }, /* R1143 */
-       { 0x0000, 0x0000 }, /* R1144 */
-       { 0x0000, 0x0000 }, /* R1145 */
-       { 0x0000, 0x0000 }, /* R1146 */
-       { 0x0000, 0x0000 }, /* R1147 */
-       { 0x0000, 0x0000 }, /* R1148 */
-       { 0x0000, 0x0000 }, /* R1149 */
-       { 0x0000, 0x0000 }, /* R1150 */
-       { 0x0000, 0x0000 }, /* R1151 */
-       { 0xFFFF, 0xFFFF }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1172 */
-       { 0x0000, 0x0000 }, /* R1173 */
-       { 0x0000, 0x0000 }, /* R1174 */
-       { 0x0000, 0x0000 }, /* R1175 */
-       { 0x0000, 0x0000 }, /* R1176 */
-       { 0x0000, 0x0000 }, /* R1177 */
-       { 0x0000, 0x0000 }, /* R1178 */
-       { 0x0000, 0x0000 }, /* R1179 */
-       { 0x0000, 0x0000 }, /* R1180 */
-       { 0x0000, 0x0000 }, /* R1181 */
-       { 0x0000, 0x0000 }, /* R1182 */
-       { 0x0000, 0x0000 }, /* R1183 */
-       { 0xFFFF, 0xFFFF }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1204 */
-       { 0x0000, 0x0000 }, /* R1205 */
-       { 0x0000, 0x0000 }, /* R1206 */
-       { 0x0000, 0x0000 }, /* R1207 */
-       { 0x0000, 0x0000 }, /* R1208 */
-       { 0x0000, 0x0000 }, /* R1209 */
-       { 0x0000, 0x0000 }, /* R1210 */
-       { 0x0000, 0x0000 }, /* R1211 */
-       { 0x0000, 0x0000 }, /* R1212 */
-       { 0x0000, 0x0000 }, /* R1213 */
-       { 0x0000, 0x0000 }, /* R1214 */
-       { 0x0000, 0x0000 }, /* R1215 */
-       { 0x0000, 0x0000 }, /* R1216 */
-       { 0x0000, 0x0000 }, /* R1217 */
-       { 0x0000, 0x0000 }, /* R1218 */
-       { 0x0000, 0x0000 }, /* R1219 */
-       { 0x0000, 0x0000 }, /* R1220 */
-       { 0x0000, 0x0000 }, /* R1221 */
-       { 0x0000, 0x0000 }, /* R1222 */
-       { 0x0000, 0x0000 }, /* R1223 */
-       { 0x0000, 0x0000 }, /* R1224 */
-       { 0x0000, 0x0000 }, /* R1225 */
-       { 0x0000, 0x0000 }, /* R1226 */
-       { 0x0000, 0x0000 }, /* R1227 */
-       { 0x0000, 0x0000 }, /* R1228 */
-       { 0x0000, 0x0000 }, /* R1229 */
-       { 0x0000, 0x0000 }, /* R1230 */
-       { 0x0000, 0x0000 }, /* R1231 */
-       { 0x0000, 0x0000 }, /* R1232 */
-       { 0x0000, 0x0000 }, /* R1233 */
-       { 0x0000, 0x0000 }, /* R1234 */
-       { 0x0000, 0x0000 }, /* R1235 */
-       { 0x0000, 0x0000 }, /* R1236 */
-       { 0x0000, 0x0000 }, /* R1237 */
-       { 0x0000, 0x0000 }, /* R1238 */
-       { 0x0000, 0x0000 }, /* R1239 */
-       { 0x0000, 0x0000 }, /* R1240 */
-       { 0x0000, 0x0000 }, /* R1241 */
-       { 0x0000, 0x0000 }, /* R1242 */
-       { 0x0000, 0x0000 }, /* R1243 */
-       { 0x0000, 0x0000 }, /* R1244 */
-       { 0x0000, 0x0000 }, /* R1245 */
-       { 0x0000, 0x0000 }, /* R1246 */
-       { 0x0000, 0x0000 }, /* R1247 */
-       { 0x0000, 0x0000 }, /* R1248 */
-       { 0x0000, 0x0000 }, /* R1249 */
-       { 0x0000, 0x0000 }, /* R1250 */
-       { 0x0000, 0x0000 }, /* R1251 */
-       { 0x0000, 0x0000 }, /* R1252 */
-       { 0x0000, 0x0000 }, /* R1253 */
-       { 0x0000, 0x0000 }, /* R1254 */
-       { 0x0000, 0x0000 }, /* R1255 */
-       { 0x0000, 0x0000 }, /* R1256 */
-       { 0x0000, 0x0000 }, /* R1257 */
-       { 0x0000, 0x0000 }, /* R1258 */
-       { 0x0000, 0x0000 }, /* R1259 */
-       { 0x0000, 0x0000 }, /* R1260 */
-       { 0x0000, 0x0000 }, /* R1261 */
-       { 0x0000, 0x0000 }, /* R1262 */
-       { 0x0000, 0x0000 }, /* R1263 */
-       { 0x0000, 0x0000 }, /* R1264 */
-       { 0x0000, 0x0000 }, /* R1265 */
-       { 0x0000, 0x0000 }, /* R1266 */
-       { 0x0000, 0x0000 }, /* R1267 */
-       { 0x0000, 0x0000 }, /* R1268 */
-       { 0x0000, 0x0000 }, /* R1269 */
-       { 0x0000, 0x0000 }, /* R1270 */
-       { 0x0000, 0x0000 }, /* R1271 */
-       { 0x0000, 0x0000 }, /* R1272 */
-       { 0x0000, 0x0000 }, /* R1273 */
-       { 0x0000, 0x0000 }, /* R1274 */
-       { 0x0000, 0x0000 }, /* R1275 */
-       { 0x0000, 0x0000 }, /* R1276 */
-       { 0x0000, 0x0000 }, /* R1277 */
-       { 0x0000, 0x0000 }, /* R1278 */
-       { 0x0000, 0x0000 }, /* R1279 */
-       { 0x00FF, 0x01FF }, /* R1280  - AIF2 ADC Left Volume */
-       { 0x00FF, 0x01FF }, /* R1281  - AIF2 ADC Right Volume */
-       { 0x00FF, 0x01FF }, /* R1282  - AIF2 DAC Left Volume */
-       { 0x00FF, 0x01FF }, /* R1283  - AIF2 DAC Right Volume */
-       { 0x0000, 0x0000 }, /* R1284 */
-       { 0x0000, 0x0000 }, /* R1285 */
-       { 0x0000, 0x0000 }, /* R1286 */
-       { 0x0000, 0x0000 }, /* R1287 */
-       { 0x0000, 0x0000 }, /* R1288 */
-       { 0x0000, 0x0000 }, /* R1289 */
-       { 0x0000, 0x0000 }, /* R1290 */
-       { 0x0000, 0x0000 }, /* R1291 */
-       { 0x0000, 0x0000 }, /* R1292 */
-       { 0x0000, 0x0000 }, /* R1293 */
-       { 0x0000, 0x0000 }, /* R1294 */
-       { 0x0000, 0x0000 }, /* R1295 */
-       { 0xF800, 0xF800 }, /* R1296  - AIF2 ADC Filters */
-       { 0x0000, 0x0000 }, /* R1297 */
-       { 0x0000, 0x0000 }, /* R1298 */
-       { 0x0000, 0x0000 }, /* R1299 */
-       { 0x0000, 0x0000 }, /* R1300 */
-       { 0x0000, 0x0000 }, /* R1301 */
-       { 0x0000, 0x0000 }, /* R1302 */
-       { 0x0000, 0x0000 }, /* R1303 */
-       { 0x0000, 0x0000 }, /* R1304 */
-       { 0x0000, 0x0000 }, /* R1305 */
-       { 0x0000, 0x0000 }, /* R1306 */
-       { 0x0000, 0x0000 }, /* R1307 */
-       { 0x0000, 0x0000 }, /* R1308 */
-       { 0x0000, 0x0000 }, /* R1309 */
-       { 0x0000, 0x0000 }, /* R1310 */
-       { 0x0000, 0x0000 }, /* R1311 */
-       { 0x02B6, 0x02B6 }, /* R1312  - AIF2 DAC Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1313  - AIF2 DAC Filters (2) */
-       { 0x0000, 0x0000 }, /* R1314 */
-       { 0x0000, 0x0000 }, /* R1315 */
-       { 0x0000, 0x0000 }, /* R1316 */
-       { 0x0000, 0x0000 }, /* R1317 */
-       { 0x0000, 0x0000 }, /* R1318 */
-       { 0x0000, 0x0000 }, /* R1319 */
-       { 0x0000, 0x0000 }, /* R1320 */
-       { 0x0000, 0x0000 }, /* R1321 */
-       { 0x0000, 0x0000 }, /* R1322 */
-       { 0x0000, 0x0000 }, /* R1323 */
-       { 0x0000, 0x0000 }, /* R1324 */
-       { 0x0000, 0x0000 }, /* R1325 */
-       { 0x0000, 0x0000 }, /* R1326 */
-       { 0x0000, 0x0000 }, /* R1327 */
-       { 0x006F, 0x006F }, /* R1328  - AIF2 DAC Noise Gate */
-       { 0x0000, 0x0000 }, /* R1329 */
-       { 0x0000, 0x0000 }, /* R1330 */
-       { 0x0000, 0x0000 }, /* R1331 */
-       { 0x0000, 0x0000 }, /* R1332 */
-       { 0x0000, 0x0000 }, /* R1333 */
-       { 0x0000, 0x0000 }, /* R1334 */
-       { 0x0000, 0x0000 }, /* R1335 */
-       { 0x0000, 0x0000 }, /* R1336 */
-       { 0x0000, 0x0000 }, /* R1337 */
-       { 0x0000, 0x0000 }, /* R1338 */
-       { 0x0000, 0x0000 }, /* R1339 */
-       { 0x0000, 0x0000 }, /* R1340 */
-       { 0x0000, 0x0000 }, /* R1341 */
-       { 0x0000, 0x0000 }, /* R1342 */
-       { 0x0000, 0x0000 }, /* R1343 */
-       { 0xFFFF, 0xFFFF }, /* R1344  - AIF2 DRC (1) */
-       { 0x1FFF, 0x1FFF }, /* R1345  - AIF2 DRC (2) */
-       { 0xFFFF, 0xFFFF }, /* R1346  - AIF2 DRC (3) */
-       { 0x07FF, 0x07FF }, /* R1347  - AIF2 DRC (4) */
-       { 0x03FF, 0x03FF }, /* R1348  - AIF2 DRC (5) */
-       { 0x0000, 0x0000 }, /* R1349 */
-       { 0x0000, 0x0000 }, /* R1350 */
-       { 0x0000, 0x0000 }, /* R1351 */
-       { 0x0000, 0x0000 }, /* R1352 */
-       { 0x0000, 0x0000 }, /* R1353 */
-       { 0x0000, 0x0000 }, /* R1354 */
-       { 0x0000, 0x0000 }, /* R1355 */
-       { 0x0000, 0x0000 }, /* R1356 */
-       { 0x0000, 0x0000 }, /* R1357 */
-       { 0x0000, 0x0000 }, /* R1358 */
-       { 0x0000, 0x0000 }, /* R1359 */
-       { 0x0000, 0x0000 }, /* R1360 */
-       { 0x0000, 0x0000 }, /* R1361 */
-       { 0x0000, 0x0000 }, /* R1362 */
-       { 0x0000, 0x0000 }, /* R1363 */
-       { 0x0000, 0x0000 }, /* R1364 */
-       { 0x0000, 0x0000 }, /* R1365 */
-       { 0x0000, 0x0000 }, /* R1366 */
-       { 0x0000, 0x0000 }, /* R1367 */
-       { 0x0000, 0x0000 }, /* R1368 */
-       { 0x0000, 0x0000 }, /* R1369 */
-       { 0x0000, 0x0000 }, /* R1370 */
-       { 0x0000, 0x0000 }, /* R1371 */
-       { 0x0000, 0x0000 }, /* R1372 */
-       { 0x0000, 0x0000 }, /* R1373 */
-       { 0x0000, 0x0000 }, /* R1374 */
-       { 0x0000, 0x0000 }, /* R1375 */
-       { 0x0000, 0x0000 }, /* R1376 */
-       { 0x0000, 0x0000 }, /* R1377 */
-       { 0x0000, 0x0000 }, /* R1378 */
-       { 0x0000, 0x0000 }, /* R1379 */
-       { 0x0000, 0x0000 }, /* R1380 */
-       { 0x0000, 0x0000 }, /* R1381 */
-       { 0x0000, 0x0000 }, /* R1382 */
-       { 0x0000, 0x0000 }, /* R1383 */
-       { 0x0000, 0x0000 }, /* R1384 */
-       { 0x0000, 0x0000 }, /* R1385 */
-       { 0x0000, 0x0000 }, /* R1386 */
-       { 0x0000, 0x0000 }, /* R1387 */
-       { 0x0000, 0x0000 }, /* R1388 */
-       { 0x0000, 0x0000 }, /* R1389 */
-       { 0x0000, 0x0000 }, /* R1390 */
-       { 0x0000, 0x0000 }, /* R1391 */
-       { 0x0000, 0x0000 }, /* R1392 */
-       { 0x0000, 0x0000 }, /* R1393 */
-       { 0x0000, 0x0000 }, /* R1394 */
-       { 0x0000, 0x0000 }, /* R1395 */
-       { 0x0000, 0x0000 }, /* R1396 */
-       { 0x0000, 0x0000 }, /* R1397 */
-       { 0x0000, 0x0000 }, /* R1398 */
-       { 0x0000, 0x0000 }, /* R1399 */
-       { 0x0000, 0x0000 }, /* R1400 */
-       { 0x0000, 0x0000 }, /* R1401 */
-       { 0x0000, 0x0000 }, /* R1402 */
-       { 0x0000, 0x0000 }, /* R1403 */
-       { 0x0000, 0x0000 }, /* R1404 */
-       { 0x0000, 0x0000 }, /* R1405 */
-       { 0x0000, 0x0000 }, /* R1406 */
-       { 0x0000, 0x0000 }, /* R1407 */
-       { 0xFFFF, 0xFFFF }, /* R1408  - AIF2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1409  - AIF2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1410  - AIF2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1411  - AIF2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1412  - AIF2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1413  - AIF2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1414  - AIF2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1415  - AIF2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1416  - AIF2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1417  - AIF2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1418  - AIF2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1419  - AIF2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1420  - AIF2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1421  - AIF2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1422  - AIF2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1423  - AIF2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1424  - AIF2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1425  - AIF2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1426  - AIF2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1427  - AIF2 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1428 */
-       { 0x0000, 0x0000 }, /* R1429 */
-       { 0x0000, 0x0000 }, /* R1430 */
-       { 0x0000, 0x0000 }, /* R1431 */
-       { 0x0000, 0x0000 }, /* R1432 */
-       { 0x0000, 0x0000 }, /* R1433 */
-       { 0x0000, 0x0000 }, /* R1434 */
-       { 0x0000, 0x0000 }, /* R1435 */
-       { 0x0000, 0x0000 }, /* R1436 */
-       { 0x0000, 0x0000 }, /* R1437 */
-       { 0x0000, 0x0000 }, /* R1438 */
-       { 0x0000, 0x0000 }, /* R1439 */
-       { 0x0000, 0x0000 }, /* R1440 */
-       { 0x0000, 0x0000 }, /* R1441 */
-       { 0x0000, 0x0000 }, /* R1442 */
-       { 0x0000, 0x0000 }, /* R1443 */
-       { 0x0000, 0x0000 }, /* R1444 */
-       { 0x0000, 0x0000 }, /* R1445 */
-       { 0x0000, 0x0000 }, /* R1446 */
-       { 0x0000, 0x0000 }, /* R1447 */
-       { 0x0000, 0x0000 }, /* R1448 */
-       { 0x0000, 0x0000 }, /* R1449 */
-       { 0x0000, 0x0000 }, /* R1450 */
-       { 0x0000, 0x0000 }, /* R1451 */
-       { 0x0000, 0x0000 }, /* R1452 */
-       { 0x0000, 0x0000 }, /* R1453 */
-       { 0x0000, 0x0000 }, /* R1454 */
-       { 0x0000, 0x0000 }, /* R1455 */
-       { 0x0000, 0x0000 }, /* R1456 */
-       { 0x0000, 0x0000 }, /* R1457 */
-       { 0x0000, 0x0000 }, /* R1458 */
-       { 0x0000, 0x0000 }, /* R1459 */
-       { 0x0000, 0x0000 }, /* R1460 */
-       { 0x0000, 0x0000 }, /* R1461 */
-       { 0x0000, 0x0000 }, /* R1462 */
-       { 0x0000, 0x0000 }, /* R1463 */
-       { 0x0000, 0x0000 }, /* R1464 */
-       { 0x0000, 0x0000 }, /* R1465 */
-       { 0x0000, 0x0000 }, /* R1466 */
-       { 0x0000, 0x0000 }, /* R1467 */
-       { 0x0000, 0x0000 }, /* R1468 */
-       { 0x0000, 0x0000 }, /* R1469 */
-       { 0x0000, 0x0000 }, /* R1470 */
-       { 0x0000, 0x0000 }, /* R1471 */
-       { 0x0000, 0x0000 }, /* R1472 */
-       { 0x0000, 0x0000 }, /* R1473 */
-       { 0x0000, 0x0000 }, /* R1474 */
-       { 0x0000, 0x0000 }, /* R1475 */
-       { 0x0000, 0x0000 }, /* R1476 */
-       { 0x0000, 0x0000 }, /* R1477 */
-       { 0x0000, 0x0000 }, /* R1478 */
-       { 0x0000, 0x0000 }, /* R1479 */
-       { 0x0000, 0x0000 }, /* R1480 */
-       { 0x0000, 0x0000 }, /* R1481 */
-       { 0x0000, 0x0000 }, /* R1482 */
-       { 0x0000, 0x0000 }, /* R1483 */
-       { 0x0000, 0x0000 }, /* R1484 */
-       { 0x0000, 0x0000 }, /* R1485 */
-       { 0x0000, 0x0000 }, /* R1486 */
-       { 0x0000, 0x0000 }, /* R1487 */
-       { 0x0000, 0x0000 }, /* R1488 */
-       { 0x0000, 0x0000 }, /* R1489 */
-       { 0x0000, 0x0000 }, /* R1490 */
-       { 0x0000, 0x0000 }, /* R1491 */
-       { 0x0000, 0x0000 }, /* R1492 */
-       { 0x0000, 0x0000 }, /* R1493 */
-       { 0x0000, 0x0000 }, /* R1494 */
-       { 0x0000, 0x0000 }, /* R1495 */
-       { 0x0000, 0x0000 }, /* R1496 */
-       { 0x0000, 0x0000 }, /* R1497 */
-       { 0x0000, 0x0000 }, /* R1498 */
-       { 0x0000, 0x0000 }, /* R1499 */
-       { 0x0000, 0x0000 }, /* R1500 */
-       { 0x0000, 0x0000 }, /* R1501 */
-       { 0x0000, 0x0000 }, /* R1502 */
-       { 0x0000, 0x0000 }, /* R1503 */
-       { 0x0000, 0x0000 }, /* R1504 */
-       { 0x0000, 0x0000 }, /* R1505 */
-       { 0x0000, 0x0000 }, /* R1506 */
-       { 0x0000, 0x0000 }, /* R1507 */
-       { 0x0000, 0x0000 }, /* R1508 */
-       { 0x0000, 0x0000 }, /* R1509 */
-       { 0x0000, 0x0000 }, /* R1510 */
-       { 0x0000, 0x0000 }, /* R1511 */
-       { 0x0000, 0x0000 }, /* R1512 */
-       { 0x0000, 0x0000 }, /* R1513 */
-       { 0x0000, 0x0000 }, /* R1514 */
-       { 0x0000, 0x0000 }, /* R1515 */
-       { 0x0000, 0x0000 }, /* R1516 */
-       { 0x0000, 0x0000 }, /* R1517 */
-       { 0x0000, 0x0000 }, /* R1518 */
-       { 0x0000, 0x0000 }, /* R1519 */
-       { 0x0000, 0x0000 }, /* R1520 */
-       { 0x0000, 0x0000 }, /* R1521 */
-       { 0x0000, 0x0000 }, /* R1522 */
-       { 0x0000, 0x0000 }, /* R1523 */
-       { 0x0000, 0x0000 }, /* R1524 */
-       { 0x0000, 0x0000 }, /* R1525 */
-       { 0x0000, 0x0000 }, /* R1526 */
-       { 0x0000, 0x0000 }, /* R1527 */
-       { 0x0000, 0x0000 }, /* R1528 */
-       { 0x0000, 0x0000 }, /* R1529 */
-       { 0x0000, 0x0000 }, /* R1530 */
-       { 0x0000, 0x0000 }, /* R1531 */
-       { 0x0000, 0x0000 }, /* R1532 */
-       { 0x0000, 0x0000 }, /* R1533 */
-       { 0x0000, 0x0000 }, /* R1534 */
-       { 0x0000, 0x0000 }, /* R1535 */
-       { 0x01EF, 0x01EF }, /* R1536  - DAC1 Mixer Volumes */
-       { 0x0037, 0x0037 }, /* R1537  - DAC1 Left Mixer Routing */
-       { 0x0037, 0x0037 }, /* R1538  - DAC1 Right Mixer Routing */
-       { 0x01EF, 0x01EF }, /* R1539  - DAC2 Mixer Volumes */
-       { 0x0037, 0x0037 }, /* R1540  - DAC2 Left Mixer Routing */
-       { 0x0037, 0x0037 }, /* R1541  - DAC2 Right Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
-       { 0x0000, 0x0000 }, /* R1546 */
-       { 0x0000, 0x0000 }, /* R1547 */
-       { 0x0000, 0x0000 }, /* R1548 */
-       { 0x0000, 0x0000 }, /* R1549 */
-       { 0x0000, 0x0000 }, /* R1550 */
-       { 0x0000, 0x0000 }, /* R1551 */
-       { 0x02FF, 0x03FF }, /* R1552  - DAC1 Left Volume */
-       { 0x02FF, 0x03FF }, /* R1553  - DAC1 Right Volume */
-       { 0x02FF, 0x03FF }, /* R1554  - DAC2 Left Volume */
-       { 0x02FF, 0x03FF }, /* R1555  - DAC2 Right Volume */
-       { 0x0003, 0x0003 }, /* R1556  - DAC Softmute */
-       { 0x0000, 0x0000 }, /* R1557 */
-       { 0x0000, 0x0000 }, /* R1558 */
-       { 0x0000, 0x0000 }, /* R1559 */
-       { 0x0000, 0x0000 }, /* R1560 */
-       { 0x0000, 0x0000 }, /* R1561 */
-       { 0x0000, 0x0000 }, /* R1562 */
-       { 0x0000, 0x0000 }, /* R1563 */
-       { 0x0000, 0x0000 }, /* R1564 */
-       { 0x0000, 0x0000 }, /* R1565 */
-       { 0x0000, 0x0000 }, /* R1566 */
-       { 0x0000, 0x0000 }, /* R1567 */
-       { 0x0003, 0x0003 }, /* R1568  - Oversampling */
-       { 0x03C3, 0x03C3 }, /* R1569  - Sidetone */
-};
-
-const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
-       0x8994,     /* R0     - Software Reset */
-       0x0000,     /* R1     - Power Management (1) */
-       0x6000,     /* R2     - Power Management (2) */
-       0x0000,     /* R3     - Power Management (3) */
-       0x0000,     /* R4     - Power Management (4) */
-       0x0000,     /* R5     - Power Management (5) */
-       0x0000,     /* R6     - Power Management (6) */
-       0x0000,     /* R7 */
-       0x0000,     /* R8 */
-       0x0000,     /* R9 */
-       0x0000,     /* R10 */
-       0x0000,     /* R11 */
-       0x0000,     /* R12 */
-       0x0000,     /* R13 */
-       0x0000,     /* R14 */
-       0x0000,     /* R15 */
-       0x0000,     /* R16 */
-       0x0000,     /* R17 */
-       0x0000,     /* R18 */
-       0x0000,     /* R19 */
-       0x0000,     /* R20 */
-       0x0000,     /* R21    - Input Mixer (1) */
-       0x0000,     /* R22 */
-       0x0000,     /* R23 */
-       0x008B,     /* R24    - Left Line Input 1&2 Volume */
-       0x008B,     /* R25    - Left Line Input 3&4 Volume */
-       0x008B,     /* R26    - Right Line Input 1&2 Volume */
-       0x008B,     /* R27    - Right Line Input 3&4 Volume */
-       0x006D,     /* R28    - Left Output Volume */
-       0x006D,     /* R29    - Right Output Volume */
-       0x0066,     /* R30    - Line Outputs Volume */
-       0x0020,     /* R31    - HPOUT2 Volume */
-       0x0079,     /* R32    - Left OPGA Volume */
-       0x0079,     /* R33    - Right OPGA Volume */
-       0x0003,     /* R34    - SPKMIXL Attenuation */
-       0x0003,     /* R35    - SPKMIXR Attenuation */
-       0x0011,     /* R36    - SPKOUT Mixers */
-       0x0140,     /* R37    - ClassD */
-       0x0079,     /* R38    - Speaker Volume Left */
-       0x0079,     /* R39    - Speaker Volume Right */
-       0x0000,     /* R40    - Input Mixer (2) */
-       0x0000,     /* R41    - Input Mixer (3) */
-       0x0000,     /* R42    - Input Mixer (4) */
-       0x0000,     /* R43    - Input Mixer (5) */
-       0x0000,     /* R44    - Input Mixer (6) */
-       0x0000,     /* R45    - Output Mixer (1) */
-       0x0000,     /* R46    - Output Mixer (2) */
-       0x0000,     /* R47    - Output Mixer (3) */
-       0x0000,     /* R48    - Output Mixer (4) */
-       0x0000,     /* R49    - Output Mixer (5) */
-       0x0000,     /* R50    - Output Mixer (6) */
-       0x0000,     /* R51    - HPOUT2 Mixer */
-       0x0000,     /* R52    - Line Mixer (1) */
-       0x0000,     /* R53    - Line Mixer (2) */
-       0x0000,     /* R54    - Speaker Mixer */
-       0x0000,     /* R55    - Additional Control */
-       0x0000,     /* R56    - AntiPOP (1) */
-       0x0000,     /* R57    - AntiPOP (2) */
-       0x0000,     /* R58    - MICBIAS */
-       0x000D,     /* R59    - LDO 1 */
-       0x0003,     /* R60    - LDO 2 */
-       0x0039,     /* R61    - MICBIAS1 */
-       0x0039,     /* R62    - MICBIAS2 */
-       0x0000,     /* R63 */
-       0x0000,     /* R64 */
-       0x0000,     /* R65 */
-       0x0000,     /* R66 */
-       0x0000,     /* R67 */
-       0x0000,     /* R68 */
-       0x0000,     /* R69 */
-       0x0000,     /* R70 */
-       0x0000,     /* R71 */
-       0x0000,     /* R72 */
-       0x0000,     /* R73 */
-       0x0000,     /* R74 */
-       0x0000,     /* R75 */
-       0x1F25,     /* R76    - Charge Pump (1) */
-       0x0000,     /* R77 */
-       0x0000,     /* R78 */
-       0x0000,     /* R79 */
-       0x0000,     /* R80 */
-       0x0004,     /* R81    - Class W (1) */
-       0x0000,     /* R82 */
-       0x0000,     /* R83 */
-       0x0000,     /* R84    - DC Servo (1) */
-       0x054A,     /* R85    - DC Servo (2) */
-       0x0000,     /* R86 */
-       0x0000,     /* R87    - DC Servo (4) */
-       0x0000,     /* R88    - DC Servo Readback */
-       0x0000,     /* R89 */
-       0x0000,     /* R90 */
-       0x0000,     /* R91 */
-       0x0000,     /* R92 */
-       0x0000,     /* R93 */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96    - Analogue HP (1) */
-       0x0000,     /* R97 */
-       0x0000,     /* R98 */
-       0x0000,     /* R99 */
-       0x0000,     /* R100 */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x0000,     /* R104 */
-       0x0000,     /* R105 */
-       0x0000,     /* R106 */
-       0x0000,     /* R107 */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 */
-       0x0000,     /* R112 */
-       0x0000,     /* R113 */
-       0x0000,     /* R114 */
-       0x0000,     /* R115 */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x0000,     /* R128 */
-       0x0000,     /* R129 */
-       0x0000,     /* R130 */
-       0x0000,     /* R131 */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 */
-       0x0000,     /* R134 */
-       0x0000,     /* R135 */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0000,     /* R140 */
-       0x0000,     /* R141 */
-       0x0000,     /* R142 */
-       0x0000,     /* R143 */
-       0x0000,     /* R144 */
-       0x0000,     /* R145 */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x0000,     /* R152 */
-       0x0000,     /* R153 */
-       0x0000,     /* R154 */
-       0x0000,     /* R155 */
-       0x0000,     /* R156 */
-       0x0000,     /* R157 */
-       0x0000,     /* R158 */
-       0x0000,     /* R159 */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       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 */
-       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 */
-       0x0000,     /* R248 */
-       0x0000,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0000,     /* R252 */
-       0x0000,     /* R253 */
-       0x0000,     /* R254 */
-       0x0000,     /* R255 */
-       0x0003,     /* R256   - Chip Revision */
-       0x8004,     /* R257   - Control Interface */
-       0x0000,     /* R258 */
-       0x0000,     /* R259 */
-       0x0000,     /* R260 */
-       0x0000,     /* R261 */
-       0x0000,     /* R262 */
-       0x0000,     /* R263 */
-       0x0000,     /* R264 */
-       0x0000,     /* R265 */
-       0x0000,     /* R266 */
-       0x0000,     /* R267 */
-       0x0000,     /* R268 */
-       0x0000,     /* R269 */
-       0x0000,     /* R270 */
-       0x0000,     /* R271 */
-       0x0000,     /* R272   - Write Sequencer Ctrl (1) */
-       0x0000,     /* R273   - Write Sequencer Ctrl (2) */
-       0x0000,     /* R274 */
-       0x0000,     /* R275 */
-       0x0000,     /* R276 */
-       0x0000,     /* R277 */
-       0x0000,     /* R278 */
-       0x0000,     /* R279 */
-       0x0000,     /* R280 */
-       0x0000,     /* R281 */
-       0x0000,     /* R282 */
-       0x0000,     /* R283 */
-       0x0000,     /* R284 */
-       0x0000,     /* R285 */
-       0x0000,     /* R286 */
-       0x0000,     /* R287 */
-       0x0000,     /* R288 */
-       0x0000,     /* R289 */
-       0x0000,     /* R290 */
-       0x0000,     /* R291 */
-       0x0000,     /* R292 */
-       0x0000,     /* R293 */
-       0x0000,     /* R294 */
-       0x0000,     /* R295 */
-       0x0000,     /* R296 */
-       0x0000,     /* R297 */
-       0x0000,     /* R298 */
-       0x0000,     /* R299 */
-       0x0000,     /* R300 */
-       0x0000,     /* R301 */
-       0x0000,     /* R302 */
-       0x0000,     /* R303 */
-       0x0000,     /* R304 */
-       0x0000,     /* R305 */
-       0x0000,     /* R306 */
-       0x0000,     /* R307 */
-       0x0000,     /* R308 */
-       0x0000,     /* R309 */
-       0x0000,     /* R310 */
-       0x0000,     /* R311 */
-       0x0000,     /* R312 */
-       0x0000,     /* R313 */
-       0x0000,     /* R314 */
-       0x0000,     /* R315 */
-       0x0000,     /* R316 */
-       0x0000,     /* R317 */
-       0x0000,     /* R318 */
-       0x0000,     /* R319 */
-       0x0000,     /* R320 */
-       0x0000,     /* R321 */
-       0x0000,     /* R322 */
-       0x0000,     /* R323 */
-       0x0000,     /* R324 */
-       0x0000,     /* R325 */
-       0x0000,     /* R326 */
-       0x0000,     /* R327 */
-       0x0000,     /* R328 */
-       0x0000,     /* R329 */
-       0x0000,     /* R330 */
-       0x0000,     /* R331 */
-       0x0000,     /* R332 */
-       0x0000,     /* R333 */
-       0x0000,     /* R334 */
-       0x0000,     /* R335 */
-       0x0000,     /* R336 */
-       0x0000,     /* R337 */
-       0x0000,     /* R338 */
-       0x0000,     /* R339 */
-       0x0000,     /* R340 */
-       0x0000,     /* R341 */
-       0x0000,     /* R342 */
-       0x0000,     /* R343 */
-       0x0000,     /* R344 */
-       0x0000,     /* R345 */
-       0x0000,     /* R346 */
-       0x0000,     /* R347 */
-       0x0000,     /* R348 */
-       0x0000,     /* R349 */
-       0x0000,     /* R350 */
-       0x0000,     /* R351 */
-       0x0000,     /* R352 */
-       0x0000,     /* R353 */
-       0x0000,     /* R354 */
-       0x0000,     /* R355 */
-       0x0000,     /* R356 */
-       0x0000,     /* R357 */
-       0x0000,     /* R358 */
-       0x0000,     /* R359 */
-       0x0000,     /* R360 */
-       0x0000,     /* R361 */
-       0x0000,     /* R362 */
-       0x0000,     /* R363 */
-       0x0000,     /* R364 */
-       0x0000,     /* R365 */
-       0x0000,     /* R366 */
-       0x0000,     /* R367 */
-       0x0000,     /* R368 */
-       0x0000,     /* R369 */
-       0x0000,     /* R370 */
-       0x0000,     /* R371 */
-       0x0000,     /* R372 */
-       0x0000,     /* R373 */
-       0x0000,     /* R374 */
-       0x0000,     /* R375 */
-       0x0000,     /* R376 */
-       0x0000,     /* R377 */
-       0x0000,     /* R378 */
-       0x0000,     /* R379 */
-       0x0000,     /* R380 */
-       0x0000,     /* R381 */
-       0x0000,     /* R382 */
-       0x0000,     /* R383 */
-       0x0000,     /* R384 */
-       0x0000,     /* R385 */
-       0x0000,     /* R386 */
-       0x0000,     /* R387 */
-       0x0000,     /* R388 */
-       0x0000,     /* R389 */
-       0x0000,     /* R390 */
-       0x0000,     /* R391 */
-       0x0000,     /* R392 */
-       0x0000,     /* R393 */
-       0x0000,     /* R394 */
-       0x0000,     /* R395 */
-       0x0000,     /* R396 */
-       0x0000,     /* R397 */
-       0x0000,     /* R398 */
-       0x0000,     /* R399 */
-       0x0000,     /* R400 */
-       0x0000,     /* R401 */
-       0x0000,     /* R402 */
-       0x0000,     /* R403 */
-       0x0000,     /* R404 */
-       0x0000,     /* R405 */
-       0x0000,     /* R406 */
-       0x0000,     /* R407 */
-       0x0000,     /* R408 */
-       0x0000,     /* R409 */
-       0x0000,     /* R410 */
-       0x0000,     /* R411 */
-       0x0000,     /* R412 */
-       0x0000,     /* R413 */
-       0x0000,     /* R414 */
-       0x0000,     /* R415 */
-       0x0000,     /* R416 */
-       0x0000,     /* R417 */
-       0x0000,     /* R418 */
-       0x0000,     /* R419 */
-       0x0000,     /* R420 */
-       0x0000,     /* R421 */
-       0x0000,     /* R422 */
-       0x0000,     /* R423 */
-       0x0000,     /* R424 */
-       0x0000,     /* R425 */
-       0x0000,     /* R426 */
-       0x0000,     /* R427 */
-       0x0000,     /* R428 */
-       0x0000,     /* R429 */
-       0x0000,     /* R430 */
-       0x0000,     /* R431 */
-       0x0000,     /* R432 */
-       0x0000,     /* R433 */
-       0x0000,     /* R434 */
-       0x0000,     /* R435 */
-       0x0000,     /* R436 */
-       0x0000,     /* R437 */
-       0x0000,     /* R438 */
-       0x0000,     /* R439 */
-       0x0000,     /* R440 */
-       0x0000,     /* R441 */
-       0x0000,     /* R442 */
-       0x0000,     /* R443 */
-       0x0000,     /* R444 */
-       0x0000,     /* R445 */
-       0x0000,     /* R446 */
-       0x0000,     /* R447 */
-       0x0000,     /* R448 */
-       0x0000,     /* R449 */
-       0x0000,     /* R450 */
-       0x0000,     /* R451 */
-       0x0000,     /* R452 */
-       0x0000,     /* R453 */
-       0x0000,     /* R454 */
-       0x0000,     /* R455 */
-       0x0000,     /* R456 */
-       0x0000,     /* R457 */
-       0x0000,     /* R458 */
-       0x0000,     /* R459 */
-       0x0000,     /* R460 */
-       0x0000,     /* R461 */
-       0x0000,     /* R462 */
-       0x0000,     /* R463 */
-       0x0000,     /* R464 */
-       0x0000,     /* R465 */
-       0x0000,     /* R466 */
-       0x0000,     /* R467 */
-       0x0000,     /* R468 */
-       0x0000,     /* R469 */
-       0x0000,     /* R470 */
-       0x0000,     /* R471 */
-       0x0000,     /* R472 */
-       0x0000,     /* R473 */
-       0x0000,     /* R474 */
-       0x0000,     /* R475 */
-       0x0000,     /* R476 */
-       0x0000,     /* R477 */
-       0x0000,     /* R478 */
-       0x0000,     /* R479 */
-       0x0000,     /* R480 */
-       0x0000,     /* R481 */
-       0x0000,     /* R482 */
-       0x0000,     /* R483 */
-       0x0000,     /* R484 */
-       0x0000,     /* R485 */
-       0x0000,     /* R486 */
-       0x0000,     /* R487 */
-       0x0000,     /* R488 */
-       0x0000,     /* R489 */
-       0x0000,     /* R490 */
-       0x0000,     /* R491 */
-       0x0000,     /* R492 */
-       0x0000,     /* R493 */
-       0x0000,     /* R494 */
-       0x0000,     /* R495 */
-       0x0000,     /* R496 */
-       0x0000,     /* R497 */
-       0x0000,     /* R498 */
-       0x0000,     /* R499 */
-       0x0000,     /* R500 */
-       0x0000,     /* R501 */
-       0x0000,     /* R502 */
-       0x0000,     /* R503 */
-       0x0000,     /* R504 */
-       0x0000,     /* R505 */
-       0x0000,     /* R506 */
-       0x0000,     /* R507 */
-       0x0000,     /* R508 */
-       0x0000,     /* R509 */
-       0x0000,     /* R510 */
-       0x0000,     /* R511 */
-       0x0000,     /* R512   - AIF1 Clocking (1) */
-       0x0000,     /* R513   - AIF1 Clocking (2) */
-       0x0000,     /* R514 */
-       0x0000,     /* R515 */
-       0x0000,     /* R516   - AIF2 Clocking (1) */
-       0x0000,     /* R517   - AIF2 Clocking (2) */
-       0x0000,     /* R518 */
-       0x0000,     /* R519 */
-       0x0000,     /* R520   - Clocking (1) */
-       0x0000,     /* R521   - Clocking (2) */
-       0x0000,     /* R522 */
-       0x0000,     /* R523 */
-       0x0000,     /* R524 */
-       0x0000,     /* R525 */
-       0x0000,     /* R526 */
-       0x0000,     /* R527 */
-       0x0083,     /* R528   - AIF1 Rate */
-       0x0083,     /* R529   - AIF2 Rate */
-       0x0000,     /* R530   - Rate Status */
-       0x0000,     /* R531 */
-       0x0000,     /* R532 */
-       0x0000,     /* R533 */
-       0x0000,     /* R534 */
-       0x0000,     /* R535 */
-       0x0000,     /* R536 */
-       0x0000,     /* R537 */
-       0x0000,     /* R538 */
-       0x0000,     /* R539 */
-       0x0000,     /* R540 */
-       0x0000,     /* R541 */
-       0x0000,     /* R542 */
-       0x0000,     /* R543 */
-       0x0000,     /* R544   - FLL1 Control (1) */
-       0x0000,     /* R545   - FLL1 Control (2) */
-       0x0000,     /* R546   - FLL1 Control (3) */
-       0x0000,     /* R547   - FLL1 Control (4) */
-       0x0C80,     /* R548   - FLL1 Control (5) */
-       0x0000,     /* R549 */
-       0x0000,     /* R550 */
-       0x0000,     /* R551 */
-       0x0000,     /* R552 */
-       0x0000,     /* R553 */
-       0x0000,     /* R554 */
-       0x0000,     /* R555 */
-       0x0000,     /* R556 */
-       0x0000,     /* R557 */
-       0x0000,     /* R558 */
-       0x0000,     /* R559 */
-       0x0000,     /* R560 */
-       0x0000,     /* R561 */
-       0x0000,     /* R562 */
-       0x0000,     /* R563 */
-       0x0000,     /* R564 */
-       0x0000,     /* R565 */
-       0x0000,     /* R566 */
-       0x0000,     /* R567 */
-       0x0000,     /* R568 */
-       0x0000,     /* R569 */
-       0x0000,     /* R570 */
-       0x0000,     /* R571 */
-       0x0000,     /* R572 */
-       0x0000,     /* R573 */
-       0x0000,     /* R574 */
-       0x0000,     /* R575 */
-       0x0000,     /* R576   - FLL2 Control (1) */
-       0x0000,     /* R577   - FLL2 Control (2) */
-       0x0000,     /* R578   - FLL2 Control (3) */
-       0x0000,     /* R579   - FLL2 Control (4) */
-       0x0C80,     /* R580   - FLL2 Control (5) */
-       0x0000,     /* R581 */
-       0x0000,     /* R582 */
-       0x0000,     /* R583 */
-       0x0000,     /* R584 */
-       0x0000,     /* R585 */
-       0x0000,     /* R586 */
-       0x0000,     /* R587 */
-       0x0000,     /* R588 */
-       0x0000,     /* R589 */
-       0x0000,     /* R590 */
-       0x0000,     /* R591 */
-       0x0000,     /* R592 */
-       0x0000,     /* R593 */
-       0x0000,     /* R594 */
-       0x0000,     /* R595 */
-       0x0000,     /* R596 */
-       0x0000,     /* R597 */
-       0x0000,     /* R598 */
-       0x0000,     /* R599 */
-       0x0000,     /* R600 */
-       0x0000,     /* R601 */
-       0x0000,     /* R602 */
-       0x0000,     /* R603 */
-       0x0000,     /* R604 */
-       0x0000,     /* R605 */
-       0x0000,     /* R606 */
-       0x0000,     /* R607 */
-       0x0000,     /* R608 */
-       0x0000,     /* R609 */
-       0x0000,     /* R610 */
-       0x0000,     /* R611 */
-       0x0000,     /* R612 */
-       0x0000,     /* R613 */
-       0x0000,     /* R614 */
-       0x0000,     /* R615 */
-       0x0000,     /* R616 */
-       0x0000,     /* R617 */
-       0x0000,     /* R618 */
-       0x0000,     /* R619 */
-       0x0000,     /* R620 */
-       0x0000,     /* R621 */
-       0x0000,     /* R622 */
-       0x0000,     /* R623 */
-       0x0000,     /* R624 */
-       0x0000,     /* R625 */
-       0x0000,     /* R626 */
-       0x0000,     /* R627 */
-       0x0000,     /* R628 */
-       0x0000,     /* R629 */
-       0x0000,     /* R630 */
-       0x0000,     /* R631 */
-       0x0000,     /* R632 */
-       0x0000,     /* R633 */
-       0x0000,     /* R634 */
-       0x0000,     /* R635 */
-       0x0000,     /* R636 */
-       0x0000,     /* R637 */
-       0x0000,     /* R638 */
-       0x0000,     /* R639 */
-       0x0000,     /* R640 */
-       0x0000,     /* R641 */
-       0x0000,     /* R642 */
-       0x0000,     /* R643 */
-       0x0000,     /* R644 */
-       0x0000,     /* R645 */
-       0x0000,     /* R646 */
-       0x0000,     /* R647 */
-       0x0000,     /* R648 */
-       0x0000,     /* R649 */
-       0x0000,     /* R650 */
-       0x0000,     /* R651 */
-       0x0000,     /* R652 */
-       0x0000,     /* R653 */
-       0x0000,     /* R654 */
-       0x0000,     /* R655 */
-       0x0000,     /* R656 */
-       0x0000,     /* R657 */
-       0x0000,     /* R658 */
-       0x0000,     /* R659 */
-       0x0000,     /* R660 */
-       0x0000,     /* R661 */
-       0x0000,     /* R662 */
-       0x0000,     /* R663 */
-       0x0000,     /* R664 */
-       0x0000,     /* R665 */
-       0x0000,     /* R666 */
-       0x0000,     /* R667 */
-       0x0000,     /* R668 */
-       0x0000,     /* R669 */
-       0x0000,     /* R670 */
-       0x0000,     /* R671 */
-       0x0000,     /* R672 */
-       0x0000,     /* R673 */
-       0x0000,     /* R674 */
-       0x0000,     /* R675 */
-       0x0000,     /* R676 */
-       0x0000,     /* R677 */
-       0x0000,     /* R678 */
-       0x0000,     /* R679 */
-       0x0000,     /* R680 */
-       0x0000,     /* R681 */
-       0x0000,     /* R682 */
-       0x0000,     /* R683 */
-       0x0000,     /* R684 */
-       0x0000,     /* R685 */
-       0x0000,     /* R686 */
-       0x0000,     /* R687 */
-       0x0000,     /* R688 */
-       0x0000,     /* R689 */
-       0x0000,     /* R690 */
-       0x0000,     /* R691 */
-       0x0000,     /* R692 */
-       0x0000,     /* R693 */
-       0x0000,     /* R694 */
-       0x0000,     /* R695 */
-       0x0000,     /* R696 */
-       0x0000,     /* R697 */
-       0x0000,     /* R698 */
-       0x0000,     /* R699 */
-       0x0000,     /* R700 */
-       0x0000,     /* R701 */
-       0x0000,     /* R702 */
-       0x0000,     /* R703 */
-       0x0000,     /* R704 */
-       0x0000,     /* R705 */
-       0x0000,     /* R706 */
-       0x0000,     /* R707 */
-       0x0000,     /* R708 */
-       0x0000,     /* R709 */
-       0x0000,     /* R710 */
-       0x0000,     /* R711 */
-       0x0000,     /* R712 */
-       0x0000,     /* R713 */
-       0x0000,     /* R714 */
-       0x0000,     /* R715 */
-       0x0000,     /* R716 */
-       0x0000,     /* R717 */
-       0x0000,     /* R718 */
-       0x0000,     /* R719 */
-       0x0000,     /* R720 */
-       0x0000,     /* R721 */
-       0x0000,     /* R722 */
-       0x0000,     /* R723 */
-       0x0000,     /* R724 */
-       0x0000,     /* R725 */
-       0x0000,     /* R726 */
-       0x0000,     /* R727 */
-       0x0000,     /* R728 */
-       0x0000,     /* R729 */
-       0x0000,     /* R730 */
-       0x0000,     /* R731 */
-       0x0000,     /* R732 */
-       0x0000,     /* R733 */
-       0x0000,     /* R734 */
-       0x0000,     /* R735 */
-       0x0000,     /* R736 */
-       0x0000,     /* R737 */
-       0x0000,     /* R738 */
-       0x0000,     /* R739 */
-       0x0000,     /* R740 */
-       0x0000,     /* R741 */
-       0x0000,     /* R742 */
-       0x0000,     /* R743 */
-       0x0000,     /* R744 */
-       0x0000,     /* R745 */
-       0x0000,     /* R746 */
-       0x0000,     /* R747 */
-       0x0000,     /* R748 */
-       0x0000,     /* R749 */
-       0x0000,     /* R750 */
-       0x0000,     /* R751 */
-       0x0000,     /* R752 */
-       0x0000,     /* R753 */
-       0x0000,     /* R754 */
-       0x0000,     /* R755 */
-       0x0000,     /* R756 */
-       0x0000,     /* R757 */
-       0x0000,     /* R758 */
-       0x0000,     /* R759 */
-       0x0000,     /* R760 */
-       0x0000,     /* R761 */
-       0x0000,     /* R762 */
-       0x0000,     /* R763 */
-       0x0000,     /* R764 */
-       0x0000,     /* R765 */
-       0x0000,     /* R766 */
-       0x0000,     /* R767 */
-       0x4050,     /* R768   - AIF1 Control (1) */
-       0x4000,     /* R769   - AIF1 Control (2) */
-       0x0000,     /* R770   - AIF1 Master/Slave */
-       0x0040,     /* R771   - AIF1 BCLK */
-       0x0040,     /* R772   - AIF1ADC LRCLK */
-       0x0040,     /* R773   - AIF1DAC LRCLK */
-       0x0004,     /* R774   - AIF1DAC Data */
-       0x0100,     /* R775   - AIF1ADC Data */
-       0x0000,     /* R776 */
-       0x0000,     /* R777 */
-       0x0000,     /* R778 */
-       0x0000,     /* R779 */
-       0x0000,     /* R780 */
-       0x0000,     /* R781 */
-       0x0000,     /* R782 */
-       0x0000,     /* R783 */
-       0x4050,     /* R784   - AIF2 Control (1) */
-       0x4000,     /* R785   - AIF2 Control (2) */
-       0x0000,     /* R786   - AIF2 Master/Slave */
-       0x0040,     /* R787   - AIF2 BCLK */
-       0x0040,     /* R788   - AIF2ADC LRCLK */
-       0x0040,     /* R789   - AIF2DAC LRCLK */
-       0x0000,     /* R790   - AIF2DAC Data */
-       0x0000,     /* R791   - AIF2ADC Data */
-       0x0000,     /* R792 */
-       0x0000,     /* R793 */
-       0x0000,     /* R794 */
-       0x0000,     /* R795 */
-       0x0000,     /* R796 */
-       0x0000,     /* R797 */
-       0x0000,     /* R798 */
-       0x0000,     /* R799 */
-       0x0000,     /* R800 */
-       0x0000,     /* R801 */
-       0x0000,     /* R802 */
-       0x0000,     /* R803 */
-       0x0000,     /* R804 */
-       0x0000,     /* R805 */
-       0x0000,     /* R806 */
-       0x0000,     /* R807 */
-       0x0000,     /* R808 */
-       0x0000,     /* R809 */
-       0x0000,     /* R810 */
-       0x0000,     /* R811 */
-       0x0000,     /* R812 */
-       0x0000,     /* R813 */
-       0x0000,     /* R814 */
-       0x0000,     /* R815 */
-       0x0000,     /* R816 */
-       0x0000,     /* R817 */
-       0x0000,     /* R818 */
-       0x0000,     /* R819 */
-       0x0000,     /* R820 */
-       0x0000,     /* R821 */
-       0x0000,     /* R822 */
-       0x0000,     /* R823 */
-       0x0000,     /* R824 */
-       0x0000,     /* R825 */
-       0x0000,     /* R826 */
-       0x0000,     /* R827 */
-       0x0000,     /* R828 */
-       0x0000,     /* R829 */
-       0x0000,     /* R830 */
-       0x0000,     /* R831 */
-       0x0000,     /* R832 */
-       0x0000,     /* R833 */
-       0x0000,     /* R834 */
-       0x0000,     /* R835 */
-       0x0000,     /* R836 */
-       0x0000,     /* R837 */
-       0x0000,     /* R838 */
-       0x0000,     /* R839 */
-       0x0000,     /* R840 */
-       0x0000,     /* R841 */
-       0x0000,     /* R842 */
-       0x0000,     /* R843 */
-       0x0000,     /* R844 */
-       0x0000,     /* R845 */
-       0x0000,     /* R846 */
-       0x0000,     /* R847 */
-       0x0000,     /* R848 */
-       0x0000,     /* R849 */
-       0x0000,     /* R850 */
-       0x0000,     /* R851 */
-       0x0000,     /* R852 */
-       0x0000,     /* R853 */
-       0x0000,     /* R854 */
-       0x0000,     /* R855 */
-       0x0000,     /* R856 */
-       0x0000,     /* R857 */
-       0x0000,     /* R858 */
-       0x0000,     /* R859 */
-       0x0000,     /* R860 */
-       0x0000,     /* R861 */
-       0x0000,     /* R862 */
-       0x0000,     /* R863 */
-       0x0000,     /* R864 */
-       0x0000,     /* R865 */
-       0x0000,     /* R866 */
-       0x0000,     /* R867 */
-       0x0000,     /* R868 */
-       0x0000,     /* R869 */
-       0x0000,     /* R870 */
-       0x0000,     /* R871 */
-       0x0000,     /* R872 */
-       0x0000,     /* R873 */
-       0x0000,     /* R874 */
-       0x0000,     /* R875 */
-       0x0000,     /* R876 */
-       0x0000,     /* R877 */
-       0x0000,     /* R878 */
-       0x0000,     /* R879 */
-       0x0000,     /* R880 */
-       0x0000,     /* R881 */
-       0x0000,     /* R882 */
-       0x0000,     /* R883 */
-       0x0000,     /* R884 */
-       0x0000,     /* R885 */
-       0x0000,     /* R886 */
-       0x0000,     /* R887 */
-       0x0000,     /* R888 */
-       0x0000,     /* R889 */
-       0x0000,     /* R890 */
-       0x0000,     /* R891 */
-       0x0000,     /* R892 */
-       0x0000,     /* R893 */
-       0x0000,     /* R894 */
-       0x0000,     /* R895 */
-       0x0000,     /* R896 */
-       0x0000,     /* R897 */
-       0x0000,     /* R898 */
-       0x0000,     /* R899 */
-       0x0000,     /* R900 */
-       0x0000,     /* R901 */
-       0x0000,     /* R902 */
-       0x0000,     /* R903 */
-       0x0000,     /* R904 */
-       0x0000,     /* R905 */
-       0x0000,     /* R906 */
-       0x0000,     /* R907 */
-       0x0000,     /* R908 */
-       0x0000,     /* R909 */
-       0x0000,     /* R910 */
-       0x0000,     /* R911 */
-       0x0000,     /* R912 */
-       0x0000,     /* R913 */
-       0x0000,     /* R914 */
-       0x0000,     /* R915 */
-       0x0000,     /* R916 */
-       0x0000,     /* R917 */
-       0x0000,     /* R918 */
-       0x0000,     /* R919 */
-       0x0000,     /* R920 */
-       0x0000,     /* R921 */
-       0x0000,     /* R922 */
-       0x0000,     /* R923 */
-       0x0000,     /* R924 */
-       0x0000,     /* R925 */
-       0x0000,     /* R926 */
-       0x0000,     /* R927 */
-       0x0000,     /* R928 */
-       0x0000,     /* R929 */
-       0x0000,     /* R930 */
-       0x0000,     /* R931 */
-       0x0000,     /* R932 */
-       0x0000,     /* R933 */
-       0x0000,     /* R934 */
-       0x0000,     /* R935 */
-       0x0000,     /* R936 */
-       0x0000,     /* R937 */
-       0x0000,     /* R938 */
-       0x0000,     /* R939 */
-       0x0000,     /* R940 */
-       0x0000,     /* R941 */
-       0x0000,     /* R942 */
-       0x0000,     /* R943 */
-       0x0000,     /* R944 */
-       0x0000,     /* R945 */
-       0x0000,     /* R946 */
-       0x0000,     /* R947 */
-       0x0000,     /* R948 */
-       0x0000,     /* R949 */
-       0x0000,     /* R950 */
-       0x0000,     /* R951 */
-       0x0000,     /* R952 */
-       0x0000,     /* R953 */
-       0x0000,     /* R954 */
-       0x0000,     /* R955 */
-       0x0000,     /* R956 */
-       0x0000,     /* R957 */
-       0x0000,     /* R958 */
-       0x0000,     /* R959 */
-       0x0000,     /* R960 */
-       0x0000,     /* R961 */
-       0x0000,     /* R962 */
-       0x0000,     /* R963 */
-       0x0000,     /* R964 */
-       0x0000,     /* R965 */
-       0x0000,     /* R966 */
-       0x0000,     /* R967 */
-       0x0000,     /* R968 */
-       0x0000,     /* R969 */
-       0x0000,     /* R970 */
-       0x0000,     /* R971 */
-       0x0000,     /* R972 */
-       0x0000,     /* R973 */
-       0x0000,     /* R974 */
-       0x0000,     /* R975 */
-       0x0000,     /* R976 */
-       0x0000,     /* R977 */
-       0x0000,     /* R978 */
-       0x0000,     /* R979 */
-       0x0000,     /* R980 */
-       0x0000,     /* R981 */
-       0x0000,     /* R982 */
-       0x0000,     /* R983 */
-       0x0000,     /* R984 */
-       0x0000,     /* R985 */
-       0x0000,     /* R986 */
-       0x0000,     /* R987 */
-       0x0000,     /* R988 */
-       0x0000,     /* R989 */
-       0x0000,     /* R990 */
-       0x0000,     /* R991 */
-       0x0000,     /* R992 */
-       0x0000,     /* R993 */
-       0x0000,     /* R994 */
-       0x0000,     /* R995 */
-       0x0000,     /* R996 */
-       0x0000,     /* R997 */
-       0x0000,     /* R998 */
-       0x0000,     /* R999 */
-       0x0000,     /* R1000 */
-       0x0000,     /* R1001 */
-       0x0000,     /* R1002 */
-       0x0000,     /* R1003 */
-       0x0000,     /* R1004 */
-       0x0000,     /* R1005 */
-       0x0000,     /* R1006 */
-       0x0000,     /* R1007 */
-       0x0000,     /* R1008 */
-       0x0000,     /* R1009 */
-       0x0000,     /* R1010 */
-       0x0000,     /* R1011 */
-       0x0000,     /* R1012 */
-       0x0000,     /* R1013 */
-       0x0000,     /* R1014 */
-       0x0000,     /* R1015 */
-       0x0000,     /* R1016 */
-       0x0000,     /* R1017 */
-       0x0000,     /* R1018 */
-       0x0000,     /* R1019 */
-       0x0000,     /* R1020 */
-       0x0000,     /* R1021 */
-       0x0000,     /* R1022 */
-       0x0000,     /* R1023 */
-       0x00C0,     /* R1024  - AIF1 ADC1 Left Volume */
-       0x00C0,     /* R1025  - AIF1 ADC1 Right Volume */
-       0x00C0,     /* R1026  - AIF1 DAC1 Left Volume */
-       0x00C0,     /* R1027  - AIF1 DAC1 Right Volume */
-       0x00C0,     /* R1028  - AIF1 ADC2 Left Volume */
-       0x00C0,     /* R1029  - AIF1 ADC2 Right Volume */
-       0x00C0,     /* R1030  - AIF1 DAC2 Left Volume */
-       0x00C0,     /* R1031  - AIF1 DAC2 Right Volume */
-       0x0000,     /* R1032 */
-       0x0000,     /* R1033 */
-       0x0000,     /* R1034 */
-       0x0000,     /* R1035 */
-       0x0000,     /* R1036 */
-       0x0000,     /* R1037 */
-       0x0000,     /* R1038 */
-       0x0000,     /* R1039 */
-       0x0000,     /* R1040  - AIF1 ADC1 Filters */
-       0x0000,     /* R1041  - AIF1 ADC2 Filters */
-       0x0000,     /* R1042 */
-       0x0000,     /* R1043 */
-       0x0000,     /* R1044 */
-       0x0000,     /* R1045 */
-       0x0000,     /* R1046 */
-       0x0000,     /* R1047 */
-       0x0000,     /* R1048 */
-       0x0000,     /* R1049 */
-       0x0000,     /* R1050 */
-       0x0000,     /* R1051 */
-       0x0000,     /* R1052 */
-       0x0000,     /* R1053 */
-       0x0000,     /* R1054 */
-       0x0000,     /* R1055 */
-       0x0200,     /* R1056  - AIF1 DAC1 Filters (1) */
-       0x0010,     /* R1057  - AIF1 DAC1 Filters (2) */
-       0x0200,     /* R1058  - AIF1 DAC2 Filters (1) */
-       0x0010,     /* R1059  - AIF1 DAC2 Filters (2) */
-       0x0000,     /* R1060 */
-       0x0000,     /* R1061 */
-       0x0000,     /* R1062 */
-       0x0000,     /* R1063 */
-       0x0000,     /* R1064 */
-       0x0000,     /* R1065 */
-       0x0000,     /* R1066 */
-       0x0000,     /* R1067 */
-       0x0000,     /* R1068 */
-       0x0000,     /* R1069 */
-       0x0000,     /* R1070 */
-       0x0000,     /* R1071 */
-       0x0068,     /* R1072  - AIF1 DAC1 Noise Gate */
-       0x0068,     /* R1073  - AIF1 DAC2 Noise Gate */
-       0x0000,     /* R1074 */
-       0x0000,     /* R1075 */
-       0x0000,     /* R1076 */
-       0x0000,     /* R1077 */
-       0x0000,     /* R1078 */
-       0x0000,     /* R1079 */
-       0x0000,     /* R1080 */
-       0x0000,     /* R1081 */
-       0x0000,     /* R1082 */
-       0x0000,     /* R1083 */
-       0x0000,     /* R1084 */
-       0x0000,     /* R1085 */
-       0x0000,     /* R1086 */
-       0x0000,     /* R1087 */
-       0x0098,     /* R1088  - AIF1 DRC1 (1) */
-       0x0845,     /* R1089  - AIF1 DRC1 (2) */
-       0x0000,     /* R1090  - AIF1 DRC1 (3) */
-       0x0000,     /* R1091  - AIF1 DRC1 (4) */
-       0x0000,     /* R1092  - AIF1 DRC1 (5) */
-       0x0000,     /* R1093 */
-       0x0000,     /* R1094 */
-       0x0000,     /* R1095 */
-       0x0000,     /* R1096 */
-       0x0000,     /* R1097 */
-       0x0000,     /* R1098 */
-       0x0000,     /* R1099 */
-       0x0000,     /* R1100 */
-       0x0000,     /* R1101 */
-       0x0000,     /* R1102 */
-       0x0000,     /* R1103 */
-       0x0098,     /* R1104  - AIF1 DRC2 (1) */
-       0x0845,     /* R1105  - AIF1 DRC2 (2) */
-       0x0000,     /* R1106  - AIF1 DRC2 (3) */
-       0x0000,     /* R1107  - AIF1 DRC2 (4) */
-       0x0000,     /* R1108  - AIF1 DRC2 (5) */
-       0x0000,     /* R1109 */
-       0x0000,     /* R1110 */
-       0x0000,     /* R1111 */
-       0x0000,     /* R1112 */
-       0x0000,     /* R1113 */
-       0x0000,     /* R1114 */
-       0x0000,     /* R1115 */
-       0x0000,     /* R1116 */
-       0x0000,     /* R1117 */
-       0x0000,     /* R1118 */
-       0x0000,     /* R1119 */
-       0x0000,     /* R1120 */
-       0x0000,     /* R1121 */
-       0x0000,     /* R1122 */
-       0x0000,     /* R1123 */
-       0x0000,     /* R1124 */
-       0x0000,     /* R1125 */
-       0x0000,     /* R1126 */
-       0x0000,     /* R1127 */
-       0x0000,     /* R1128 */
-       0x0000,     /* R1129 */
-       0x0000,     /* R1130 */
-       0x0000,     /* R1131 */
-       0x0000,     /* R1132 */
-       0x0000,     /* R1133 */
-       0x0000,     /* R1134 */
-       0x0000,     /* R1135 */
-       0x0000,     /* R1136 */
-       0x0000,     /* R1137 */
-       0x0000,     /* R1138 */
-       0x0000,     /* R1139 */
-       0x0000,     /* R1140 */
-       0x0000,     /* R1141 */
-       0x0000,     /* R1142 */
-       0x0000,     /* R1143 */
-       0x0000,     /* R1144 */
-       0x0000,     /* R1145 */
-       0x0000,     /* R1146 */
-       0x0000,     /* R1147 */
-       0x0000,     /* R1148 */
-       0x0000,     /* R1149 */
-       0x0000,     /* R1150 */
-       0x0000,     /* R1151 */
-       0x6318,     /* R1152  - AIF1 DAC1 EQ Gains (1) */
-       0x6300,     /* R1153  - AIF1 DAC1 EQ Gains (2) */
-       0x0FCA,     /* R1154  - AIF1 DAC1 EQ Band 1 A */
-       0x0400,     /* R1155  - AIF1 DAC1 EQ Band 1 B */
-       0x00D8,     /* R1156  - AIF1 DAC1 EQ Band 1 PG */
-       0x1EB5,     /* R1157  - AIF1 DAC1 EQ Band 2 A */
-       0xF145,     /* R1158  - AIF1 DAC1 EQ Band 2 B */
-       0x0B75,     /* R1159  - AIF1 DAC1 EQ Band 2 C */
-       0x01C5,     /* R1160  - AIF1 DAC1 EQ Band 2 PG */
-       0x1C58,     /* R1161  - AIF1 DAC1 EQ Band 3 A */
-       0xF373,     /* R1162  - AIF1 DAC1 EQ Band 3 B */
-       0x0A54,     /* R1163  - AIF1 DAC1 EQ Band 3 C */
-       0x0558,     /* R1164  - AIF1 DAC1 EQ Band 3 PG */
-       0x168E,     /* R1165  - AIF1 DAC1 EQ Band 4 A */
-       0xF829,     /* R1166  - AIF1 DAC1 EQ Band 4 B */
-       0x07AD,     /* R1167  - AIF1 DAC1 EQ Band 4 C */
-       0x1103,     /* R1168  - AIF1 DAC1 EQ Band 4 PG */
-       0x0564,     /* R1169  - AIF1 DAC1 EQ Band 5 A */
-       0x0559,     /* R1170  - AIF1 DAC1 EQ Band 5 B */
-       0x4000,     /* R1171  - AIF1 DAC1 EQ Band 5 PG */
-       0x0000,     /* R1172 */
-       0x0000,     /* R1173 */
-       0x0000,     /* R1174 */
-       0x0000,     /* R1175 */
-       0x0000,     /* R1176 */
-       0x0000,     /* R1177 */
-       0x0000,     /* R1178 */
-       0x0000,     /* R1179 */
-       0x0000,     /* R1180 */
-       0x0000,     /* R1181 */
-       0x0000,     /* R1182 */
-       0x0000,     /* R1183 */
-       0x6318,     /* R1184  - AIF1 DAC2 EQ Gains (1) */
-       0x6300,     /* R1185  - AIF1 DAC2 EQ Gains (2) */
-       0x0FCA,     /* R1186  - AIF1 DAC2 EQ Band 1 A */
-       0x0400,     /* R1187  - AIF1 DAC2 EQ Band 1 B */
-       0x00D8,     /* R1188  - AIF1 DAC2 EQ Band 1 PG */
-       0x1EB5,     /* R1189  - AIF1 DAC2 EQ Band 2 A */
-       0xF145,     /* R1190  - AIF1 DAC2 EQ Band 2 B */
-       0x0B75,     /* R1191  - AIF1 DAC2 EQ Band 2 C */
-       0x01C5,     /* R1192  - AIF1 DAC2 EQ Band 2 PG */
-       0x1C58,     /* R1193  - AIF1 DAC2 EQ Band 3 A */
-       0xF373,     /* R1194  - AIF1 DAC2 EQ Band 3 B */
-       0x0A54,     /* R1195  - AIF1 DAC2 EQ Band 3 C */
-       0x0558,     /* R1196  - AIF1 DAC2 EQ Band 3 PG */
-       0x168E,     /* R1197  - AIF1 DAC2 EQ Band 4 A */
-       0xF829,     /* R1198  - AIF1 DAC2 EQ Band 4 B */
-       0x07AD,     /* R1199  - AIF1 DAC2 EQ Band 4 C */
-       0x1103,     /* R1200  - AIF1 DAC2 EQ Band 4 PG */
-       0x0564,     /* R1201  - AIF1 DAC2 EQ Band 5 A */
-       0x0559,     /* R1202  - AIF1 DAC2 EQ Band 5 B */
-       0x4000,     /* R1203  - AIF1 DAC2 EQ Band 5 PG */
-       0x0000,     /* R1204 */
-       0x0000,     /* R1205 */
-       0x0000,     /* R1206 */
-       0x0000,     /* R1207 */
-       0x0000,     /* R1208 */
-       0x0000,     /* R1209 */
-       0x0000,     /* R1210 */
-       0x0000,     /* R1211 */
-       0x0000,     /* R1212 */
-       0x0000,     /* R1213 */
-       0x0000,     /* R1214 */
-       0x0000,     /* R1215 */
-       0x0000,     /* R1216 */
-       0x0000,     /* R1217 */
-       0x0000,     /* R1218 */
-       0x0000,     /* R1219 */
-       0x0000,     /* R1220 */
-       0x0000,     /* R1221 */
-       0x0000,     /* R1222 */
-       0x0000,     /* R1223 */
-       0x0000,     /* R1224 */
-       0x0000,     /* R1225 */
-       0x0000,     /* R1226 */
-       0x0000,     /* R1227 */
-       0x0000,     /* R1228 */
-       0x0000,     /* R1229 */
-       0x0000,     /* R1230 */
-       0x0000,     /* R1231 */
-       0x0000,     /* R1232 */
-       0x0000,     /* R1233 */
-       0x0000,     /* R1234 */
-       0x0000,     /* R1235 */
-       0x0000,     /* R1236 */
-       0x0000,     /* R1237 */
-       0x0000,     /* R1238 */
-       0x0000,     /* R1239 */
-       0x0000,     /* R1240 */
-       0x0000,     /* R1241 */
-       0x0000,     /* R1242 */
-       0x0000,     /* R1243 */
-       0x0000,     /* R1244 */
-       0x0000,     /* R1245 */
-       0x0000,     /* R1246 */
-       0x0000,     /* R1247 */
-       0x0000,     /* R1248 */
-       0x0000,     /* R1249 */
-       0x0000,     /* R1250 */
-       0x0000,     /* R1251 */
-       0x0000,     /* R1252 */
-       0x0000,     /* R1253 */
-       0x0000,     /* R1254 */
-       0x0000,     /* R1255 */
-       0x0000,     /* R1256 */
-       0x0000,     /* R1257 */
-       0x0000,     /* R1258 */
-       0x0000,     /* R1259 */
-       0x0000,     /* R1260 */
-       0x0000,     /* R1261 */
-       0x0000,     /* R1262 */
-       0x0000,     /* R1263 */
-       0x0000,     /* R1264 */
-       0x0000,     /* R1265 */
-       0x0000,     /* R1266 */
-       0x0000,     /* R1267 */
-       0x0000,     /* R1268 */
-       0x0000,     /* R1269 */
-       0x0000,     /* R1270 */
-       0x0000,     /* R1271 */
-       0x0000,     /* R1272 */
-       0x0000,     /* R1273 */
-       0x0000,     /* R1274 */
-       0x0000,     /* R1275 */
-       0x0000,     /* R1276 */
-       0x0000,     /* R1277 */
-       0x0000,     /* R1278 */
-       0x0000,     /* R1279 */
-       0x00C0,     /* R1280  - AIF2 ADC Left Volume */
-       0x00C0,     /* R1281  - AIF2 ADC Right Volume */
-       0x00C0,     /* R1282  - AIF2 DAC Left Volume */
-       0x00C0,     /* R1283  - AIF2 DAC Right Volume */
-       0x0000,     /* R1284 */
-       0x0000,     /* R1285 */
-       0x0000,     /* R1286 */
-       0x0000,     /* R1287 */
-       0x0000,     /* R1288 */
-       0x0000,     /* R1289 */
-       0x0000,     /* R1290 */
-       0x0000,     /* R1291 */
-       0x0000,     /* R1292 */
-       0x0000,     /* R1293 */
-       0x0000,     /* R1294 */
-       0x0000,     /* R1295 */
-       0x0000,     /* R1296  - AIF2 ADC Filters */
-       0x0000,     /* R1297 */
-       0x0000,     /* R1298 */
-       0x0000,     /* R1299 */
-       0x0000,     /* R1300 */
-       0x0000,     /* R1301 */
-       0x0000,     /* R1302 */
-       0x0000,     /* R1303 */
-       0x0000,     /* R1304 */
-       0x0000,     /* R1305 */
-       0x0000,     /* R1306 */
-       0x0000,     /* R1307 */
-       0x0000,     /* R1308 */
-       0x0000,     /* R1309 */
-       0x0000,     /* R1310 */
-       0x0000,     /* R1311 */
-       0x0200,     /* R1312  - AIF2 DAC Filters (1) */
-       0x0010,     /* R1313  - AIF2 DAC Filters (2) */
-       0x0000,     /* R1314 */
-       0x0000,     /* R1315 */
-       0x0000,     /* R1316 */
-       0x0000,     /* R1317 */
-       0x0000,     /* R1318 */
-       0x0000,     /* R1319 */
-       0x0000,     /* R1320 */
-       0x0000,     /* R1321 */
-       0x0000,     /* R1322 */
-       0x0000,     /* R1323 */
-       0x0000,     /* R1324 */
-       0x0000,     /* R1325 */
-       0x0000,     /* R1326 */
-       0x0000,     /* R1327 */
-       0x0068,     /* R1328  - AIF2 DAC Noise Gate */
-       0x0000,     /* R1329 */
-       0x0000,     /* R1330 */
-       0x0000,     /* R1331 */
-       0x0000,     /* R1332 */
-       0x0000,     /* R1333 */
-       0x0000,     /* R1334 */
-       0x0000,     /* R1335 */
-       0x0000,     /* R1336 */
-       0x0000,     /* R1337 */
-       0x0000,     /* R1338 */
-       0x0000,     /* R1339 */
-       0x0000,     /* R1340 */
-       0x0000,     /* R1341 */
-       0x0000,     /* R1342 */
-       0x0000,     /* R1343 */
-       0x0098,     /* R1344  - AIF2 DRC (1) */
-       0x0845,     /* R1345  - AIF2 DRC (2) */
-       0x0000,     /* R1346  - AIF2 DRC (3) */
-       0x0000,     /* R1347  - AIF2 DRC (4) */
-       0x0000,     /* R1348  - AIF2 DRC (5) */
-       0x0000,     /* R1349 */
-       0x0000,     /* R1350 */
-       0x0000,     /* R1351 */
-       0x0000,     /* R1352 */
-       0x0000,     /* R1353 */
-       0x0000,     /* R1354 */
-       0x0000,     /* R1355 */
-       0x0000,     /* R1356 */
-       0x0000,     /* R1357 */
-       0x0000,     /* R1358 */
-       0x0000,     /* R1359 */
-       0x0000,     /* R1360 */
-       0x0000,     /* R1361 */
-       0x0000,     /* R1362 */
-       0x0000,     /* R1363 */
-       0x0000,     /* R1364 */
-       0x0000,     /* R1365 */
-       0x0000,     /* R1366 */
-       0x0000,     /* R1367 */
-       0x0000,     /* R1368 */
-       0x0000,     /* R1369 */
-       0x0000,     /* R1370 */
-       0x0000,     /* R1371 */
-       0x0000,     /* R1372 */
-       0x0000,     /* R1373 */
-       0x0000,     /* R1374 */
-       0x0000,     /* R1375 */
-       0x0000,     /* R1376 */
-       0x0000,     /* R1377 */
-       0x0000,     /* R1378 */
-       0x0000,     /* R1379 */
-       0x0000,     /* R1380 */
-       0x0000,     /* R1381 */
-       0x0000,     /* R1382 */
-       0x0000,     /* R1383 */
-       0x0000,     /* R1384 */
-       0x0000,     /* R1385 */
-       0x0000,     /* R1386 */
-       0x0000,     /* R1387 */
-       0x0000,     /* R1388 */
-       0x0000,     /* R1389 */
-       0x0000,     /* R1390 */
-       0x0000,     /* R1391 */
-       0x0000,     /* R1392 */
-       0x0000,     /* R1393 */
-       0x0000,     /* R1394 */
-       0x0000,     /* R1395 */
-       0x0000,     /* R1396 */
-       0x0000,     /* R1397 */
-       0x0000,     /* R1398 */
-       0x0000,     /* R1399 */
-       0x0000,     /* R1400 */
-       0x0000,     /* R1401 */
-       0x0000,     /* R1402 */
-       0x0000,     /* R1403 */
-       0x0000,     /* R1404 */
-       0x0000,     /* R1405 */
-       0x0000,     /* R1406 */
-       0x0000,     /* R1407 */
-       0x6318,     /* R1408  - AIF2 EQ Gains (1) */
-       0x6300,     /* R1409  - AIF2 EQ Gains (2) */
-       0x0FCA,     /* R1410  - AIF2 EQ Band 1 A */
-       0x0400,     /* R1411  - AIF2 EQ Band 1 B */
-       0x00D8,     /* R1412  - AIF2 EQ Band 1 PG */
-       0x1EB5,     /* R1413  - AIF2 EQ Band 2 A */
-       0xF145,     /* R1414  - AIF2 EQ Band 2 B */
-       0x0B75,     /* R1415  - AIF2 EQ Band 2 C */
-       0x01C5,     /* R1416  - AIF2 EQ Band 2 PG */
-       0x1C58,     /* R1417  - AIF2 EQ Band 3 A */
-       0xF373,     /* R1418  - AIF2 EQ Band 3 B */
-       0x0A54,     /* R1419  - AIF2 EQ Band 3 C */
-       0x0558,     /* R1420  - AIF2 EQ Band 3 PG */
-       0x168E,     /* R1421  - AIF2 EQ Band 4 A */
-       0xF829,     /* R1422  - AIF2 EQ Band 4 B */
-       0x07AD,     /* R1423  - AIF2 EQ Band 4 C */
-       0x1103,     /* R1424  - AIF2 EQ Band 4 PG */
-       0x0564,     /* R1425  - AIF2 EQ Band 5 A */
-       0x0559,     /* R1426  - AIF2 EQ Band 5 B */
-       0x4000,     /* R1427  - AIF2 EQ Band 5 PG */
-       0x0000,     /* R1428 */
-       0x0000,     /* R1429 */
-       0x0000,     /* R1430 */
-       0x0000,     /* R1431 */
-       0x0000,     /* R1432 */
-       0x0000,     /* R1433 */
-       0x0000,     /* R1434 */
-       0x0000,     /* R1435 */
-       0x0000,     /* R1436 */
-       0x0000,     /* R1437 */
-       0x0000,     /* R1438 */
-       0x0000,     /* R1439 */
-       0x0000,     /* R1440 */
-       0x0000,     /* R1441 */
-       0x0000,     /* R1442 */
-       0x0000,     /* R1443 */
-       0x0000,     /* R1444 */
-       0x0000,     /* R1445 */
-       0x0000,     /* R1446 */
-       0x0000,     /* R1447 */
-       0x0000,     /* R1448 */
-       0x0000,     /* R1449 */
-       0x0000,     /* R1450 */
-       0x0000,     /* R1451 */
-       0x0000,     /* R1452 */
-       0x0000,     /* R1453 */
-       0x0000,     /* R1454 */
-       0x0000,     /* R1455 */
-       0x0000,     /* R1456 */
-       0x0000,     /* R1457 */
-       0x0000,     /* R1458 */
-       0x0000,     /* R1459 */
-       0x0000,     /* R1460 */
-       0x0000,     /* R1461 */
-       0x0000,     /* R1462 */
-       0x0000,     /* R1463 */
-       0x0000,     /* R1464 */
-       0x0000,     /* R1465 */
-       0x0000,     /* R1466 */
-       0x0000,     /* R1467 */
-       0x0000,     /* R1468 */
-       0x0000,     /* R1469 */
-       0x0000,     /* R1470 */
-       0x0000,     /* R1471 */
-       0x0000,     /* R1472 */
-       0x0000,     /* R1473 */
-       0x0000,     /* R1474 */
-       0x0000,     /* R1475 */
-       0x0000,     /* R1476 */
-       0x0000,     /* R1477 */
-       0x0000,     /* R1478 */
-       0x0000,     /* R1479 */
-       0x0000,     /* R1480 */
-       0x0000,     /* R1481 */
-       0x0000,     /* R1482 */
-       0x0000,     /* R1483 */
-       0x0000,     /* R1484 */
-       0x0000,     /* R1485 */
-       0x0000,     /* R1486 */
-       0x0000,     /* R1487 */
-       0x0000,     /* R1488 */
-       0x0000,     /* R1489 */
-       0x0000,     /* R1490 */
-       0x0000,     /* R1491 */
-       0x0000,     /* R1492 */
-       0x0000,     /* R1493 */
-       0x0000,     /* R1494 */
-       0x0000,     /* R1495 */
-       0x0000,     /* R1496 */
-       0x0000,     /* R1497 */
-       0x0000,     /* R1498 */
-       0x0000,     /* R1499 */
-       0x0000,     /* R1500 */
-       0x0000,     /* R1501 */
-       0x0000,     /* R1502 */
-       0x0000,     /* R1503 */
-       0x0000,     /* R1504 */
-       0x0000,     /* R1505 */
-       0x0000,     /* R1506 */
-       0x0000,     /* R1507 */
-       0x0000,     /* R1508 */
-       0x0000,     /* R1509 */
-       0x0000,     /* R1510 */
-       0x0000,     /* R1511 */
-       0x0000,     /* R1512 */
-       0x0000,     /* R1513 */
-       0x0000,     /* R1514 */
-       0x0000,     /* R1515 */
-       0x0000,     /* R1516 */
-       0x0000,     /* R1517 */
-       0x0000,     /* R1518 */
-       0x0000,     /* R1519 */
-       0x0000,     /* R1520 */
-       0x0000,     /* R1521 */
-       0x0000,     /* R1522 */
-       0x0000,     /* R1523 */
-       0x0000,     /* R1524 */
-       0x0000,     /* R1525 */
-       0x0000,     /* R1526 */
-       0x0000,     /* R1527 */
-       0x0000,     /* R1528 */
-       0x0000,     /* R1529 */
-       0x0000,     /* R1530 */
-       0x0000,     /* R1531 */
-       0x0000,     /* R1532 */
-       0x0000,     /* R1533 */
-       0x0000,     /* R1534 */
-       0x0000,     /* R1535 */
-       0x0000,     /* R1536  - DAC1 Mixer Volumes */
-       0x0000,     /* R1537  - DAC1 Left Mixer Routing */
-       0x0000,     /* R1538  - DAC1 Right Mixer Routing */
-       0x0000,     /* R1539  - DAC2 Mixer Volumes */
-       0x0000,     /* R1540  - DAC2 Left Mixer Routing */
-       0x0000,     /* R1541  - DAC2 Right Mixer Routing */
-       0x0000,     /* R1542  - AIF1 ADC1 Left Mixer Routing */
-       0x0000,     /* R1543  - AIF1 ADC1 Right Mixer Routing */
-       0x0000,     /* R1544  - AIF1 ADC2 Left Mixer Routing */
-       0x0000,     /* R1545  - AIF1 ADC2 Right mixer Routing */
-       0x0000,     /* R1546 */
-       0x0000,     /* R1547 */
-       0x0000,     /* R1548 */
-       0x0000,     /* R1549 */
-       0x0000,     /* R1550 */
-       0x0000,     /* R1551 */
-       0x02C0,     /* R1552  - DAC1 Left Volume */
-       0x02C0,     /* R1553  - DAC1 Right Volume */
-       0x02C0,     /* R1554  - DAC2 Left Volume */
-       0x02C0,     /* R1555  - DAC2 Right Volume */
-       0x0000,     /* R1556  - DAC Softmute */
-       0x0000,     /* R1557 */
-       0x0000,     /* R1558 */
-       0x0000,     /* R1559 */
-       0x0000,     /* R1560 */
-       0x0000,     /* R1561 */
-       0x0000,     /* R1562 */
-       0x0000,     /* R1563 */
-       0x0000,     /* R1564 */
-       0x0000,     /* R1565 */
-       0x0000,     /* R1566 */
-       0x0000,     /* R1567 */
-       0x0002,     /* R1568  - Oversampling */
-       0x0000,     /* R1569  - Sidetone */
-};
index d0c545b73d7865c04b9fefd286b85b7fe63fc5b2..93d27b6602571c3f600f9272defe0b05f12a8c3b 100644 (file)
 #include "wm8994.h"
 #include "wm_hubs.h"
 
+#define WM1811_JACKDET_MODE_NONE  0x0000
+#define WM1811_JACKDET_MODE_JACK  0x0100
+#define WM1811_JACKDET_MODE_MIC   0x0080
+#define WM1811_JACKDET_MODE_AUDIO 0x0180
+
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
@@ -53,103 +58,69 @@ static int wm8994_retune_mobile_base[] = {
        WM8994_AIF2_EQ_GAINS_1,
 };
 
-static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
-{
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
-
-       switch (reg) {
-       case WM8994_GPIO_1:
-       case WM8994_GPIO_2:
-       case WM8994_GPIO_3:
-       case WM8994_GPIO_4:
-       case WM8994_GPIO_5:
-       case WM8994_GPIO_6:
-       case WM8994_GPIO_7:
-       case WM8994_GPIO_8:
-       case WM8994_GPIO_9:
-       case WM8994_GPIO_10:
-       case WM8994_GPIO_11:
-       case WM8994_INTERRUPT_STATUS_1:
-       case WM8994_INTERRUPT_STATUS_2:
-       case WM8994_INTERRUPT_RAW_STATUS_2:
-               return 1;
-
-       case WM8958_DSP2_PROGRAM:
-       case WM8958_DSP2_CONFIG:
-       case WM8958_DSP2_EXECCONTROL:
-               if (control->type == WM8958)
-                       return 1;
-               else
-                       return 0;
+static void wm8958_default_micdet(u16 status, void *data);
 
-       default:
-               break;
-       }
+static const struct wm8958_micd_rate micdet_rates[] = {
+       { 32768,       true,  1, 4 },
+       { 32768,       false, 1, 1 },
+       { 44100 * 256, true,  7, 10 },
+       { 44100 * 256, false, 7, 10 },
+};
 
-       if (reg >= WM8994_CACHE_SIZE)
-               return 0;
-       return wm8994_access_masks[reg].readable != 0;
-}
+static const struct wm8958_micd_rate jackdet_rates[] = {
+       { 32768,       true,  0, 1 },
+       { 32768,       false, 0, 1 },
+       { 44100 * 256, true,  7, 10 },
+       { 44100 * 256, false, 7, 10 },
+};
 
-static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
 {
-       if (reg >= WM8994_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:
-       case WM8958_DSP2_EXECCONTROL:
-       case WM8958_MIC_DETECT_3:
-       case WM8994_DC_SERVO_4E:
-               return 1;
-       default:
-               return 0;
-       }
-}
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       int best, i, sysclk, val;
+       bool idle;
+       const struct wm8958_micd_rate *rates;
+       int num_rates;
 
-static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
-       unsigned int value)
-{
-       int ret;
+       if (wm8994->jack_cb != wm8958_default_micdet)
+               return;
 
-       BUG_ON(reg > WM8994_MAX_REGISTER);
+       idle = !wm8994->jack_mic;
 
-       if (!wm8994_volatile(codec, reg)) {
-               ret = snd_soc_cache_write(codec, reg, value);
-               if (ret != 0)
-                       dev_err(codec->dev, "Cache write to %x failed: %d\n",
-                               reg, ret);
+       sysclk = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (sysclk & WM8994_SYSCLK_SRC)
+               sysclk = wm8994->aifclk[1];
+       else
+               sysclk = wm8994->aifclk[0];
+
+       if (wm8994->pdata && wm8994->pdata->micd_rates) {
+               rates = wm8994->pdata->micd_rates;
+               num_rates = wm8994->pdata->num_micd_rates;
+       } else if (wm8994->jackdet) {
+               rates = jackdet_rates;
+               num_rates = ARRAY_SIZE(jackdet_rates);
+       } else {
+               rates = micdet_rates;
+               num_rates = ARRAY_SIZE(micdet_rates);
        }
 
-       return wm8994_reg_write(codec->control_data, reg, value);
-}
-
-static unsigned int wm8994_read(struct snd_soc_codec *codec,
-                               unsigned int reg)
-{
-       unsigned int val;
-       int ret;
-
-       BUG_ON(reg > WM8994_MAX_REGISTER);
-
-       if (!wm8994_volatile(codec, reg) && wm8994_readable(codec, reg) &&
-           reg < codec->driver->reg_cache_size) {
-               ret = snd_soc_cache_read(codec, reg, &val);
-               if (ret >= 0)
-                       return val;
-               else
-                       dev_err(codec->dev, "Cache read from %x failed: %d\n",
-                               reg, ret);
+       best = 0;
+       for (i = 0; i < num_rates; i++) {
+               if (rates[i].idle != idle)
+                       continue;
+               if (abs(rates[i].sysclk - sysclk) <
+                   abs(rates[best].sysclk - sysclk))
+                       best = i;
+               else if (rates[best].idle != idle)
+                       best = i;
        }
 
-       return wm8994_reg_read(codec->control_data, reg);
+       val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
+               | rates[best].rate << WM8958_MICD_RATE_SHIFT;
+
+       snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                           WM8958_MICD_BIAS_STARTTIME_MASK |
+                           WM8958_MICD_RATE_MASK, val);
 }
 
 static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
@@ -221,8 +192,10 @@ static int configure_clock(struct snd_soc_codec *codec)
         */
 
        /* If they're equal it doesn't matter which is used */
-       if (wm8994->aifclk[0] == wm8994->aifclk[1])
+       if (wm8994->aifclk[0] == wm8994->aifclk[1]) {
+               wm8958_micd_set_rate(codec);
                return 0;
+       }
 
        if (wm8994->aifclk[0] < wm8994->aifclk[1])
                new = WM8994_SYSCLK_SRC;
@@ -231,10 +204,10 @@ static int configure_clock(struct snd_soc_codec *codec)
 
        change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
                                     WM8994_SYSCLK_SRC, new);
-       if (!change)
-               return 0;
+       if (change)
+               snd_soc_dapm_sync(&codec->dapm);
 
-       snd_soc_dapm_sync(&codec->dapm);
+       wm8958_micd_set_rate(codec);
 
        return 0;
 }
@@ -708,6 +681,74 @@ SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
               mixin_boost_tlv),
 };
 
+/* We run all mode setting through a function to enforce audio mode */
+static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8994->active_refcount)
+               mode = WM1811_JACKDET_MODE_AUDIO;
+
+       snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                           WM1811_JACKDET_MODE_MASK, mode);
+
+       if (mode == WM1811_JACKDET_MODE_MIC)
+               msleep(2);
+}
+
+static void active_reference(struct snd_soc_codec *codec)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       wm8994->active_refcount++;
+
+       dev_dbg(codec->dev, "Active refcount incremented, now %d\n",
+               wm8994->active_refcount);
+
+       if (wm8994->active_refcount == 1) {
+               /* If we're using jack detection go into audio mode */
+               if (wm8994->jackdet && wm8994->jack_cb) {
+                       snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                           WM1811_JACKDET_MODE_MASK,
+                                           WM1811_JACKDET_MODE_AUDIO);
+                       msleep(2);
+               }
+       }
+
+       mutex_unlock(&wm8994->accdet_lock);
+}
+
+static void active_dereference(struct snd_soc_codec *codec)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       u16 mode;
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       wm8994->active_refcount--;
+
+       dev_dbg(codec->dev, "Active refcount decremented, now %d\n",
+               wm8994->active_refcount);
+
+       if (wm8994->active_refcount == 0) {
+               /* Go into appropriate detection only mode */
+               if (wm8994->jackdet && wm8994->jack_cb) {
+                       if (wm8994->jack_mic || wm8994->mic_detecting)
+                               mode = WM1811_JACKDET_MODE_MIC;
+                       else
+                               mode = WM1811_JACKDET_MODE_JACK;
+
+                       snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                           WM1811_JACKDET_MODE_MASK,
+                                           mode);
+               }
+       }
+
+       mutex_unlock(&wm8994->accdet_lock);
+}
+
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
@@ -1768,7 +1809,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                          unsigned int freq_in, unsigned int freq_out)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
        int reg_offset, ret;
        struct fll_div fll;
        u16 reg, aif1, aif2;
@@ -1865,6 +1906,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        if (freq_out) {
                /* Enable VMID if we need it */
                if (!was_enabled) {
+                       active_reference(codec);
+
                        switch (control->type) {
                        case WM8994:
                                vmid_reference(codec);
@@ -1908,6 +1951,8 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                        default:
                                break;
                        }
+
+                       active_dereference(codec);
                }
        }
 
@@ -2017,20 +2062,33 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       struct wm8994 *control = codec->control_data;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->wm8994;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
+               /* MICBIAS into regulating mode */
+               switch (control->type) {
+               case WM8958:
+               case WM1811:
+                       snd_soc_update_bits(codec, WM8958_MICBIAS1,
+                                           WM8958_MICB1_MODE, 0);
+                       snd_soc_update_bits(codec, WM8958_MICBIAS2,
+                                           WM8958_MICB2_MODE, 0);
+                       break;
+               default:
+                       break;
+               }
+
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+                       active_reference(codec);
                break;
 
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       pm_runtime_get_sync(codec->dev);
-
                        switch (control->type) {
                        case WM8994:
                                if (wm8994->revision < 4) {
@@ -2077,25 +2135,40 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                            WM8994_LINEOUT2_DISCH);
                }
 
+               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+                       active_dereference(codec);
 
+               /* MICBIAS into bypass mode on newer devices */
+               switch (control->type) {
+               case WM8958:
+               case WM1811:
+                       snd_soc_update_bits(codec, WM8958_MICBIAS1,
+                                           WM8958_MICB1_MODE,
+                                           WM8958_MICB1_MODE);
+                       snd_soc_update_bits(codec, WM8958_MICBIAS2,
+                                           WM8958_MICB2_MODE,
+                                           WM8958_MICB2_MODE);
+                       break;
+               default:
+                       break;
+               }
                break;
 
        case SND_SOC_BIAS_OFF:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
                        wm8994->cur_fw = NULL;
-
-                       pm_runtime_put(codec->dev);
-               }
                break;
        }
        codec->dapm.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;
-       struct wm8994 *control = codec->control_data;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->wm8994;
        int ms_reg;
        int aif1_reg;
        int ms = 0;
@@ -2395,7 +2468,8 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       struct wm8994 *control = codec->control_data;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->wm8994;
        int aif1_reg;
        int aif1 = 0;
 
@@ -2536,7 +2610,7 @@ static int wm8994_aif2_probe(struct snd_soc_dai *dai)
 #define WM8994_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 wm8994_aif1_dai_ops = {
+static const 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,
@@ -2546,7 +2620,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_tristate   = wm8994_set_tristate,
 };
 
-static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
+static const 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,
@@ -2556,7 +2630,7 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
        .set_tristate   = wm8994_set_tristate,
 };
 
-static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
+static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
        .hw_params      = wm8994_aif3_hw_params,
        .set_tristate   = wm8994_set_tristate,
 };
@@ -2623,10 +2697,10 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
 };
 
 #ifdef CONFIG_PM
-static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8994_suspend(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
        int i, ret;
 
        switch (control->type) {
@@ -2634,6 +2708,9 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
                snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
                break;
        case WM1811:
+               snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                   WM1811_JACKDET_MODE_MASK, 0);
+               /* Fall through */
        case WM8958:
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                                    WM8958_MICD_ENA, 0);
@@ -2657,14 +2734,14 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
        int i, ret;
        unsigned int val, mask;
 
        if (wm8994->revision < 4) {
                /* force a HW read */
-               val = wm8994_reg_read(codec->control_data,
-                                     WM8994_POWER_MANAGEMENT_5);
+               ret = regmap_read(control->regmap,
+                                 WM8994_POWER_MANAGEMENT_5, &val);
 
                /* modify the cache only */
                codec->cache_only = 1;
@@ -2703,6 +2780,13 @@ static int wm8994_resume(struct snd_soc_codec *codec)
                                            WM8994_MICD_ENA, WM8994_MICD_ENA);
                break;
        case WM1811:
+               if (wm8994->jackdet && wm8994->jack_cb) {
+                       /* Restart from idle */
+                       snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
+                                           WM1811_JACKDET_MODE_MASK,
+                                           WM1811_JACKDET_MODE_JACK);
+                       break;
+               }
        case WM8958:
                if (wm8994->jack_cb)
                        snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
@@ -2815,8 +2899,8 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                };
 
                /* We need an array of texts for the enum API */
-               wm8994->drc_texts = kmalloc(sizeof(char *)
-                                           * pdata->num_drc_cfgs, GFP_KERNEL);
+               wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev,
+                           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",
@@ -2879,7 +2963,7 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_micdet *micdet;
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
        int reg;
 
        if (control->type != WM8994)
@@ -2962,21 +3046,136 @@ static void wm8958_default_micdet(u16 status, void *data)
 {
        struct snd_soc_codec *codec = data;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       int report = 0;
+       int report;
+
+       dev_dbg(codec->dev, "MICDET %x\n", status);
+
+       /* Either nothing present or just starting detection */
+       if (!(status & WM8958_MICD_STS)) {
+               if (!wm8994->jackdet) {
+                       /* If nothing present then clear our statuses */
+                       dev_dbg(codec->dev, "Detected open circuit\n");
+                       wm8994->jack_mic = false;
+                       wm8994->mic_detecting = true;
+
+                       wm8958_micd_set_rate(codec);
+
+                       snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+                                           wm8994->btn_mask |
+                                            SND_JACK_HEADSET);
+               }
+               return;
+       }
+
+       /* If the measurement is showing a high impedence we've got a
+        * microphone.
+        */
+       if (wm8994->mic_detecting && (status & 0x600)) {
+               dev_dbg(codec->dev, "Detected microphone\n");
+
+               wm8994->mic_detecting = false;
+               wm8994->jack_mic = true;
+
+               wm8958_micd_set_rate(codec);
+
+               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADSET,
+                                   SND_JACK_HEADSET);
+       }
+
+
+       if (wm8994->mic_detecting && status & 0x4) {
+               dev_dbg(codec->dev, "Detected headphone\n");
+               wm8994->mic_detecting = false;
+
+               wm8958_micd_set_rate(codec);
+
+               snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+                                   SND_JACK_HEADSET);
+
+               /* If we have jackdet that will detect removal */
+               if (wm8994->jackdet) {
+                       snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                           WM8958_MICD_ENA, 0);
+
+                       wm1811_jackdet_set_mode(codec,
+                                               WM1811_JACKDET_MODE_JACK);
+               }
+       }
+
+       /* Report short circuit as a button */
+       if (wm8994->jack_mic) {
+               report = 0;
+               if (status & 0x4)
+                       report |= SND_JACK_BTN_0;
+
+               if (status & 0x8)
+                       report |= SND_JACK_BTN_1;
+
+               if (status & 0x10)
+                       report |= SND_JACK_BTN_2;
+
+               if (status & 0x20)
+                       report |= SND_JACK_BTN_3;
+
+               if (status & 0x40)
+                       report |= SND_JACK_BTN_4;
+
+               if (status & 0x80)
+                       report |= SND_JACK_BTN_5;
+
+               snd_soc_jack_report(wm8994->micdet[0].jack, report,
+                                   wm8994->btn_mask);
+       }
+}
+
+static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
+{
+       struct wm8994_priv *wm8994 = data;
+       struct snd_soc_codec *codec = wm8994->codec;
+       int reg;
+
+       mutex_lock(&wm8994->accdet_lock);
+
+       reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
+       if (reg < 0) {
+               dev_err(codec->dev, "Failed to read jack status: %d\n", reg);
+               mutex_unlock(&wm8994->accdet_lock);
+               return IRQ_NONE;
+       }
+
+       dev_dbg(codec->dev, "JACKDET %x\n", reg);
 
-       /* If nothing present then clear our statuses */
-       if (!(status & WM8958_MICD_STS))
-               goto done;
+       if (reg & WM1811_JACKDET_LVL) {
+               dev_dbg(codec->dev, "Jack detected\n");
 
-       report = SND_JACK_MICROPHONE;
+               snd_soc_jack_report(wm8994->micdet[0].jack,
+                                   SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+
+               /*
+                * Start off measument of microphone impedence to find
+                * out what's actually there.
+                */
+               wm8994->mic_detecting = true;
+               wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_MIC);
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                   WM8958_MICD_ENA, WM8958_MICD_ENA);
+       } else {
+               dev_dbg(codec->dev, "Jack not detected\n");
 
-       /* Everything else is buttons; just assign slots */
-       if (status & 0x1c)
-               report |= SND_JACK_BTN_0;
+               snd_soc_jack_report(wm8994->micdet[0].jack, 0,
+                                   SND_JACK_MECHANICAL | SND_JACK_HEADSET |
+                                   wm8994->btn_mask);
 
-done:
-       snd_soc_jack_report(wm8994->micdet[0].jack, report,
-                           SND_JACK_BTN_0 | SND_JACK_MICROPHONE);
+               wm8994->mic_detecting = false;
+               wm8994->jack_mic = false;
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                   WM8958_MICD_ENA, 0);
+               wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
+       }
+
+       mutex_unlock(&wm8994->accdet_lock);
+
+       return IRQ_HANDLED;
 }
 
 /**
@@ -2999,7 +3198,8 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      wm8958_micdet_cb cb, void *cb_data)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
+       u16 micd_lvl_sel;
 
        switch (control->type) {
        case WM1811:
@@ -3016,15 +3216,50 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                        cb_data = codec;
                }
 
+               snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
+
                wm8994->micdet[0].jack = jack;
                wm8994->jack_cb = cb;
                wm8994->jack_cb_data = cb_data;
 
-               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
-                                   WM8958_MICD_ENA, WM8958_MICD_ENA);
+               wm8994->mic_detecting = true;
+               wm8994->jack_mic = false;
+
+               wm8958_micd_set_rate(codec);
+
+               /* Detect microphones and short circuits by default */
+               if (wm8994->pdata->micd_lvl_sel)
+                       micd_lvl_sel = wm8994->pdata->micd_lvl_sel;
+               else
+                       micd_lvl_sel = 0x41;
+
+               wm8994->btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                       SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                       SND_JACK_BTN_4 | SND_JACK_BTN_5;
+
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
+                                   WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
+
+               WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
+
+               /*
+                * If we can use jack detection start off with that,
+                * otherwise jump straight to microphone detection.
+                */
+               if (wm8994->jackdet) {
+                       snd_soc_update_bits(codec, WM8994_LDO_1,
+                                           WM8994_LDO1_DISCH, 0);
+                       wm1811_jackdet_set_mode(codec,
+                                               WM1811_JACKDET_MODE_JACK);
+               } else {
+                       snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                           WM8958_MICD_ENA, WM8958_MICD_ENA);
+               }
+
        } else {
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                                    WM8958_MICD_ENA, 0);
+               snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
        }
 
        return 0;
@@ -3037,6 +3272,18 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        struct snd_soc_codec *codec = wm8994->codec;
        int reg, count;
 
+       mutex_lock(&wm8994->accdet_lock);
+
+       /*
+        * Jack detection may have detected a removal simulataneously
+        * with an update of the MICDET status; if so it will have
+        * stopped detection and we can ignore this interrupt.
+        */
+       if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) {
+               mutex_unlock(&wm8994->accdet_lock);
+               return IRQ_HANDLED;
+       }
+
        /* We may occasionally read a detection without an impedence
         * range being provided - if that happens loop again.
         */
@@ -3044,6 +3291,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        do {
                reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
                if (reg < 0) {
+                       mutex_unlock(&wm8994->accdet_lock);
                        dev_err(codec->dev,
                                "Failed to read mic detect status: %d\n",
                                reg);
@@ -3074,6 +3322,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                dev_warn(codec->dev, "Accessory detection with no callback\n");
 
 out:
+       mutex_unlock(&wm8994->accdet_lock);
+
        return IRQ_HANDLED;
 }
 
@@ -3106,22 +3356,28 @@ static irqreturn_t wm8994_temp_shut(int irq, void *data)
 
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
-       struct wm8994 *control;
+       struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
        struct wm8994_priv *wm8994;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
+       unsigned int reg;
        int ret, i;
 
-       codec->control_data = dev_get_drvdata(codec->dev->parent);
-       control = codec->control_data;
+       codec->control_data = control->regmap;
 
-       wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
+       wm8994 = devm_kzalloc(codec->dev, sizeof(struct wm8994_priv),
+                             GFP_KERNEL);
        if (wm8994 == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm8994);
 
+       snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
+
+       wm8994->wm8994 = dev_get_drvdata(codec->dev->parent);
        wm8994->pdata = dev_get_platdata(codec->dev->parent);
        wm8994->codec = codec;
 
+       mutex_init(&wm8994->accdet_lock);
+
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
 
@@ -3134,25 +3390,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        pm_runtime_enable(codec->dev);
        pm_runtime_resume(codec->dev);
 
-       /* Read our current status back from the chip - we don't want to
-        * reset as this may interfere with the GPIO or LDO operation. */
-       for (i = 0; i < WM8994_CACHE_SIZE; i++) {
-               if (!wm8994_readable(codec, i) || wm8994_volatile(codec, i))
-                       continue;
-
-               ret = wm8994_reg_read(codec->control_data, i);
-               if (ret <= 0)
-                       continue;
-
-               ret = snd_soc_cache_write(codec, i, ret);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to initialise cache for 0x%x: %d\n",
-                               i, ret);
-                       goto err;
-               }
-       }
-
        /* Set revision-specific configuration */
        wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
        switch (control->type) {
@@ -3200,14 +3437,14 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
-       wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
+       wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR,
                           wm8994_fifo_error, "FIFO error", codec);
-       wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_WARN,
+       wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN,
                           wm8994_temp_warn, "Thermal warning", codec);
-       wm8994_request_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT,
+       wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
                           wm8994_temp_shut, "Thermal shutdown", codec);
 
-       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+       ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
                                 wm_hubs_dcs_done, "DC servo done",
                                 &wm8994->hubs);
        if (ret == 0)
@@ -3227,7 +3464,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                         ret);
                }
 
-               ret = wm8994_request_irq(codec->control_data,
+               ret = wm8994_request_irq(wm8994->wm8994,
                                         WM8994_IRQ_MIC1_SHRT,
                                         wm8994_mic_irq, "Mic 1 short",
                                         wm8994);
@@ -3236,7 +3473,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                 "Failed to request Mic1 short IRQ: %d\n",
                                 ret);
 
-               ret = wm8994_request_irq(codec->control_data,
+               ret = wm8994_request_irq(wm8994->wm8994,
                                         WM8994_IRQ_MIC2_DET,
                                         wm8994_mic_irq, "Mic 2 detect",
                                         wm8994);
@@ -3245,7 +3482,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                 "Failed to request Mic2 detect IRQ: %d\n",
                                 ret);
 
-               ret = wm8994_request_irq(codec->control_data,
+               ret = wm8994_request_irq(wm8994->wm8994,
                                         WM8994_IRQ_MIC2_SHRT,
                                         wm8994_mic_irq, "Mic 2 short",
                                         wm8994);
@@ -3270,9 +3507,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
        }
 
+       switch (control->type) {
+       case WM1811:
+               if (wm8994->revision > 1) {
+                       ret = wm8994_request_irq(wm8994->wm8994,
+                                                WM8994_IRQ_GPIO(6),
+                                                wm1811_jackdet_irq, "JACKDET",
+                                                wm8994);
+                       if (ret == 0)
+                               wm8994->jackdet = true;
+               }
+               break;
+       default:
+               break;
+       }
+
        wm8994->fll_locked_irq = true;
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
-               ret = wm8994_request_irq(codec->control_data,
+               ret = wm8994_request_irq(wm8994->wm8994,
                                         WM8994_IRQ_FLL1_LOCK + i,
                                         wm8994_fll_locked_irq, "FLL lock",
                                         &wm8994->fll_locked[i]);
@@ -3284,24 +3536,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
         * 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);
+       ret = regmap_read(control->regmap, WM8994_GPIO_1, &reg);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret);
                goto err_irq;
        }
-       if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+       if ((reg & 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);
+       ret = regmap_read(control->regmap, WM8994_GPIO_6, &reg);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret);
                goto err_irq;
        }
-       if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
+       if ((reg & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
                wm8994->lrclk_shared[1] = 1;
                wm8994_dai[1].symmetric_rates = 1;
        } else {
@@ -3368,6 +3620,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        }
 
+       /* Put MICBIAS into bypass mode by default on newer devices */
+       switch (control->type) {
+       case WM8958:
+       case WM1811:
+               snd_soc_update_bits(codec, WM8958_MICBIAS1,
+                                   WM8958_MICB1_MODE, WM8958_MICB1_MODE);
+               snd_soc_update_bits(codec, WM8958_MICBIAS2,
+                                   WM8958_MICB2_MODE, WM8958_MICB2_MODE);
+               break;
+       default:
+               break;
+       }
+
        wm8994_update_class_w(codec);
 
        wm8994_handle_pdata(wm8994);
@@ -3479,28 +3744,29 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        return 0;
 
 err_irq:
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
+       if (wm8994->jackdet)
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_SHRT, wm8994);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET, wm8994);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT, wm8994);
        if (wm8994->micdet_irq)
                free_irq(wm8994->micdet_irq, wm8994);
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
-               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
                                &wm8994->fll_locked[i]);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
                        &wm8994->hubs);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec);
-err:
-       kfree(wm8994);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, codec);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec);
+
        return ret;
 }
 
 static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct wm8994 *control = codec->control_data;
+       struct wm8994 *control = wm8994->wm8994;
        int i;
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -3508,24 +3774,27 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
        pm_runtime_disable(codec->dev);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
-               wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
                                &wm8994->fll_locked[i]);
 
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
                        &wm8994->hubs);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_SHUT, codec);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_TEMP_WARN, codec);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, codec);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, codec);
+       wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, codec);
+
+       if (wm8994->jackdet)
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_GPIO(6), wm8994);
 
        switch (control->type) {
        case WM8994:
                if (wm8994->micdet_irq)
                        free_irq(wm8994->micdet_irq, wm8994);
-               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC2_DET,
                                wm8994);
-               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_SHRT,
                                wm8994);
-               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
+               wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
                                wm8994);
                break;
 
@@ -3542,27 +3811,24 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
        if (wm8994->enh_eq)
                release_firmware(wm8994->enh_eq);
        kfree(wm8994->retune_mobile_texts);
-       kfree(wm8994->drc_texts);
-       kfree(wm8994);
 
        return 0;
 }
 
+static int wm8994_soc_volatile(struct snd_soc_codec *codec,
+                              unsigned int reg)
+{
+       return true;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
        .probe =        wm8994_codec_probe,
        .remove =       wm8994_codec_remove,
        .suspend =      wm8994_suspend,
        .resume =       wm8994_resume,
-       .read =         wm8994_read,
-       .write =        wm8994_write,
-       .readable_register = wm8994_readable,
-       .volatile_register = wm8994_volatile,
        .set_bias_level = wm8994_set_bias_level,
-
-       .reg_cache_size = WM8994_CACHE_SIZE,
-       .reg_cache_default = wm8994_reg_defaults,
-       .reg_word_size = 2,
-       .compress_type = SND_SOC_RBTREE_COMPRESSION,
+       .reg_cache_size = WM8994_MAX_REGISTER,
+       .volatile_register = wm8994_soc_volatile,
 };
 
 static int __devinit wm8994_probe(struct platform_device *pdev)
@@ -3586,18 +3852,7 @@ static struct platform_driver wm8994_codec_driver = {
        .remove = __devexit_p(wm8994_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_platform_driver(wm8994_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM8994 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index f4f1355efc82ec9708e24993525d65aad9b54e1b..c3a42474ab19a6656fdd8549c3068559318b1a05 100644 (file)
@@ -39,16 +39,6 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      wm8958_micdet_cb cb, void *cb_data);
 
-#define WM8994_CACHE_SIZE 1570
-
-struct wm8994_access_mask {
-       unsigned short readable;   /* Mask of readable bits */
-       unsigned short writable;   /* Mask of writable bits */
-};
-
-extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
-extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
-
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event);
 
@@ -70,10 +60,11 @@ struct wm8994_fll_config {
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 
+struct wm8994;
+
 struct wm8994_priv {
        struct wm_hubs_data hubs;
-       enum snd_soc_control_type control_type;
-       void *control_data;
+       struct wm8994 *wm8994;
        struct snd_soc_codec *codec;
        int sysclk[2];
        int sysclk_rate[2];
@@ -84,6 +75,7 @@ struct wm8994_priv {
        bool fll_locked_irq;
 
        int vmid_refcount;
+       int active_refcount;
 
        int dac_rates[2];
        int lrclk_shared[2];
@@ -125,7 +117,12 @@ struct wm8994_priv {
        const char **enh_eq_texts;
        struct soc_enum enh_eq_enum;
 
+       struct mutex accdet_lock;
        struct wm8994_micdet micdet[2];
+       bool mic_detecting;
+       bool jack_mic;
+       int btn_mask;
+       bool jackdet;
 
        wm8958_micdet_cb jack_cb;
        void *jack_cb_data;
index 78eeb21e66964be9f2457083cf4217b5ac0d5fbd..c8aada597d7049cfc756cf887a886bd9f30cd54b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
@@ -43,88 +44,331 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
        "MICVDD"
 };
 
-static const u16 wm8995_reg_defs[WM8995_MAX_REGISTER + 1] = {
-       [0]     = 0x8995, [5]     = 0x0100, [16]    = 0x000b, [17]    = 0x000b,
-       [24]    = 0x02c0, [25]    = 0x02c0, [26]    = 0x02c0, [27]    = 0x02c0,
-       [28]    = 0x000f, [32]    = 0x0005, [33]    = 0x0005, [40]    = 0x0003,
-       [41]    = 0x0013, [48]    = 0x0004, [56]    = 0x09f8, [64]    = 0x1f25,
-       [69]    = 0x0004, [82]    = 0xaaaa, [84]    = 0x2a2a, [146]   = 0x0060,
-       [256]   = 0x0002, [257]   = 0x8004, [520]   = 0x0010, [528]   = 0x0083,
-       [529]   = 0x0083, [548]   = 0x0c80, [580]   = 0x0c80, [768]   = 0x4050,
-       [769]   = 0x4000, [771]   = 0x0040, [772]   = 0x0040, [773]   = 0x0040,
-       [774]   = 0x0004, [775]   = 0x0100, [784]   = 0x4050, [785]   = 0x4000,
-       [787]   = 0x0040, [788]   = 0x0040, [789]   = 0x0040, [1024]  = 0x00c0,
-       [1025]  = 0x00c0, [1026]  = 0x00c0, [1027]  = 0x00c0, [1028]  = 0x00c0,
-       [1029]  = 0x00c0, [1030]  = 0x00c0, [1031]  = 0x00c0, [1056]  = 0x0200,
-       [1057]  = 0x0010, [1058]  = 0x0200, [1059]  = 0x0010, [1088]  = 0x0098,
-       [1089]  = 0x0845, [1104]  = 0x0098, [1105]  = 0x0845, [1152]  = 0x6318,
-       [1153]  = 0x6300, [1154]  = 0x0fca, [1155]  = 0x0400, [1156]  = 0x00d8,
-       [1157]  = 0x1eb5, [1158]  = 0xf145, [1159]  = 0x0b75, [1160]  = 0x01c5,
-       [1161]  = 0x1c58, [1162]  = 0xf373, [1163]  = 0x0a54, [1164]  = 0x0558,
-       [1165]  = 0x168e, [1166]  = 0xf829, [1167]  = 0x07ad, [1168]  = 0x1103,
-       [1169]  = 0x0564, [1170]  = 0x0559, [1171]  = 0x4000, [1184]  = 0x6318,
-       [1185]  = 0x6300, [1186]  = 0x0fca, [1187]  = 0x0400, [1188]  = 0x00d8,
-       [1189]  = 0x1eb5, [1190]  = 0xf145, [1191]  = 0x0b75, [1192]  = 0x01c5,
-       [1193]  = 0x1c58, [1194]  = 0xf373, [1195]  = 0x0a54, [1196]  = 0x0558,
-       [1197]  = 0x168e, [1198]  = 0xf829, [1199]  = 0x07ad, [1200]  = 0x1103,
-       [1201]  = 0x0564, [1202]  = 0x0559, [1203]  = 0x4000, [1280]  = 0x00c0,
-       [1281]  = 0x00c0, [1282]  = 0x00c0, [1283]  = 0x00c0, [1312]  = 0x0200,
-       [1313]  = 0x0010, [1344]  = 0x0098, [1345]  = 0x0845, [1408]  = 0x6318,
-       [1409]  = 0x6300, [1410]  = 0x0fca, [1411]  = 0x0400, [1412]  = 0x00d8,
-       [1413]  = 0x1eb5, [1414]  = 0xf145, [1415]  = 0x0b75, [1416]  = 0x01c5,
-       [1417]  = 0x1c58, [1418]  = 0xf373, [1419]  = 0x0a54, [1420]  = 0x0558,
-       [1421]  = 0x168e, [1422]  = 0xf829, [1423]  = 0x07ad, [1424]  = 0x1103,
-       [1425]  = 0x0564, [1426]  = 0x0559, [1427]  = 0x4000, [1568]  = 0x0002,
-       [1792]  = 0xa100, [1793]  = 0xa101, [1794]  = 0xa101, [1795]  = 0xa101,
-       [1796]  = 0xa101, [1797]  = 0xa101, [1798]  = 0xa101, [1799]  = 0xa101,
-       [1800]  = 0xa101, [1801]  = 0xa101, [1802]  = 0xa101, [1803]  = 0xa101,
-       [1804]  = 0xa101, [1805]  = 0xa101, [1825]  = 0x0055, [1848]  = 0x3fff,
-       [1849]  = 0x1fff, [2049]  = 0x0001, [2050]  = 0x0069, [2056]  = 0x0002,
-       [2057]  = 0x0003, [2058]  = 0x0069, [12288] = 0x0001, [12289] = 0x0001,
-       [12291] = 0x0006, [12292] = 0x0040, [12293] = 0x0001, [12294] = 0x000f,
-       [12295] = 0x0006, [12296] = 0x0001, [12297] = 0x0003, [12298] = 0x0104,
-       [12300] = 0x0060, [12301] = 0x0011, [12302] = 0x0401, [12304] = 0x0050,
-       [12305] = 0x0003, [12306] = 0x0100, [12308] = 0x0051, [12309] = 0x0003,
-       [12310] = 0x0104, [12311] = 0x000a, [12312] = 0x0060, [12313] = 0x003b,
-       [12314] = 0x0502, [12315] = 0x0100, [12316] = 0x2fff, [12320] = 0x2fff,
-       [12324] = 0x2fff, [12328] = 0x2fff, [12332] = 0x2fff, [12336] = 0x2fff,
-       [12340] = 0x2fff, [12344] = 0x2fff, [12348] = 0x2fff, [12352] = 0x0001,
-       [12353] = 0x0001, [12355] = 0x0006, [12356] = 0x0040, [12357] = 0x0001,
-       [12358] = 0x000f, [12359] = 0x0006, [12360] = 0x0001, [12361] = 0x0003,
-       [12362] = 0x0104, [12364] = 0x0060, [12365] = 0x0011, [12366] = 0x0401,
-       [12368] = 0x0050, [12369] = 0x0003, [12370] = 0x0100, [12372] = 0x0060,
-       [12373] = 0x003b, [12374] = 0x0502, [12375] = 0x0100, [12376] = 0x2fff,
-       [12380] = 0x2fff, [12384] = 0x2fff, [12388] = 0x2fff, [12392] = 0x2fff,
-       [12396] = 0x2fff, [12400] = 0x2fff, [12404] = 0x2fff, [12408] = 0x2fff,
-       [12412] = 0x2fff, [12416] = 0x0001, [12417] = 0x0001, [12419] = 0x0006,
-       [12420] = 0x0040, [12421] = 0x0001, [12422] = 0x000f, [12423] = 0x0006,
-       [12424] = 0x0001, [12425] = 0x0003, [12426] = 0x0106, [12428] = 0x0061,
-       [12429] = 0x0011, [12430] = 0x0401, [12432] = 0x0050, [12433] = 0x0003,
-       [12434] = 0x0102, [12436] = 0x0051, [12437] = 0x0003, [12438] = 0x0106,
-       [12439] = 0x000a, [12440] = 0x0061, [12441] = 0x003b, [12442] = 0x0502,
-       [12443] = 0x0100, [12444] = 0x2fff, [12448] = 0x2fff, [12452] = 0x2fff,
-       [12456] = 0x2fff, [12460] = 0x2fff, [12464] = 0x2fff, [12468] = 0x2fff,
-       [12472] = 0x2fff, [12476] = 0x2fff, [12480] = 0x0001, [12481] = 0x0001,
-       [12483] = 0x0006, [12484] = 0x0040, [12485] = 0x0001, [12486] = 0x000f,
-       [12487] = 0x0006, [12488] = 0x0001, [12489] = 0x0003, [12490] = 0x0106,
-       [12492] = 0x0061, [12493] = 0x0011, [12494] = 0x0401, [12496] = 0x0050,
-       [12497] = 0x0003, [12498] = 0x0102, [12500] = 0x0061, [12501] = 0x003b,
-       [12502] = 0x0502, [12503] = 0x0100, [12504] = 0x2fff, [12508] = 0x2fff,
-       [12512] = 0x2fff, [12516] = 0x2fff, [12520] = 0x2fff, [12524] = 0x2fff,
-       [12528] = 0x2fff, [12532] = 0x2fff, [12536] = 0x2fff, [12540] = 0x2fff,
-       [12544] = 0x0060, [12546] = 0x0601, [12548] = 0x0050, [12550] = 0x0100,
-       [12552] = 0x0001, [12554] = 0x0104, [12555] = 0x0100, [12556] = 0x2fff,
-       [12560] = 0x2fff, [12564] = 0x2fff, [12568] = 0x2fff, [12572] = 0x2fff,
-       [12576] = 0x2fff, [12580] = 0x2fff, [12584] = 0x2fff, [12588] = 0x2fff,
-       [12592] = 0x2fff, [12596] = 0x2fff, [12600] = 0x2fff, [12604] = 0x2fff,
-       [12608] = 0x0061, [12610] = 0x0601, [12612] = 0x0050, [12614] = 0x0102,
-       [12616] = 0x0001, [12618] = 0x0106, [12619] = 0x0100, [12620] = 0x2fff,
-       [12624] = 0x2fff, [12628] = 0x2fff, [12632] = 0x2fff, [12636] = 0x2fff,
-       [12640] = 0x2fff, [12644] = 0x2fff, [12648] = 0x2fff, [12652] = 0x2fff,
-       [12656] = 0x2fff, [12660] = 0x2fff, [12664] = 0x2fff, [12668] = 0x2fff,
-       [12672] = 0x0060, [12674] = 0x0601, [12676] = 0x0061, [12678] = 0x0601,
-       [12680] = 0x0050, [12682] = 0x0300, [12684] = 0x0001, [12686] = 0x0304,
-       [12688] = 0x0040, [12690] = 0x000f, [12692] = 0x0001, [12695] = 0x0100
+static struct reg_default wm8995_reg_defaults[] = {
+       { 0, 0x8995 },
+       { 5, 0x0100 },
+       { 16, 0x000b },
+       { 17, 0x000b },
+       { 24, 0x02c0 },
+       { 25, 0x02c0 },
+       { 26, 0x02c0 },
+       { 27, 0x02c0 },
+       { 28, 0x000f },
+       { 32, 0x0005 },
+       { 33, 0x0005 },
+       { 40, 0x0003 },
+       { 41, 0x0013 },
+       { 48, 0x0004 },
+       { 56, 0x09f8 },
+       { 64, 0x1f25 },
+       { 69, 0x0004 },
+       { 82, 0xaaaa },
+       { 84, 0x2a2a },
+       { 146, 0x0060 },
+       { 256, 0x0002 },
+       { 257, 0x8004 },
+       { 520, 0x0010 },
+       { 528, 0x0083 },
+       { 529, 0x0083 },
+       { 548, 0x0c80 },
+       { 580, 0x0c80 },
+       { 768, 0x4050 },
+       { 769, 0x4000 },
+       { 771, 0x0040 },
+       { 772, 0x0040 },
+       { 773, 0x0040 },
+       { 774, 0x0004 },
+       { 775, 0x0100 },
+       { 784, 0x4050 },
+       { 785, 0x4000 },
+       { 787, 0x0040 },
+       { 788, 0x0040 },
+       { 789, 0x0040 },
+       { 1024, 0x00c0 },
+       { 1025, 0x00c0 },
+       { 1026, 0x00c0 },
+       { 1027, 0x00c0 },
+       { 1028, 0x00c0 },
+       { 1029, 0x00c0 },
+       { 1030, 0x00c0 },
+       { 1031, 0x00c0 },
+       { 1056, 0x0200 },
+       { 1057, 0x0010 },
+       { 1058, 0x0200 },
+       { 1059, 0x0010 },
+       { 1088, 0x0098 },
+       { 1089, 0x0845 },
+       { 1104, 0x0098 },
+       { 1105, 0x0845 },
+       { 1152, 0x6318 },
+       { 1153, 0x6300 },
+       { 1154, 0x0fca },
+       { 1155, 0x0400 },
+       { 1156, 0x00d8 },
+       { 1157, 0x1eb5 },
+       { 1158, 0xf145 },
+       { 1159, 0x0b75 },
+       { 1160, 0x01c5 },
+       { 1161, 0x1c58 },
+       { 1162, 0xf373 },
+       { 1163, 0x0a54 },
+       { 1164, 0x0558 },
+       { 1165, 0x168e },
+       { 1166, 0xf829 },
+       { 1167, 0x07ad },
+       { 1168, 0x1103 },
+       { 1169, 0x0564 },
+       { 1170, 0x0559 },
+       { 1171, 0x4000 },
+       { 1184, 0x6318 },
+       { 1185, 0x6300 },
+       { 1186, 0x0fca },
+       { 1187, 0x0400 },
+       { 1188, 0x00d8 },
+       { 1189, 0x1eb5 },
+       { 1190, 0xf145 },
+       { 1191, 0x0b75 },
+       { 1192, 0x01c5 },
+       { 1193, 0x1c58 },
+       { 1194, 0xf373 },
+       { 1195, 0x0a54 },
+       { 1196, 0x0558 },
+       { 1197, 0x168e },
+       { 1198, 0xf829 },
+       { 1199, 0x07ad },
+       { 1200, 0x1103 },
+       { 1201, 0x0564 },
+       { 1202, 0x0559 },
+       { 1203, 0x4000 },
+       { 1280, 0x00c0 },
+       { 1281, 0x00c0 },
+       { 1282, 0x00c0 },
+       { 1283, 0x00c0 },
+       { 1312, 0x0200 },
+       { 1313, 0x0010 },
+       { 1344, 0x0098 },
+       { 1345, 0x0845 },
+       { 1408, 0x6318 },
+       { 1409, 0x6300 },
+       { 1410, 0x0fca },
+       { 1411, 0x0400 },
+       { 1412, 0x00d8 },
+       { 1413, 0x1eb5 },
+       { 1414, 0xf145 },
+       { 1415, 0x0b75 },
+       { 1416, 0x01c5 },
+       { 1417, 0x1c58 },
+       { 1418, 0xf373 },
+       { 1419, 0x0a54 },
+       { 1420, 0x0558 },
+       { 1421, 0x168e },
+       { 1422, 0xf829 },
+       { 1423, 0x07ad },
+       { 1424, 0x1103 },
+       { 1425, 0x0564 },
+       { 1426, 0x0559 },
+       { 1427, 0x4000 },
+       { 1568, 0x0002 },
+       { 1792, 0xa100 },
+       { 1793, 0xa101 },
+       { 1794, 0xa101 },
+       { 1795, 0xa101 },
+       { 1796, 0xa101 },
+       { 1797, 0xa101 },
+       { 1798, 0xa101 },
+       { 1799, 0xa101 },
+       { 1800, 0xa101 },
+       { 1801, 0xa101 },
+       { 1802, 0xa101 },
+       { 1803, 0xa101 },
+       { 1804, 0xa101 },
+       { 1805, 0xa101 },
+       { 1825, 0x0055 },
+       { 1848, 0x3fff },
+       { 1849, 0x1fff },
+       { 2049, 0x0001 },
+       { 2050, 0x0069 },
+       { 2056, 0x0002 },
+       { 2057, 0x0003 },
+       { 2058, 0x0069 },
+       { 12288, 0x0001 },
+       { 12289, 0x0001 },
+       { 12291, 0x0006 },
+       { 12292, 0x0040 },
+       { 12293, 0x0001 },
+       { 12294, 0x000f },
+       { 12295, 0x0006 },
+       { 12296, 0x0001 },
+       { 12297, 0x0003 },
+       { 12298, 0x0104 },
+       { 12300, 0x0060 },
+       { 12301, 0x0011 },
+       { 12302, 0x0401 },
+       { 12304, 0x0050 },
+       { 12305, 0x0003 },
+       { 12306, 0x0100 },
+       { 12308, 0x0051 },
+       { 12309, 0x0003 },
+       { 12310, 0x0104 },
+       { 12311, 0x000a },
+       { 12312, 0x0060 },
+       { 12313, 0x003b },
+       { 12314, 0x0502 },
+       { 12315, 0x0100 },
+       { 12316, 0x2fff },
+       { 12320, 0x2fff },
+       { 12324, 0x2fff },
+       { 12328, 0x2fff },
+       { 12332, 0x2fff },
+       { 12336, 0x2fff },
+       { 12340, 0x2fff },
+       { 12344, 0x2fff },
+       { 12348, 0x2fff },
+       { 12352, 0x0001 },
+       { 12353, 0x0001 },
+       { 12355, 0x0006 },
+       { 12356, 0x0040 },
+       { 12357, 0x0001 },
+       { 12358, 0x000f },
+       { 12359, 0x0006 },
+       { 12360, 0x0001 },
+       { 12361, 0x0003 },
+       { 12362, 0x0104 },
+       { 12364, 0x0060 },
+       { 12365, 0x0011 },
+       { 12366, 0x0401 },
+       { 12368, 0x0050 },
+       { 12369, 0x0003 },
+       { 12370, 0x0100 },
+       { 12372, 0x0060 },
+       { 12373, 0x003b },
+       { 12374, 0x0502 },
+       { 12375, 0x0100 },
+       { 12376, 0x2fff },
+       { 12380, 0x2fff },
+       { 12384, 0x2fff },
+       { 12388, 0x2fff },
+       { 12392, 0x2fff },
+       { 12396, 0x2fff },
+       { 12400, 0x2fff },
+       { 12404, 0x2fff },
+       { 12408, 0x2fff },
+       { 12412, 0x2fff },
+       { 12416, 0x0001 },
+       { 12417, 0x0001 },
+       { 12419, 0x0006 },
+       { 12420, 0x0040 },
+       { 12421, 0x0001 },
+       { 12422, 0x000f },
+       { 12423, 0x0006 },
+       { 12424, 0x0001 },
+       { 12425, 0x0003 },
+       { 12426, 0x0106 },
+       { 12428, 0x0061 },
+       { 12429, 0x0011 },
+       { 12430, 0x0401 },
+       { 12432, 0x0050 },
+       { 12433, 0x0003 },
+       { 12434, 0x0102 },
+       { 12436, 0x0051 },
+       { 12437, 0x0003 },
+       { 12438, 0x0106 },
+       { 12439, 0x000a },
+       { 12440, 0x0061 },
+       { 12441, 0x003b },
+       { 12442, 0x0502 },
+       { 12443, 0x0100 },
+       { 12444, 0x2fff },
+       { 12448, 0x2fff },
+       { 12452, 0x2fff },
+       { 12456, 0x2fff },
+       { 12460, 0x2fff },
+       { 12464, 0x2fff },
+       { 12468, 0x2fff },
+       { 12472, 0x2fff },
+       { 12476, 0x2fff },
+       { 12480, 0x0001 },
+       { 12481, 0x0001 },
+       { 12483, 0x0006 },
+       { 12484, 0x0040 },
+       { 12485, 0x0001 },
+       { 12486, 0x000f },
+       { 12487, 0x0006 },
+       { 12488, 0x0001 },
+       { 12489, 0x0003 },
+       { 12490, 0x0106 },
+       { 12492, 0x0061 },
+       { 12493, 0x0011 },
+       { 12494, 0x0401 },
+       { 12496, 0x0050 },
+       { 12497, 0x0003 },
+       { 12498, 0x0102 },
+       { 12500, 0x0061 },
+       { 12501, 0x003b },
+       { 12502, 0x0502 },
+       { 12503, 0x0100 },
+       { 12504, 0x2fff },
+       { 12508, 0x2fff },
+       { 12512, 0x2fff },
+       { 12516, 0x2fff },
+       { 12520, 0x2fff },
+       { 12524, 0x2fff },
+       { 12528, 0x2fff },
+       { 12532, 0x2fff },
+       { 12536, 0x2fff },
+       { 12540, 0x2fff },
+       { 12544, 0x0060 },
+       { 12546, 0x0601 },
+       { 12548, 0x0050 },
+       { 12550, 0x0100 },
+       { 12552, 0x0001 },
+       { 12554, 0x0104 },
+       { 12555, 0x0100 },
+       { 12556, 0x2fff },
+       { 12560, 0x2fff },
+       { 12564, 0x2fff },
+       { 12568, 0x2fff },
+       { 12572, 0x2fff },
+       { 12576, 0x2fff },
+       { 12580, 0x2fff },
+       { 12584, 0x2fff },
+       { 12588, 0x2fff },
+       { 12592, 0x2fff },
+       { 12596, 0x2fff },
+       { 12600, 0x2fff },
+       { 12604, 0x2fff },
+       { 12608, 0x0061 },
+       { 12610, 0x0601 },
+       { 12612, 0x0050 },
+       { 12614, 0x0102 },
+       { 12616, 0x0001 },
+       { 12618, 0x0106 },
+       { 12619, 0x0100 },
+       { 12620, 0x2fff },
+       { 12624, 0x2fff },
+       { 12628, 0x2fff },
+       { 12632, 0x2fff },
+       { 12636, 0x2fff },
+       { 12640, 0x2fff },
+       { 12644, 0x2fff },
+       { 12648, 0x2fff },
+       { 12652, 0x2fff },
+       { 12656, 0x2fff },
+       { 12660, 0x2fff },
+       { 12664, 0x2fff },
+       { 12668, 0x2fff },
+       { 12672, 0x0060 },
+       { 12674, 0x0601 },
+       { 12676, 0x0061 },
+       { 12678, 0x0601 },
+       { 12680, 0x0050 },
+       { 12682, 0x0300 },
+       { 12684, 0x0001 },
+       { 12686, 0x0304 },
+       { 12688, 0x0040 },
+       { 12690, 0x000f },
+       { 12692, 0x0001 },
+       { 12695, 0x0100 },
 };
 
 struct fll_config {
@@ -134,7 +378,7 @@ struct fll_config {
 };
 
 struct wm8995_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        int sysclk[2];
        int mclk[2];
        int aifclk[2];
@@ -156,7 +400,7 @@ static int wm8995_regulator_event_##n(struct notifier_block *nb, \
        struct wm8995_priv *wm8995 = container_of(nb, struct wm8995_priv, \
                                     disable_nb[n]); \
        if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8995->codec->cache_sync = 1; \
+               regcache_mark_dirty(wm8995->regmap);    \
        } \
        return 0; \
 }
@@ -688,8 +932,10 @@ static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {
        SND_SOC_DAPM_MIXER("IN1R PGA", SND_SOC_NOPM, 0, 0,
                &in1r_pga, 1),
 
-       SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8995_POWER_MANAGEMENT_1, 8, 0),
-       SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8995_POWER_MANAGEMENT_1, 9, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8995_POWER_MANAGEMENT_1, 8, 0,
+                           NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8995_POWER_MANAGEMENT_1, 9, 0,
+                           NULL, 0),
 
        SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8995_AIF1_CLOCKING_1, 0, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8995_AIF2_CLOCKING_1, 0, 0, NULL, 0),
@@ -947,31 +1193,244 @@ static const struct snd_soc_dapm_route wm8995_intercon[] = {
        { "SPK2R", NULL, "SPK2R Driver" }
 };
 
-static int wm8995_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8995_readable(struct device *dev, unsigned int reg)
 {
-       /* out of bounds registers are generally considered
-        * volatile to support register banks that are partially
-        * owned by something else for e.g. a DSP
-        */
-       if (reg > WM8995_MAX_CACHED_REGISTER)
-               return 1;
-
        switch (reg) {
        case WM8995_SOFTWARE_RESET:
+       case WM8995_POWER_MANAGEMENT_1:
+       case WM8995_POWER_MANAGEMENT_2:
+       case WM8995_POWER_MANAGEMENT_3:
+       case WM8995_POWER_MANAGEMENT_4:
+       case WM8995_POWER_MANAGEMENT_5:
+       case WM8995_LEFT_LINE_INPUT_1_VOLUME:
+       case WM8995_RIGHT_LINE_INPUT_1_VOLUME:
+       case WM8995_LEFT_LINE_INPUT_CONTROL:
+       case WM8995_DAC1_LEFT_VOLUME:
+       case WM8995_DAC1_RIGHT_VOLUME:
+       case WM8995_DAC2_LEFT_VOLUME:
+       case WM8995_DAC2_RIGHT_VOLUME:
+       case WM8995_OUTPUT_VOLUME_ZC_1:
+       case WM8995_MICBIAS_1:
+       case WM8995_MICBIAS_2:
+       case WM8995_LDO_1:
+       case WM8995_LDO_2:
+       case WM8995_ACCESSORY_DETECT_MODE1:
+       case WM8995_ACCESSORY_DETECT_MODE2:
+       case WM8995_HEADPHONE_DETECT1:
+       case WM8995_HEADPHONE_DETECT2:
+       case WM8995_MIC_DETECT_1:
+       case WM8995_MIC_DETECT_2:
+       case WM8995_CHARGE_PUMP_1:
+       case WM8995_CLASS_W_1:
+       case WM8995_DC_SERVO_1:
+       case WM8995_DC_SERVO_2:
+       case WM8995_DC_SERVO_3:
+       case WM8995_DC_SERVO_5:
+       case WM8995_DC_SERVO_6:
+       case WM8995_DC_SERVO_7:
        case WM8995_DC_SERVO_READBACK_0:
+       case WM8995_ANALOGUE_HP_1:
+       case WM8995_ANALOGUE_HP_2:
+       case WM8995_CHIP_REVISION:
+       case WM8995_CONTROL_INTERFACE_1:
+       case WM8995_CONTROL_INTERFACE_2:
+       case WM8995_WRITE_SEQUENCER_CTRL_1:
+       case WM8995_WRITE_SEQUENCER_CTRL_2:
+       case WM8995_AIF1_CLOCKING_1:
+       case WM8995_AIF1_CLOCKING_2:
+       case WM8995_AIF2_CLOCKING_1:
+       case WM8995_AIF2_CLOCKING_2:
+       case WM8995_CLOCKING_1:
+       case WM8995_CLOCKING_2:
+       case WM8995_AIF1_RATE:
+       case WM8995_AIF2_RATE:
+       case WM8995_RATE_STATUS:
+       case WM8995_FLL1_CONTROL_1:
+       case WM8995_FLL1_CONTROL_2:
+       case WM8995_FLL1_CONTROL_3:
+       case WM8995_FLL1_CONTROL_4:
+       case WM8995_FLL1_CONTROL_5:
+       case WM8995_FLL2_CONTROL_1:
+       case WM8995_FLL2_CONTROL_2:
+       case WM8995_FLL2_CONTROL_3:
+       case WM8995_FLL2_CONTROL_4:
+       case WM8995_FLL2_CONTROL_5:
+       case WM8995_AIF1_CONTROL_1:
+       case WM8995_AIF1_CONTROL_2:
+       case WM8995_AIF1_MASTER_SLAVE:
+       case WM8995_AIF1_BCLK:
+       case WM8995_AIF1ADC_LRCLK:
+       case WM8995_AIF1DAC_LRCLK:
+       case WM8995_AIF1DAC_DATA:
+       case WM8995_AIF1ADC_DATA:
+       case WM8995_AIF2_CONTROL_1:
+       case WM8995_AIF2_CONTROL_2:
+       case WM8995_AIF2_MASTER_SLAVE:
+       case WM8995_AIF2_BCLK:
+       case WM8995_AIF2ADC_LRCLK:
+       case WM8995_AIF2DAC_LRCLK:
+       case WM8995_AIF2DAC_DATA:
+       case WM8995_AIF2ADC_DATA:
+       case WM8995_AIF1_ADC1_LEFT_VOLUME:
+       case WM8995_AIF1_ADC1_RIGHT_VOLUME:
+       case WM8995_AIF1_DAC1_LEFT_VOLUME:
+       case WM8995_AIF1_DAC1_RIGHT_VOLUME:
+       case WM8995_AIF1_ADC2_LEFT_VOLUME:
+       case WM8995_AIF1_ADC2_RIGHT_VOLUME:
+       case WM8995_AIF1_DAC2_LEFT_VOLUME:
+       case WM8995_AIF1_DAC2_RIGHT_VOLUME:
+       case WM8995_AIF1_ADC1_FILTERS:
+       case WM8995_AIF1_ADC2_FILTERS:
+       case WM8995_AIF1_DAC1_FILTERS_1:
+       case WM8995_AIF1_DAC1_FILTERS_2:
+       case WM8995_AIF1_DAC2_FILTERS_1:
+       case WM8995_AIF1_DAC2_FILTERS_2:
+       case WM8995_AIF1_DRC1_1:
+       case WM8995_AIF1_DRC1_2:
+       case WM8995_AIF1_DRC1_3:
+       case WM8995_AIF1_DRC1_4:
+       case WM8995_AIF1_DRC1_5:
+       case WM8995_AIF1_DRC2_1:
+       case WM8995_AIF1_DRC2_2:
+       case WM8995_AIF1_DRC2_3:
+       case WM8995_AIF1_DRC2_4:
+       case WM8995_AIF1_DRC2_5:
+       case WM8995_AIF1_DAC1_EQ_GAINS_1:
+       case WM8995_AIF1_DAC1_EQ_GAINS_2:
+       case WM8995_AIF1_DAC1_EQ_BAND_1_A:
+       case WM8995_AIF1_DAC1_EQ_BAND_1_B:
+       case WM8995_AIF1_DAC1_EQ_BAND_1_PG:
+       case WM8995_AIF1_DAC1_EQ_BAND_2_A:
+       case WM8995_AIF1_DAC1_EQ_BAND_2_B:
+       case WM8995_AIF1_DAC1_EQ_BAND_2_C:
+       case WM8995_AIF1_DAC1_EQ_BAND_2_PG:
+       case WM8995_AIF1_DAC1_EQ_BAND_3_A:
+       case WM8995_AIF1_DAC1_EQ_BAND_3_B:
+       case WM8995_AIF1_DAC1_EQ_BAND_3_C:
+       case WM8995_AIF1_DAC1_EQ_BAND_3_PG:
+       case WM8995_AIF1_DAC1_EQ_BAND_4_A:
+       case WM8995_AIF1_DAC1_EQ_BAND_4_B:
+       case WM8995_AIF1_DAC1_EQ_BAND_4_C:
+       case WM8995_AIF1_DAC1_EQ_BAND_4_PG:
+       case WM8995_AIF1_DAC1_EQ_BAND_5_A:
+       case WM8995_AIF1_DAC1_EQ_BAND_5_B:
+       case WM8995_AIF1_DAC1_EQ_BAND_5_PG:
+       case WM8995_AIF1_DAC2_EQ_GAINS_1:
+       case WM8995_AIF1_DAC2_EQ_GAINS_2:
+       case WM8995_AIF1_DAC2_EQ_BAND_1_A:
+       case WM8995_AIF1_DAC2_EQ_BAND_1_B:
+       case WM8995_AIF1_DAC2_EQ_BAND_1_PG:
+       case WM8995_AIF1_DAC2_EQ_BAND_2_A:
+       case WM8995_AIF1_DAC2_EQ_BAND_2_B:
+       case WM8995_AIF1_DAC2_EQ_BAND_2_C:
+       case WM8995_AIF1_DAC2_EQ_BAND_2_PG:
+       case WM8995_AIF1_DAC2_EQ_BAND_3_A:
+       case WM8995_AIF1_DAC2_EQ_BAND_3_B:
+       case WM8995_AIF1_DAC2_EQ_BAND_3_C:
+       case WM8995_AIF1_DAC2_EQ_BAND_3_PG:
+       case WM8995_AIF1_DAC2_EQ_BAND_4_A:
+       case WM8995_AIF1_DAC2_EQ_BAND_4_B:
+       case WM8995_AIF1_DAC2_EQ_BAND_4_C:
+       case WM8995_AIF1_DAC2_EQ_BAND_4_PG:
+       case WM8995_AIF1_DAC2_EQ_BAND_5_A:
+       case WM8995_AIF1_DAC2_EQ_BAND_5_B:
+       case WM8995_AIF1_DAC2_EQ_BAND_5_PG:
+       case WM8995_AIF2_ADC_LEFT_VOLUME:
+       case WM8995_AIF2_ADC_RIGHT_VOLUME:
+       case WM8995_AIF2_DAC_LEFT_VOLUME:
+       case WM8995_AIF2_DAC_RIGHT_VOLUME:
+       case WM8995_AIF2_ADC_FILTERS:
+       case WM8995_AIF2_DAC_FILTERS_1:
+       case WM8995_AIF2_DAC_FILTERS_2:
+       case WM8995_AIF2_DRC_1:
+       case WM8995_AIF2_DRC_2:
+       case WM8995_AIF2_DRC_3:
+       case WM8995_AIF2_DRC_4:
+       case WM8995_AIF2_DRC_5:
+       case WM8995_AIF2_EQ_GAINS_1:
+       case WM8995_AIF2_EQ_GAINS_2:
+       case WM8995_AIF2_EQ_BAND_1_A:
+       case WM8995_AIF2_EQ_BAND_1_B:
+       case WM8995_AIF2_EQ_BAND_1_PG:
+       case WM8995_AIF2_EQ_BAND_2_A:
+       case WM8995_AIF2_EQ_BAND_2_B:
+       case WM8995_AIF2_EQ_BAND_2_C:
+       case WM8995_AIF2_EQ_BAND_2_PG:
+       case WM8995_AIF2_EQ_BAND_3_A:
+       case WM8995_AIF2_EQ_BAND_3_B:
+       case WM8995_AIF2_EQ_BAND_3_C:
+       case WM8995_AIF2_EQ_BAND_3_PG:
+       case WM8995_AIF2_EQ_BAND_4_A:
+       case WM8995_AIF2_EQ_BAND_4_B:
+       case WM8995_AIF2_EQ_BAND_4_C:
+       case WM8995_AIF2_EQ_BAND_4_PG:
+       case WM8995_AIF2_EQ_BAND_5_A:
+       case WM8995_AIF2_EQ_BAND_5_B:
+       case WM8995_AIF2_EQ_BAND_5_PG:
+       case WM8995_DAC1_MIXER_VOLUMES:
+       case WM8995_DAC1_LEFT_MIXER_ROUTING:
+       case WM8995_DAC1_RIGHT_MIXER_ROUTING:
+       case WM8995_DAC2_MIXER_VOLUMES:
+       case WM8995_DAC2_LEFT_MIXER_ROUTING:
+       case WM8995_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING:
+       case WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING:
+       case WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING:
+       case WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING:
+       case WM8995_DAC_SOFTMUTE:
+       case WM8995_OVERSAMPLING:
+       case WM8995_SIDETONE:
+       case WM8995_GPIO_1:
+       case WM8995_GPIO_2:
+       case WM8995_GPIO_3:
+       case WM8995_GPIO_4:
+       case WM8995_GPIO_5:
+       case WM8995_GPIO_6:
+       case WM8995_GPIO_7:
+       case WM8995_GPIO_8:
+       case WM8995_GPIO_9:
+       case WM8995_GPIO_10:
+       case WM8995_GPIO_11:
+       case WM8995_GPIO_12:
+       case WM8995_GPIO_13:
+       case WM8995_GPIO_14:
+       case WM8995_PULL_CONTROL_1:
+       case WM8995_PULL_CONTROL_2:
        case WM8995_INTERRUPT_STATUS_1:
        case WM8995_INTERRUPT_STATUS_2:
+       case WM8995_INTERRUPT_RAW_STATUS_2:
        case WM8995_INTERRUPT_STATUS_1_MASK:
        case WM8995_INTERRUPT_STATUS_2_MASK:
        case WM8995_INTERRUPT_CONTROL:
+       case WM8995_LEFT_PDM_SPEAKER_1:
+       case WM8995_RIGHT_PDM_SPEAKER_1:
+       case WM8995_PDM_SPEAKER_1_MUTE_SEQUENCE:
+       case WM8995_LEFT_PDM_SPEAKER_2:
+       case WM8995_RIGHT_PDM_SPEAKER_2:
+       case WM8995_PDM_SPEAKER_2_MUTE_SEQUENCE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool wm8995_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8995_SOFTWARE_RESET:
+       case WM8995_DC_SERVO_READBACK_0:
+       case WM8995_INTERRUPT_STATUS_1:
+       case WM8995_INTERRUPT_STATUS_2:
+       case WM8995_INTERRUPT_CONTROL:
        case WM8995_ACCESSORY_DETECT_MODE1:
        case WM8995_ACCESSORY_DETECT_MODE2:
        case WM8995_HEADPHONE_DETECT1:
        case WM8995_HEADPHONE_DETECT2:
-               return 1;
+       case WM8995_RATE_STATUS:
+               return true;
+       default:
+               return false;
        }
-
-       return 0;
 }
 
 static int wm8995_aif_mute(struct snd_soc_dai *dai, int mute)
@@ -1526,7 +1985,7 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
                        if (ret)
                                return ret;
 
-                       ret = snd_soc_cache_sync(codec);
+                       ret = regcache_sync(wm8995->regmap);
                        if (ret) {
                                dev_err(codec->dev,
                                        "Failed to sync cache: %d\n", ret);
@@ -1550,7 +2009,7 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
 }
 
 #ifdef CONFIG_PM
-static int wm8995_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm8995_suspend(struct snd_soc_codec *codec)
 {
        wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -1592,7 +2051,8 @@ static int wm8995_probe(struct snd_soc_codec *codec)
        wm8995 = snd_soc_codec_get_drvdata(codec);
        wm8995->codec = codec;
 
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, wm8995->control_type);
+       codec->control_data = wm8995->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
                return ret;
@@ -1696,7 +2156,7 @@ err_reg_get:
 #define WM8995_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 wm8995_aif1_dai_ops = {
+static const struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
        .set_sysclk = wm8995_set_dai_sysclk,
        .set_fmt = wm8995_set_dai_fmt,
        .hw_params = wm8995_hw_params,
@@ -1705,7 +2165,7 @@ static struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
        .set_tristate = wm8995_set_tristate,
 };
 
-static struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
+static const struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
        .set_sysclk = wm8995_set_dai_sysclk,
        .set_fmt = wm8995_set_dai_fmt,
        .hw_params = wm8995_hw_params,
@@ -1714,7 +2174,7 @@ static struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
        .set_tristate = wm8995_set_tristate,
 };
 
-static struct snd_soc_dai_ops wm8995_aif3_dai_ops = {
+static const struct snd_soc_dai_ops wm8995_aif3_dai_ops = {
        .set_tristate = wm8995_set_tristate,
 };
 
@@ -1781,11 +2241,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .suspend = wm8995_suspend,
        .resume = wm8995_resume,
        .set_bias_level = wm8995_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8995_reg_defs),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8995_reg_defs,
-       .volatile_register = wm8995_volatile,
-       .compress_type = SND_SOC_RBTREE_COMPRESSION
+};
+
+static struct regmap_config wm8995_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .max_register = WM8995_MAX_REGISTER,
+       .reg_defaults = wm8995_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8995_reg_defaults),
+       .volatile_reg = wm8995_volatile,
+       .readable_reg = wm8995_readable,
+       .cache_type = REGCACHE_RBTREE,
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -1798,21 +2265,37 @@ static int __devinit wm8995_spi_probe(struct spi_device *spi)
        if (!wm8995)
                return -ENOMEM;
 
-       wm8995->control_type = SND_SOC_SPI;
        spi_set_drvdata(spi, wm8995);
 
+       wm8995->regmap = regmap_init_spi(spi, &wm8995_regmap);
+       if (IS_ERR(wm8995->regmap)) {
+               ret = PTR_ERR(wm8995->regmap);
+               dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+               goto err_alloc;
+       }
+
        ret = snd_soc_register_codec(&spi->dev,
                                     &soc_codec_dev_wm8995, wm8995_dai,
                                     ARRAY_SIZE(wm8995_dai));
        if (ret < 0)
-               kfree(wm8995);
+               goto err_regmap;
+
+       return ret;
+
+err_regmap:
+       regmap_exit(wm8995->regmap);
+err_alloc:
+       kfree(wm8995);
+
        return ret;
 }
 
 static int __devexit wm8995_spi_remove(struct spi_device *spi)
 {
+       struct wm8995_priv *wm8995 = spi_get_drvdata(spi);
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
+       regmap_exit(wm8995->regmap);
+       kfree(wm8995);
        return 0;
 }
 
@@ -1837,21 +2320,40 @@ static __devinit int wm8995_i2c_probe(struct i2c_client *i2c,
        if (!wm8995)
                return -ENOMEM;
 
-       wm8995->control_type = SND_SOC_I2C;
        i2c_set_clientdata(i2c, wm8995);
 
+       wm8995->regmap = regmap_init_i2c(i2c, &wm8995_regmap);
+       if (IS_ERR(wm8995->regmap)) {
+               ret = PTR_ERR(wm8995->regmap);
+               dev_err(&i2c->dev, "Failed to register regmap: %d\n", ret);
+               goto err_alloc;
+       }
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8995, wm8995_dai,
                                     ARRAY_SIZE(wm8995_dai));
-       if (ret < 0)
-               kfree(wm8995);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
+               goto err_regmap;
+       }
+
+       return ret;
+
+err_regmap:
+       regmap_exit(wm8995->regmap);
+err_alloc:
+       kfree(wm8995);
+
        return ret;
 }
 
 static __devexit int wm8995_i2c_remove(struct i2c_client *client)
 {
+       struct wm8995_priv *wm8995 = i2c_get_clientdata(client);
+
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+       regmap_exit(wm8995->regmap);
+       kfree(wm8995);
        return 0;
 }
 
index a33b04d1719537409eb186c02a7e5dedfcbc7683..d8da10fe5b522a0ab2ba584d9ac6afe8383a776f 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gcd.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
@@ -49,6 +50,8 @@ static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
 };
 
 struct wm8996_priv {
+       struct device *dev;
+       struct regmap *regmap;
        struct snd_soc_codec *codec;
 
        int ldo1ena;
@@ -105,7 +108,7 @@ static int wm8996_regulator_event_##n(struct notifier_block *nb, \
        struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \
                                                  disable_nb[n]); \
        if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8996->codec->cache_sync = 1; \
+               regcache_cache_only(wm8996->regmap, true);      \
        } \
        return 0; \
 }
@@ -114,297 +117,365 @@ WM8996_REGULATOR_EVENT(0)
 WM8996_REGULATOR_EVENT(1)
 WM8996_REGULATOR_EVENT(2)
 
-static const u16 wm8996_reg[WM8996_MAX_REGISTER] = {
-       [WM8996_SOFTWARE_RESET] = 0x8996,
-       [WM8996_POWER_MANAGEMENT_7] = 0x10,
-       [WM8996_DAC1_HPOUT1_VOLUME] = 0x88,
-       [WM8996_DAC2_HPOUT2_VOLUME] = 0x88,
-       [WM8996_DAC1_LEFT_VOLUME] = 0x2c0,
-       [WM8996_DAC1_RIGHT_VOLUME] = 0x2c0,
-       [WM8996_DAC2_LEFT_VOLUME] = 0x2c0,
-       [WM8996_DAC2_RIGHT_VOLUME] = 0x2c0,
-       [WM8996_OUTPUT1_LEFT_VOLUME] = 0x80,
-       [WM8996_OUTPUT1_RIGHT_VOLUME] = 0x80,
-       [WM8996_OUTPUT2_LEFT_VOLUME] = 0x80,
-       [WM8996_OUTPUT2_RIGHT_VOLUME] = 0x80,
-       [WM8996_MICBIAS_1] = 0x39,
-       [WM8996_MICBIAS_2] = 0x39,
-       [WM8996_LDO_1] = 0x3,
-       [WM8996_LDO_2] = 0x13,
-       [WM8996_ACCESSORY_DETECT_MODE_1] = 0x4,
-       [WM8996_HEADPHONE_DETECT_1] = 0x20,
-       [WM8996_MIC_DETECT_1] = 0x7600,
-       [WM8996_MIC_DETECT_2] = 0xbf,
-       [WM8996_CHARGE_PUMP_1] = 0x1f25,
-       [WM8996_CHARGE_PUMP_2] = 0xab19,
-       [WM8996_DC_SERVO_5] = 0x2a2a,
-       [WM8996_CONTROL_INTERFACE_1] = 0x8004,
-       [WM8996_CLOCKING_1] = 0x10,
-       [WM8996_AIF_RATE] = 0x83,
-       [WM8996_FLL_CONTROL_4] = 0x5dc0,
-       [WM8996_FLL_CONTROL_5] = 0xc84,
-       [WM8996_FLL_EFS_2] = 0x2,
-       [WM8996_AIF1_TX_LRCLK_1] = 0x80,
-       [WM8996_AIF1_TX_LRCLK_2] = 0x8,
-       [WM8996_AIF1_RX_LRCLK_1] = 0x80,
-       [WM8996_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8996_AIF1RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8996_AIF1TX_TEST] = 0x7,
-       [WM8996_AIF2_TX_LRCLK_1] = 0x80,
-       [WM8996_AIF2_TX_LRCLK_2] = 0x8,
-       [WM8996_AIF2_RX_LRCLK_1] = 0x80,
-       [WM8996_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8996_AIF2RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8996_AIF2TX_TEST] = 0x1,
-       [WM8996_DSP1_TX_LEFT_VOLUME] = 0xc0,
-       [WM8996_DSP1_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8996_DSP1_RX_LEFT_VOLUME] = 0xc0,
-       [WM8996_DSP1_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8996_DSP1_TX_FILTERS] = 0x2000,
-       [WM8996_DSP1_RX_FILTERS_1] = 0x200,
-       [WM8996_DSP1_RX_FILTERS_2] = 0x10,
-       [WM8996_DSP1_DRC_1] = 0x98,
-       [WM8996_DSP1_DRC_2] = 0x845,
-       [WM8996_DSP1_RX_EQ_GAINS_1] = 0x6318,
-       [WM8996_DSP1_RX_EQ_GAINS_2] = 0x6300,
-       [WM8996_DSP1_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8996_DSP1_RX_EQ_BAND_1_B] = 0x400,
-       [WM8996_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8996_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8996_DSP1_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8996_DSP1_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8996_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8996_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8996_DSP1_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8996_DSP1_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8996_DSP1_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8996_DSP1_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8996_DSP1_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8996_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8996_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8996_DSP1_RX_EQ_BAND_5_A] = 0x564,
-       [WM8996_DSP1_RX_EQ_BAND_5_B] = 0x559,
-       [WM8996_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8996_DSP2_TX_LEFT_VOLUME] = 0xc0,
-       [WM8996_DSP2_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8996_DSP2_RX_LEFT_VOLUME] = 0xc0,
-       [WM8996_DSP2_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8996_DSP2_TX_FILTERS] = 0x2000,
-       [WM8996_DSP2_RX_FILTERS_1] = 0x200,
-       [WM8996_DSP2_RX_FILTERS_2] = 0x10,
-       [WM8996_DSP2_DRC_1] = 0x98,
-       [WM8996_DSP2_DRC_2] = 0x845,
-       [WM8996_DSP2_RX_EQ_GAINS_1] = 0x6318,
-       [WM8996_DSP2_RX_EQ_GAINS_2] = 0x6300,
-       [WM8996_DSP2_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8996_DSP2_RX_EQ_BAND_1_B] = 0x400,
-       [WM8996_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8996_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8996_DSP2_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8996_DSP2_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8996_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8996_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8996_DSP2_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8996_DSP2_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8996_DSP2_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8996_DSP2_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8996_DSP2_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8996_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8996_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8996_DSP2_RX_EQ_BAND_5_A] = 0x564,
-       [WM8996_DSP2_RX_EQ_BAND_5_B] = 0x559,
-       [WM8996_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8996_OVERSAMPLING] = 0xd,
-       [WM8996_SIDETONE] = 0x1040,
-       [WM8996_GPIO_1] = 0xa101,
-       [WM8996_GPIO_2] = 0xa101,
-       [WM8996_GPIO_3] = 0xa101,
-       [WM8996_GPIO_4] = 0xa101,
-       [WM8996_GPIO_5] = 0xa101,
-       [WM8996_PULL_CONTROL_2] = 0x140,
-       [WM8996_INTERRUPT_STATUS_1_MASK] = 0x1f,
-       [WM8996_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
-       [WM8996_RIGHT_PDM_SPEAKER] = 0x1,
-       [WM8996_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
-       [WM8996_PDM_SPEAKER_VOLUME] = 0x66,
-       [WM8996_WRITE_SEQUENCER_0] = 0x1,
-       [WM8996_WRITE_SEQUENCER_1] = 0x1,
-       [WM8996_WRITE_SEQUENCER_3] = 0x6,
-       [WM8996_WRITE_SEQUENCER_4] = 0x40,
-       [WM8996_WRITE_SEQUENCER_5] = 0x1,
-       [WM8996_WRITE_SEQUENCER_6] = 0xf,
-       [WM8996_WRITE_SEQUENCER_7] = 0x6,
-       [WM8996_WRITE_SEQUENCER_8] = 0x1,
-       [WM8996_WRITE_SEQUENCER_9] = 0x3,
-       [WM8996_WRITE_SEQUENCER_10] = 0x104,
-       [WM8996_WRITE_SEQUENCER_12] = 0x60,
-       [WM8996_WRITE_SEQUENCER_13] = 0x11,
-       [WM8996_WRITE_SEQUENCER_14] = 0x401,
-       [WM8996_WRITE_SEQUENCER_16] = 0x50,
-       [WM8996_WRITE_SEQUENCER_17] = 0x3,
-       [WM8996_WRITE_SEQUENCER_18] = 0x100,
-       [WM8996_WRITE_SEQUENCER_20] = 0x51,
-       [WM8996_WRITE_SEQUENCER_21] = 0x3,
-       [WM8996_WRITE_SEQUENCER_22] = 0x104,
-       [WM8996_WRITE_SEQUENCER_23] = 0xa,
-       [WM8996_WRITE_SEQUENCER_24] = 0x60,
-       [WM8996_WRITE_SEQUENCER_25] = 0x3b,
-       [WM8996_WRITE_SEQUENCER_26] = 0x502,
-       [WM8996_WRITE_SEQUENCER_27] = 0x100,
-       [WM8996_WRITE_SEQUENCER_28] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_32] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_36] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_40] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_44] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_48] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_52] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_56] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_60] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_64] = 0x1,
-       [WM8996_WRITE_SEQUENCER_65] = 0x1,
-       [WM8996_WRITE_SEQUENCER_67] = 0x6,
-       [WM8996_WRITE_SEQUENCER_68] = 0x40,
-       [WM8996_WRITE_SEQUENCER_69] = 0x1,
-       [WM8996_WRITE_SEQUENCER_70] = 0xf,
-       [WM8996_WRITE_SEQUENCER_71] = 0x6,
-       [WM8996_WRITE_SEQUENCER_72] = 0x1,
-       [WM8996_WRITE_SEQUENCER_73] = 0x3,
-       [WM8996_WRITE_SEQUENCER_74] = 0x104,
-       [WM8996_WRITE_SEQUENCER_76] = 0x60,
-       [WM8996_WRITE_SEQUENCER_77] = 0x11,
-       [WM8996_WRITE_SEQUENCER_78] = 0x401,
-       [WM8996_WRITE_SEQUENCER_80] = 0x50,
-       [WM8996_WRITE_SEQUENCER_81] = 0x3,
-       [WM8996_WRITE_SEQUENCER_82] = 0x100,
-       [WM8996_WRITE_SEQUENCER_84] = 0x60,
-       [WM8996_WRITE_SEQUENCER_85] = 0x3b,
-       [WM8996_WRITE_SEQUENCER_86] = 0x502,
-       [WM8996_WRITE_SEQUENCER_87] = 0x100,
-       [WM8996_WRITE_SEQUENCER_88] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_92] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_96] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_100] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_104] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_108] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_112] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_116] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_120] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_124] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_128] = 0x1,
-       [WM8996_WRITE_SEQUENCER_129] = 0x1,
-       [WM8996_WRITE_SEQUENCER_131] = 0x6,
-       [WM8996_WRITE_SEQUENCER_132] = 0x40,
-       [WM8996_WRITE_SEQUENCER_133] = 0x1,
-       [WM8996_WRITE_SEQUENCER_134] = 0xf,
-       [WM8996_WRITE_SEQUENCER_135] = 0x6,
-       [WM8996_WRITE_SEQUENCER_136] = 0x1,
-       [WM8996_WRITE_SEQUENCER_137] = 0x3,
-       [WM8996_WRITE_SEQUENCER_138] = 0x106,
-       [WM8996_WRITE_SEQUENCER_140] = 0x61,
-       [WM8996_WRITE_SEQUENCER_141] = 0x11,
-       [WM8996_WRITE_SEQUENCER_142] = 0x401,
-       [WM8996_WRITE_SEQUENCER_144] = 0x50,
-       [WM8996_WRITE_SEQUENCER_145] = 0x3,
-       [WM8996_WRITE_SEQUENCER_146] = 0x102,
-       [WM8996_WRITE_SEQUENCER_148] = 0x51,
-       [WM8996_WRITE_SEQUENCER_149] = 0x3,
-       [WM8996_WRITE_SEQUENCER_150] = 0x106,
-       [WM8996_WRITE_SEQUENCER_151] = 0xa,
-       [WM8996_WRITE_SEQUENCER_152] = 0x61,
-       [WM8996_WRITE_SEQUENCER_153] = 0x3b,
-       [WM8996_WRITE_SEQUENCER_154] = 0x502,
-       [WM8996_WRITE_SEQUENCER_155] = 0x100,
-       [WM8996_WRITE_SEQUENCER_156] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_160] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_164] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_168] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_172] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_176] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_180] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_184] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_188] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_192] = 0x1,
-       [WM8996_WRITE_SEQUENCER_193] = 0x1,
-       [WM8996_WRITE_SEQUENCER_195] = 0x6,
-       [WM8996_WRITE_SEQUENCER_196] = 0x40,
-       [WM8996_WRITE_SEQUENCER_197] = 0x1,
-       [WM8996_WRITE_SEQUENCER_198] = 0xf,
-       [WM8996_WRITE_SEQUENCER_199] = 0x6,
-       [WM8996_WRITE_SEQUENCER_200] = 0x1,
-       [WM8996_WRITE_SEQUENCER_201] = 0x3,
-       [WM8996_WRITE_SEQUENCER_202] = 0x106,
-       [WM8996_WRITE_SEQUENCER_204] = 0x61,
-       [WM8996_WRITE_SEQUENCER_205] = 0x11,
-       [WM8996_WRITE_SEQUENCER_206] = 0x401,
-       [WM8996_WRITE_SEQUENCER_208] = 0x50,
-       [WM8996_WRITE_SEQUENCER_209] = 0x3,
-       [WM8996_WRITE_SEQUENCER_210] = 0x102,
-       [WM8996_WRITE_SEQUENCER_212] = 0x61,
-       [WM8996_WRITE_SEQUENCER_213] = 0x3b,
-       [WM8996_WRITE_SEQUENCER_214] = 0x502,
-       [WM8996_WRITE_SEQUENCER_215] = 0x100,
-       [WM8996_WRITE_SEQUENCER_216] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_220] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_224] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_228] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_232] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_236] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_240] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_244] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_248] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_252] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_256] = 0x60,
-       [WM8996_WRITE_SEQUENCER_258] = 0x601,
-       [WM8996_WRITE_SEQUENCER_260] = 0x50,
-       [WM8996_WRITE_SEQUENCER_262] = 0x100,
-       [WM8996_WRITE_SEQUENCER_264] = 0x1,
-       [WM8996_WRITE_SEQUENCER_266] = 0x104,
-       [WM8996_WRITE_SEQUENCER_267] = 0x100,
-       [WM8996_WRITE_SEQUENCER_268] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_272] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_276] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_280] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_284] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_288] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_292] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_296] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_300] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_304] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_308] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_312] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_316] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_320] = 0x61,
-       [WM8996_WRITE_SEQUENCER_322] = 0x601,
-       [WM8996_WRITE_SEQUENCER_324] = 0x50,
-       [WM8996_WRITE_SEQUENCER_326] = 0x102,
-       [WM8996_WRITE_SEQUENCER_328] = 0x1,
-       [WM8996_WRITE_SEQUENCER_330] = 0x106,
-       [WM8996_WRITE_SEQUENCER_331] = 0x100,
-       [WM8996_WRITE_SEQUENCER_332] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_336] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_340] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_344] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_348] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_352] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_356] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_360] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_364] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_368] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_372] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_376] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_380] = 0x2fff,
-       [WM8996_WRITE_SEQUENCER_384] = 0x60,
-       [WM8996_WRITE_SEQUENCER_386] = 0x601,
-       [WM8996_WRITE_SEQUENCER_388] = 0x61,
-       [WM8996_WRITE_SEQUENCER_390] = 0x601,
-       [WM8996_WRITE_SEQUENCER_392] = 0x50,
-       [WM8996_WRITE_SEQUENCER_394] = 0x300,
-       [WM8996_WRITE_SEQUENCER_396] = 0x1,
-       [WM8996_WRITE_SEQUENCER_398] = 0x304,
-       [WM8996_WRITE_SEQUENCER_400] = 0x40,
-       [WM8996_WRITE_SEQUENCER_402] = 0xf,
-       [WM8996_WRITE_SEQUENCER_404] = 0x1,
-       [WM8996_WRITE_SEQUENCER_407] = 0x100,
+static struct reg_default wm8996_reg[] = {
+       { WM8996_SOFTWARE_RESET, 0x8996 },
+       { WM8996_POWER_MANAGEMENT_1, 0x0 },
+       { WM8996_POWER_MANAGEMENT_2, 0x0 },
+       { WM8996_POWER_MANAGEMENT_3, 0x0 },
+       { WM8996_POWER_MANAGEMENT_4, 0x0 },
+       { WM8996_POWER_MANAGEMENT_5, 0x0 },
+       { WM8996_POWER_MANAGEMENT_6, 0x0 },
+       { WM8996_POWER_MANAGEMENT_7, 0x10 },
+       { WM8996_POWER_MANAGEMENT_8, 0x0 },
+       { WM8996_LEFT_LINE_INPUT_VOLUME, 0x0 },
+       { WM8996_RIGHT_LINE_INPUT_VOLUME, 0x0 },
+       { WM8996_LINE_INPUT_CONTROL, 0x0 },
+       { WM8996_DAC1_HPOUT1_VOLUME, 0x88 },
+       { WM8996_DAC2_HPOUT2_VOLUME, 0x88 },
+       { WM8996_DAC1_LEFT_VOLUME, 0x2c0 },
+       { WM8996_DAC1_RIGHT_VOLUME, 0x2c0 },
+       { WM8996_DAC2_LEFT_VOLUME, 0x2c0 },
+       { WM8996_DAC2_RIGHT_VOLUME, 0x2c0 },
+       { WM8996_OUTPUT1_LEFT_VOLUME, 0x80 },
+       { WM8996_OUTPUT1_RIGHT_VOLUME, 0x80 },
+       { WM8996_OUTPUT2_LEFT_VOLUME, 0x80 },
+       { WM8996_OUTPUT2_RIGHT_VOLUME, 0x80 },
+       { WM8996_MICBIAS_1, 0x39 },
+       { WM8996_MICBIAS_2, 0x39 },
+       { WM8996_LDO_1, 0x3 },
+       { WM8996_LDO_2, 0x13 },
+       { WM8996_ACCESSORY_DETECT_MODE_1, 0x4 },
+       { WM8996_ACCESSORY_DETECT_MODE_2, 0x0 },
+       { WM8996_HEADPHONE_DETECT_1, 0x20 },
+       { WM8996_HEADPHONE_DETECT_2, 0x0 },
+       { WM8996_MIC_DETECT_1, 0x7600 },
+       { WM8996_MIC_DETECT_2, 0xbf },
+       { WM8996_CHARGE_PUMP_1, 0x1f25 },
+       { WM8996_CHARGE_PUMP_2, 0xab19 },
+       { WM8996_DC_SERVO_1, 0x0 },
+       { WM8996_DC_SERVO_2, 0x0 },
+       { WM8996_DC_SERVO_3, 0x0 },
+       { WM8996_DC_SERVO_5, 0x2a2a },
+       { WM8996_DC_SERVO_6, 0x0 },
+       { WM8996_DC_SERVO_7, 0x0 },
+       { WM8996_ANALOGUE_HP_1, 0x0 },
+       { WM8996_ANALOGUE_HP_2, 0x0 },
+       { WM8996_CONTROL_INTERFACE_1, 0x8004 },
+       { WM8996_WRITE_SEQUENCER_CTRL_1, 0x0 },
+       { WM8996_WRITE_SEQUENCER_CTRL_2, 0x0 },
+       { WM8996_AIF_CLOCKING_1, 0x0 },
+       { WM8996_AIF_CLOCKING_2, 0x0 },
+       { WM8996_CLOCKING_1, 0x10 },
+       { WM8996_CLOCKING_2, 0x0 },
+       { WM8996_AIF_RATE, 0x83 },
+       { WM8996_FLL_CONTROL_1, 0x0 },
+       { WM8996_FLL_CONTROL_2, 0x0 },
+       { WM8996_FLL_CONTROL_3, 0x0 },
+       { WM8996_FLL_CONTROL_4, 0x5dc0 },
+       { WM8996_FLL_CONTROL_5, 0xc84 },
+       { WM8996_FLL_EFS_1, 0x0 },
+       { WM8996_FLL_EFS_2, 0x2 },
+       { WM8996_AIF1_CONTROL, 0x0 },
+       { WM8996_AIF1_BCLK, 0x0 },
+       { WM8996_AIF1_TX_LRCLK_1, 0x80 },
+       { WM8996_AIF1_TX_LRCLK_2, 0x8 },
+       { WM8996_AIF1_RX_LRCLK_1, 0x80 },
+       { WM8996_AIF1_RX_LRCLK_2, 0x0 },
+       { WM8996_AIF1TX_DATA_CONFIGURATION_1, 0x1818 },
+       { WM8996_AIF1TX_DATA_CONFIGURATION_2, 0 },
+       { WM8996_AIF1RX_DATA_CONFIGURATION, 0x1818 },
+       { WM8996_AIF1TX_CHANNEL_0_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_CHANNEL_2_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_CHANNEL_3_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_CHANNEL_4_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_CHANNEL_5_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_0_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_1_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_2_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_3_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_4_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_CHANNEL_5_CONFIGURATION, 0x0 },
+       { WM8996_AIF1RX_MONO_CONFIGURATION, 0x0 },
+       { WM8996_AIF1TX_TEST, 0x7 },
+       { WM8996_AIF2_CONTROL, 0x0 },
+       { WM8996_AIF2_BCLK, 0x0 },
+       { WM8996_AIF2_TX_LRCLK_1, 0x80 },
+       { WM8996_AIF2_TX_LRCLK_2, 0x8 },
+       { WM8996_AIF2_RX_LRCLK_1, 0x80 },
+       { WM8996_AIF2_RX_LRCLK_2, 0x0 },
+       { WM8996_AIF2TX_DATA_CONFIGURATION_1, 0x1818 },
+       { WM8996_AIF2RX_DATA_CONFIGURATION, 0x1818 },
+       { WM8996_AIF2RX_DATA_CONFIGURATION, 0x0 },
+       { WM8996_AIF2TX_CHANNEL_0_CONFIGURATION, 0x0 },
+       { WM8996_AIF2TX_CHANNEL_1_CONFIGURATION, 0x0 },
+       { WM8996_AIF2RX_CHANNEL_0_CONFIGURATION, 0x0 },
+       { WM8996_AIF2RX_CHANNEL_1_CONFIGURATION, 0x0 },
+       { WM8996_AIF2RX_MONO_CONFIGURATION, 0x0 },
+       { WM8996_AIF2TX_TEST, 0x1 },
+       { WM8996_DSP1_TX_LEFT_VOLUME, 0xc0 },
+       { WM8996_DSP1_TX_RIGHT_VOLUME, 0xc0 },
+       { WM8996_DSP1_RX_LEFT_VOLUME, 0xc0 },
+       { WM8996_DSP1_RX_RIGHT_VOLUME, 0xc0 },
+       { WM8996_DSP1_TX_FILTERS, 0x2000 },
+       { WM8996_DSP1_RX_FILTERS_1, 0x200 },
+       { WM8996_DSP1_RX_FILTERS_2, 0x10 },
+       { WM8996_DSP1_DRC_1, 0x98 },
+       { WM8996_DSP1_DRC_2, 0x845 },
+       { WM8996_DSP1_RX_EQ_GAINS_1, 0x6318 },
+       { WM8996_DSP1_RX_EQ_GAINS_2, 0x6300 },
+       { WM8996_DSP1_RX_EQ_BAND_1_A, 0xfca },
+       { WM8996_DSP1_RX_EQ_BAND_1_B, 0x400 },
+       { WM8996_DSP1_RX_EQ_BAND_1_PG, 0xd8 },
+       { WM8996_DSP1_RX_EQ_BAND_2_A, 0x1eb5 },
+       { WM8996_DSP1_RX_EQ_BAND_2_B, 0xf145 },
+       { WM8996_DSP1_RX_EQ_BAND_2_C, 0xb75 },
+       { WM8996_DSP1_RX_EQ_BAND_2_PG, 0x1c5 },
+       { WM8996_DSP1_RX_EQ_BAND_3_A, 0x1c58 },
+       { WM8996_DSP1_RX_EQ_BAND_3_B, 0xf373 },
+       { WM8996_DSP1_RX_EQ_BAND_3_C, 0xa54 },
+       { WM8996_DSP1_RX_EQ_BAND_3_PG, 0x558 },
+       { WM8996_DSP1_RX_EQ_BAND_4_A, 0x168e },
+       { WM8996_DSP1_RX_EQ_BAND_4_B, 0xf829 },
+       { WM8996_DSP1_RX_EQ_BAND_4_C, 0x7ad },
+       { WM8996_DSP1_RX_EQ_BAND_4_PG, 0x1103 },
+       { WM8996_DSP1_RX_EQ_BAND_5_A, 0x564 },
+       { WM8996_DSP1_RX_EQ_BAND_5_B, 0x559 },
+       { WM8996_DSP1_RX_EQ_BAND_5_PG, 0x4000 },
+       { WM8996_DSP2_TX_LEFT_VOLUME, 0xc0 },
+       { WM8996_DSP2_TX_RIGHT_VOLUME, 0xc0 },
+       { WM8996_DSP2_RX_LEFT_VOLUME, 0xc0 },
+       { WM8996_DSP2_RX_RIGHT_VOLUME, 0xc0 },
+       { WM8996_DSP2_TX_FILTERS, 0x2000 },
+       { WM8996_DSP2_RX_FILTERS_1, 0x200 },
+       { WM8996_DSP2_RX_FILTERS_2, 0x10 },
+       { WM8996_DSP2_DRC_1, 0x98 },
+       { WM8996_DSP2_DRC_2, 0x845 },
+       { WM8996_DSP2_RX_EQ_GAINS_1, 0x6318 },
+       { WM8996_DSP2_RX_EQ_GAINS_2, 0x6300 },
+       { WM8996_DSP2_RX_EQ_BAND_1_A, 0xfca },
+       { WM8996_DSP2_RX_EQ_BAND_1_B, 0x400 },
+       { WM8996_DSP2_RX_EQ_BAND_1_PG, 0xd8 },
+       { WM8996_DSP2_RX_EQ_BAND_2_A, 0x1eb5 },
+       { WM8996_DSP2_RX_EQ_BAND_2_B, 0xf145 },
+       { WM8996_DSP2_RX_EQ_BAND_2_C, 0xb75 },
+       { WM8996_DSP2_RX_EQ_BAND_2_PG, 0x1c5 },
+       { WM8996_DSP2_RX_EQ_BAND_3_A, 0x1c58 },
+       { WM8996_DSP2_RX_EQ_BAND_3_B, 0xf373 },
+       { WM8996_DSP2_RX_EQ_BAND_3_C, 0xa54 },
+       { WM8996_DSP2_RX_EQ_BAND_3_PG, 0x558 },
+       { WM8996_DSP2_RX_EQ_BAND_4_A, 0x168e },
+       { WM8996_DSP2_RX_EQ_BAND_4_B, 0xf829 },
+       { WM8996_DSP2_RX_EQ_BAND_4_C, 0x7ad },
+       { WM8996_DSP2_RX_EQ_BAND_4_PG, 0x1103 },
+       { WM8996_DSP2_RX_EQ_BAND_5_A, 0x564 },
+       { WM8996_DSP2_RX_EQ_BAND_5_B, 0x559 },
+       { WM8996_DSP2_RX_EQ_BAND_5_PG, 0x4000 },
+       { WM8996_DAC1_MIXER_VOLUMES, 0x0 },
+       { WM8996_DAC1_LEFT_MIXER_ROUTING, 0x0 },
+       { WM8996_DAC1_RIGHT_MIXER_ROUTING, 0x0 },
+       { WM8996_DAC2_MIXER_VOLUMES, 0x0 },
+       { WM8996_DAC2_LEFT_MIXER_ROUTING, 0x0 },
+       { WM8996_DAC2_RIGHT_MIXER_ROUTING, 0x0 },
+       { WM8996_DSP1_TX_LEFT_MIXER_ROUTING, 0x0 },
+       { WM8996_DSP1_TX_RIGHT_MIXER_ROUTING, 0x0 },
+       { WM8996_DSP2_TX_LEFT_MIXER_ROUTING, 0x0 },
+       { WM8996_DSP2_TX_RIGHT_MIXER_ROUTING, 0x0 },
+       { WM8996_DSP_TX_MIXER_SELECT, 0x0 },
+       { WM8996_DAC_SOFTMUTE, 0x0 },
+       { WM8996_OVERSAMPLING, 0xd },
+       { WM8996_SIDETONE, 0x1040 },
+       { WM8996_GPIO_1, 0xa101 },
+       { WM8996_GPIO_2, 0xa101 },
+       { WM8996_GPIO_3, 0xa101 },
+       { WM8996_GPIO_4, 0xa101 },
+       { WM8996_GPIO_5, 0xa101 },
+       { WM8996_PULL_CONTROL_1, 0x0 },
+       { WM8996_PULL_CONTROL_2, 0x140 },
+       { WM8996_INTERRUPT_STATUS_1_MASK, 0x1f },
+       { WM8996_INTERRUPT_STATUS_2_MASK, 0x1ecf },
+       { WM8996_LEFT_PDM_SPEAKER, 0x0 },
+       { WM8996_RIGHT_PDM_SPEAKER, 0x1 },
+       { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 },
+       { WM8996_PDM_SPEAKER_VOLUME, 0x66 },
+       { WM8996_WRITE_SEQUENCER_0, 0x1 },
+       { WM8996_WRITE_SEQUENCER_1, 0x1 },
+       { WM8996_WRITE_SEQUENCER_3, 0x6 },
+       { WM8996_WRITE_SEQUENCER_4, 0x40 },
+       { WM8996_WRITE_SEQUENCER_5, 0x1 },
+       { WM8996_WRITE_SEQUENCER_6, 0xf },
+       { WM8996_WRITE_SEQUENCER_7, 0x6 },
+       { WM8996_WRITE_SEQUENCER_8, 0x1 },
+       { WM8996_WRITE_SEQUENCER_9, 0x3 },
+       { WM8996_WRITE_SEQUENCER_10, 0x104 },
+       { WM8996_WRITE_SEQUENCER_12, 0x60 },
+       { WM8996_WRITE_SEQUENCER_13, 0x11 },
+       { WM8996_WRITE_SEQUENCER_14, 0x401 },
+       { WM8996_WRITE_SEQUENCER_16, 0x50 },
+       { WM8996_WRITE_SEQUENCER_17, 0x3 },
+       { WM8996_WRITE_SEQUENCER_18, 0x100 },
+       { WM8996_WRITE_SEQUENCER_20, 0x51 },
+       { WM8996_WRITE_SEQUENCER_21, 0x3 },
+       { WM8996_WRITE_SEQUENCER_22, 0x104 },
+       { WM8996_WRITE_SEQUENCER_23, 0xa },
+       { WM8996_WRITE_SEQUENCER_24, 0x60 },
+       { WM8996_WRITE_SEQUENCER_25, 0x3b },
+       { WM8996_WRITE_SEQUENCER_26, 0x502 },
+       { WM8996_WRITE_SEQUENCER_27, 0x100 },
+       { WM8996_WRITE_SEQUENCER_28, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_32, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_36, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_40, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_44, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_48, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_52, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_56, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_60, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_64, 0x1 },
+       { WM8996_WRITE_SEQUENCER_65, 0x1 },
+       { WM8996_WRITE_SEQUENCER_67, 0x6 },
+       { WM8996_WRITE_SEQUENCER_68, 0x40 },
+       { WM8996_WRITE_SEQUENCER_69, 0x1 },
+       { WM8996_WRITE_SEQUENCER_70, 0xf },
+       { WM8996_WRITE_SEQUENCER_71, 0x6 },
+       { WM8996_WRITE_SEQUENCER_72, 0x1 },
+       { WM8996_WRITE_SEQUENCER_73, 0x3 },
+       { WM8996_WRITE_SEQUENCER_74, 0x104 },
+       { WM8996_WRITE_SEQUENCER_76, 0x60 },
+       { WM8996_WRITE_SEQUENCER_77, 0x11 },
+       { WM8996_WRITE_SEQUENCER_78, 0x401 },
+       { WM8996_WRITE_SEQUENCER_80, 0x50 },
+       { WM8996_WRITE_SEQUENCER_81, 0x3 },
+       { WM8996_WRITE_SEQUENCER_82, 0x100 },
+       { WM8996_WRITE_SEQUENCER_84, 0x60 },
+       { WM8996_WRITE_SEQUENCER_85, 0x3b },
+       { WM8996_WRITE_SEQUENCER_86, 0x502 },
+       { WM8996_WRITE_SEQUENCER_87, 0x100 },
+       { WM8996_WRITE_SEQUENCER_88, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_92, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_96, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_100, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_104, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_108, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_112, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_116, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_120, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_124, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_128, 0x1 },
+       { WM8996_WRITE_SEQUENCER_129, 0x1 },
+       { WM8996_WRITE_SEQUENCER_131, 0x6 },
+       { WM8996_WRITE_SEQUENCER_132, 0x40 },
+       { WM8996_WRITE_SEQUENCER_133, 0x1 },
+       { WM8996_WRITE_SEQUENCER_134, 0xf },
+       { WM8996_WRITE_SEQUENCER_135, 0x6 },
+       { WM8996_WRITE_SEQUENCER_136, 0x1 },
+       { WM8996_WRITE_SEQUENCER_137, 0x3 },
+       { WM8996_WRITE_SEQUENCER_138, 0x106 },
+       { WM8996_WRITE_SEQUENCER_140, 0x61 },
+       { WM8996_WRITE_SEQUENCER_141, 0x11 },
+       { WM8996_WRITE_SEQUENCER_142, 0x401 },
+       { WM8996_WRITE_SEQUENCER_144, 0x50 },
+       { WM8996_WRITE_SEQUENCER_145, 0x3 },
+       { WM8996_WRITE_SEQUENCER_146, 0x102 },
+       { WM8996_WRITE_SEQUENCER_148, 0x51 },
+       { WM8996_WRITE_SEQUENCER_149, 0x3 },
+       { WM8996_WRITE_SEQUENCER_150, 0x106 },
+       { WM8996_WRITE_SEQUENCER_151, 0xa },
+       { WM8996_WRITE_SEQUENCER_152, 0x61 },
+       { WM8996_WRITE_SEQUENCER_153, 0x3b },
+       { WM8996_WRITE_SEQUENCER_154, 0x502 },
+       { WM8996_WRITE_SEQUENCER_155, 0x100 },
+       { WM8996_WRITE_SEQUENCER_156, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_160, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_164, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_168, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_172, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_176, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_180, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_184, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_188, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_192, 0x1 },
+       { WM8996_WRITE_SEQUENCER_193, 0x1 },
+       { WM8996_WRITE_SEQUENCER_195, 0x6 },
+       { WM8996_WRITE_SEQUENCER_196, 0x40 },
+       { WM8996_WRITE_SEQUENCER_197, 0x1 },
+       { WM8996_WRITE_SEQUENCER_198, 0xf },
+       { WM8996_WRITE_SEQUENCER_199, 0x6 },
+       { WM8996_WRITE_SEQUENCER_200, 0x1 },
+       { WM8996_WRITE_SEQUENCER_201, 0x3 },
+       { WM8996_WRITE_SEQUENCER_202, 0x106 },
+       { WM8996_WRITE_SEQUENCER_204, 0x61 },
+       { WM8996_WRITE_SEQUENCER_205, 0x11 },
+       { WM8996_WRITE_SEQUENCER_206, 0x401 },
+       { WM8996_WRITE_SEQUENCER_208, 0x50 },
+       { WM8996_WRITE_SEQUENCER_209, 0x3 },
+       { WM8996_WRITE_SEQUENCER_210, 0x102 },
+       { WM8996_WRITE_SEQUENCER_212, 0x61 },
+       { WM8996_WRITE_SEQUENCER_213, 0x3b },
+       { WM8996_WRITE_SEQUENCER_214, 0x502 },
+       { WM8996_WRITE_SEQUENCER_215, 0x100 },
+       { WM8996_WRITE_SEQUENCER_216, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_220, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_224, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_228, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_232, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_236, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_240, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_244, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_248, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_252, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_256, 0x60 },
+       { WM8996_WRITE_SEQUENCER_258, 0x601 },
+       { WM8996_WRITE_SEQUENCER_260, 0x50 },
+       { WM8996_WRITE_SEQUENCER_262, 0x100 },
+       { WM8996_WRITE_SEQUENCER_264, 0x1 },
+       { WM8996_WRITE_SEQUENCER_266, 0x104 },
+       { WM8996_WRITE_SEQUENCER_267, 0x100 },
+       { WM8996_WRITE_SEQUENCER_268, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_272, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_276, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_280, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_284, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_288, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_292, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_296, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_300, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_304, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_308, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_312, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_316, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_320, 0x61 },
+       { WM8996_WRITE_SEQUENCER_322, 0x601 },
+       { WM8996_WRITE_SEQUENCER_324, 0x50 },
+       { WM8996_WRITE_SEQUENCER_326, 0x102 },
+       { WM8996_WRITE_SEQUENCER_328, 0x1 },
+       { WM8996_WRITE_SEQUENCER_330, 0x106 },
+       { WM8996_WRITE_SEQUENCER_331, 0x100 },
+       { WM8996_WRITE_SEQUENCER_332, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_336, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_340, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_344, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_348, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_352, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_356, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_360, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_364, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_368, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_372, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_376, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_380, 0x2fff },
+       { WM8996_WRITE_SEQUENCER_384, 0x60 },
+       { WM8996_WRITE_SEQUENCER_386, 0x601 },
+       { WM8996_WRITE_SEQUENCER_388, 0x61 },
+       { WM8996_WRITE_SEQUENCER_390, 0x601 },
+       { WM8996_WRITE_SEQUENCER_392, 0x50 },
+       { WM8996_WRITE_SEQUENCER_394, 0x300 },
+       { WM8996_WRITE_SEQUENCER_396, 0x1 },
+       { WM8996_WRITE_SEQUENCER_398, 0x304 },
+       { WM8996_WRITE_SEQUENCER_400, 0x40 },
+       { WM8996_WRITE_SEQUENCER_402, 0xf },
+       { WM8996_WRITE_SEQUENCER_404, 0x1 },
+       { WM8996_WRITE_SEQUENCER_407, 0x100 },
 };
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
@@ -1413,8 +1484,7 @@ static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
        { "SPKDAT", NULL, "SPKR PGA" },
 };
 
-static int wm8996_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
+static bool wm8996_readable_register(struct device *dev, unsigned int reg)
 {
        /* Due to the sparseness of the register map the compiler
         * output from an explicit switch statement ends up being much
@@ -1621,8 +1691,7 @@ static int wm8996_readable_register(struct snd_soc_codec *codec,
        }
 }
 
-static int wm8996_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
+static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8996_SOFTWARE_RESET:
@@ -1646,9 +1715,15 @@ static int wm8996_volatile_register(struct snd_soc_codec *codec,
        }
 }
 
-static int wm8996_reset(struct snd_soc_codec *codec)
+static int wm8996_reset(struct wm8996_priv *wm8996)
 {
-       return snd_soc_write(codec, WM8996_SOFTWARE_RESET, 0x8915);
+       if (wm8996->pdata.ldo_ena > 0) {
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+               return 0;
+       } else {
+               return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET,
+                                   0x8915);
+       }
 }
 
 static const int bclk_divs[] = {
@@ -1723,13 +1798,13 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
                                msleep(5);
                        }
 
-                       codec->cache_only = false;
-                       snd_soc_cache_sync(codec);
+                       regcache_cache_only(codec->control_data, false);
+                       regcache_sync(codec->control_data);
                }
                break;
 
        case SND_SOC_BIAS_OFF:
-               codec->cache_only = true;
+               regcache_cache_only(codec->control_data, true);
                if (wm8996->pdata.ldo_ena >= 0)
                        gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
                regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
@@ -2252,48 +2327,45 @@ static inline struct wm8996_priv *gpio_to_wm8996(struct gpio_chip *chip)
 static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
-       struct snd_soc_codec *codec = wm8996->codec;
 
-       snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
-                           WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
+       regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+                          WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
 }
 
 static int wm8996_gpio_direction_out(struct gpio_chip *chip,
                                     unsigned offset, int value)
 {
        struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
-       struct snd_soc_codec *codec = wm8996->codec;
        int val;
 
        val = (1 << WM8996_GP1_FN_SHIFT) | (!!value << WM8996_GP1_LVL_SHIFT);
 
-       return snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
-                                  WM8996_GP1_FN_MASK | WM8996_GP1_DIR |
-                                  WM8996_GP1_LVL, val);
+       return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+                                 WM8996_GP1_FN_MASK | WM8996_GP1_DIR |
+                                 WM8996_GP1_LVL, val);
 }
 
 static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
-       struct snd_soc_codec *codec = wm8996->codec;
+       unsigned int reg;
        int ret;
 
-       ret = snd_soc_read(codec, WM8996_GPIO_1 + offset);
+       ret = regmap_read(wm8996->regmap, WM8996_GPIO_1 + offset, &reg);
        if (ret < 0)
                return ret;
 
-       return (ret & WM8996_GP1_LVL) != 0;
+       return (reg & WM8996_GP1_LVL) != 0;
 }
 
 static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
-       struct snd_soc_codec *codec = wm8996->codec;
 
-       return snd_soc_update_bits(codec, WM8996_GPIO_1 + offset,
-                                  WM8996_GP1_FN_MASK | WM8996_GP1_DIR,
-                                  (1 << WM8996_GP1_FN_SHIFT) |
-                                  (1 << WM8996_GP1_DIR_SHIFT));
+       return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
+                                 WM8996_GP1_FN_MASK | WM8996_GP1_DIR,
+                                 (1 << WM8996_GP1_FN_SHIFT) |
+                                 (1 << WM8996_GP1_DIR_SHIFT));
 }
 
 static struct gpio_chip wm8996_template_chip = {
@@ -2306,14 +2378,13 @@ static struct gpio_chip wm8996_template_chip = {
        .can_sleep              = 1,
 };
 
-static void wm8996_init_gpio(struct snd_soc_codec *codec)
+static void wm8996_init_gpio(struct wm8996_priv *wm8996)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        wm8996->gpio_chip = wm8996_template_chip;
        wm8996->gpio_chip.ngpio = 5;
-       wm8996->gpio_chip.dev = codec->dev;
+       wm8996->gpio_chip.dev = wm8996->dev;
 
        if (wm8996->pdata.gpio_base)
                wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
@@ -2322,24 +2393,23 @@ static void wm8996_init_gpio(struct snd_soc_codec *codec)
 
        ret = gpiochip_add(&wm8996->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+               dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret);
 }
 
-static void wm8996_free_gpio(struct snd_soc_codec *codec)
+static void wm8996_free_gpio(struct wm8996_priv *wm8996)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        ret = gpiochip_remove(&wm8996->gpio_chip);
        if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+               dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
 }
 #else
-static void wm8996_init_gpio(struct snd_soc_codec *codec)
+static void wm8996_init_gpio(struct wm8996_priv *wm8996)
 {
 }
 
-static void wm8996_free_gpio(struct snd_soc_codec *codec)
+static void wm8996_free_gpio(struct wm8996_priv *wm8996)
 {
 }
 #endif
@@ -2502,8 +2572,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
                                    SND_JACK_BTN_0);
 
                snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-                                   WM8996_MICD_RATE_MASK,
-                                   WM8996_MICD_RATE_MASK);
+                                   WM8996_MICD_RATE_MASK |
+                                   WM8996_MICD_BIAS_STARTTIME_MASK,
+                                   WM8996_MICD_RATE_MASK |
+                                   9 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
                return;
        }
 
@@ -2520,8 +2592,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
                        /* Increase poll rate to give better responsiveness
                         * for buttons */
                        snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-                                           WM8996_MICD_RATE_MASK,
-                                           5 << WM8996_MICD_RATE_SHIFT);
+                                           WM8996_MICD_RATE_MASK |
+                                           WM8996_MICD_BIAS_STARTTIME_MASK,
+                                           5 << WM8996_MICD_RATE_SHIFT |
+                                           7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
                } else {
                        dev_dbg(codec->dev, "Mic button up\n");
                        snd_soc_jack_report(wm8996->jack, 0, SND_JACK_BTN_0);
@@ -2569,8 +2643,10 @@ static void wm8996_micd(struct snd_soc_codec *codec)
                         * responsiveness.
                         */
                        snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
-                                           WM8996_MICD_RATE_MASK,
-                                           7 << WM8996_MICD_RATE_SHIFT);
+                                           WM8996_MICD_RATE_MASK |
+                                           WM8996_MICD_BIAS_STARTTIME_MASK,
+                                           7 << WM8996_MICD_RATE_SHIFT |
+                                           7 << WM8996_MICD_BIAS_STARTTIME_SHIFT);
                }
        }
 }
@@ -2693,6 +2769,18 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
                        "Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
+static const struct regmap_config wm8996_regmap = {
+       .reg_bits = 16,
+       .val_bits = 16,
+
+       .max_register = WM8996_MAX_REGISTER,
+       .reg_defaults = wm8996_reg,
+       .num_reg_defaults = ARRAY_SIZE(wm8996_reg),
+       .volatile_reg = wm8996_volatile_register,
+       .readable_reg = wm8996_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int wm8996_probe(struct snd_soc_codec *codec)
 {
        int ret;
@@ -2708,19 +2796,11 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 
        dapm->idle_bias_off = true;
 
-       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
-               wm8996->supplies[i].supply = wm8996_supply_names[i];
+       codec->control_data = wm8996->regmap;
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8996->supplies),
-                                wm8996->supplies);
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                goto err;
        }
 
@@ -2728,13 +2808,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
        wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
        wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
 
-       wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD");
-       if (IS_ERR(wm8996->cpvdd)) {
-               ret = PTR_ERR(wm8996->cpvdd);
-               dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
-               goto err_get;
-       }
-
        /* This should really be moved into the regulator core */
        for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
                ret = regulator_register_notifier(wm8996->supplies[i].consumer,
@@ -2746,50 +2819,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
                }
        }
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
-                                   wm8996->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_cpvdd;
-       }
-
-       if (wm8996->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
-               msleep(5);
-       }
-
-       ret = snd_soc_read(codec, WM8996_SOFTWARE_RESET);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
-               goto err_enable;
-       }
-       if (ret != 0x8915) {
-               dev_err(codec->dev, "Device is not a WM8996, ID %x\n", ret);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8996_CHIP_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 & WM8996_CHIP_REV_MASK) + 'A');
-
-       if (wm8996->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
-       } else {
-               ret = wm8996_reset(codec);
-               if (ret < 0) {
-                       dev_err(codec->dev, "Failed to issue reset\n");
-                       goto err_enable;
-               }
-       }
-
-       codec->cache_only = true;
+       regcache_cache_only(codec->control_data, true);
 
        /* Apply platform data settings */
        snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL,
@@ -2947,10 +2977,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
                                    WM8996_AIF2TX_LRCLK_MODE,
                                    WM8996_AIF2TX_LRCLK_MODE);
 
-       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
-
-       wm8996_init_gpio(codec);
-
        if (i2c->irq) {
                if (wm8996->pdata.irq_flags)
                        irq_flags = wm8996->pdata.irq_flags;
@@ -2988,15 +3014,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
 
        return 0;
 
-err_enable:
-       if (wm8996->pdata.ldo_ena >= 0)
-               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
-err_cpvdd:
-       regulator_put(wm8996->cpvdd);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 err:
        return ret;
 }
@@ -3013,8 +3030,6 @@ static int wm8996_remove(struct snd_soc_codec *codec)
        if (i2c->irq)
                free_irq(i2c->irq, codec);
 
-       wm8996_free_gpio(codec);
-
        for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
                regulator_unregister_notifier(wm8996->supplies[i].consumer,
                                              &wm8996->disable_nb[i]);
@@ -3024,17 +3039,17 @@ static int wm8996_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static int wm8996_soc_volatile_register(struct snd_soc_codec *codec,
+                                       unsigned int reg)
+{
+       return true;
+}
+
 static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
        .probe =        wm8996_probe,
        .remove =       wm8996_remove,
        .set_bias_level = wm8996_set_bias_level,
        .seq_notifier = wm8996_seq_notifier,
-       .reg_cache_size = WM8996_MAX_REGISTER + 1,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8996_reg,
-       .volatile_register = wm8996_volatile_register,
-       .readable_register = wm8996_readable_register,
-       .compress_type = SND_SOC_RBTREE_COMPRESSION,
        .controls = wm8996_snd_controls,
        .num_controls = ARRAY_SIZE(wm8996_snd_controls),
        .dapm_widgets = wm8996_dapm_widgets,
@@ -3042,6 +3057,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
        .dapm_routes = wm8996_dapm_routes,
        .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes),
        .set_pll = wm8996_set_fll,
+       .reg_cache_size = WM8996_MAX_REGISTER,
+       .volatile_register = wm8996_soc_volatile_register,
 };
 
 #define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
@@ -3050,7 +3067,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8996 = {
                        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
                        SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops wm8996_dai_ops = {
+static const struct snd_soc_dai_ops wm8996_dai_ops = {
        .set_fmt = wm8996_set_fmt,
        .hw_params = wm8996_hw_params,
        .set_sysclk = wm8996_set_sysclk,
@@ -3099,13 +3116,16 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8996_priv *wm8996;
-       int ret;
+       int ret, i;
+       unsigned int reg;
 
-       wm8996 = kzalloc(sizeof(struct wm8996_priv), GFP_KERNEL);
+       wm8996 = devm_kzalloc(&i2c->dev, sizeof(struct wm8996_priv),
+                             GFP_KERNEL);
        if (wm8996 == NULL)
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, wm8996);
+       wm8996->dev = &i2c->dev;
 
        if (dev_get_platdata(&i2c->dev))
                memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev),
@@ -3121,19 +3141,97 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
                }
        }
 
+       for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
+               wm8996->supplies[i].supply = wm8996_supply_names[i];
+
+       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8996->supplies),
+                                wm8996->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               goto err_gpio;
+       }
+
+       wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD");
+       if (IS_ERR(wm8996->cpvdd)) {
+               ret = PTR_ERR(wm8996->cpvdd);
+               dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+                                   wm8996->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_cpvdd;
+       }
+
+       if (wm8996->pdata.ldo_ena > 0) {
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1);
+               msleep(5);
+       }
+
+       wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap);
+       if (IS_ERR(wm8996->regmap)) {
+               ret = PTR_ERR(wm8996->regmap);
+               dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+               goto err_enable;
+       }
+
+       ret = regmap_read(wm8996->regmap, WM8996_SOFTWARE_RESET, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
+               goto err_regmap;
+       }
+       if (reg != 0x8915) {
+               dev_err(&i2c->dev, "Device is not a WM8996, ID %x\n", ret);
+               ret = -EINVAL;
+               goto err_regmap;
+       }
+
+       ret = regmap_read(wm8996->regmap, WM8996_CHIP_REVISION, &reg);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_regmap;
+       }
+
+       dev_info(&i2c->dev, "revision %c\n",
+                (reg & WM8996_CHIP_REV_MASK) + 'A');
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+
+       ret = wm8996_reset(wm8996);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to issue reset\n");
+               goto err_regmap;
+       }
+
+       wm8996_init_gpio(wm8996);
+
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8996, wm8996_dai,
                                     ARRAY_SIZE(wm8996_dai));
        if (ret < 0)
-               goto err_gpio;
+               goto err_gpiolib;
 
        return ret;
 
+err_gpiolib:
+       wm8996_free_gpio(wm8996);
+err_regmap:
+       regmap_exit(wm8996->regmap);
+err_enable:
+       if (wm8996->pdata.ldo_ena > 0)
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+       regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err_cpvdd:
+       regulator_put(wm8996->cpvdd);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
 err_gpio:
        if (wm8996->pdata.ldo_ena > 0)
                gpio_free(wm8996->pdata.ldo_ena);
 err:
-       kfree(wm8996);
 
        return ret;
 }
@@ -3143,9 +3241,14 @@ static __devexit int wm8996_i2c_remove(struct i2c_client *client)
        struct wm8996_priv *wm8996 = i2c_get_clientdata(client);
 
        snd_soc_unregister_codec(&client->dev);
-       if (wm8996->pdata.ldo_ena > 0)
+       wm8996_free_gpio(wm8996);
+       regulator_put(wm8996->cpvdd);
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+       regmap_exit(wm8996->regmap);
+       if (wm8996->pdata.ldo_ena > 0) {
+               gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
                gpio_free(wm8996->pdata.ldo_ena);
-       kfree(i2c_get_clientdata(client));
+       }
        return 0;
 }
 
index 4a398c3bfe84aea9ef4f6c8540f09b8b2bf34282..a6bab392700e94bfe138e8ae2322f1df47d3a70d 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/device.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/wm9081.h>
 #include "wm9081.h"
 
-static u16 wm9081_reg_defaults[] = {
-       0x0000,     /* R0  - Software Reset */
-       0x0000,     /* R1 */
-       0x00B9,     /* R2  - Analogue Lineout */
-       0x00B9,     /* R3  - Analogue Speaker PGA */
-       0x0001,     /* R4  - VMID Control */
-       0x0068,     /* R5  - Bias Control 1 */
-       0x0000,     /* R6 */
-       0x0000,     /* R7  - Analogue Mixer */
-       0x0000,     /* R8  - Anti Pop Control */
-       0x01DB,     /* R9  - Analogue Speaker 1 */
-       0x0018,     /* R10 - Analogue Speaker 2 */
-       0x0180,     /* R11 - Power Management */
-       0x0000,     /* R12 - Clock Control 1 */
-       0x0038,     /* R13 - Clock Control 2 */
-       0x4000,     /* R14 - Clock Control 3 */
-       0x0000,     /* R15 */
-       0x0000,     /* R16 - FLL Control 1 */
-       0x0200,     /* R17 - FLL Control 2 */
-       0x0000,     /* R18 - FLL Control 3 */
-       0x0204,     /* R19 - FLL Control 4 */
-       0x0000,     /* R20 - FLL Control 5 */
-       0x0000,     /* R21 */
-       0x0000,     /* R22 - Audio Interface 1 */
-       0x0002,     /* R23 - Audio Interface 2 */
-       0x0008,     /* R24 - Audio Interface 3 */
-       0x0022,     /* R25 - Audio Interface 4 */
-       0x0000,     /* R26 - Interrupt Status */
-       0x0006,     /* R27 - Interrupt Status Mask */
-       0x0000,     /* R28 - Interrupt Polarity */
-       0x0000,     /* R29 - Interrupt Control */
-       0x00C0,     /* R30 - DAC Digital 1 */
-       0x0008,     /* R31 - DAC Digital 2 */
-       0x09AF,     /* R32 - DRC 1 */
-       0x4201,     /* R33 - DRC 2 */
-       0x0000,     /* R34 - DRC 3 */
-       0x0000,     /* R35 - DRC 4 */
-       0x0000,     /* R36 */
-       0x0000,     /* R37 */
-       0x0000,     /* R38 - Write Sequencer 1 */
-       0x0000,     /* R39 - Write Sequencer 2 */
-       0x0002,     /* R40 - MW Slave 1 */
-       0x0000,     /* R41 */
-       0x0000,     /* R42 - EQ 1 */
-       0x0000,     /* R43 - EQ 2 */
-       0x0FCA,     /* R44 - EQ 3 */
-       0x0400,     /* R45 - EQ 4 */
-       0x00B8,     /* R46 - EQ 5 */
-       0x1EB5,     /* R47 - EQ 6 */
-       0xF145,     /* R48 - EQ 7 */
-       0x0B75,     /* R49 - EQ 8 */
-       0x01C5,     /* R50 - EQ 9 */
-       0x169E,     /* R51 - EQ 10 */
-       0xF829,     /* R52 - EQ 11 */
-       0x07AD,     /* R53 - EQ 12 */
-       0x1103,     /* R54 - EQ 13 */
-       0x1C58,     /* R55 - EQ 14 */
-       0xF373,     /* R56 - EQ 15 */
-       0x0A54,     /* R57 - EQ 16 */
-       0x0558,     /* R58 - EQ 17 */
-       0x0564,     /* R59 - EQ 18 */
-       0x0559,     /* R60 - EQ 19 */
-       0x4000,     /* R61 - EQ 20 */
+static struct reg_default wm9081_reg[] = {
+       {  2, 0x00B9 },     /* R2  - Analogue Lineout */
+       {  3, 0x00B9 },     /* R3  - Analogue Speaker PGA */
+       {  4, 0x0001 },     /* R4  - VMID Control */
+       {  5, 0x0068 },     /* R5  - Bias Control 1 */
+       {  7, 0x0000 },     /* R7  - Analogue Mixer */
+       {  8, 0x0000 },     /* R8  - Anti Pop Control */
+       {  9, 0x01DB },     /* R9  - Analogue Speaker 1 */
+       { 10, 0x0018 },     /* R10 - Analogue Speaker 2 */
+       { 11, 0x0180 },     /* R11 - Power Management */
+       { 12, 0x0000 },     /* R12 - Clock Control 1 */
+       { 13, 0x0038 },     /* R13 - Clock Control 2 */
+       { 14, 0x4000 },     /* R14 - Clock Control 3 */
+       { 16, 0x0000 },     /* R16 - FLL Control 1 */
+       { 17, 0x0200 },     /* R17 - FLL Control 2 */
+       { 18, 0x0000 },     /* R18 - FLL Control 3 */
+       { 19, 0x0204 },     /* R19 - FLL Control 4 */
+       { 20, 0x0000 },     /* R20 - FLL Control 5 */
+       { 22, 0x0000 },     /* R22 - Audio Interface 1 */
+       { 23, 0x0002 },     /* R23 - Audio Interface 2 */
+       { 24, 0x0008 },     /* R24 - Audio Interface 3 */
+       { 25, 0x0022 },     /* R25 - Audio Interface 4 */
+       { 27, 0x0006 },     /* R27 - Interrupt Status Mask */
+       { 28, 0x0000 },     /* R28 - Interrupt Polarity */
+       { 29, 0x0000 },     /* R29 - Interrupt Control */
+       { 30, 0x00C0 },     /* R30 - DAC Digital 1 */
+       { 31, 0x0008 },     /* R31 - DAC Digital 2 */
+       { 32, 0x09AF },     /* R32 - DRC 1 */
+       { 33, 0x4201 },     /* R33 - DRC 2 */
+       { 34, 0x0000 },     /* R34 - DRC 3 */
+       { 35, 0x0000 },     /* R35 - DRC 4 */
+       { 38, 0x0000 },     /* R38 - Write Sequencer 1 */
+       { 39, 0x0000 },     /* R39 - Write Sequencer 2 */
+       { 40, 0x0002 },     /* R40 - MW Slave 1 */
+       { 42, 0x0000 },     /* R42 - EQ 1 */
+       { 43, 0x0000 },     /* R43 - EQ 2 */
+       { 44, 0x0FCA },     /* R44 - EQ 3 */
+       { 45, 0x0400 },     /* R45 - EQ 4 */
+       { 46, 0x00B8 },     /* R46 - EQ 5 */
+       { 47, 0x1EB5 },     /* R47 - EQ 6 */
+       { 48, 0xF145 },     /* R48 - EQ 7 */
+       { 49, 0x0B75 },     /* R49 - EQ 8 */
+       { 50, 0x01C5 },     /* R50 - EQ 9 */
+       { 51, 0x169E },     /* R51 - EQ 10 */
+       { 52, 0xF829 },     /* R52 - EQ 11 */
+       { 53, 0x07AD },     /* R53 - EQ 12 */
+       { 54, 0x1103 },     /* R54 - EQ 13 */
+       { 55, 0x1C58 },     /* R55 - EQ 14 */
+       { 56, 0xF373 },     /* R56 - EQ 15 */
+       { 57, 0x0A54 },     /* R57 - EQ 16 */
+       { 58, 0x0558 },     /* R58 - EQ 17 */
+       { 59, 0x0564 },     /* R59 - EQ 18 */
+       { 60, 0x0559 },     /* R60 - EQ 19 */
+       { 61, 0x4000 },     /* R61 - EQ 20 */
 };
 
 static struct {
@@ -156,7 +147,7 @@ static struct {
 };
 
 struct wm9081_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        int sysclk_source;
        int mclk_rate;
        int sysclk_rate;
@@ -169,20 +160,84 @@ struct wm9081_priv {
        struct wm9081_pdata pdata;
 };
 
-static int wm9081_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm9081_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM9081_SOFTWARE_RESET:
        case WM9081_INTERRUPT_STATUS:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
+       }
+}
+
+static bool wm9081_readable_register(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM9081_SOFTWARE_RESET:
+       case WM9081_ANALOGUE_LINEOUT:
+       case WM9081_ANALOGUE_SPEAKER_PGA:
+       case WM9081_VMID_CONTROL:
+       case WM9081_BIAS_CONTROL_1:
+       case WM9081_ANALOGUE_MIXER:
+       case WM9081_ANTI_POP_CONTROL:
+       case WM9081_ANALOGUE_SPEAKER_1:
+       case WM9081_ANALOGUE_SPEAKER_2:
+       case WM9081_POWER_MANAGEMENT:
+       case WM9081_CLOCK_CONTROL_1:
+       case WM9081_CLOCK_CONTROL_2:
+       case WM9081_CLOCK_CONTROL_3:
+       case WM9081_FLL_CONTROL_1:
+       case WM9081_FLL_CONTROL_2:
+       case WM9081_FLL_CONTROL_3:
+       case WM9081_FLL_CONTROL_4:
+       case WM9081_FLL_CONTROL_5:
+       case WM9081_AUDIO_INTERFACE_1:
+       case WM9081_AUDIO_INTERFACE_2:
+       case WM9081_AUDIO_INTERFACE_3:
+       case WM9081_AUDIO_INTERFACE_4:
+       case WM9081_INTERRUPT_STATUS:
+       case WM9081_INTERRUPT_STATUS_MASK:
+       case WM9081_INTERRUPT_POLARITY:
+       case WM9081_INTERRUPT_CONTROL:
+       case WM9081_DAC_DIGITAL_1:
+       case WM9081_DAC_DIGITAL_2:
+       case WM9081_DRC_1:
+       case WM9081_DRC_2:
+       case WM9081_DRC_3:
+       case WM9081_DRC_4:
+       case WM9081_WRITE_SEQUENCER_1:
+       case WM9081_WRITE_SEQUENCER_2:
+       case WM9081_MW_SLAVE_1:
+       case WM9081_EQ_1:
+       case WM9081_EQ_2:
+       case WM9081_EQ_3:
+       case WM9081_EQ_4:
+       case WM9081_EQ_5:
+       case WM9081_EQ_6:
+       case WM9081_EQ_7:
+       case WM9081_EQ_8:
+       case WM9081_EQ_9:
+       case WM9081_EQ_10:
+       case WM9081_EQ_11:
+       case WM9081_EQ_12:
+       case WM9081_EQ_13:
+       case WM9081_EQ_14:
+       case WM9081_EQ_15:
+       case WM9081_EQ_16:
+       case WM9081_EQ_17:
+       case WM9081_EQ_18:
+       case WM9081_EQ_19:
+       case WM9081_EQ_20:
+               return true;
+       default:
+               return false;
        }
 }
 
-static int wm9081_reset(struct snd_soc_codec *codec)
+static int wm9081_reset(struct regmap *map)
 {
-       return snd_soc_write(codec, WM9081_SOFTWARE_RESET, 0);
+       return regmap_write(map, WM9081_SOFTWARE_RESET, 0x9081);
 }
 
 static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
@@ -737,6 +792,7 @@ SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
                    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
 };
 
 
@@ -759,6 +815,7 @@ static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
        { "Speaker PGA", NULL, "CLK_SYS" },
 
        { "Speaker", NULL, "Speaker PGA" },
+       { "Speaker", NULL, "TSENSE" },
 
        { "SPKN", NULL, "Speaker" },
        { "SPKP", NULL, "Speaker" },
@@ -767,84 +824,74 @@ static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
 static int wm9081_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
                /* VMID=2*40k */
-               reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
-               reg &= ~WM9081_VMID_SEL_MASK;
-               reg |= 0x2;
-               snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
+               snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+                                   WM9081_VMID_SEL_MASK, 0x2);
 
                /* Normal bias current */
-               reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
-               reg &= ~WM9081_STBY_BIAS_ENA;
-               snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+                                   WM9081_STBY_BIAS_ENA, 0);
                break;
 
        case SND_SOC_BIAS_STANDBY:
                /* Initial cold start */
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Disable LINEOUT discharge */
-                       reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
-                       reg &= ~WM9081_LINEOUT_DISCH;
-                       snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+                       snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
+                                           WM9081_LINEOUT_DISCH, 0);
 
                        /* Select startup bias source */
-                       reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
-                       reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA;
-                       snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
+                       snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+                                           WM9081_BIAS_SRC | WM9081_BIAS_ENA,
+                                           WM9081_BIAS_SRC | WM9081_BIAS_ENA);
 
                        /* VMID 2*4k; Soft VMID ramp enable */
-                       reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
-                       reg |= WM9081_VMID_RAMP | 0x6;
-                       snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
+                       snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+                                           WM9081_VMID_RAMP |
+                                           WM9081_VMID_SEL_MASK,
+                                           WM9081_VMID_RAMP | 0x6);
 
                        mdelay(100);
 
                        /* Normal bias enable & soft start off */
-                       reg &= ~WM9081_VMID_RAMP;
-                       snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
+                       snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+                                           WM9081_VMID_RAMP, 0);
 
                        /* Standard bias source */
-                       reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
-                       reg &= ~WM9081_BIAS_SRC;
-                       snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
+                       snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+                                           WM9081_BIAS_SRC, 0);
                }
 
                /* VMID 2*240k */
-               reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
-               reg &= ~WM9081_VMID_SEL_MASK;
-               reg |= 0x04;
-               snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
+               snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+                                   WM9081_VMID_SEL_MASK, 0x04);
 
                /* Standby bias current on */
-               reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
-               reg |= WM9081_STBY_BIAS_ENA;
-               snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+                                   WM9081_STBY_BIAS_ENA,
+                                   WM9081_STBY_BIAS_ENA);
                break;
 
        case SND_SOC_BIAS_OFF:
                /* Startup bias source and disable bias */
-               reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1);
-               reg |= WM9081_BIAS_SRC;
-               reg &= ~WM9081_BIAS_ENA;
-               snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg);
+               snd_soc_update_bits(codec, WM9081_BIAS_CONTROL_1,
+                                   WM9081_BIAS_SRC | WM9081_BIAS_ENA,
+                                   WM9081_BIAS_SRC);
 
                /* Disable VMID with soft ramping */
-               reg = snd_soc_read(codec, WM9081_VMID_CONTROL);
-               reg &= ~WM9081_VMID_SEL_MASK;
-               reg |= WM9081_VMID_RAMP;
-               snd_soc_write(codec, WM9081_VMID_CONTROL, reg);
+               snd_soc_update_bits(codec, WM9081_VMID_CONTROL,
+                                   WM9081_VMID_RAMP | WM9081_VMID_SEL_MASK,
+                                   WM9081_VMID_RAMP);
 
                /* Actively discharge LINEOUT */
-               reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
-               reg |= WM9081_LINEOUT_DISCH;
-               snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg);
+               snd_soc_update_bits(codec, WM9081_ANTI_POP_CONTROL,
+                                   WM9081_LINEOUT_DISCH,
+                                   WM9081_LINEOUT_DISCH);
                break;
        }
 
@@ -1185,7 +1232,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
        (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 wm9081_dai_ops = {
+static const struct snd_soc_dai_ops wm9081_dai_ops = {
        .hw_params = wm9081_hw_params,
        .set_fmt = wm9081_set_dai_fmt,
        .digital_mute = wm9081_digital_mute,
@@ -1213,25 +1260,14 @@ static int wm9081_probe(struct snd_soc_codec *codec)
        int ret;
        u16 reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
+       codec->control_data = wm9081->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
-       if (reg != 0x9081) {
-               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
-               ret = -EINVAL;
-               return ret;
-       }
-
-       ret = wm9081_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               return ret;
-       }
-
        reg = 0;
        if (wm9081->pdata.irq_high)
                reg |= WM9081_IRQ_POL;
@@ -1243,11 +1279,10 @@ static int wm9081_probe(struct snd_soc_codec *codec)
        wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Enable zero cross by default */
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
-       snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
-       snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
-                    reg | WM9081_SPKPGAZC);
+       snd_soc_update_bits(codec, WM9081_ANALOGUE_LINEOUT,
+                           WM9081_LINEOUTZC, WM9081_LINEOUTZC);
+       snd_soc_update_bits(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+                           WM9081_SPKPGAZC, WM9081_SPKPGAZC);
 
        if (!wm9081->pdata.num_retune_configs) {
                dev_dbg(codec->dev,
@@ -1266,7 +1301,7 @@ static int wm9081_remove(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm9081_suspend(struct snd_soc_codec *codec)
 {
        wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -1275,15 +1310,9 @@ static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int wm9081_resume(struct snd_soc_codec *codec)
 {
-       u16 *reg_cache = codec->reg_cache;
-       int i;
-
-       for (i = 0; i < codec->driver->reg_cache_size; i++) {
-               if (i == WM9081_SOFTWARE_RESET)
-                       continue;
+       struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
 
-               snd_soc_write(codec, i, reg_cache[i]);
-       }
+       regcache_sync(wm9081->regmap);
 
        wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -1303,11 +1332,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
        .set_sysclk = wm9081_set_sysclk,
        .set_bias_level = wm9081_set_bias_level,
 
-       .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm9081_reg_defaults,
-       .volatile_register = wm9081_volatile_register,
-
        .controls         = wm9081_snd_controls,
        .num_controls     = ARRAY_SIZE(wm9081_snd_controls),
        .dapm_widgets     = wm9081_dapm_widgets,
@@ -1316,19 +1340,56 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
        .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths),
 };
 
+static const struct regmap_config wm9081_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+
+       .max_register = WM9081_MAX_REGISTER,
+       .reg_defaults = wm9081_reg,
+       .num_reg_defaults = ARRAY_SIZE(wm9081_reg),
+       .volatile_reg = wm9081_volatile_register,
+       .readable_reg = wm9081_readable_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm9081_priv *wm9081;
+       unsigned int reg;
        int ret;
 
-       wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
+       wm9081 = devm_kzalloc(&i2c->dev, sizeof(struct wm9081_priv),
+                             GFP_KERNEL);
        if (wm9081 == NULL)
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, wm9081);
-       wm9081->control_type = SND_SOC_I2C;
+
+       wm9081->regmap = regmap_init_i2c(i2c, &wm9081_regmap);
+       if (IS_ERR(wm9081->regmap)) {
+               ret = PTR_ERR(wm9081->regmap);
+               dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+               goto err;
+       }
+
+       ret = regmap_read(wm9081->regmap, WM9081_SOFTWARE_RESET, &reg);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+               goto err_regmap;
+       }
+       if (reg != 0x9081) {
+               dev_err(&i2c->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+               ret = -EINVAL;
+               goto err_regmap;
+       }
+
+       ret = wm9081_reset(wm9081->regmap);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to issue reset\n");
+               goto err_regmap;
+       }
 
        if (dev_get_platdata(&i2c->dev))
                memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
@@ -1337,14 +1398,23 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm9081, &wm9081_dai, 1);
        if (ret < 0)
-               kfree(wm9081);
+               goto err_regmap;
+
+       return 0;
+
+err_regmap:
+       regmap_exit(wm9081->regmap);
+err:
+
        return ret;
 }
 
 static __devexit int wm9081_i2c_remove(struct i2c_client *client)
 {
+       struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
+
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+       regmap_exit(wm9081->regmap);
        return 0;
 }
 
index f94c06057c64c31ac6e4bd70fbf80799cc52837d..41ebe0dce772c908bcbcf53fdaff8264ac497e55 100644 (file)
@@ -513,18 +513,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Restore the register cache */
-                       for (i = 1; i < codec->driver->reg_cache_size; i++) {
-                               if (reg_cache[i] == wm9090_reg_defaults[i])
-                                       continue;
-                               if (wm9090_volatile(codec, i))
-                                       continue;
-
-                               ret = snd_soc_write(codec, i, reg_cache[i]);
-                               if (ret != 0)
-                                       dev_warn(codec->dev,
-                                                "Failed to restore register %d: %d\n",
-                                                i, ret);
-                       }
+                       snd_soc_cache_sync(codec);
                }
 
                /* We keep VMID off during standby since the combination of
@@ -604,7 +593,7 @@ static int wm9090_probe(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state)
+static int wm9090_suspend(struct snd_soc_codec *codec)
 {
        wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
@@ -647,7 +636,7 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
        struct wm9090_priv *wm9090;
        int ret;
 
-       wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
+       wm9090 = devm_kzalloc(&i2c->dev, sizeof(*wm9090), GFP_KERNEL);
        if (wm9090 == NULL) {
                dev_err(&i2c->dev, "Can not allocate memory\n");
                return -ENOMEM;
@@ -661,8 +650,6 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm9090,  NULL, 0);
-       if (ret < 0)
-               kfree(wm9090);
        return ret;
 }
 
@@ -671,7 +658,6 @@ static int __devexit wm9090_i2c_remove(struct i2c_client *i2c)
        struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
 
        snd_soc_unregister_codec(&i2c->dev);
-       kfree(wm9090);
 
        return 0;
 }
@@ -685,7 +671,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id);
 
 static struct i2c_driver wm9090_i2c_driver = {
        .driver = {
-               .name = "wm9090-codec",
+               .name = "wm9090",
                .owner = THIS_MODULE,
        },
        .probe = wm9090_i2c_probe,
index 646b58dda849192777adc69d66ab54bb14891928..40c92ead85a34526e4ce5d49c09e43595b8ae6c1 100644 (file)
@@ -258,7 +258,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
                        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
                        SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops wm9705_dai_ops = {
+static const struct snd_soc_dai_ops wm9705_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
@@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
+static int wm9705_soc_suspend(struct snd_soc_codec *codec)
 {
        soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
 
@@ -406,17 +406,7 @@ static struct platform_driver wm9705_codec_driver = {
        .remove = __devexit_p(wm9705_remove),
 };
 
-static int __init wm9705_init(void)
-{
-       return platform_driver_register(&wm9705_codec_driver);
-}
-module_init(wm9705_init);
-
-static void __exit wm9705_exit(void)
-{
-       platform_driver_unregister(&wm9705_codec_driver);
-}
-module_exit(wm9705_exit);
+module_platform_driver(wm9705_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM9705 driver");
 MODULE_AUTHOR("Ian Molton");
index 90117f8156e83c8da98b1f53fdb23573be4f9a03..b7b31f84c10b579432591d7d7caff670b1b6d9b7 100644 (file)
@@ -505,11 +505,11 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
                SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
+static const struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
        .prepare        = ac97_prepare,
 };
 
-static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
+static const struct snd_soc_dai_ops wm9712_dai_ops_aux = {
        .prepare        = ac97_aux_prepare,
 };
 
@@ -583,8 +583,7 @@ err:
        return -EIO;
 }
 
-static int wm9712_soc_suspend(struct snd_soc_codec *codec,
-       pm_message_t state)
+static int wm9712_soc_suspend(struct snd_soc_codec *codec)
 {
        wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
@@ -694,17 +693,7 @@ static struct platform_driver wm9712_codec_driver = {
        .remove = __devexit_p(wm9712_remove),
 };
 
-static int __init wm9712_init(void)
-{
-       return platform_driver_register(&wm9712_codec_driver);
-}
-module_init(wm9712_init);
-
-static void __exit wm9712_exit(void)
-{
-       platform_driver_unregister(&wm9712_codec_driver);
-}
-module_exit(wm9712_exit);
+module_platform_driver(wm9712_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 7167cb6787dba44efdc25a4550d12d24bbb026c6..2b8479bfcd93b822c48daa1f4e6797cf679d8cec 100644 (file)
@@ -1026,19 +1026,19 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
        (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
         SNDRV_PCM_FORMAT_S24_LE)
 
-static struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
+static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
        .prepare        = ac97_hifi_prepare,
        .set_clkdiv     = wm9713_set_dai_clkdiv,
        .set_pll        = wm9713_set_dai_pll,
 };
 
-static struct snd_soc_dai_ops wm9713_dai_ops_aux = {
+static const struct snd_soc_dai_ops wm9713_dai_ops_aux = {
        .prepare        = ac97_aux_prepare,
        .set_clkdiv     = wm9713_set_dai_clkdiv,
        .set_pll        = wm9713_set_dai_pll,
 };
 
-static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
+static const struct snd_soc_dai_ops wm9713_dai_ops_voice = {
        .hw_params      = wm9713_pcm_hw_params,
        .set_clkdiv     = wm9713_set_dai_clkdiv,
        .set_pll        = wm9713_set_dai_pll,
@@ -1140,8 +1140,7 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9713_soc_suspend(struct snd_soc_codec *codec,
-       pm_message_t state)
+static int wm9713_soc_suspend(struct snd_soc_codec *codec)
 {
        u16 reg;
 
@@ -1277,17 +1276,7 @@ static struct platform_driver wm9713_codec_driver = {
        .remove = __devexit_p(wm9713_remove),
 };
 
-static int __init wm9713_init(void)
-{
-       return platform_driver_register(&wm9713_codec_driver);
-}
-module_init(wm9713_init);
-
-static void __exit wm9713_exit(void)
-{
-       platform_driver_unregister(&wm9713_codec_driver);
-}
-module_exit(wm9713_exit);
+module_platform_driver(wm9713_codec_driver);
 
 MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 48e61e912400fb2d2cca4ad74d9faf17a3075444..2a61094075f86dfd40fff87787b2dba70804b36d 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
-#include <linux/platform_device.h>
 #include <linux/mfd/wm8994/registers.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -611,8 +610,8 @@ SND_SOC_DAPM_INPUT("IN1RP"),
 SND_SOC_DAPM_INPUT("IN2RN"),
 SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
 
-SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
-SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
 
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
                   in1l_pga, ARRAY_SIZE(in1l_pga)),
@@ -654,6 +653,7 @@ SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
 SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
                   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
 
+SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
 SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
                 NULL, 0),
 SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
@@ -789,10 +789,12 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
        { "SPKL Driver", NULL, "VMID" },
        { "SPKL Driver", NULL, "SPKL Boost" },
        { "SPKL Driver", NULL, "CLK_SYS" },
+       { "SPKL Driver", NULL, "TSHUT" },
 
        { "SPKR Driver", NULL, "VMID" },
        { "SPKR Driver", NULL, "SPKR Boost" },
        { "SPKR Driver", NULL, "CLK_SYS" },
+       { "SPKR Driver", NULL, "TSHUT" },
 
        { "SPKOUTLP", NULL, "SPKL Driver" },
        { "SPKOUTLN", NULL, "SPKL Driver" },
index f78c3f0f280c23e12065a1c9ad226dc981e944c3..10a2d8c788b73a434af2de950fdf3a3ad3652091 100644 (file)
@@ -242,6 +242,7 @@ static struct snd_soc_dai_link da850_evm_dai = {
 /* davinci dm6446 evm audio machine driver */
 static struct snd_soc_card dm6446_snd_soc_card_evm = {
        .name = "DaVinci DM6446 EVM",
+       .owner = THIS_MODULE,
        .dai_link = &dm6446_evm_dai,
        .num_links = 1,
 };
@@ -249,6 +250,7 @@ static struct snd_soc_card dm6446_snd_soc_card_evm = {
 /* davinci dm355 evm audio machine driver */
 static struct snd_soc_card dm355_snd_soc_card_evm = {
        .name = "DaVinci DM355 EVM",
+       .owner = THIS_MODULE,
        .dai_link = &dm355_evm_dai,
        .num_links = 1,
 };
@@ -256,6 +258,7 @@ static struct snd_soc_card dm355_snd_soc_card_evm = {
 /* davinci dm365 evm audio machine driver */
 static struct snd_soc_card dm365_snd_soc_card_evm = {
        .name = "DaVinci DM365 EVM",
+       .owner = THIS_MODULE,
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
 };
@@ -263,18 +266,21 @@ static struct snd_soc_card dm365_snd_soc_card_evm = {
 /* davinci dm6467 evm audio machine driver */
 static struct snd_soc_card dm6467_snd_soc_card_evm = {
        .name = "DaVinci DM6467 EVM",
+       .owner = THIS_MODULE,
        .dai_link = dm6467_evm_dai,
        .num_links = ARRAY_SIZE(dm6467_evm_dai),
 };
 
 static struct snd_soc_card da830_snd_soc_card = {
        .name = "DA830/OMAP-L137 EVM",
+       .owner = THIS_MODULE,
        .dai_link = &da830_evm_dai,
        .num_links = 1,
 };
 
 static struct snd_soc_card da850_snd_soc_card = {
        .name = "DA850/OMAP-L138 EVM",
+       .owner = THIS_MODULE,
        .dai_link = &da850_evm_dai,
        .num_links = 1,
 };
index 300e12118c0093722f1e2b5f527b8627cdbab116..0a74b9587a2c089796f2e4f9f1ca933f15e1f12a 100644 (file)
@@ -620,7 +620,7 @@ static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
 
 #define DAVINCI_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
-static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+static const struct snd_soc_dai_ops davinci_i2s_dai_ops = {
        .startup        = davinci_i2s_startup,
        .shutdown       = davinci_i2s_shutdown,
        .prepare        = davinci_i2s_prepare,
@@ -661,18 +661,18 @@ static int davinci_i2s_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start, resource_size(mem),
-                                   pdev->name);
+       ioarea = devm_request_mem_region(&pdev->dev, mem->start,
+                                        resource_size(mem),
+                                        pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "McBSP region already claimed\n");
                return -EBUSY;
        }
 
-       dev = kzalloc(sizeof(struct davinci_mcbsp_dev), GFP_KERNEL);
-       if (!dev) {
-               ret = -ENOMEM;
-               goto err_release_region;
-       }
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev),
+                          GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
        if (pdata) {
                dev->enable_channel_combine = pdata->enable_channel_combine;
                dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size =
@@ -691,13 +691,11 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q    = ram_chan_q;
 
        dev->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dev->clk)) {
-               ret = -ENODEV;
-               goto err_free_mem;
-       }
+       if (IS_ERR(dev->clk))
+               return -ENODEV;
        clk_enable(dev->clk);
 
-       dev->base = ioremap(mem->start, resource_size(mem));
+       dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!dev->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
@@ -715,7 +713,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENXIO;
-               goto err_iounmap;
+               goto err_release_clk;
        }
        dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
 
@@ -723,7 +721,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENXIO;
-               goto err_iounmap;
+               goto err_release_clk;
        }
        dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
        dev->dev = &pdev->dev;
@@ -732,35 +730,24 @@ static int davinci_i2s_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
        if (ret != 0)
-               goto err_iounmap;
+               goto err_release_clk;
 
        return 0;
 
-err_iounmap:
-       iounmap(dev->base);
 err_release_clk:
        clk_disable(dev->clk);
        clk_put(dev->clk);
-err_free_mem:
-       kfree(dev);
-err_release_region:
-       release_mem_region(mem->start, resource_size(mem));
-
        return ret;
 }
 
 static int davinci_i2s_remove(struct platform_device *pdev)
 {
        struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
-       struct resource *mem;
 
        snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
-       kfree(dev);
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
 
        return 0;
 }
@@ -774,17 +761,7 @@ static struct platform_driver davinci_mcbsp_driver = {
        },
 };
 
-static int __init davinci_i2s_init(void)
-{
-       return platform_driver_register(&davinci_mcbsp_driver);
-}
-module_init(davinci_i2s_init);
-
-static void __exit davinci_i2s_exit(void)
-{
-       platform_driver_unregister(&davinci_mcbsp_driver);
-}
-module_exit(davinci_i2s_exit);
+module_platform_driver(davinci_mcbsp_driver);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
index 7173df254a9150b0f69d527f7cd2f6ab02cfc7e3..95441bfc819026071020915d6e4e3c53d2dec593 100644 (file)
@@ -813,7 +813,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
        .startup        = davinci_mcasp_startup,
        .trigger        = davinci_mcasp_trigger,
        .hw_params      = davinci_mcasp_hw_params,
@@ -865,38 +865,35 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        struct resource *mem, *ioarea, *res;
        struct snd_platform_data *pdata;
        struct davinci_audio_dev *dev;
-       int ret = 0;
+       int ret;
 
-       dev = kzalloc(sizeof(struct davinci_audio_dev), GFP_KERNEL);
+       dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),
+                          GFP_KERNEL);
        if (!dev)
                return  -ENOMEM;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
                dev_err(&pdev->dev, "no mem resource?\n");
-               ret = -ENODEV;
-               goto err_release_data;
+               return -ENODEV;
        }
 
-       ioarea = request_mem_region(mem->start,
+       ioarea = devm_request_mem_region(&pdev->dev, mem->start,
                        resource_size(mem), pdev->name);
        if (!ioarea) {
                dev_err(&pdev->dev, "Audio region already claimed\n");
-               ret = -EBUSY;
-               goto err_release_data;
+               return -EBUSY;
        }
 
        pdata = pdev->dev.platform_data;
        dev->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dev->clk)) {
-               ret = -ENODEV;
-               goto err_release_region;
-       }
+       if (IS_ERR(dev->clk))
+               return -ENODEV;
 
        clk_enable(dev->clk);
        dev->clk_active = 1;
 
-       dev->base = ioremap(mem->start, resource_size(mem));
+       dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!dev->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
@@ -924,7 +921,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENODEV;
-               goto err_iounmap;
+               goto err_release_clk;
        }
 
        dma_data->channel = res->start;
@@ -940,7 +937,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
                ret = -ENODEV;
-               goto err_iounmap;
+               goto err_release_clk;
        }
 
        dma_data->channel = res->start;
@@ -948,37 +945,24 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
 
        if (ret != 0)
-               goto err_iounmap;
+               goto err_release_clk;
        return 0;
 
-err_iounmap:
-       iounmap(dev->base);
 err_release_clk:
        clk_disable(dev->clk);
        clk_put(dev->clk);
-err_release_region:
-       release_mem_region(mem->start, resource_size(mem));
-err_release_data:
-       kfree(dev);
-
        return ret;
 }
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
        struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
-       struct resource *mem;
 
        snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
 
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem->start, resource_size(mem));
-
-       kfree(dev);
-
        return 0;
 }
 
@@ -991,17 +975,7 @@ static struct platform_driver davinci_mcasp_driver = {
        },
 };
 
-static int __init davinci_mcasp_init(void)
-{
-       return platform_driver_register(&davinci_mcasp_driver);
-}
-module_init(davinci_mcasp_init);
-
-static void __exit davinci_mcasp_exit(void)
-{
-       platform_driver_unregister(&davinci_mcasp_driver);
-}
-module_exit(davinci_mcasp_exit);
+module_platform_driver(davinci_mcasp_driver);
 
 MODULE_AUTHOR("Steve Chen");
 MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
index d5fe08cc5db7ec83efbfcb2b8b13d6094c2bf986..b26401f87b8509ea23eea61e1530f77eeb082377 100644 (file)
@@ -831,7 +831,6 @@ static u64 davinci_pcm_dmamask = 0xffffffff;
 static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
@@ -840,7 +839,7 @@ static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK,
                        pcm_hardware_playback.buffer_bytes_max);
@@ -848,7 +847,7 @@ static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        return ret;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE,
                        pcm_hardware_capture.buffer_bytes_max);
@@ -886,17 +885,7 @@ static struct platform_driver davinci_pcm_driver = {
        .remove = __devexit_p(davinci_soc_platform_remove),
 };
 
-static int __init snd_davinci_pcm_init(void)
-{
-       return platform_driver_register(&davinci_pcm_driver);
-}
-module_init(snd_davinci_pcm_init);
-
-static void __exit snd_davinci_pcm_exit(void)
-{
-       platform_driver_unregister(&davinci_pcm_driver);
-}
-module_exit(snd_davinci_pcm_exit);
+module_platform_driver(davinci_pcm_driver);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
index 0fe558c65145683b5951cf343e828746562b5ccc..f71175b29e38fb26aeeb8d6c6e4a1a45af789db2 100644 (file)
@@ -93,6 +93,7 @@ static struct snd_soc_dai_link sffsdr_dai = {
 /* davinci-sffsdr audio machine driver */
 static struct snd_soc_card snd_soc_sffsdr = {
        .name = "DaVinci SFFSDR",
+       .owner = THIS_MODULE,
        .dai_link = &sffsdr_dai,
        .num_links = 1,
 };
index 1f11525d97e805ade146e26fe45cf9eb48ed432c..da030ff883d570683603ca041a636b634a42181c 100644 (file)
@@ -183,7 +183,7 @@ static int davinci_vcif_startup(struct snd_pcm_substream *substream,
 
 #define DAVINCI_VCIF_RATES     SNDRV_PCM_RATE_8000_48000
 
-static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
+static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
        .startup        = davinci_vcif_startup,
        .trigger        = davinci_vcif_trigger,
        .hw_params      = davinci_vcif_hw_params,
@@ -210,7 +210,9 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        struct davinci_vcif_dev *davinci_vcif_dev;
        int ret;
 
-       davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL);
+       davinci_vcif_dev = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct davinci_vcif_dev),
+                                       GFP_KERNEL);
        if (!davinci_vcif_dev) {
                dev_dbg(&pdev->dev,
                        "could not allocate memory for private data\n");
@@ -235,23 +237,15 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
        if (ret != 0) {
                dev_err(&pdev->dev, "could not register dai\n");
-               goto fail;
+               return ret;
        }
 
        return 0;
-
-fail:
-       kfree(davinci_vcif_dev);
-
-       return ret;
 }
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-       struct davinci_vcif_dev *davinci_vcif_dev = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_dai(&pdev->dev);
-       kfree(davinci_vcif_dev);
 
        return 0;
 }
@@ -265,17 +259,7 @@ static struct platform_driver davinci_vcif_driver = {
        },
 };
 
-static int __init davinci_vcif_init(void)
-{
-       return platform_driver_probe(&davinci_vcif_driver, davinci_vcif_probe);
-}
-module_init(davinci_vcif_init);
-
-static void __exit davinci_vcif_exit(void)
-{
-       platform_driver_unregister(&davinci_vcif_driver);
-}
-module_exit(davinci_vcif_exit);
+module_platform_driver(davinci_vcif_driver);
 
 MODULE_AUTHOR("Miguel Aguilar");
 MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");
index 51930b6a83af193f3f802df490df3f00b7930cd1..bae5cbbbd2b2d28c817c954f25e6dfc08faed22c 100644 (file)
@@ -48,18 +48,6 @@ static int edb93xx_hw_params(struct snd_pcm_substream *substream,
        else
                mclk_rate = rate * 64 * 2;
 
-       err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (err)
-               return err;
-
-       err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (err)
-               return err;
-
        err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
                                     SND_SOC_CLOCK_IN);
        if (err)
@@ -80,11 +68,14 @@ static struct snd_soc_dai_link edb93xx_dai = {
        .cpu_dai_name   = "ep93xx-i2s",
        .codec_name     = "spi0.0",
        .codec_dai_name = "cs4271-hifi",
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+                         SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &edb93xx_ops,
 };
 
 static struct snd_soc_card snd_soc_edb93xx = {
        .name           = "EDB93XX",
+       .owner          = THIS_MODULE,
        .dai_link       = &edb93xx_dai,
        .num_links      = 1,
 };
@@ -131,17 +122,7 @@ static struct platform_driver edb93xx_driver = {
        .remove         = __devexit_p(edb93xx_remove),
 };
 
-static int __init edb93xx_init(void)
-{
-       return platform_driver_register(&edb93xx_driver);
-}
-module_init(edb93xx_init);
-
-static void __exit edb93xx_exit(void)
-{
-       platform_driver_unregister(&edb93xx_driver);
-}
-module_exit(edb93xx_exit);
+module_platform_driver(edb93xx_driver);
 
 MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
 MODULE_DESCRIPTION("ALSA SoC EDB93xx");
index 3cd6158d83e13f486e8c564cbef8ac809b2d7af8..0678637abd66c6110524fa7bd3ee17d8e4abf8d9 100644 (file)
@@ -330,7 +330,7 @@ static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
+static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
        .startup        = ep93xx_ac97_startup,
        .trigger        = ep93xx_ac97_trigger,
 };
@@ -449,17 +449,7 @@ static struct platform_driver ep93xx_ac97_driver = {
        },
 };
 
-static int __init ep93xx_ac97_init(void)
-{
-       return platform_driver_register(&ep93xx_ac97_driver);
-}
-module_init(ep93xx_ac97_init);
-
-static void __exit ep93xx_ac97_exit(void)
-{
-       platform_driver_unregister(&ep93xx_ac97_driver);
-}
-module_exit(ep93xx_ac97_exit);
+module_platform_driver(ep93xx_ac97_driver);
 
 MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
index 099614e16651bb78c78e0c805aa56c72c97fe9e9..f7a62348e3fe022a3bc7ba4faa06b9e19f5c23a0 100644 (file)
@@ -338,7 +338,7 @@ static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
 #define ep93xx_i2s_resume      NULL
 #endif
 
-static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
        .startup        = ep93xx_i2s_startup,
        .shutdown       = ep93xx_i2s_shutdown,
        .hw_params      = ep93xx_i2s_hw_params,
@@ -464,18 +464,7 @@ static struct platform_driver ep93xx_i2s_driver = {
        },
 };
 
-static int __init ep93xx_i2s_init(void)
-{
-       return platform_driver_register(&ep93xx_i2s_driver);
-}
-
-static void __exit ep93xx_i2s_exit(void)
-{
-       platform_driver_unregister(&ep93xx_i2s_driver);
-}
-
-module_init(ep93xx_i2s_init);
-module_exit(ep93xx_i2s_exit);
+module_platform_driver(ep93xx_i2s_driver);
 
 MODULE_ALIAS("platform:ep93xx-i2s");
 MODULE_AUTHOR("Ryan Mallon");
index d00230a591b19efc8f4df849b7dbe07cb6cb665c..3fc96130d1a6b0ccb76470e979eb34896682e965 100644 (file)
@@ -286,7 +286,6 @@ static u64 ep93xx_pcm_dmamask = 0xffffffff;
 static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -295,14 +294,14 @@ static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -339,18 +338,7 @@ static struct platform_driver ep93xx_pcm_driver = {
        .remove = __devexit_p(ep93xx_soc_platform_remove),
 };
 
-static int __init ep93xx_soc_platform_init(void)
-{
-       return platform_driver_register(&ep93xx_pcm_driver);
-}
-
-static void __exit ep93xx_soc_platform_exit(void)
-{
-       platform_driver_unregister(&ep93xx_pcm_driver);
-}
-
-module_init(ep93xx_soc_platform_init);
-module_exit(ep93xx_soc_platform_exit);
+module_platform_driver(ep93xx_pcm_driver);
 
 MODULE_AUTHOR("Ryan Mallon");
 MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
index 968cb316d5115cf0d99bebf6d1fb1a47aef3a4e8..dd997094eb301f8134b0b11db3a12ac6ed16d782 100644 (file)
@@ -34,6 +34,7 @@ static struct snd_soc_dai_link simone_dai = {
 
 static struct snd_soc_card snd_soc_simone = {
        .name           = "Sim.One",
+       .owner          = THIS_MODULE,
        .dai_link       = &simone_dai,
        .num_links      = 1,
 };
@@ -81,17 +82,7 @@ static struct platform_driver simone_driver = {
        .remove         = __devexit_p(simone_remove),
 };
 
-static int __init simone_init(void)
-{
-       return platform_driver_register(&simone_driver);
-}
-module_init(simone_init);
-
-static void __exit simone_exit(void)
-{
-       platform_driver_unregister(&simone_driver);
-}
-module_exit(simone_exit);
+module_platform_driver(simone_driver);
 
 MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
index 2cde43321eecc44545a9a1415c9b96d1780f3766..ccae34a3f280dc08d8e33942389f46b27215ec87 100644 (file)
@@ -33,16 +33,6 @@ static int snappercl15_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
-       err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-
-       err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 
-                                 SND_SOC_DAIFMT_NB_IF |                  
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (err)
-               return err;
-
        err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, 
                                     SND_SOC_CLOCK_IN);
        if (err)
@@ -96,11 +86,14 @@ static struct snd_soc_dai_link snappercl15_dai = {
        .codec_name     = "tlv320aic23-codec.0-001a",
        .platform_name  =  "ep93xx-pcm-audio",
        .init           = snappercl15_tlv320aic23_init,
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
+                         SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &snappercl15_ops,
 };
 
 static struct snd_soc_card snd_soc_snappercl15 = {
        .name           = "Snapper CL15",
+       .owner          = THIS_MODULE,
        .dai_link       = &snappercl15_dai,
        .num_links      = 1,
 };
@@ -147,18 +140,7 @@ static struct platform_driver snappercl15_driver = {
        .remove         = __devexit_p(snappercl15_remove),
 };
 
-static int __init snappercl15_init(void)
-{
-       return platform_driver_register(&snappercl15_driver);
-}
-
-static void __exit snappercl15_exit(void)
-{
-       platform_driver_unregister(&snappercl15_driver);
-}
-
-module_init(snappercl15_init);
-module_exit(snappercl15_exit);
+module_platform_driver(snappercl15_driver);
 
 MODULE_AUTHOR("Ryan Mallon");
 MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
index 108b5d8bd0e944bc2f0525c930c35df643e1a500..b2acd3293ea886217290ede96d0c3350cc07f7fe 100644 (file)
@@ -31,8 +31,6 @@
 
 #define DRV_NAME "efika-audio-fabric"
 
-static struct snd_soc_card card;
-
 static struct snd_soc_dai_link efika_fabric_dai[] = {
 {
        .name = "AC97",
@@ -52,6 +50,13 @@ static struct snd_soc_dai_link efika_fabric_dai[] = {
 },
 };
 
+static struct snd_soc_card card = {
+       .name = "Efika",
+       .owner = THIS_MODULE,
+       .dai_link = efika_fabric_dai,
+       .num_links = ARRAY_SIZE(efika_fabric_dai),
+};
+
 static __init int efika_fabric_init(void)
 {
        struct platform_device *pdev;
@@ -60,11 +65,6 @@ static __init int efika_fabric_init(void)
        if (!of_machine_is_compatible("bplan,efika"))
                return -ENODEV;
 
-       card.name = "Efika";
-       card.dai_link = efika_fabric_dai;
-       card.num_links = ARRAY_SIZE(efika_fabric_dai);
-
-
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
                pr_err("efika_fabric_init: platform_device_alloc() failed\n");
index ef15402a3bc4948311c69b4b69da9ebd7055ee58..4f59bbaba48f4fcb8ae70e0ced615f19ab71404e 100644 (file)
@@ -992,20 +992,7 @@ static struct platform_driver fsl_soc_dma_driver = {
        .remove = __devexit_p(fsl_soc_dma_remove),
 };
 
-static int __init fsl_soc_dma_init(void)
-{
-       pr_info("Freescale Elo DMA ASoC PCM Driver\n");
-
-       return platform_driver_register(&fsl_soc_dma_driver);
-}
-
-static void __exit fsl_soc_dma_exit(void)
-{
-       platform_driver_unregister(&fsl_soc_dma_driver);
-}
-
-module_init(fsl_soc_dma_init);
-module_exit(fsl_soc_dma_exit);
+module_platform_driver(fsl_soc_dma_driver);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
index 83c4bd5b2dd76bbf3f401c5a6bf0159d337f29b4..3e066966d8783f8c7e558c9c8677b64406c6b17b 100644 (file)
@@ -514,7 +514,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
-static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
        .hw_params      = fsl_ssi_hw_params,
        .shutdown       = fsl_ssi_shutdown,
@@ -793,20 +793,7 @@ static struct platform_driver fsl_ssi_driver = {
        .remove = fsl_ssi_remove,
 };
 
-static int __init fsl_ssi_init(void)
-{
-       printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
-
-       return platform_driver_register(&fsl_ssi_driver);
-}
-
-static void __exit fsl_ssi_exit(void)
-{
-       platform_driver_unregister(&fsl_ssi_driver);
-}
-
-module_init(fsl_ssi_init);
-module_exit(fsl_ssi_exit);
+module_platform_driver(fsl_ssi_driver);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
index 5c6c2457386e9145dfaa513697c425f372f1cbfd..e7803d34c425a35a8be366ccd5b9324b8eb41cad 100644 (file)
@@ -526,17 +526,7 @@ static struct platform_driver mpc5200_hpcd_of_driver = {
        }
 };
 
-static int __init mpc5200_hpcd_init(void)
-{
-       return platform_driver_register(&mpc5200_hpcd_of_driver);
-}
-module_init(mpc5200_hpcd_init);
-
-static void __exit mpc5200_hpcd_exit(void)
-{
-       platform_driver_unregister(&mpc5200_hpcd_of_driver);
-}
-module_exit(mpc5200_hpcd_exit);
+module_platform_driver(mpc5200_hpcd_of_driver);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
index ad36b095bb79ce268ba754a2dbe95446b510efc4..ffa00a2eb7704439341debdcf7cafe2310e4ce94 100644 (file)
@@ -226,12 +226,12 @@ static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
 /**
  * psc_ac97_dai_template: template CPU Digital Audio Interface
  */
-static struct snd_soc_dai_ops psc_ac97_analog_ops = {
+static const struct snd_soc_dai_ops psc_ac97_analog_ops = {
        .hw_params      = psc_ac97_hw_analog_params,
        .trigger        = psc_ac97_trigger,
 };
 
-static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
        .hw_params      = psc_ac97_hw_digital_params,
 };
 
@@ -325,21 +325,7 @@ static struct platform_driver psc_ac97_driver = {
        },
 };
 
-/* ---------------------------------------------------------------------
- * Module setup and teardown; simply register the of_platform driver
- * for the PSC in AC97 mode.
- */
-static int __init psc_ac97_init(void)
-{
-       return platform_driver_register(&psc_ac97_driver);
-}
-module_init(psc_ac97_init);
-
-static void __exit psc_ac97_exit(void)
-{
-       platform_driver_unregister(&psc_ac97_driver);
-}
-module_exit(psc_ac97_exit);
+module_platform_driver(psc_ac97_driver);
 
 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
 MODULE_DESCRIPTION("mpc5200 AC97 module");
index 87cf2a5c2b2c2957e77fb17e94fa36038e6e318c..7b530327553ad998f0cdf81635e3af218418e414 100644 (file)
@@ -123,7 +123,7 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 /**
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
-static struct snd_soc_dai_ops psc_i2s_dai_ops = {
+static const struct snd_soc_dai_ops psc_i2s_dai_ops = {
        .hw_params      = psc_i2s_hw_params,
        .set_sysclk     = psc_i2s_set_sysclk,
        .set_fmt        = psc_i2s_set_fmt,
@@ -222,21 +222,7 @@ static struct platform_driver psc_i2s_driver = {
        },
 };
 
-/* ---------------------------------------------------------------------
- * Module setup and teardown; simply register the of_platform driver
- * for the PSC in I2S mode.
- */
-static int __init psc_i2s_init(void)
-{
-       return platform_driver_register(&psc_i2s_driver);
-}
-module_init(psc_i2s_init);
-
-static void __exit psc_i2s_exit(void)
-{
-       platform_driver_unregister(&psc_i2s_driver);
-}
-module_exit(psc_i2s_exit);
+module_platform_driver(psc_i2s_driver);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
index ae49f1c78c6de797bd193946b1d350aa00bd8a40..0ea4a5a96e06533e53ae95e5bebd60cdc16e7832 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
+#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
@@ -249,8 +250,9 @@ static int get_parent_cell_index(struct device_node *np)
 static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 {
        const u32 *iprop;
-       int bus, addr;
+       int addr;
        char temp[DAI_NAME_SIZE];
+       struct i2c_client *i2c;
 
        of_modalias_node(np, temp, DAI_NAME_SIZE);
 
@@ -260,11 +262,12 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 
        addr = be32_to_cpup(iprop);
 
-       bus = get_parent_cell_index(np);
-       if (bus < 0)
-               return bus;
+       /* We need the adapter number */
+       i2c = of_find_i2c_device_by_node(np);
+       if (!i2c)
+               return -ENODEV;
 
-       snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+       snprintf(buf, len, "%s-codec.%u-%04x", temp, i2c->adapter->nr, addr);
 
        return 0;
 }
index 2c064a9824adf84d345829be5d6d80544df5c7d8..a5d4e80a9cf441140d017c8a0228770761999661 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
+#include <linux/of_i2c.h>
 #include <sound/soc.h>
 #include <asm/fsl_guts.h>
 
@@ -252,8 +253,9 @@ static int get_parent_cell_index(struct device_node *np)
 static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 {
        const u32 *iprop;
-       int bus, addr;
+       int addr;
        char temp[DAI_NAME_SIZE];
+       struct i2c_client *i2c;
 
        of_modalias_node(np, temp, DAI_NAME_SIZE);
 
@@ -263,11 +265,12 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 
        addr = be32_to_cpup(iprop);
 
-       bus = get_parent_cell_index(np);
-       if (bus < 0)
-               return bus;
+       /* We need the adapter number */
+       i2c = of_find_i2c_device_by_node(np);
+       if (!i2c)
+               return -ENODEV;
 
-       snprintf(buf, len, "%s.%u-%04x", temp, bus, addr);
+       snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
 
        return 0;
 }
@@ -540,12 +543,6 @@ static struct platform_driver p1022_ds_driver = {
        .probe = p1022_ds_probe,
        .remove = __devexit_p(p1022_ds_remove),
        .driver = {
-               /* The name must match the 'model' property in the device tree,
-                * in lowercase letters, but only the part after that last
-                * comma.  This is because some model properties have a "fsl,"
-                * prefix.
-                */
-               .name = "snd-soc-p1022",
                .owner = THIS_MODULE,
        },
 };
@@ -559,13 +556,39 @@ static int __init p1022_ds_init(void)
 {
        struct device_node *guts_np;
        struct resource res;
+       const char *sprop;
+
+       /*
+        * Check if we're actually running on a P1022DS.  Older device trees
+        * have a model of "fsl,P1022" and newer ones use "fsl,P1022DS", so we
+        * need to support both.  The SSI driver uses that property to link to
+        * the machine driver, so have to match it.
+        */
+       sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+       if (!sprop) {
+               pr_err("snd-soc-p1022ds: missing /model node");
+               return -ENODEV;
+       }
+
+       pr_debug("snd-soc-p1022ds: board model name is %s\n", sprop);
 
-       pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
+       /*
+        * The name of this board, taken from the device tree.  Normally, this is a*
+        * fixed string, but some P1022DS device trees have a /model property of
+        * "fsl,P1022", and others have "fsl,P1022DS".
+        */
+       if (strcasecmp(sprop, "fsl,p1022ds") == 0)
+               p1022_ds_driver.driver.name = "snd-soc-p1022ds";
+       else if (strcasecmp(sprop, "fsl,p1022") == 0)
+               p1022_ds_driver.driver.name = "snd-soc-p1022";
+       else
+               return -ENODEV;
 
        /* Get the physical address of the global utilities registers */
        guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
        if (of_address_to_resource(guts_np, 0, &res)) {
-               pr_err("p1022-ds: missing/invalid global utilities node\n");
+               pr_err("snd-soc-p1022ds: missing/invalid global utils node\n");
+               of_node_put(guts_np);
                return -EINVAL;
        }
        guts_phys = res.start;
index ba4d85e317ed459907601b1df426738ddf88ee68..b3af55dcde9de54bbe2547e0ef16dcc2ce9288df 100644 (file)
@@ -31,8 +31,6 @@
 
 #define DRV_NAME "pcm030-audio-fabric"
 
-static struct snd_soc_card card;
-
 static struct snd_soc_dai_link pcm030_fabric_dai[] = {
 {
        .name = "AC97",
@@ -52,6 +50,13 @@ static struct snd_soc_dai_link pcm030_fabric_dai[] = {
 },
 };
 
+static struct snd_soc_card card = {
+       .name = "pcm030",
+       .owner = THIS_MODULE,
+       .dai_link = pcm030_fabric_dai,
+       .num_links = ARRAY_SIZE(pcm030_fabric_dai),
+};
+
 static __init int pcm030_fabric_init(void)
 {
        struct platform_device *pdev;
@@ -60,11 +65,6 @@ static __init int pcm030_fabric_init(void)
        if (!of_machine_is_compatible("phytec,pcm030"))
                return -ENODEV;
 
-
-       card.name = "pcm030";
-       card.dai_link = pcm030_fabric_dai;
-       card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
-
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
                pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
index 75fb4b83548bffe68884cd9c7a77c5b5c5659af4..1c1fdd10f73f6b39e39f01a318d3df3bc6ad74f5 100644 (file)
@@ -87,6 +87,7 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
 
 static struct snd_soc_card eukrea_tlv320 = {
        .name           = "cpuimx-audio",
+       .owner          = THIS_MODULE,
        .dai_link       = &eukrea_tlv320_dai,
        .num_links      = 1,
 };
index 43fdc24f7e8d6fdf323f096fee6c01682c433a24..1cf2fe889f6adaa885c77bf2c74da9dd9f56a3d8 100644 (file)
@@ -326,16 +326,6 @@ static struct platform_driver imx_pcm_driver = {
        .remove = __devexit_p(imx_soc_platform_remove),
 };
 
-static int __init snd_imx_pcm_init(void)
-{
-       return platform_driver_register(&imx_pcm_driver);
-}
-module_init(snd_imx_pcm_init);
-
-static void __exit snd_imx_pcm_exit(void)
-{
-       platform_driver_unregister(&imx_pcm_driver);
-}
-module_exit(snd_imx_pcm_exit);
+module_platform_driver(imx_pcm_driver);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:imx-pcm-audio");
index 8df0fae21943b64d9bb99ffd462b679592a69742..456b7d723d6660176acbfb82436cf2f938985bab 100644 (file)
@@ -331,14 +331,6 @@ static struct platform_driver imx_pcm_driver = {
        .remove = __devexit_p(imx_soc_platform_remove),
 };
 
-static int __init snd_imx_pcm_init(void)
-{
-       return platform_driver_register(&imx_pcm_driver);
-}
-module_init(snd_imx_pcm_init);
+module_platform_driver(imx_pcm_driver);
 
-static void __exit snd_imx_pcm_exit(void)
-{
-       platform_driver_unregister(&imx_pcm_driver);
-}
-module_exit(snd_imx_pcm_exit);
+MODULE_LICENSE("GPL");
index 4c05e2b8f4d2bf3bd09309c5e254e8bce02814b6..01d1f749cf021908ead5cb27e30966a17f144ca6 100644 (file)
@@ -342,7 +342,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
+static const 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,
@@ -757,18 +757,7 @@ static struct platform_driver imx_ssi_driver = {
        },
 };
 
-static int __init imx_ssi_init(void)
-{
-       return platform_driver_register(&imx_ssi_driver);
-}
-
-static void __exit imx_ssi_exit(void)
-{
-       platform_driver_unregister(&imx_ssi_driver);
-}
-
-module_init(imx_ssi_init);
-module_exit(imx_ssi_exit);
+module_platform_driver(imx_ssi_driver);
 
 /* Module information */
 MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
index 054110b91d42da07cf6c37a95a8b706d681d411c..3c2eed9094d57b135594ae3cd444c498cf19459a 100644 (file)
@@ -86,6 +86,7 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
 
 static struct snd_soc_card mx27vis_aic32x4 = {
        .name           = "visstrim_m10-audio",
+       .owner          = THIS_MODULE,
        .dai_link       = &mx27vis_aic32x4_dai,
        .num_links      = 1,
 };
index a7deb5cb2433d575997e61624efa01be616cd2fa..6ac12111de6a4ad108be9a0d39684389cc8b3c49 100644 (file)
@@ -38,6 +38,7 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
 
 static struct snd_soc_card imx_phycore = {
        .name           = "PhyCORE-ac97-audio",
+       .owner          = THIS_MODULE,
        .dai_link       = imx_phycore_dai_ac97,
        .num_links      = ARRAY_SIZE(imx_phycore_dai_ac97),
 };
index 490a1260c228c059acdbb6d2f0324c2b782b2431..37480c90e9979265e43171326d4bfab6310d25f5 100644 (file)
@@ -255,6 +255,7 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
 
 static struct snd_soc_card wm1133_ev1 = {
        .name = "WM1133-EV1",
+       .owner = THIS_MODULE,
        .dai_link = &wm1133_ev1_dai,
        .num_links = 1,
 };
index cd22a54b2f14b3cd408d64acbbc519786320f573..a5af7c42e62bb7ce641e13d3635c3c5312fc167b 100644 (file)
@@ -392,7 +392,7 @@ static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
+static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
        .startup = jz4740_i2s_startup,
        .shutdown = jz4740_i2s_shutdown,
        .trigger = jz4740_i2s_trigger,
@@ -519,17 +519,7 @@ static struct platform_driver jz4740_i2s_driver = {
        },
 };
 
-static int __init jz4740_i2s_init(void)
-{
-       return platform_driver_register(&jz4740_i2s_driver);
-}
-module_init(jz4740_i2s_init);
-
-static void __exit jz4740_i2s_exit(void)
-{
-       platform_driver_unregister(&jz4740_i2s_driver);
-}
-module_exit(jz4740_i2s_exit);
+module_platform_driver(jz4740_i2s_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
 MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver");
index d1989cde9f14d0d442531066f96b2a6e9c4f3525..9b8cf256847d1ef8ace03ee8b0a94a1735a03eae 100644 (file)
@@ -302,7 +302,6 @@ static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
 static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -312,14 +311,14 @@ static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto err;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -356,17 +355,7 @@ static struct platform_driver jz4740_pcm_driver = {
        },
 };
 
-static int __init jz4740_soc_platform_init(void)
-{
-       return platform_driver_register(&jz4740_pcm_driver);
-}
-module_init(jz4740_soc_platform_init);
-
-static void __exit jz4740_soc_platform_exit(void)
-{
-       return platform_driver_unregister(&jz4740_pcm_driver);
-}
-module_exit(jz4740_soc_platform_exit);
+module_platform_driver(jz4740_pcm_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
index c5fc339f68f1b792bf42932c8390590d5c4a058e..0097c3b13a1a31a1e1d48c99d71d62d3db72281d 100644 (file)
@@ -81,6 +81,7 @@ static struct snd_soc_dai_link qi_lb60_dai = {
 
 static struct snd_soc_card qi_lb60 = {
        .name = "QI LB60",
+       .owner = THIS_MODULE,
        .dai_link = &qi_lb60_dai,
        .num_links = 1,
 
index df12e0993f5a1fc394850ecce3ab38ed7a89ce76..d038540271285f90b8d093643fcfeb7de07cc8b6 100644 (file)
@@ -318,7 +318,6 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
 static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret;
 
@@ -327,14 +326,14 @@ static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -391,17 +390,7 @@ static struct platform_driver kirkwood_pcm_driver = {
        .remove = __devexit_p(kirkwood_soc_platform_remove),
 };
 
-static int __init kirkwood_pcm_init(void)
-{
-       return platform_driver_register(&kirkwood_pcm_driver);
-}
-module_init(kirkwood_pcm_init);
-
-static void __exit kirkwood_pcm_exit(void)
-{
-       platform_driver_unregister(&kirkwood_pcm_driver);
-}
-module_exit(kirkwood_pcm_exit);
+module_platform_driver(kirkwood_pcm_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
index 715e841c05072edeb469f1e99dc4aa60ad2821c5..3cb9aa4299d38ff3845dfc83b96c7b701f73cea5 100644 (file)
@@ -373,7 +373,7 @@ static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
        .startup        = kirkwood_i2s_startup,
        .trigger        = kirkwood_i2s_trigger,
        .hw_params      = kirkwood_i2s_hw_params,
@@ -441,13 +441,12 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                goto err_ioremap;
        }
 
-       if (!data || !data->dram) {
+       if (!data) {
                dev_err(&pdev->dev, "no platform data ?!\n");
                err = -EINVAL;
                goto err_ioremap;
        }
 
-       priv->dram = data->dram;
        priv->burst = data->burst;
 
        return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
@@ -483,17 +482,7 @@ static struct platform_driver kirkwood_i2s_driver = {
        },
 };
 
-static int __init kirkwood_i2s_init(void)
-{
-       return platform_driver_register(&kirkwood_i2s_driver);
-}
-module_init(kirkwood_i2s_init);
-
-static void __exit kirkwood_i2s_exit(void)
-{
-       platform_driver_unregister(&kirkwood_i2s_driver);
-}
-module_exit(kirkwood_i2s_exit);
+module_platform_driver(kirkwood_i2s_driver);
 
 /* Module information */
 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
index d863afb3ee521098b36a1a7b4a50293a52903082..55d2ed3df30d6296dfaad03857e64ddde5505775 100644 (file)
@@ -26,18 +26,7 @@ static int openrd_client_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-       unsigned int freq, fmt;
-
-       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0)
-               return ret;
+       unsigned int freq;
 
        switch (params_rate(params)) {
        default:
@@ -69,6 +58,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
        .platform_name = "kirkwood-pcm-audio",
        .codec_dai_name = "cs42l51-hifi",
        .codec_name = "cs42l51-codec.0-004a",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
        .ops = &openrd_client_ops,
 },
 };
@@ -76,6 +66,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 
 static struct snd_soc_card openrd_client = {
        .name = "OpenRD Client",
+       .owner = THIS_MODULE,
        .dai_link = openrd_client_dai,
        .num_links = ARRAY_SIZE(openrd_client_dai),
 };
index c772b3cf4039f77386dbc4d77551b70a0e8a1323..b47cc4e9b746a39dc7d91e86244d430c03b0fde3 100644 (file)
@@ -25,18 +25,7 @@ static int t5325_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-       unsigned int freq, fmt;
-
-       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0)
-               return ret;
+       unsigned int freq;
 
        freq = params_rate(params) * 256;
 
@@ -70,11 +59,6 @@ static int t5325_dai_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(dapm, t5325_dapm_widgets,
-                               ARRAY_SIZE(t5325_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, t5325_route, ARRAY_SIZE(t5325_route));
-
        snd_soc_dapm_enable_pin(dapm, "Mic Jack");
        snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        snd_soc_dapm_enable_pin(dapm, "Speaker");
@@ -90,6 +74,7 @@ static struct snd_soc_dai_link t5325_dai[] = {
        .platform_name = "kirkwood-pcm-audio",
        .codec_dai_name = "alc5621-hifi",
        .codec_name = "alc562x-codec.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
        .ops = &t5325_ops,
        .init = t5325_dai_init,
 },
@@ -98,8 +83,14 @@ static struct snd_soc_dai_link t5325_dai[] = {
 
 static struct snd_soc_card t5325 = {
        .name = "t5325",
+       .owner = THIS_MODULE,
        .dai_link = t5325_dai,
        .num_links = ARRAY_SIZE(t5325_dai),
+
+       .dapm_widgets = t5325_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(t5325_dapm_widgets),
+       .dapm_routes = t5325_route,
+       .num_dapm_routes = ARRAY_SIZE(t5325_route),
 };
 
 static struct platform_device *t5325_snd_device;
index bb6e6a5648c9b73687900b28ec9f6d12e770412d..9047436b3937248c91ba8a3630176dd169bd2fd5 100644 (file)
@@ -123,7 +123,6 @@ struct kirkwood_dma_data {
        void __iomem *io;
        int irq;
        int burst;
-       struct mbus_dram_target_info *dram;
 };
 
 #endif
index 29350428f1c2a4e5a078ca446eb6e076abaacb00..61c10bf503d229f7a191a12ceb17232b63af4597 100644 (file)
@@ -1,7 +1,6 @@
 config SND_MFLD_MACHINE
        tristate "SOC Machine Audio driver for Intel Medfield MID platform"
        depends on INTEL_SCU_IPC
-       depends on SND_INTEL_SST
        select SND_SOC_SN95031
        select SND_SST_PLATFORM
        help
index cca693ae1bd444e5b12d7617f56a160453dafd9e..6f77eef0f13164b08507c15a1c554e9a1f35c9dc 100644 (file)
@@ -281,7 +281,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
        return ret_val;
 }
 
-struct snd_soc_dai_link mfld_msic_dailink[] = {
+static struct snd_soc_dai_link mfld_msic_dailink[] = {
        {
                .name = "Medfield Headset",
                .stream_name = "Headset",
@@ -323,6 +323,7 @@ struct snd_soc_dai_link mfld_msic_dailink[] = {
 /* SoC card */
 static struct snd_soc_card snd_soc_card_mfld = {
        .name = "medfield_audio",
+       .owner = THIS_MODULE,
        .dai_link = mfld_msic_dailink,
        .num_links = ARRAY_SIZE(mfld_msic_dailink),
 };
@@ -428,19 +429,7 @@ static struct platform_driver snd_mfld_mc_driver = {
        .remove = __devexit_p(snd_mfld_mc_remove),
 };
 
-static int __init snd_mfld_driver_init(void)
-{
-       pr_debug("snd_mfld_driver_init called\n");
-       return platform_driver_register(&snd_mfld_mc_driver);
-}
-module_init(snd_mfld_driver_init);
-
-static void __exit snd_mfld_driver_exit(void)
-{
-       pr_debug("snd_mfld_driver_exit called\n");
-       platform_driver_unregister(&snd_mfld_mc_driver);
-}
-module_exit(snd_mfld_driver_exit);
+module_platform_driver(snd_mfld_mc_driver);
 
 MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
index 23057020aa0fb01abff851ae0fa4e3f75d9cf30c..d34563b12c3b4e4579a33aa57df16e1738409a66 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h"
-#include "../../../drivers/staging/intel_sst/intel_sst.h"
 #include "sst_platform.h"
 
+static struct sst_device *sst;
+static DEFINE_MUTEX(sst_lock);
+
+int sst_register_dsp(struct sst_device *dev)
+{
+       BUG_ON(!dev);
+       if (!try_module_get(dev->dev->driver->owner))
+               return -ENODEV;
+       mutex_lock(&sst_lock);
+       if (sst) {
+               pr_err("we already have a device %s\n", sst->name);
+               module_put(dev->dev->driver->owner);
+               mutex_unlock(&sst_lock);
+               return -EEXIST;
+       }
+       pr_debug("registering device %s\n", dev->name);
+       sst = dev;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_register_dsp);
+
+int sst_unregister_dsp(struct sst_device *dev)
+{
+       BUG_ON(!dev);
+       if (dev != sst)
+               return -EINVAL;
+
+       mutex_lock(&sst_lock);
+
+       if (!sst) {
+               mutex_unlock(&sst_lock);
+               return -EIO;
+       }
+
+       module_put(sst->dev->driver->owner);
+       pr_debug("unreg %s\n", sst->name);
+       sst = NULL;
+       mutex_unlock(&sst_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sst_unregister_dsp);
+
 static struct snd_pcm_hardware sst_platform_pcm_hw = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED |
                        SNDRV_PCM_INFO_DOUBLE |
@@ -135,37 +176,34 @@ static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
 }
 
 static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
-                               struct snd_sst_stream_params *param)
+                               struct sst_pcm_params *param)
 {
 
-       param->uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
-       param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
-       param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
-       param->uc.pcm_params.reserved = 0;
-       param->uc.pcm_params.sfreq = substream->runtime->rate;
-       param->uc.pcm_params.ring_buffer_size =
-                                       snd_pcm_lib_buffer_bytes(substream);
-       param->uc.pcm_params.period_count = substream->runtime->period_size;
-       param->uc.pcm_params.ring_buffer_addr =
-                               virt_to_phys(substream->dma_buffer.area);
-       pr_debug("period_cnt = %d\n", param->uc.pcm_params.period_count);
-       pr_debug("sfreq= %d, wd_sz = %d\n",
-                param->uc.pcm_params.sfreq, param->uc.pcm_params.pcm_wd_sz);
+       param->codec = SST_CODEC_TYPE_PCM;
+       param->num_chan = (u8) substream->runtime->channels;
+       param->pcm_wd_sz = substream->runtime->sample_bits;
+       param->reserved = 0;
+       param->sfreq = substream->runtime->rate;
+       param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream);
+       param->period_count = substream->runtime->period_size;
+       param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area);
+       pr_debug("period_cnt = %d\n", param->period_count);
+       pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz);
 }
 
 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
-       struct snd_sst_stream_params param = {{{0,},},};
-       struct snd_sst_params str_params = {0};
+       struct sst_pcm_params param = {0};
+       struct sst_stream_params str_params = {0};
        int ret_val;
 
        /* set codec params and inform SST driver the same */
        sst_fill_pcm_params(substream, &param);
        substream->runtime->dma_area = substream->dma_buffer.area;
        str_params.sparams = param;
-       str_params.codec =  param.uc.pcm_params.codec;
+       str_params.codec =  param.codec;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                str_params.ops = STREAM_OPS_PLAYBACK;
                str_params.device_type = substream->pcm->device + 1;
@@ -177,7 +215,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
                pr_debug("Capture stream,Device %d\n",
                                        substream->pcm->device);
        }
-       ret_val = stream->sstdrv_ops->pcm_control->open(&str_params);
+       ret_val = stream->ops->open(&str_params);
        pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
        if (ret_val < 0)
                return ret_val;
@@ -216,7 +254,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
        stream->stream_info.mad_substream = substream;
        stream->stream_info.buffer_ptr = 0;
        stream->stream_info.sfreq = substream->runtime->rate;
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(
+       ret_val = stream->ops->device_control(
                        SST_SND_STREAM_INIT, &stream->stream_info);
        if (ret_val)
                pr_err("control_set ret error %d\n", ret_val);
@@ -229,7 +267,7 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct sst_runtime_stream *stream;
-       int ret_val = 0;
+       int ret_val;
 
        pr_debug("sst_platform_open called\n");
 
@@ -243,27 +281,27 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
        if (!stream)
                return -ENOMEM;
        spin_lock_init(&stream->status_lock);
-       stream->stream_info.str_id = 0;
-       sst_set_stream_status(stream, SST_PLATFORM_INIT);
-       stream->stream_info.mad_substream = substream;
-       /* allocate memory for SST API set */
-       stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops),
-                                                       GFP_KERNEL);
-       if (!stream->sstdrv_ops) {
-               pr_err("sst: mem allocation for ops fail\n");
+
+       /* get the sst ops */
+       mutex_lock(&sst_lock);
+       if (!sst) {
+               pr_err("no device available to run\n");
+               mutex_unlock(&sst_lock);
                kfree(stream);
-               return -ENOMEM;
+               return -ENODEV;
        }
-       stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
-       stream->sstdrv_ops->module_name = SST_CARD_NAMES;
-       /* registering with SST driver to get access to SST APIs to use */
-       ret_val = register_sst_card(stream->sstdrv_ops);
-       if (ret_val) {
-               pr_err("sst: sst card registration failed\n");
-               kfree(stream->sstdrv_ops);
+       if (!try_module_get(sst->dev->driver->owner)) {
+               mutex_unlock(&sst_lock);
                kfree(stream);
-               return ret_val;
+               return -ENODEV;
        }
+       stream->ops = sst->ops;
+       mutex_unlock(&sst_lock);
+
+       stream->stream_info.str_id = 0;
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       stream->stream_info.mad_substream = substream;
+       /* allocate memory for SST API set */
        runtime->private_data = stream;
 
        return 0;
@@ -278,9 +316,8 @@ static int sst_platform_close(struct snd_pcm_substream *substream)
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        if (str_id)
-               ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
-       unregister_sst_card(stream->sstdrv_ops);
-       kfree(stream->sstdrv_ops);
+               ret_val = stream->ops->close(str_id);
+       module_put(sst->dev->driver->owner);
        kfree(stream);
        return ret_val;
 }
@@ -294,8 +331,8 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        if (stream->stream_info.str_id) {
-               ret_val = stream->sstdrv_ops->pcm_control->device_control(
-                                       SST_SND_DROP, &str_id);
+               ret_val = stream->ops->device_control(
+                               SST_SND_DROP, &str_id);
                return ret_val;
        }
 
@@ -347,8 +384,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
        default:
                return -EINVAL;
        }
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(str_cmd,
-                                                               &str_id);
+       ret_val = stream->ops->device_control(str_cmd, &str_id);
        if (!ret_val)
                sst_set_stream_status(stream, status);
 
@@ -368,7 +404,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        if (status == SST_PLATFORM_INIT)
                return 0;
        str_info = &stream->stream_info;
-       ret_val = stream->sstdrv_ops->pcm_control->device_control(
+       ret_val = stream->ops->device_control(
                                SST_SND_BUFFER_POINTER, str_info);
        if (ret_val) {
                pr_err("sst: error code = %d\n", ret_val);
@@ -408,15 +444,14 @@ static void sst_pcm_free(struct snd_pcm *pcm)
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
-int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
+static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int retval = 0;
 
        pr_debug("sst_pcm_new called\n");
-       if (dai->driver->playback.channels_min ||
-                       dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
+                       pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                retval =  snd_pcm_lib_preallocate_pages_for_all(pcm,
                        SNDRV_DMA_TYPE_CONTINUOUS,
                        snd_dma_continuous_data(GFP_KERNEL),
@@ -428,7 +463,7 @@ int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
        return retval;
 }
-struct snd_soc_platform_driver sst_soc_platform_drv = {
+static struct snd_soc_platform_driver sst_soc_platform_drv = {
        .ops            = &sst_platform_ops,
        .pcm_new        = sst_pcm_new,
        .pcm_free       = sst_pcm_free,
@@ -439,6 +474,7 @@ static int sst_platform_probe(struct platform_device *pdev)
        int ret;
 
        pr_debug("sst_platform_probe called\n");
+       sst = NULL;
        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
        if (ret) {
                pr_err("registering soc platform failed\n");
@@ -472,19 +508,7 @@ static struct platform_driver sst_platform_driver = {
        .remove         = sst_platform_remove,
 };
 
-static int __init sst_soc_platform_init(void)
-{
-       pr_debug("sst_soc_platform_init called\n");
-       return platform_driver_register(&sst_platform_driver);
-}
-module_init(sst_soc_platform_init);
-
-static void __exit sst_soc_platform_exit(void)
-{
-       platform_driver_unregister(&sst_platform_driver);
-       pr_debug("sst_soc_platform_exit success\n");
-}
-module_exit(sst_soc_platform_exit);
+module_platform_driver(sst_platform_driver);
 
 MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
 MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
index df370286694f89de7dbfce2cba1a29ae3dfcf7ee..f04f4f72daa0548f9f8e158c9cc96129cf4951fc 100644 (file)
 #define SST_MIN_PERIODS                2
 #define SST_MAX_PERIODS                (1024*2)
 #define SST_FIFO_SIZE          0
-#define SST_CARD_NAMES         "intel_mid_card"
-#define MSIC_VENDOR_ID         3
+#define SST_CODEC_TYPE_PCM     1
 
-struct sst_runtime_stream {
-       int     stream_status;
-       struct pcm_stream_info stream_info;
-       struct intel_sst_card_ops *sstdrv_ops;
-       spinlock_t      status_lock;
+struct pcm_stream_info {
+       int str_id;
+       void *mad_substream;
+       void (*period_elapsed) (void *mad_substream);
+       unsigned long long buffer_ptr;
+       int sfreq;
 };
 
 enum sst_drv_status {
@@ -60,4 +60,72 @@ enum sst_drv_status {
        SST_PLATFORM_DROPPED,
 };
 
+enum sst_controls {
+       SST_SND_ALLOC =                 0x00,
+       SST_SND_PAUSE =                 0x01,
+       SST_SND_RESUME =                0x02,
+       SST_SND_DROP =                  0x03,
+       SST_SND_FREE =                  0x04,
+       SST_SND_BUFFER_POINTER =        0x05,
+       SST_SND_STREAM_INIT =           0x06,
+       SST_SND_START    =              0x07,
+       SST_MAX_CONTROLS =              0x07,
+};
+
+enum sst_stream_ops {
+       STREAM_OPS_PLAYBACK = 0,
+       STREAM_OPS_CAPTURE,
+};
+
+enum sst_audio_device_type {
+       SND_SST_DEVICE_HEADSET = 1,
+       SND_SST_DEVICE_IHF,
+       SND_SST_DEVICE_VIBRA,
+       SND_SST_DEVICE_HAPTIC,
+       SND_SST_DEVICE_CAPTURE,
+};
+
+/* PCM Parameters */
+struct sst_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u32 ring_buffer_size;
+       u32 period_count;       /* period elapsed in samples*/
+       u32 ring_buffer_addr;
+};
+
+struct sst_stream_params {
+       u32 result;
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct sst_pcm_params sparams;
+};
+
+struct sst_ops {
+       int (*open) (struct sst_stream_params *str_param);
+       int (*device_control) (int cmd, void *arg);
+       int (*close) (unsigned int str_id);
+};
+
+struct sst_runtime_stream {
+       int     stream_status;
+       struct pcm_stream_info stream_info;
+       struct sst_ops *ops;
+       spinlock_t      status_lock;
+};
+
+struct sst_device {
+       char *name;
+       struct device *dev;
+       struct sst_ops *ops;
+};
+
+int sst_register_dsp(struct sst_device *sst);
+int sst_unregister_dsp(struct sst_device *sst);
 #endif
index f39d7dd9fbcb5956cf55f989ae0a869bfe7bd336..0e12f4e0a76d60ac10dab9b70ad4e12f80e0d0c7 100644 (file)
@@ -346,17 +346,7 @@ static struct platform_driver mxs_pcm_driver = {
        .remove = __devexit_p(mxs_soc_platform_remove),
 };
 
-static int __init snd_mxs_pcm_init(void)
-{
-       return platform_driver_register(&mxs_pcm_driver);
-}
-module_init(snd_mxs_pcm_init);
-
-static void __exit snd_mxs_pcm_exit(void)
-{
-       platform_driver_unregister(&mxs_pcm_driver);
-}
-module_exit(snd_mxs_pcm_exit);
+module_platform_driver(mxs_pcm_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:mxs-pcm-audio");
index d775b0761e0aff51f483f58895eff5f503bd07c9..dccfb37a96261dd1523ca5e3bf13f1145d0b68e0 100644 (file)
@@ -550,7 +550,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
        (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
        SNDRV_PCM_FMTBIT_S24_LE)
 
-static struct snd_soc_dai_ops mxs_saif_dai_ops = {
+static const struct snd_soc_dai_ops mxs_saif_dai_ops = {
        .startup = mxs_saif_startup,
        .trigger = mxs_saif_trigger,
        .prepare = mxs_saif_prepare,
@@ -779,18 +779,8 @@ static struct platform_driver mxs_saif_driver = {
        },
 };
 
-static int __init mxs_saif_init(void)
-{
-       return platform_driver_register(&mxs_saif_driver);
-}
-
-static void __exit mxs_saif_exit(void)
-{
-       platform_driver_unregister(&mxs_saif_driver);
-}
+module_platform_driver(mxs_saif_driver);
 
-module_init(mxs_saif_init);
-module_exit(mxs_saif_exit);
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("MXS ASoC SAIF driver");
 MODULE_LICENSE("GPL");
index 1c57f6630a48d8ff1e3a626677114bbe8f024f27..60f052b7cf223b6573a1116153552acb76849f0a 100644 (file)
@@ -105,6 +105,7 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
 
 static struct snd_soc_card mxs_sgtl5000 = {
        .name           = "mxs_sgtl5000",
+       .owner          = THIS_MODULE,
        .dai_link       = mxs_sgtl5000_dai,
        .num_links      = ARRAY_SIZE(mxs_sgtl5000_dai),
 };
@@ -156,17 +157,7 @@ static struct platform_driver mxs_sgtl5000_audio_driver = {
        .remove = __devexit_p(mxs_sgtl5000_remove),
 };
 
-static int __init mxs_sgtl5000_init(void)
-{
-       return platform_driver_register(&mxs_sgtl5000_audio_driver);
-}
-module_init(mxs_sgtl5000_init);
-
-static void __exit mxs_sgtl5000_exit(void)
-{
-       platform_driver_unregister(&mxs_sgtl5000_audio_driver);
-}
-module_exit(mxs_sgtl5000_exit);
+module_platform_driver(mxs_sgtl5000_audio_driver);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
 MODULE_DESCRIPTION("MXS ALSA SoC Machine driver");
index a4e3237956e26dc499602f9b7397cf196c7ee5ec..45d11ddaeea9110a66182eaaa18047c8465ff90b 100644 (file)
@@ -291,7 +291,7 @@ static int nuc900_ac97_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
+static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
        .trigger        = nuc900_ac97_trigger,
 };
 
@@ -406,18 +406,7 @@ static struct platform_driver nuc900_ac97_driver = {
        .remove         = __devexit_p(nuc900_ac97_drvremove),
 };
 
-static int __init nuc900_ac97_init(void)
-{
-       return platform_driver_register(&nuc900_ac97_driver);
-}
-
-static void __exit nuc900_ac97_exit(void)
-{
-       platform_driver_unregister(&nuc900_ac97_driver);
-}
-
-module_init(nuc900_ac97_init);
-module_exit(nuc900_ac97_exit);
+module_platform_driver(nuc900_ac97_driver);
 
 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
 MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
index 38a2d0d883b53f592e5512546c9245ca57399209..2f6e6fd6e05c64c3fa49faad83a10245ec18d43b 100644 (file)
@@ -32,6 +32,7 @@ static struct snd_soc_dai_link nuc900evb_ac97_dai = {
 
 static struct snd_soc_card nuc900evb_audio_machine = {
        .name           = "NUC900EVB_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &nuc900evb_ac97_dai,
        .num_links      = 1,
 };
index ae8d6806966ba935cbbebd3ec11c5bdaa82ad8c4..37585b47f4e3c4a5ea48ce7513ef08093de7e08d 100644 (file)
@@ -358,17 +358,7 @@ static struct platform_driver nuc900_pcm_driver = {
        .remove = __devexit_p(nuc900_soc_platform_remove),
 };
 
-static int __init nuc900_pcm_init(void)
-{
-       return platform_driver_register(&nuc900_pcm_driver);
-}
-module_init(nuc900_pcm_init);
-
-static void __exit nuc900_pcm_exit(void)
-{
-       platform_driver_unregister(&nuc900_pcm_driver);
-}
-module_exit(nuc900_pcm_exit);
+module_platform_driver(nuc900_pcm_driver);
 
 MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
 MODULE_DESCRIPTION("nuc900 Audio DMA module");
index fe83d0d176be4b43d34bacc8f34e10e3973c234f..fb1bf2581efb1b224aadbdd040ec83feab61f88d 100644 (file)
@@ -2,6 +2,9 @@ config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
        depends on ARCH_OMAP
 
+config SND_OMAP_SOC_DMIC
+       tristate
+
 config SND_OMAP_SOC_MCBSP
        tristate
        select OMAP_MCBSP
@@ -97,8 +100,10 @@ config SND_OMAP_SOC_SDP3430
 config SND_OMAP_SOC_SDP4430
        tristate "SoC Audio support for Texas Instruments SDP4430"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_4430SDP
+       select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
+       select SND_SOC_DMIC
        help
          Say Y if you want to add support for SoC audio on Texas Instruments
          SDP4430.
index 052fd758722eb0cdc2db322476546228d5e534e8..1fd723fb559d0e14b55bd4b2bf549f77a532ea5c 100644 (file)
@@ -1,10 +1,12 @@
 # OMAP Platform Support
 snd-soc-omap-objs := omap-pcm.o
+snd-soc-omap-dmic-objs := omap-dmic.o
 snd-soc-omap-mcbsp-objs := omap-mcbsp.o
 snd-soc-omap-mcpdm-objs := omap-mcpdm.o
 snd-soc-omap-hdmi-objs := omap-hdmi.o
 
 obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
+obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
 obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
 obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
index c1cd4a0cbe9e6f573625c42acd0883fe20bb7e3e..add4866d7e67bce97b95083f2d36ce4f06e4ccd9 100644 (file)
@@ -107,6 +107,7 @@ static struct snd_soc_dai_link am3517evm_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_am3517evm = {
        .name = "am3517evm",
+       .owner = THIS_MODULE,
        .dai_link = &am3517evm_dai,
        .num_links = 1,
 
index ccb8a6aa1817acec4d71f0b5988faaf547e35599..a67f4370bc9f8fc0096e92abb8ba6cbc3771c220 100644 (file)
@@ -431,22 +431,20 @@ static int ams_delta_set_bias_level(struct snd_soc_card *card,
                                    struct snd_soc_dapm_context *dapm,
                                    enum snd_soc_bias_level level)
 {
-       struct snd_soc_codec *codec = card->rtd->codec;
-
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+               if (card->dapm.bias_level == SND_SOC_BIAS_OFF)
                        ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
                                                AMS_DELTA_LATCH2_MODEM_NRESET);
                break;
        case SND_SOC_BIAS_OFF:
-               if (codec->dapm.bias_level != SND_SOC_BIAS_OFF)
+               if (card->dapm.bias_level != SND_SOC_BIAS_OFF)
                        ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
                                                0);
        }
-       codec->dapm.bias_level = level;
+       card->dapm.bias_level = level;
 
        return 0;
 }
@@ -474,7 +472,7 @@ static int ams_delta_digital_mute(struct snd_soc_dai *dai, int mute)
 }
 
 /* Our codec DAI probably doesn't have its own .ops structure */
-static struct snd_soc_dai_ops ams_delta_dai_ops = {
+static const struct snd_soc_dai_ops ams_delta_dai_ops = {
        .digital_mute = ams_delta_digital_mute,
 };
 
@@ -597,6 +595,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
 /* Audio card driver */
 static struct snd_soc_card ams_delta_audio_card = {
        .name = "AMS_DELTA",
+       .owner = THIS_MODULE,
        .dai_link = &ams_delta_dai_link,
        .num_links = 1,
        .set_bias_level = ams_delta_set_bias_level,
index 591fbf8f7cd95a57002c1980e7ac9233e55fc710..ccae58a1339cc859e88a2346663fdb812ac3b9c0 100644 (file)
@@ -72,6 +72,7 @@ static struct snd_soc_dai_link igep2_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_igep2 = {
        .name = "igep2",
+       .owner = THIS_MODULE,
        .dai_link = &igep2_dai,
        .num_links = 1,
 };
index fc6209b3f20c92ae4b1824fb29a13624b7b1f1d5..597be412f1e40080336be9604940cbfab72012fd 100644 (file)
@@ -289,6 +289,7 @@ static struct snd_soc_dai_link n810_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_n810 = {
        .name = "N810",
+       .owner = THIS_MODULE,
        .dai_link = &n810_dai,
        .num_links = 1,
 
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
new file mode 100644 (file)
index 0000000..0855c1c
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * omap-dmic.c  --  OMAP ASoC DMIC DAI driver
+ *
+ * Copyright (C) 2010 - 2011 Texas Instruments
+ *
+ * Author: David Lambert <dlambert@ti.com>
+ *        Misael Lopez Cruz <misael.lopez@ti.com>
+ *        Liam Girdwood <lrg@ti.com>
+ *        Peter Ujfalusi <peter.ujfalusi@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/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <plat/dma.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "omap-pcm.h"
+#include "omap-dmic.h"
+
+struct omap_dmic {
+       struct device *dev;
+       void __iomem *io_base;
+       struct clk *fclk;
+       int fclk_freq;
+       int out_freq;
+       int clk_div;
+       int sysclk;
+       int threshold;
+       u32 ch_enabled;
+       bool active;
+       struct mutex mutex;
+};
+
+/*
+ * Stream DMA parameters
+ */
+static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
+       .name           = "DMIC capture",
+       .data_type      = OMAP_DMA_DATA_TYPE_S32,
+       .sync_mode      = OMAP_DMA_SYNC_PACKET,
+};
+
+static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
+{
+       __raw_writel(val, dmic->io_base + reg);
+}
+
+static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
+{
+       return __raw_readl(dmic->io_base + reg);
+}
+
+static inline void omap_dmic_start(struct omap_dmic *dmic)
+{
+       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+
+       /* Configure DMA controller */
+       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_SET_REG,
+                       OMAP_DMIC_DMA_ENABLE);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl | dmic->ch_enabled);
+}
+
+static inline void omap_dmic_stop(struct omap_dmic *dmic)
+{
+       u32 ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
+                       ctrl & ~OMAP_DMIC_UP_ENABLE_MASK);
+
+       /* Disable DMA request generation */
+       omap_dmic_write(dmic, OMAP_DMIC_DMAENABLE_CLR_REG,
+                       OMAP_DMIC_DMA_ENABLE);
+
+}
+
+static inline int dmic_is_enabled(struct omap_dmic *dmic)
+{
+       return omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG) &
+                                               OMAP_DMIC_UP_ENABLE_MASK;
+}
+
+static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       int ret = 0;
+
+       mutex_lock(&dmic->mutex);
+
+       if (!dai->active) {
+               snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
+               dmic->active = 1;
+       } else {
+               ret = -EBUSY;
+       }
+
+       mutex_unlock(&dmic->mutex);
+
+       return ret;
+}
+
+static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
+                                   struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       mutex_lock(&dmic->mutex);
+
+       if (!dai->active)
+               dmic->active = 0;
+
+       mutex_unlock(&dmic->mutex);
+}
+
+static int omap_dmic_select_divider(struct omap_dmic *dmic, int sample_rate)
+{
+       int divider = -EINVAL;
+
+       /*
+        * 192KHz rate is only supported with 19.2MHz/3.84MHz clock
+        * configuration.
+        */
+       if (sample_rate == 192000) {
+               if (dmic->fclk_freq == 19200000 && dmic->out_freq == 3840000)
+                       divider = 0x6; /* Divider: 5 (192KHz sampling rate) */
+               else
+                       dev_err(dmic->dev,
+                               "invalid clock configuration for 192KHz\n");
+
+               return divider;
+       }
+
+       switch (dmic->out_freq) {
+       case 1536000:
+               if (dmic->fclk_freq != 24576000)
+                       goto div_err;
+               divider = 0x4; /* Divider: 16 */
+               break;
+       case 2400000:
+               switch (dmic->fclk_freq) {
+               case 12000000:
+                       divider = 0x5; /* Divider: 5 */
+                       break;
+               case 19200000:
+                       divider = 0x0; /* Divider: 8 */
+                       break;
+               case 24000000:
+                       divider = 0x2; /* Divider: 10 */
+                       break;
+               default:
+                       goto div_err;
+               }
+               break;
+       case 3072000:
+               if (dmic->fclk_freq != 24576000)
+                       goto div_err;
+               divider = 0x3; /* Divider: 8 */
+               break;
+       case 3840000:
+               if (dmic->fclk_freq != 19200000)
+                       goto div_err;
+               divider = 0x1; /* Divider: 5 (96KHz sampling rate) */
+               break;
+       default:
+               dev_err(dmic->dev, "invalid out frequency: %dHz\n",
+                       dmic->out_freq);
+               break;
+       }
+
+       return divider;
+
+div_err:
+       dev_err(dmic->dev, "invalid out frequency %dHz for %dHz input\n",
+               dmic->out_freq, dmic->fclk_freq);
+       return -EINVAL;
+}
+
+static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       int channels;
+
+       dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
+       if (dmic->clk_div < 0) {
+               dev_err(dmic->dev, "no valid divider for %dHz from %dHz\n",
+                       dmic->out_freq, dmic->fclk_freq);
+               return -EINVAL;
+       }
+
+       dmic->ch_enabled = 0;
+       channels = params_channels(params);
+       switch (channels) {
+       case 6:
+               dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
+       case 4:
+               dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
+       case 2:
+               dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
+               break;
+       default:
+               dev_err(dmic->dev, "invalid number of legacy channels\n");
+               return -EINVAL;
+       }
+
+       /* packet size is threshold * channels */
+       omap_dmic_dai_dma_params.packet_size = dmic->threshold * channels;
+       snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+
+       return 0;
+}
+
+static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       u32 ctrl;
+
+       /* Configure uplink threshold */
+       omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold);
+
+       ctrl = omap_dmic_read(dmic, OMAP_DMIC_CTRL_REG);
+
+       /* Set dmic out format */
+       ctrl &= ~(OMAP_DMIC_FORMAT | OMAP_DMIC_POLAR_MASK);
+       ctrl |= (OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
+                OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
+
+       /* Configure dmic clock divider */
+       ctrl &= ~OMAP_DMIC_CLK_DIV_MASK;
+       ctrl |= OMAP_DMIC_CLK_DIV(dmic->clk_div);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, ctrl);
+
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG,
+                       ctrl | OMAP_DMICOUTFORMAT_LJUST | OMAP_DMIC_POLAR1 |
+                       OMAP_DMIC_POLAR2 | OMAP_DMIC_POLAR3);
+
+       return 0;
+}
+
+static int omap_dmic_dai_trigger(struct snd_pcm_substream *substream,
+                                 int cmd, struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               omap_dmic_start(dmic);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               omap_dmic_stop(dmic);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int omap_dmic_select_fclk(struct omap_dmic *dmic, int clk_id,
+                                unsigned int freq)
+{
+       struct clk *parent_clk;
+       char *parent_clk_name;
+       int ret = 0;
+
+       switch (freq) {
+       case 12000000:
+       case 19200000:
+       case 24000000:
+       case 24576000:
+               break;
+       default:
+               dev_err(dmic->dev, "invalid input frequency: %dHz\n", freq);
+               dmic->fclk_freq = 0;
+               return -EINVAL;
+       }
+
+       if (dmic->sysclk == clk_id) {
+               dmic->fclk_freq = freq;
+               return 0;
+       }
+
+       /* re-parent not allowed if a stream is ongoing */
+       if (dmic->active && dmic_is_enabled(dmic)) {
+               dev_err(dmic->dev, "can't re-parent when DMIC active\n");
+               return -EBUSY;
+       }
+
+       switch (clk_id) {
+       case OMAP_DMIC_SYSCLK_PAD_CLKS:
+               parent_clk_name = "pad_clks_ck";
+               break;
+       case OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS:
+               parent_clk_name = "slimbus_clk";
+               break;
+       case OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS:
+               parent_clk_name = "dmic_sync_mux_ck";
+               break;
+       default:
+               dev_err(dmic->dev, "fclk clk_id (%d) not supported\n", clk_id);
+               return -EINVAL;
+       }
+
+       parent_clk = clk_get(dmic->dev, parent_clk_name);
+       if (IS_ERR(parent_clk)) {
+               dev_err(dmic->dev, "can't get %s\n", parent_clk_name);
+               return -ENODEV;
+       }
+
+       mutex_lock(&dmic->mutex);
+       if (dmic->active) {
+               /* disable clock while reparenting */
+               pm_runtime_put_sync(dmic->dev);
+               ret = clk_set_parent(dmic->fclk, parent_clk);
+               pm_runtime_get_sync(dmic->dev);
+       } else {
+               ret = clk_set_parent(dmic->fclk, parent_clk);
+       }
+       mutex_unlock(&dmic->mutex);
+
+       if (ret < 0) {
+               dev_err(dmic->dev, "re-parent failed\n");
+               goto err_busy;
+       }
+
+       dmic->sysclk = clk_id;
+       dmic->fclk_freq = freq;
+
+err_busy:
+       clk_put(parent_clk);
+
+       return ret;
+}
+
+static int omap_dmic_select_outclk(struct omap_dmic *dmic, int clk_id,
+                                   unsigned int freq)
+{
+       int ret = 0;
+
+       if (clk_id != OMAP_DMIC_ABE_DMIC_CLK) {
+               dev_err(dmic->dev, "output clk_id (%d) not supported\n",
+                       clk_id);
+               return -EINVAL;
+       }
+
+       switch (freq) {
+       case 1536000:
+       case 2400000:
+       case 3072000:
+       case 3840000:
+               dmic->out_freq = freq;
+               break;
+       default:
+               dev_err(dmic->dev, "invalid out frequency: %dHz\n", freq);
+               dmic->out_freq = 0;
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int omap_dmic_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                   unsigned int freq, int dir)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       if (dir == SND_SOC_CLOCK_IN)
+               return omap_dmic_select_fclk(dmic, clk_id, freq);
+       else if (dir == SND_SOC_CLOCK_OUT)
+               return omap_dmic_select_outclk(dmic, clk_id, freq);
+
+       dev_err(dmic->dev, "invalid clock direction (%d)\n", dir);
+       return -EINVAL;
+}
+
+static const struct snd_soc_dai_ops omap_dmic_dai_ops = {
+       .startup        = omap_dmic_dai_startup,
+       .shutdown       = omap_dmic_dai_shutdown,
+       .hw_params      = omap_dmic_dai_hw_params,
+       .prepare        = omap_dmic_dai_prepare,
+       .trigger        = omap_dmic_dai_trigger,
+       .set_sysclk     = omap_dmic_set_dai_sysclk,
+};
+
+static int omap_dmic_probe(struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_enable(dmic->dev);
+
+       /* Disable lines while request is ongoing */
+       pm_runtime_get_sync(dmic->dev);
+       omap_dmic_write(dmic, OMAP_DMIC_CTRL_REG, 0x00);
+       pm_runtime_put_sync(dmic->dev);
+
+       /* Configure DMIC threshold value */
+       dmic->threshold = OMAP_DMIC_THRES_MAX - 3;
+       return 0;
+}
+
+static int omap_dmic_remove(struct snd_soc_dai *dai)
+{
+       struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_disable(dmic->dev);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver omap_dmic_dai = {
+       .name = "omap-dmic",
+       .probe = omap_dmic_probe,
+       .remove = omap_dmic_remove,
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 6,
+               .rates = SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .ops = &omap_dmic_dai_ops,
+};
+
+static __devinit int asoc_dmic_probe(struct platform_device *pdev)
+{
+       struct omap_dmic *dmic;
+       struct resource *res;
+       int ret;
+
+       dmic = devm_kzalloc(&pdev->dev, sizeof(struct omap_dmic), GFP_KERNEL);
+       if (!dmic)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, dmic);
+       dmic->dev = &pdev->dev;
+       dmic->sysclk = OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS;
+
+       mutex_init(&dmic->mutex);
+
+       dmic->fclk = clk_get(dmic->dev, "dmic_fck");
+       if (IS_ERR(dmic->fclk)) {
+               dev_err(dmic->dev, "cant get dmic_fck\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+       if (!res) {
+               dev_err(dmic->dev, "invalid dma memory resource\n");
+               ret = -ENODEV;
+               goto err_put_clk;
+       }
+       omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(dmic->dev, "invalid dma resource\n");
+               ret = -ENODEV;
+               goto err_put_clk;
+       }
+       omap_dmic_dai_dma_params.dma_req = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       if (!res) {
+               dev_err(dmic->dev, "invalid memory resource\n");
+               ret = -ENODEV;
+               goto err_put_clk;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res), pdev->name)) {
+               dev_err(dmic->dev, "memory region already claimed\n");
+               ret = -ENODEV;
+               goto err_put_clk;
+       }
+
+       dmic->io_base = devm_ioremap(&pdev->dev, res->start,
+                                    resource_size(res));
+       if (!dmic->io_base) {
+               ret = -ENOMEM;
+               goto err_put_clk;
+       }
+
+       ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
+       if (ret)
+               goto err_put_clk;
+
+       return 0;
+
+err_put_clk:
+       clk_put(dmic->fclk);
+       return ret;
+}
+
+static int __devexit asoc_dmic_remove(struct platform_device *pdev)
+{
+       struct omap_dmic *dmic = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+       clk_put(dmic->fclk);
+
+       return 0;
+}
+
+static struct platform_driver asoc_dmic_driver = {
+       .driver = {
+               .name = "omap-dmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = asoc_dmic_probe,
+       .remove = __devexit_p(asoc_dmic_remove),
+};
+
+module_platform_driver(asoc_dmic_driver);
+
+MODULE_ALIAS("platform:omap-dmic");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("OMAP DMIC ASoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-dmic.h b/sound/soc/omap/omap-dmic.h
new file mode 100644 (file)
index 0000000..231e728
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * omap-dmic.h  --  OMAP Digital Microphone Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _OMAP_DMIC_H
+#define _OMAP_DMIC_H
+
+#define OMAP_DMIC_REVISION_REG         0x00
+#define OMAP_DMIC_SYSCONFIG_REG                0x10
+#define OMAP_DMIC_IRQSTATUS_RAW_REG    0x24
+#define OMAP_DMIC_IRQSTATUS_REG                0x28
+#define OMAP_DMIC_IRQENABLE_SET_REG    0x2C
+#define OMAP_DMIC_IRQENABLE_CLR_REG    0x30
+#define OMAP_DMIC_IRQWAKE_EN_REG       0x34
+#define OMAP_DMIC_DMAENABLE_SET_REG    0x38
+#define OMAP_DMIC_DMAENABLE_CLR_REG    0x3C
+#define OMAP_DMIC_DMAWAKEEN_REG                0x40
+#define OMAP_DMIC_CTRL_REG             0x44
+#define OMAP_DMIC_DATA_REG             0x48
+#define OMAP_DMIC_FIFO_CTRL_REG                0x4C
+#define OMAP_DMIC_FIFO_DMIC1R_DATA_REG 0x50
+#define OMAP_DMIC_FIFO_DMIC1L_DATA_REG 0x54
+#define OMAP_DMIC_FIFO_DMIC2R_DATA_REG 0x58
+#define OMAP_DMIC_FIFO_DMIC2L_DATA_REG 0x5C
+#define OMAP_DMIC_FIFO_DMIC3R_DATA_REG 0x60
+#define OMAP_DMIC_FIFO_DMIC3L_DATA_REG 0x64
+
+/* IRQSTATUS_RAW, IRQSTATUS, IRQENABLE_SET, IRQENABLE_CLR bit fields */
+#define OMAP_DMIC_IRQ                  (1 << 0)
+#define OMAP_DMIC_IRQ_FULL             (1 << 1)
+#define OMAP_DMIC_IRQ_ALMST_EMPTY      (1 << 2)
+#define OMAP_DMIC_IRQ_EMPTY            (1 << 3)
+#define OMAP_DMIC_IRQ_MASK             0x07
+
+/* DMIC_DMAENABLE bit fields */
+#define OMAP_DMIC_DMA_ENABLE           0x1
+
+/* DMIC_CTRL bit fields */
+#define OMAP_DMIC_UP1_ENABLE           (1 << 0)
+#define OMAP_DMIC_UP2_ENABLE           (1 << 1)
+#define OMAP_DMIC_UP3_ENABLE           (1 << 2)
+#define OMAP_DMIC_UP_ENABLE_MASK       0x7
+#define OMAP_DMIC_FORMAT               (1 << 3)
+#define OMAP_DMIC_POLAR1               (1 << 4)
+#define OMAP_DMIC_POLAR2               (1 << 5)
+#define OMAP_DMIC_POLAR3               (1 << 6)
+#define OMAP_DMIC_POLAR_MASK           (0x7 << 4)
+#define OMAP_DMIC_CLK_DIV(x)           (((x) & 0x7) << 7)
+#define OMAP_DMIC_CLK_DIV_MASK         (0x7 << 7)
+#define        OMAP_DMIC_RESET                 (1 << 10)
+
+#define OMAP_DMICOUTFORMAT_LJUST       (0 << 3)
+#define OMAP_DMICOUTFORMAT_RJUST       (1 << 3)
+
+/* DMIC_FIFO_CTRL bit fields */
+#define OMAP_DMIC_THRES_MAX            0xF
+
+enum omap_dmic_clk {
+       OMAP_DMIC_SYSCLK_PAD_CLKS,              /* PAD_CLKS */
+       OMAP_DMIC_SYSCLK_SLIMBLUS_CLKS,         /* SLIMBUS_CLK */
+       OMAP_DMIC_SYSCLK_SYNC_MUX_CLKS,         /* DMIC_SYNC_MUX_CLK */
+       OMAP_DMIC_ABE_DMIC_CLK,                 /* abe_dmic_clk */
+};
+
+#endif
index 36c6eaeffb026b226d39aedff9b97e4688621362..38e0defa7078a9cf57f4d9c8fd7c2a6c3336fdd0 100644 (file)
@@ -83,7 +83,7 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
        return err;
 }
 
-static struct snd_soc_dai_ops omap_hdmi_dai_ops = {
+static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
        .startup        = omap_hdmi_dai_startup,
        .hw_params      = omap_hdmi_dai_hw_params,
 };
@@ -139,17 +139,7 @@ static struct platform_driver hdmi_dai_driver = {
        .remove = __devexit_p(omap_hdmi_remove),
 };
 
-static int __init hdmi_dai_init(void)
-{
-       return platform_driver_register(&hdmi_dai_driver);
-}
-module_init(hdmi_dai_init);
-
-static void __exit hdmi_dai_exit(void)
-{
-       platform_driver_unregister(&hdmi_dai_driver);
-}
-module_exit(hdmi_dai_exit);
+module_platform_driver(hdmi_dai_driver);
 
 MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
 MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
index 4314647e735eff71a8f038263e2f0e4a640d8d24..017371913ec3cf0629acbdc549d8bbe99d5f7ea7 100644 (file)
@@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        default:
                return -EINVAL;
        }
-       if (cpu_is_omap34xx()) {
+       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
                dma_data->set_threshold = omap_mcbsp_set_threshold;
                /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
                if (omap_mcbsp_get_dma_op_mode(bus_id) ==
@@ -599,7 +599,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-static struct snd_soc_dai_ops mcbsp_dai_ops = {
+static const struct snd_soc_dai_ops mcbsp_dai_ops = {
        .startup        = omap_mcbsp_dai_startup,
        .shutdown       = omap_mcbsp_dai_shutdown,
        .trigger        = omap_mcbsp_dai_trigger,
@@ -785,17 +785,7 @@ static struct platform_driver asoc_mcbsp_driver = {
        .remove = __devexit_p(asoc_mcbsp_remove),
 };
 
-static int __init snd_omap_mcbsp_init(void)
-{
-       return platform_driver_register(&asoc_mcbsp_driver);
-}
-module_init(snd_omap_mcbsp_init);
-
-static void __exit snd_omap_mcbsp_exit(void)
-{
-       platform_driver_unregister(&asoc_mcbsp_driver);
-}
-module_exit(snd_omap_mcbsp_exit);
+module_platform_driver(asoc_mcbsp_driver);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
index 41d17067cc739a05ac085443cdbe1fd6e984593e..0e25df4fa9e5cf20e380582a36082e23596d2f0b 100644 (file)
@@ -266,8 +266,6 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
        mutex_lock(&mcpdm->mutex);
 
        if (!dai->active) {
-               pm_runtime_get_sync(mcpdm->dev);
-
                /* Enable watch dog for ES above ES 1.0 to avoid saturation */
                if (omap_rev() != OMAP4430_REV_ES1_0) {
                        u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
@@ -295,9 +293,6 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                        omap_mcpdm_stop(mcpdm);
                        omap_mcpdm_close_streams(mcpdm);
                }
-
-               if (!omap_mcpdm_active(mcpdm))
-                       pm_runtime_put_sync(mcpdm->dev);
        }
 
        mutex_unlock(&mcpdm->mutex);
@@ -367,7 +362,7 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
+static const struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
        .startup        = omap_mcpdm_dai_startup,
        .shutdown       = omap_mcpdm_dai_shutdown,
        .hw_params      = omap_mcpdm_dai_hw_params,
@@ -520,17 +515,7 @@ static struct platform_driver asoc_mcpdm_driver = {
        .remove = __devexit_p(asoc_mcpdm_remove),
 };
 
-static int __init snd_omap_mcpdm_init(void)
-{
-       return platform_driver_register(&asoc_mcpdm_driver);
-}
-module_init(snd_omap_mcpdm_init);
-
-static void __exit snd_omap_mcpdm_exit(void)
-{
-       platform_driver_unregister(&asoc_mcpdm_driver);
-}
-module_exit(snd_omap_mcpdm_exit);
+module_platform_driver(asoc_mcpdm_driver);
 
 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
 MODULE_DESCRIPTION("OMAP PDM SoC Interface");
index 6ede7dc6c10a9ef858ef6016c87f0abbd93fa9fe..a59bd352d34231981a99998a27ce6ad611f584ec 100644 (file)
@@ -378,7 +378,6 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
 static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -387,14 +386,14 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -433,17 +432,7 @@ static struct platform_driver omap_pcm_driver = {
        .remove = __devexit_p(omap_pcm_remove),
 };
 
-static int __init snd_omap_pcm_init(void)
-{
-       return platform_driver_register(&omap_pcm_driver);
-}
-module_init(snd_omap_pcm_init);
-
-static void __exit snd_omap_pcm_exit(void)
-{
-       platform_driver_unregister(&omap_pcm_driver);
-}
-module_exit(snd_omap_pcm_exit);
+module_platform_driver(omap_pcm_driver);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
index 68578959e4aa014b93bf6c09eb59cf2cef04996a..071fcb09b8b27df357394ef0e11adbd1bf543b6e 100644 (file)
@@ -70,6 +70,7 @@ static struct snd_soc_dai_link omap3evm_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap3evm = {
        .name = "omap3evm",
+       .owner = THIS_MODULE,
        .dai_link = &omap3evm_dai,
        .num_links = 1,
 };
index 7605c37c91e79f085c81d952d0fc9d09f91fdf0d..07794bd10952f7355232a64cd46790e9283d02a0 100644 (file)
@@ -233,6 +233,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
 /* SoC card */
 static struct snd_soc_card snd_soc_card_omap3pandora = {
        .name = "omap3pandora",
+       .owner = THIS_MODULE,
        .dai_link = omap3pandora_dai,
        .num_links = ARRAY_SIZE(omap3pandora_dai),
 };
index 8671261ba16d3d831a72fc9ef74024f34af52939..28d689b2714db4e009190fa8af3b1c31481659b8 100644 (file)
@@ -74,6 +74,7 @@ static struct snd_soc_dai_link omap4_hdmi_dai = {
 
 static struct snd_soc_card snd_soc_omap4_hdmi = {
        .name = "OMAP4HDMI",
+       .owner = THIS_MODULE,
        .dai_link = &omap4_hdmi_dai,
        .num_links = 1,
 };
@@ -112,17 +113,7 @@ static struct platform_driver omap4_hdmi_driver = {
        .remove = __devexit_p(omap4_hdmi_remove),
 };
 
-static int __init omap4_hdmi_init(void)
-{
-       return platform_driver_register(&omap4_hdmi_driver);
-}
-module_init(omap4_hdmi_init);
-
-static void __exit omap4_hdmi_exit(void)
-{
-       platform_driver_unregister(&omap4_hdmi_driver);
-}
-module_exit(omap4_hdmi_exit);
+module_platform_driver(omap4_hdmi_driver);
 
 MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
 MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver");
index 351ec9db384d4590ae6d34103e98316d80dc9a61..d859b597e7ec973cf5477b0bd9f620f5be55b4ab 100644 (file)
@@ -108,6 +108,7 @@ static struct snd_soc_dai_link osk_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_osk = {
        .name = "OSK5912",
+       .owner = THIS_MODULE,
        .dai_link = &osk_dai,
        .num_links = 1,
 
index c3550aeee533d55a2bcbb534c811a549721d99b7..2ee889c502564f42fa69ac8ef31c3f9dd22fe0af 100644 (file)
@@ -72,6 +72,7 @@ static struct snd_soc_dai_link overo_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_overo = {
        .name = "overo",
+       .owner = THIS_MODULE,
        .dai_link = &overo_dai,
        .num_links = 1,
 };
index 4cabb74d97e9a3489dbd9abcb1fe3707cb70cef5..fada6ef43eeae736750ef60de289efb0fa48af1d 100644 (file)
@@ -365,7 +365,7 @@ static struct snd_soc_dai_link rx51_dai[] = {
        },
 };
 
-struct snd_soc_aux_dev rx51_aux_dev[] = {
+static struct snd_soc_aux_dev rx51_aux_dev[] = {
        {
                .name = "TLV320AIC34b",
                .codec_name = "tlv320aic3x-codec.2-0019",
@@ -383,6 +383,7 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = {
 /* Audio card */
 static struct snd_soc_card rx51_sound_card = {
        .name = "RX-51",
+       .owner = THIS_MODULE,
        .dai_link = rx51_dai,
        .num_links = ARRAY_SIZE(rx51_dai),
        .aux_dev = rx51_aux_dev,
index e8fbf8efdbb85dc120dfc3173180851e9a05be81..2c850662ea7ea79f70978ac19916cf07c9ee7542 100644 (file)
@@ -213,6 +213,7 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp3430 = {
        .name = "SDP3430",
+       .owner = THIS_MODULE,
        .dai_link = sdp3430_dai,
        .num_links = ARRAY_SIZE(sdp3430_dai),
 
index 03d9fa4192fe611a9119986ce17ed9e18648ee4c..175ba9a04edfbd449b8b4822df6b5d1561a25e3a 100644 (file)
@@ -33,6 +33,7 @@
 #include <plat/hardware.h>
 #include <plat/mux.h>
 
+#include "omap-dmic.h"
 #include "omap-mcpdm.h"
 #include "omap-pcm.h"
 #include "../codecs/twl6040.h"
@@ -67,6 +68,32 @@ static struct snd_soc_ops sdp4430_ops = {
        .hw_params = sdp4430_hw_params,
 };
 
+static int sdp4430_dmic_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret = 0;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
+                                    19200000, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set DMIC cpu system clock\n");
+               return ret;
+       }
+       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
+                                    SND_SOC_CLOCK_OUT);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set DMIC output clock\n");
+               return ret;
+       }
+       return 0;
+}
+
+static struct snd_soc_ops sdp4430_dmic_ops = {
+       .hw_params = sdp4430_dmic_hw_params,
+};
+
 /* Headset jack */
 static struct snd_soc_jack hs_jack;
 
@@ -148,23 +175,60 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
        return ret;
 }
 
+static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
+       SND_SOC_DAPM_MIC("Digital Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route dmic_audio_map[] = {
+       {"DMic", NULL, "Digital Mic1 Bias"},
+       {"Digital Mic1 Bias", NULL, "Digital Mic"},
+};
+
+static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
+                               ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
+       if (ret)
+               return ret;
+
+       return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
+                               ARRAY_SIZE(dmic_audio_map));
+}
+
 /* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link sdp4430_dai = {
-       .name = "TWL6040",
-       .stream_name = "TWL6040",
-       .cpu_dai_name = "omap-mcpdm",
-       .codec_dai_name = "twl6040-legacy",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "twl6040-codec",
-       .init = sdp4430_twl6040_init,
-       .ops = &sdp4430_ops,
+static struct snd_soc_dai_link sdp4430_dai[] = {
+       {
+               .name = "TWL6040",
+               .stream_name = "TWL6040",
+               .cpu_dai_name = "omap-mcpdm",
+               .codec_dai_name = "twl6040-legacy",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl6040-codec",
+               .init = sdp4430_twl6040_init,
+               .ops = &sdp4430_ops,
+       },
+       {
+               .name = "DMIC",
+               .stream_name = "DMIC Capture",
+               .cpu_dai_name = "omap-dmic",
+               .codec_dai_name = "dmic-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "dmic-codec",
+               .init = sdp4430_dmic_init,
+               .ops = &sdp4430_dmic_ops,
+       },
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp4430 = {
        .name = "SDP4430",
-       .dai_link = &sdp4430_dai,
-       .num_links = 1,
+       .owner = THIS_MODULE,
+       .dai_link = sdp4430_dai,
+       .num_links = ARRAY_SIZE(sdp4430_dai),
 
        .dapm_widgets = sdp4430_twl6040_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
index 7641a7fa8f972dc6a32460e11be18b3a3a68c889..981616d61f6762ff459f1a7dd8c3fa9e2a621fd4 100644 (file)
@@ -157,6 +157,7 @@ static struct snd_soc_dai_link zoom2_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_zoom2 = {
        .name = "Zoom2",
+       .owner = THIS_MODULE,
        .dai_link = zoom2_dai,
        .num_links = ARRAY_SIZE(zoom2_dai),
 
index b0e2fb720910533d442be66e68db112dbbc93dce..bc21944851c4c69f274fc4df418dd499e45a0bdd 100644 (file)
@@ -142,18 +142,6 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
@@ -239,7 +227,7 @@ SND_SOC_DAPM_HP("Headset Jack", NULL),
 };
 
 /* Corgi machine audio map (connections to the codec pins) */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route corgi_audio_map[] = {
 
        /* headset Jack  - in = micin, out = LHPOUT*/
        {"Headset Jack", NULL, "LHPOUT"},
@@ -281,24 +269,10 @@ static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        snd_soc_dapm_nc_pin(dapm, "LLINEIN");
        snd_soc_dapm_nc_pin(dapm, "RLINEIN");
 
-       /* Add corgi specific controls */
-       err = snd_soc_add_controls(codec, wm8731_corgi_controls,
-                               ARRAY_SIZE(wm8731_corgi_controls));
-       if (err < 0)
-               return err;
-
-       /* Add corgi specific widgets */
-       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-                                 ARRAY_SIZE(wm8731_dapm_widgets));
-
-       /* Set up corgi specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -311,48 +285,61 @@ static struct snd_soc_dai_link corgi_dai = {
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8731.0-001b",
        .init = corgi_wm8731_init,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &corgi_ops,
 };
 
 /* corgi audio machine driver */
-static struct snd_soc_card snd_soc_corgi = {
+static struct snd_soc_card corgi = {
        .name = "Corgi",
+       .owner = THIS_MODULE,
        .dai_link = &corgi_dai,
        .num_links = 1,
-};
 
-static struct platform_device *corgi_snd_device;
+       .controls = wm8731_corgi_controls,
+       .num_controls = ARRAY_SIZE(wm8731_corgi_controls),
+       .dapm_widgets = wm8731_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+       .dapm_routes = corgi_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(corgi_audio_map),
+};
 
-static int __init corgi_init(void)
+static int __devinit corgi_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &corgi;
        int ret;
 
-       if (!(machine_is_corgi() || machine_is_shepherd() ||
-             machine_is_husky()))
-               return -ENODEV;
-
-       corgi_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!corgi_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(corgi_snd_device, &snd_soc_corgi);
-       ret = platform_device_add(corgi_snd_device);
+       card->dev = &pdev->dev;
 
+       ret = snd_soc_register_card(card);
        if (ret)
-               platform_device_put(corgi_snd_device);
-
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
        return ret;
 }
 
-static void __exit corgi_exit(void)
+static int __devexit corgi_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(corgi_snd_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(corgi_init);
-module_exit(corgi_exit);
+static struct platform_driver corgi_driver = {
+       .driver         = {
+               .name   = "corgi-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = corgi_probe,
+       .remove         = __devexit_p(corgi_remove),
+};
+
+module_platform_driver(corgi_driver);
 
 /* Module information */
 MODULE_AUTHOR("Richard Purdie");
 MODULE_DESCRIPTION("ALSA SoC Corgi");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:corgi-audio");
index 35ed7eb8cff2e6793147cd52c2acec6a9d86e6b6..7b1bc2390039ab324b5146daf63c5a72ec21411e 100644 (file)
@@ -133,78 +133,60 @@ static struct snd_soc_dai_link e740_dai[] = {
 
 static struct snd_soc_card e740 = {
        .name = "Toshiba e740",
+       .owner = THIS_MODULE,
        .dai_link = e740_dai,
        .num_links = ARRAY_SIZE(e740_dai),
 };
 
-static struct platform_device *e740_snd_device;
+static struct gpio e740_audio_gpios[] = {
+       { GPIO_E740_MIC_ON, GPIOF_OUT_INIT_LOW, "Mic amp" },
+       { GPIO_E740_AMP_ON, GPIOF_OUT_INIT_LOW, "Output amp" },
+       { GPIO_E740_WM9705_nAVDD2, GPIOF_OUT_INIT_HIGH, "Audio power" },
+};
 
-static int __init e740_init(void)
+static int __devinit e740_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &e740;
        int ret;
 
-       if (!machine_is_e740())
-               return -ENODEV;
-
-       ret = gpio_request(GPIO_E740_MIC_ON,  "Mic amp");
+       ret = gpio_request_array(e740_audio_gpios,
+                                ARRAY_SIZE(e740_audio_gpios));
        if (ret)
                return ret;
 
-       ret = gpio_request(GPIO_E740_AMP_ON, "Output amp");
-       if (ret)
-               goto free_mic_amp_gpio;
-
-       ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power");
-       if (ret)
-               goto free_op_amp_gpio;
-
-       /* Disable audio */
-       ret = gpio_direction_output(GPIO_E740_MIC_ON, 0);
-       if (ret)
-               goto free_apwr_gpio;
-       ret = gpio_direction_output(GPIO_E740_AMP_ON, 0);
-       if (ret)
-               goto free_apwr_gpio;
-       ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1);
-       if (ret)
-               goto free_apwr_gpio;
+       card->dev = &pdev->dev;
 
-       e740_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!e740_snd_device) {
-               ret = -ENOMEM;
-               goto free_apwr_gpio;
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
        }
-
-       platform_set_drvdata(e740_snd_device, &e740);
-       ret = platform_device_add(e740_snd_device);
-
-       if (!ret)
-               return 0;
-
-/* Fail gracefully */
-       platform_device_put(e740_snd_device);
-free_apwr_gpio:
-       gpio_free(GPIO_E740_WM9705_nAVDD2);
-free_op_amp_gpio:
-       gpio_free(GPIO_E740_AMP_ON);
-free_mic_amp_gpio:
-       gpio_free(GPIO_E740_MIC_ON);
-
        return ret;
 }
 
-static void __exit e740_exit(void)
+static int __devexit e740_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(e740_snd_device);
-       gpio_free(GPIO_E740_WM9705_nAVDD2);
-       gpio_free(GPIO_E740_AMP_ON);
-       gpio_free(GPIO_E740_MIC_ON);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(e740_init);
-module_exit(e740_exit);
+static struct platform_driver e740_driver = {
+       .driver         = {
+               .name   = "e740-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = e740_probe,
+       .remove         = __devexit_p(e740_remove),
+};
+
+module_platform_driver(e740_driver);
 
 /* Module information */
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 MODULE_DESCRIPTION("ALSA SoC driver for e740");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e740-audio");
index ce5f056009a7d5770ae85d4bce9bfff73eb538b7..47b89d71e287bc087640cdf064a7c4f6a92cdfea 100644 (file)
@@ -116,68 +116,59 @@ static struct snd_soc_dai_link e750_dai[] = {
 
 static struct snd_soc_card e750 = {
        .name = "Toshiba e750",
+       .owner = THIS_MODULE,
        .dai_link = e750_dai,
        .num_links = ARRAY_SIZE(e750_dai),
 };
 
-static struct platform_device *e750_snd_device;
+static struct gpio e750_audio_gpios[] = {
+       { GPIO_E750_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Headphone amp" },
+       { GPIO_E750_SPK_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" },
+};
 
-static int __init e750_init(void)
+static int __devinit e750_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &e750;
        int ret;
 
-       if (!machine_is_e750())
-               return -ENODEV;
-
-       ret = gpio_request(GPIO_E750_HP_AMP_OFF,  "Headphone amp");
+       ret = gpio_request_array(e750_audio_gpios,
+                                ARRAY_SIZE(e750_audio_gpios));
        if (ret)
                return ret;
 
-       ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp");
-       if (ret)
-               goto free_hp_amp_gpio;
-
-       ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1);
-       if (ret)
-               goto free_spk_amp_gpio;
-
-       ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1);
-       if (ret)
-               goto free_spk_amp_gpio;
+       card->dev = &pdev->dev;
 
-       e750_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!e750_snd_device) {
-               ret = -ENOMEM;
-               goto free_spk_amp_gpio;
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
        }
-
-       platform_set_drvdata(e750_snd_device, &e750);
-       ret = platform_device_add(e750_snd_device);
-
-       if (!ret)
-               return 0;
-
-/* Fail gracefully */
-       platform_device_put(e750_snd_device);
-free_spk_amp_gpio:
-       gpio_free(GPIO_E750_SPK_AMP_OFF);
-free_hp_amp_gpio:
-       gpio_free(GPIO_E750_HP_AMP_OFF);
-
        return ret;
 }
 
-static void __exit e750_exit(void)
+static int __devexit e750_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(e750_snd_device);
-       gpio_free(GPIO_E750_SPK_AMP_OFF);
-       gpio_free(GPIO_E750_HP_AMP_OFF);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(e750_init);
-module_exit(e750_exit);
+static struct platform_driver e750_driver = {
+       .driver         = {
+               .name   = "e750-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = e750_probe,
+       .remove         = __devexit_p(e750_remove),
+};
+
+module_platform_driver(e750_driver);
 
 /* Module information */
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 MODULE_DESCRIPTION("ALSA SoC driver for e750");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e750-audio");
index 6a8f38b6c3799800b2c283fd231f388584eeeaaf..ea9707ec6f28e706847e9991ee756747eac5309a 100644 (file)
@@ -106,66 +106,59 @@ static struct snd_soc_dai_link e800_dai[] = {
 
 static struct snd_soc_card e800 = {
        .name = "Toshiba e800",
+       .owner = THIS_MODULE,
        .dai_link = e800_dai,
        .num_links = ARRAY_SIZE(e800_dai),
 };
 
-static struct platform_device *e800_snd_device;
+static struct gpio e800_audio_gpios[] = {
+       { GPIO_E800_SPK_AMP_ON, GPIOF_OUT_INIT_HIGH, "Headphone amp" },
+       { GPIO_E800_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" },
+};
 
-static int __init e800_init(void)
+static int __devinit e800_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &e800;
        int ret;
 
-       if (!machine_is_e800())
-               return -ENODEV;
-
-       ret = gpio_request(GPIO_E800_HP_AMP_OFF,  "Headphone amp");
+       ret = gpio_request_array(e800_audio_gpios,
+                                ARRAY_SIZE(e800_audio_gpios));
        if (ret)
                return ret;
 
-       ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp");
-       if (ret)
-               goto free_hp_amp_gpio;
-
-       ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1);
-       if (ret)
-               goto free_spk_amp_gpio;
-
-       ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1);
-       if (ret)
-               goto free_spk_amp_gpio;
-
-       e800_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!e800_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(e800_snd_device, &e800);
-       ret = platform_device_add(e800_snd_device);
-
-       if (!ret)
-               return 0;
-
-/* Fail gracefully */
-       platform_device_put(e800_snd_device);
-free_spk_amp_gpio:
-       gpio_free(GPIO_E800_SPK_AMP_ON);
-free_hp_amp_gpio:
-       gpio_free(GPIO_E800_HP_AMP_OFF);
+       card->dev = &pdev->dev;
 
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
+       }
        return ret;
 }
 
-static void __exit e800_exit(void)
+static int __devexit e800_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(e800_snd_device);
-       gpio_free(GPIO_E800_SPK_AMP_ON);
-       gpio_free(GPIO_E800_HP_AMP_OFF);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(e800_init);
-module_exit(e800_exit);
+static struct platform_driver e800_driver = {
+       .driver         = {
+               .name   = "e800-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = e800_probe,
+       .remove         = __devexit_p(e800_remove),
+};
+
+module_platform_driver(e800_driver);
 
 /* Module information */
 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
 MODULE_DESCRIPTION("ALSA SoC driver for e800");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e800-audio");
index b13a4252812da77235f05ebe24359b9ea0950832..64743a05aeae96172a3fe18e2163c7e1f453635b 100644 (file)
@@ -54,6 +54,7 @@ static struct snd_soc_dai_link em_x270_dai[] = {
 
 static struct snd_soc_card em_x270 = {
        .name = "EM-X270",
+       .owner = THIS_MODULE,
        .dai_link = em_x270_dai,
        .num_links = ARRAY_SIZE(em_x270_dai),
 };
index c664e33fb6d732c239e00d115df663a1b4b5908f..2a342c92d829563fbe3089bac84e486078ce8ef3 100644 (file)
@@ -65,20 +65,6 @@ static int hx4700_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-                       SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-                       SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the I2S system clock as output */
        ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
                        SND_SOC_CLOCK_OUT);
@@ -175,12 +161,15 @@ static struct snd_soc_dai_link hx4700_dai = {
        .platform_name = "pxa-pcm-audio",
        .codec_name = "ak4641.0-0012",
        .init = hx4700_ak4641_init,
+       .dai_fmt = SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &hx4700_ops,
 };
 
 /* hx4700 audio machine driver */
 static struct snd_soc_card snd_soc_card_hx4700 = {
        .name                   = "iPAQ hx4700",
+       .owner                  = THIS_MODULE,
        .dai_link               = &hx4700_dai,
        .num_links              = 1,
        .dapm_widgets           = hx4700_dapm_widgets,
@@ -237,18 +226,7 @@ static struct platform_driver hx4700_audio_driver = {
        .remove = __devexit_p(hx4700_audio_remove),
 };
 
-static int __init hx4700_modinit(void)
-{
-       return platform_driver_register(&hx4700_audio_driver);
-}
-module_init(hx4700_modinit);
-
-static void __exit hx4700_modexit(void)
-{
-       platform_driver_unregister(&hx4700_audio_driver);
-}
-
-module_exit(hx4700_modexit);
+module_platform_driver(hx4700_audio_driver);
 
 MODULE_AUTHOR("Philipp Zabel");
 MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
index 154fc6f234389e74d4354770b6057074377f6be2..b93dafd32b809e63dd8280441261cde86da9f9ab 100644 (file)
@@ -30,20 +30,6 @@ static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                 | SND_SOC_DAIFMT_NB_NF
-                                 | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* CPU should be clock master */
-       ret = snd_soc_dai_set_fmt(cpu_dai,  SND_SOC_DAIFMT_I2S
-                                 | SND_SOC_DAIFMT_NB_NF
-                                 | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
                                     SND_SOC_CLOCK_IN);
        if (ret < 0)
@@ -67,42 +53,52 @@ static struct snd_soc_dai_link imote2_dai = {
        .codec_dai_name = "wm8940-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8940-codec.0-0034",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &imote2_asoc_ops,
 };
 
-static struct snd_soc_card snd_soc_imote2 = {
+static struct snd_soc_card imote2 = {
        .name = "Imote2",
+       .owner = THIS_MODULE,
        .dai_link = &imote2_dai,
        .num_links = 1,
 };
 
-static struct platform_device *imote2_snd_device;
-
-static int __init imote2_asoc_init(void)
+static int __devinit imote2_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &imote2;
        int ret;
 
-       if (!machine_is_intelmote2())
-               return -ENODEV;
-       imote2_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!imote2_snd_device)
-               return -ENOMEM;
+       card->dev = &pdev->dev;
 
-       platform_set_drvdata(imote2_snd_device, &snd_soc_imote2);
-       ret = platform_device_add(imote2_snd_device);
+       ret = snd_soc_register_card(card);
        if (ret)
-               platform_device_put(imote2_snd_device);
-
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
        return ret;
 }
-module_init(imote2_asoc_init);
 
-static void __exit imote2_asoc_exit(void)
+static int __devexit imote2_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(imote2_snd_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
 }
-module_exit(imote2_asoc_exit);
+
+static struct platform_driver imote2_driver = {
+       .driver         = {
+               .name   = "imote2-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = imote2_probe,
+       .remove         = __devexit_p(imote2_remove),
+};
+
+module_platform_driver(imote2_driver);
 
 MODULE_AUTHOR("Jonathan Cameron");
 MODULE_DESCRIPTION("ALSA SoC Imote 2");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imote2-audio");
index e79f516c400e6df35a57b41356fe3ce39882e3ca..3f7a8ecb97206b875469d5de5a2bf21410dd9034 100644 (file)
@@ -452,6 +452,7 @@ static struct snd_soc_dai_link magician_dai[] = {
 /* magician audio machine driver */
 static struct snd_soc_card snd_soc_card_magician = {
        .name = "Magician",
+       .owner = THIS_MODULE,
        .dai_link = magician_dai,
        .num_links = ARRAY_SIZE(magician_dai),
 
index 0b8d1ee738a45ae82c2e3dc22efca0d2ab6c152a..9c585af59b5f52e572f61699a346e794f7579299 100644 (file)
@@ -181,6 +181,7 @@ static struct snd_soc_dai_link mioa701_dai[] = {
 
 static struct snd_soc_card mioa701 = {
        .name = "MioA701",
+       .owner = THIS_MODULE,
        .dai_link = mioa701_dai,
        .num_links = ARRAY_SIZE(mioa701_dai),
 };
@@ -227,18 +228,7 @@ static struct platform_driver mioa701_wm9713_driver = {
        },
 };
 
-static int __init mioa701_asoc_init(void)
-{
-       return platform_driver_register(&mioa701_wm9713_driver);
-}
-
-static void __exit mioa701_asoc_exit(void)
-{
-       platform_driver_unregister(&mioa701_wm9713_driver);
-}
-
-module_init(mioa701_asoc_init);
-module_exit(mioa701_asoc_exit);
+module_platform_driver(mioa701_wm9713_driver);
 
 /* Module information */
 MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
index 7edc1fb71fae05288eebd25ce16d82d122c83227..db24bc685bd3ddb6a1dfb6076eec9fdbf128c7d1 100644 (file)
@@ -146,6 +146,7 @@ static struct snd_soc_dai_link palm27x_dai[] = {
 
 static struct snd_soc_card palm27x_asoc = {
        .name = "Palm/PXA27x",
+       .owner = THIS_MODULE,
        .dai_link = palm27x_dai,
        .num_links = ARRAY_SIZE(palm27x_dai),
 };
@@ -201,18 +202,7 @@ static struct platform_driver palm27x_wm9712_driver = {
        },
 };
 
-static int __init palm27x_asoc_init(void)
-{
-       return platform_driver_register(&palm27x_wm9712_driver);
-}
-
-static void __exit palm27x_asoc_exit(void)
-{
-       platform_driver_unregister(&palm27x_wm9712_driver);
-}
-
-module_init(palm27x_asoc_init);
-module_exit(palm27x_asoc_exit);
+module_platform_driver(palm27x_wm9712_driver);
 
 /* Module information */
 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
index 4c29bc1f9cfedf10de921fd8eb338290ff0c5564..fd0ed10c6fe7346065ee18c65d0cb02f4cee6724 100644 (file)
@@ -121,18 +121,6 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
@@ -214,7 +202,7 @@ SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
 };
 
 /* Corgi machine connections to the codec pins */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route poodle_audio_map[] = {
 
        /* headphone connected to LHPOUT1, RHPOUT1 */
        {"Headphone Jack", NULL, "LHPOUT"},
@@ -246,25 +234,11 @@ static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        snd_soc_dapm_nc_pin(dapm, "LLINEIN");
        snd_soc_dapm_nc_pin(dapm, "RLINEIN");
        snd_soc_dapm_enable_pin(dapm, "MICIN");
 
-       /* Add poodle specific controls */
-       err = snd_soc_add_controls(codec, wm8731_poodle_controls,
-                               ARRAY_SIZE(wm8731_poodle_controls));
-       if (err < 0)
-               return err;
-
-       /* Add poodle specific widgets */
-       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-                                 ARRAY_SIZE(wm8731_dapm_widgets));
-
-       /* Set up poodle specific audio path audio_map */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -277,26 +251,31 @@ static struct snd_soc_dai_link poodle_dai = {
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8731.0-001b",
        .init = poodle_wm8731_init,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &poodle_ops,
 };
 
 /* poodle audio machine driver */
-static struct snd_soc_card snd_soc_poodle = {
+static struct snd_soc_card poodle = {
        .name = "Poodle",
        .dai_link = &poodle_dai,
        .num_links = 1,
        .owner = THIS_MODULE,
-};
 
-static struct platform_device *poodle_snd_device;
+       .controls = wm8731_poodle_controls,
+       .num_controls = ARRAY_SIZE(wm8731_poodle_controls),
+       .dapm_widgets = wm8731_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+       .dapm_routes = poodle_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
+};
 
-static int __init poodle_init(void)
+static int __devinit poodle_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &poodle;
        int ret;
 
-       if (!machine_is_poodle())
-               return -ENODEV;
-
        locomo_gpio_set_dir(&poodle_locomo_device.dev,
                POODLE_LOCOMO_GPIO_AMP_ON, 0);
        /* should we mute HP at startup - burning power ?*/
@@ -305,28 +284,36 @@ static int __init poodle_init(void)
        locomo_gpio_set_dir(&poodle_locomo_device.dev,
                POODLE_LOCOMO_GPIO_MUTE_R, 0);
 
-       poodle_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!poodle_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(poodle_snd_device, &snd_soc_poodle);
-       ret = platform_device_add(poodle_snd_device);
+       card->dev = &pdev->dev;
 
+       ret = snd_soc_register_card(card);
        if (ret)
-               platform_device_put(poodle_snd_device);
-
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
        return ret;
 }
 
-static void __exit poodle_exit(void)
+static int __devexit poodle_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(poodle_snd_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(poodle_init);
-module_exit(poodle_exit);
+static struct platform_driver poodle_driver = {
+       .driver         = {
+               .name   = "poodle-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = poodle_probe,
+       .remove         = __devexit_p(poodle_remove),
+};
+
+module_platform_driver(poodle_driver);
 
 /* Module information */
 MODULE_AUTHOR("Richard Purdie");
 MODULE_DESCRIPTION("ALSA SoC Poodle");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:poodle-audio");
index 8ad93ee2e92bfe312157b46eabbe251b9db35f9d..a57cfbc038e3cc1522c33b98d9fd648203948337 100644 (file)
@@ -771,7 +771,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
                            SNDRV_PCM_FMTBIT_S24_LE |   \
                            SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .startup        = pxa_ssp_startup,
        .shutdown       = pxa_ssp_shutdown,
        .trigger        = pxa_ssp_trigger,
@@ -825,17 +825,7 @@ static struct platform_driver asoc_ssp_driver = {
        .remove = __devexit_p(asoc_ssp_remove),
 };
 
-static int __init pxa_ssp_init(void)
-{
-       return platform_driver_register(&asoc_ssp_driver);
-}
-module_init(pxa_ssp_init);
-
-static void __exit pxa_ssp_exit(void)
-{
-       platform_driver_unregister(&asoc_ssp_driver);
-}
-module_exit(pxa_ssp_exit);
+module_platform_driver(asoc_ssp_driver);
 
 /* Module information */
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index ac51c6d25c4291998bd7ffc6b4d51a0c0148923a..837ff341fd6dda45954f2ec34fd263f24a54d62e 100644 (file)
@@ -163,15 +163,15 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000)
 
-static struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
+static const struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
        .hw_params      = pxa2xx_ac97_hw_params,
 };
 
-static struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
+static const struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
        .hw_params      = pxa2xx_ac97_hw_aux_params,
 };
 
-static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
+static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
        .hw_params      = pxa2xx_ac97_hw_mic_params,
 };
 
@@ -263,17 +263,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
        },
 };
 
-static int __init pxa_ac97_init(void)
-{
-       return platform_driver_register(&pxa2xx_ac97_driver);
-}
-module_init(pxa_ac97_init);
-
-static void __exit pxa_ac97_exit(void)
-{
-       platform_driver_unregister(&pxa2xx_ac97_driver);
-}
-module_exit(pxa_ac97_exit);
+module_platform_driver(pxa2xx_ac97_driver);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
index 11be5952a5066fa30163a3b51143b9dfb41b05e7..609abd51e55fef65ed8ec34157165b3e1a55b700 100644 (file)
@@ -331,7 +331,7 @@ static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
-static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
        .startup        = pxa2xx_i2s_startup,
        .shutdown       = pxa2xx_i2s_shutdown,
        .trigger        = pxa2xx_i2s_trigger,
index 600676f709a927b2c4a568d03fd8869dafff721a..fdd6bedef9bd7d818dadf36049df53ed067d842d 100644 (file)
@@ -141,17 +141,7 @@ static struct platform_driver pxa_pcm_driver = {
        .remove = __devexit_p(pxa2xx_soc_platform_remove),
 };
 
-static int __init snd_pxa_pcm_init(void)
-{
-       return platform_driver_register(&pxa_pcm_driver);
-}
-module_init(snd_pxa_pcm_init);
-
-static void __exit snd_pxa_pcm_exit(void)
-{
-       platform_driver_unregister(&pxa_pcm_driver);
-}
-module_exit(snd_pxa_pcm_exit);
+module_platform_driver(pxa_pcm_driver);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
index b899a3bc8f42356cce6e9c6f1629bf0402f5706d..ba1545188ec66150b953234bd086f5cccc0f0882 100644 (file)
@@ -260,6 +260,7 @@ static struct snd_soc_dai_link snd_soc_raumfeld_speaker_dai[] =
 
 static struct snd_soc_card snd_soc_raumfeld_connector = {
        .name           = "Raumfeld Connector",
+       .owner          = THIS_MODULE,
        .dai_link       = snd_soc_raumfeld_connector_dai,
        .num_links      = ARRAY_SIZE(snd_soc_raumfeld_connector_dai),
        .suspend_post   = raumfeld_analog_suspend,
@@ -268,6 +269,7 @@ static struct snd_soc_card snd_soc_raumfeld_connector = {
 
 static struct snd_soc_card snd_soc_raumfeld_speaker = {
        .name           = "Raumfeld Speaker",
+       .owner          = THIS_MODULE,
        .dai_link       = snd_soc_raumfeld_speaker_dai,
        .num_links      = ARRAY_SIZE(snd_soc_raumfeld_speaker_dai),
        .suspend_post   = raumfeld_analog_suspend,
index d9467a2c6de0ec635d0c4d9a0cc8f838b24f8f64..c34146b776b4885faa090fa2cae671874e6acc72 100644 (file)
@@ -51,7 +51,7 @@ static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
 };
 
 /* saarb machine audio map */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route saarb_audio_map[] = {
        {"Headset Stereophone", NULL, "HS1"},
        {"Headset Stereophone", NULL, "HS2"},
 
@@ -92,15 +92,6 @@ static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
 
        return ret;
@@ -119,25 +110,28 @@ static struct snd_soc_dai_link saarb_dai[] = {
                .platform_name  = "pxa-pcm-audio",
                .codec_name     = "88pm860x-codec",
                .init           = saarb_pm860x_init,
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM,
                .ops            = &saarb_i2s_ops,
        },
 };
 
 static struct snd_soc_card snd_soc_card_saarb = {
        .name = "Saarb",
+       .owner = THIS_MODULE,
        .dai_link = saarb_dai,
        .num_links = ARRAY_SIZE(saarb_dai),
+
+       .dapm_widgets = saarb_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(saarb_dapm_widgets),
+       .dapm_routes = saarb_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(saarb_audio_map),
 };
 
 static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       snd_soc_dapm_new_controls(dapm, saarb_dapm_widgets,
-                                 ARRAY_SIZE(saarb_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* connected pins */
        snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
index c2d6ff9b1588a63c7faed4477e944b5948da51d7..90c5245c4742493bc7406d27d5d7bf11d2a74423 100644 (file)
@@ -143,18 +143,6 @@ static int spitz_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
@@ -234,7 +222,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
 };
 
 /* Spitz machine audio_map */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route spitz_audio_map[] = {
 
        /* headphone connected to LOUT1, ROUT1 */
        {"Headphone Jack", NULL, "LOUT1"},
@@ -277,7 +265,6 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int err;
 
        /* NC codec pins */
        snd_soc_dapm_nc_pin(dapm, "RINPUT1");
@@ -288,19 +275,6 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_nc_pin(dapm, "OUT3");
        snd_soc_dapm_nc_pin(dapm, "MONO1");
 
-       /* Add spitz specific controls */
-       err = snd_soc_add_controls(codec, wm8750_spitz_controls,
-                               ARRAY_SIZE(wm8750_spitz_controls));
-       if (err < 0)
-               return err;
-
-       /* Add spitz specific widgets */
-       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
-                                 ARRAY_SIZE(wm8750_dapm_widgets));
-
-       /* Set up spitz specific audio paths */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        return 0;
 }
 
@@ -313,14 +287,24 @@ static struct snd_soc_dai_link spitz_dai = {
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8750.0-001b",
        .init = spitz_wm8750_init,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &spitz_ops,
 };
 
 /* spitz audio machine driver */
 static struct snd_soc_card snd_soc_spitz = {
        .name = "Spitz",
+       .owner = THIS_MODULE,
        .dai_link = &spitz_dai,
        .num_links = 1,
+
+       .controls = wm8750_spitz_controls,
+       .num_controls = ARRAY_SIZE(wm8750_spitz_controls),
+       .dapm_widgets = wm8750_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+       .dapm_routes = spitz_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
 };
 
 static struct platform_device *spitz_snd_device;
index eeec892e0e0480ac07a167cfc84f626ea552121d..8b5ab8f72726258b7e604c24e4c766baa594465d 100644 (file)
@@ -51,7 +51,7 @@ static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
 };
 
 /* tavorevb3 machine audio map */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route evb3_audio_map[] = {
        {"Headset Stereophone", NULL, "HS1"},
        {"Headset Stereophone", NULL, "HS2"},
 
@@ -92,16 +92,6 @@ static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
        return ret;
 }
@@ -119,25 +109,28 @@ static struct snd_soc_dai_link evb3_dai[] = {
                .platform_name  = "pxa-pcm-audio",
                .codec_name     = "88pm860x-codec",
                .init           = evb3_pm860x_init,
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM,
                .ops            = &evb3_i2s_ops,
        },
 };
 
 static struct snd_soc_card snd_soc_card_evb3 = {
        .name = "Tavor EVB3",
+       .owner = THIS_MODULE,
        .dai_link = evb3_dai,
        .num_links = ARRAY_SIZE(evb3_dai),
+
+       .dapm_widgets = evb3_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(evb3_dapm_widgets),
+       .dapm_routes = evb3_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(evb3_audio_map),
 };
 
 static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       snd_soc_dapm_new_controls(dapm, evb3_dapm_widgets,
-                                 ARRAY_SIZE(evb3_dapm_widgets));
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* connected pins */
        snd_soc_dapm_enable_pin(dapm, "Ext Speaker");
index 620fc69ae6324507a6feab69f3ea66d33f2d5d6d..564ef08a89f2d410efae0d45dcdc1691d9e32b5d 100644 (file)
@@ -34,8 +34,6 @@
 #include "../codecs/wm9712.h"
 #include "pxa2xx-ac97.h"
 
-static struct snd_soc_card tosa;
-
 #define TOSA_HP        0
 #define TOSA_MIC_INT   1
 #define TOSA_HEADSET   2
@@ -236,70 +234,56 @@ static struct snd_soc_dai_link tosa_dai[] = {
 },
 };
 
-static int tosa_probe(struct snd_soc_card *card)
-{
-       int ret;
-
-       ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack");
-       if (ret)
-               return ret;
-       ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0);
-       if (ret)
-               gpio_free(TOSA_GPIO_L_MUTE);
-
-       return ret;
-}
-
-static int tosa_remove(struct snd_soc_card *card)
-{
-       gpio_free(TOSA_GPIO_L_MUTE);
-       return 0;
-}
-
 static struct snd_soc_card tosa = {
        .name = "Tosa",
+       .owner = THIS_MODULE,
        .dai_link = tosa_dai,
        .num_links = ARRAY_SIZE(tosa_dai),
-       .probe = tosa_probe,
-       .remove = tosa_remove,
 };
 
-static struct platform_device *tosa_snd_device;
-
-static int __init tosa_init(void)
+static int __devinit tosa_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &tosa;
        int ret;
 
-       if (!machine_is_tosa())
-               return -ENODEV;
-
-       tosa_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!tosa_snd_device) {
-               ret = -ENOMEM;
-               goto err_alloc;
-       }
-
-       platform_set_drvdata(tosa_snd_device, &tosa);
-       ret = platform_device_add(tosa_snd_device);
-
-       if (!ret)
-               return 0;
+       ret = gpio_request_one(TOSA_GPIO_L_MUTE, GPIOF_OUT_INIT_LOW,
+                              "Headphone Jack");
+       if (ret)
+               return ret;
 
-       platform_device_put(tosa_snd_device);
+       card->dev = &pdev->dev;
 
-err_alloc:
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               gpio_free(TOSA_GPIO_L_MUTE);
+       }
        return ret;
 }
 
-static void __exit tosa_exit(void)
+static int __devexit tosa_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(tosa_snd_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       gpio_free(TOSA_GPIO_L_MUTE);
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(tosa_init);
-module_exit(tosa_exit);
+static struct platform_driver tosa_driver = {
+       .driver         = {
+               .name   = "tosa-audio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tosa_probe,
+       .remove         = __devexit_p(tosa_remove),
+};
+
+module_platform_driver(tosa_driver);
 
 /* Module information */
 MODULE_AUTHOR("Richard Purdie");
 MODULE_DESCRIPTION("ALSA SoC Tosa");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tosa-audio");
index b311ffe04b71f6a0a1e87bd7470f0b50a422ecd3..76ccb172d0a77ed23be7b1fc441e388ce41b57fe 100644 (file)
@@ -56,18 +56,6 @@ static int z2_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
                SND_SOC_CLOCK_IN);
@@ -124,7 +112,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
 };
 
 /* Z2 machine audio_map */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route z2_audio_map[] = {
 
        /* headphone connected to LOUT1, ROUT1 */
        {"Headphone Jack", NULL, "LOUT1"},
@@ -154,13 +142,6 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
        snd_soc_dapm_disable_pin(dapm, "OUT3");
        snd_soc_dapm_disable_pin(dapm, "MONO1");
 
-       /* Add z2 specific widgets */
-       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
-                                ARRAY_SIZE(wm8750_dapm_widgets));
-
-       /* Set up z2 specific audio paths */
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
        /* Jack detection API stuff */
        ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
                                &hs_jack);
@@ -196,14 +177,22 @@ static struct snd_soc_dai_link z2_dai = {
        .platform_name = "pxa-pcm-audio",
        .codec_name     = "wm8750.0-001b",
        .init           = z2_wm8750_init,
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &z2_ops,
 };
 
 /* z2 audio machine driver */
 static struct snd_soc_card snd_soc_z2 = {
        .name           = "Z2",
+       .owner          = THIS_MODULE,
        .dai_link       = &z2_dai,
        .num_links      = 1,
+
+       .dapm_widgets = wm8750_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+       .dapm_routes = z2_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(z2_audio_map),
 };
 
 static struct platform_device *z2_snd_device;
index 580aae38e502ce859e0d58978f0f0c0d0b30d4ba..ceb656695b0fbc2f438779ac8331052063d83643 100644 (file)
@@ -249,6 +249,7 @@ static int zylonite_resume_pre(struct snd_soc_card *card)
 
 static struct snd_soc_card zylonite = {
        .name = "Zylonite",
+       .owner = THIS_MODULE,
        .probe = &zylonite_probe,
        .remove = &zylonite_remove,
        .suspend_post = &zylonite_suspend_post,
index 3052f64b2403929a62fec3c8257aedec40c8a7a2..aaabdbaec19c6cf389f887669af54a3558f16aba 100644 (file)
@@ -409,7 +409,7 @@ static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
                         SNDRV_PCM_RATE_8000_192000)
 #define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
+static const struct snd_soc_dai_ops s6000_i2s_dai_ops = {
        .set_fmt = s6000_i2s_set_dai_fmt,
        .set_clkdiv = s6000_i2s_set_clkdiv,
        .hw_params = s6000_i2s_hw_params,
@@ -604,17 +604,7 @@ static struct platform_driver s6000_i2s_driver = {
        },
 };
 
-static int __init s6000_i2s_init(void)
-{
-       return platform_driver_register(&s6000_i2s_driver);
-}
-module_init(s6000_i2s_init);
-
-static void __exit s6000_i2s_exit(void)
-{
-       platform_driver_unregister(&s6000_i2s_driver);
-}
-module_exit(s6000_i2s_exit);
+module_platform_driver(s6000_i2s_driver);
 
 MODULE_AUTHOR("Daniel Gloeckner");
 MODULE_DESCRIPTION("Stretch s6000 family I2S SoC Interface");
index 55efc2bdf0bd0a4fd73f938299764222601a5014..43c014f362f60643a9f5f4d798a2c651b6c0af1b 100644 (file)
@@ -520,17 +520,7 @@ static struct platform_driver s6000_pcm_driver = {
        .remove = __devexit_p(s6000_soc_platform_remove),
 };
 
-static int __init snd_s6000_pcm_init(void)
-{
-       return platform_driver_register(&s6000_pcm_driver);
-}
-module_init(snd_s6000_pcm_init);
-
-static void __exit snd_s6000_pcm_exit(void)
-{
-       platform_driver_unregister(&s6000_pcm_driver);
-}
-module_exit(snd_s6000_pcm_exit);
+module_platform_driver(s6000_pcm_driver);
 
 MODULE_AUTHOR("Daniel Gloeckner");
 MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
index 5890e431852f1cc5d0f0d663595a0543db14a66c..58cfb1eb7dd3aece2e20b7c45421b0aa5cab5533 100644 (file)
@@ -187,6 +187,7 @@ static struct snd_soc_dai_link s6105_dai = {
 /* s6105 audio machine driver */
 static struct snd_soc_card snd_soc_card_s6105 = {
        .name = "Stretch IP Camera",
+       .owner = THIS_MODULE,
        .dai_link = &s6105_dai,
        .num_links = 1,
 };
index 53aaa69eda0365c40a909573d7cbb23901311d75..f3417f2311b819bd4a3eb5590b26c338c162de05 100644 (file)
@@ -193,8 +193,22 @@ config SND_SOC_SPEYSIDE
        select SND_SOC_WM9081
        select SND_SOC_WM1250_EV1
 
-config SND_SOC_SPEYSIDE_WM8962
-       tristate "Audio support for Wolfson Speyside with WM8962"
+config SND_SOC_TOBERMORY
+       tristate "Audio support for Wolfson Tobermory"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8962
+
+config SND_SOC_LOWLAND
+       tristate "Audio support for Wolfson Lowland"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM5100
+       select SND_SOC_WM9081
+
+config SND_SOC_LITTLEMILL
+       tristate "Audio support for Wolfson Littlemill"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select MFD_WM8994
+       select SND_SOC_WM8994
index 8509d3c4366e76178c5cdb0a1a75573b9934b3a7..9d03beb40c86909e51671f531ef67e43fe73a0d8 100644 (file)
@@ -39,7 +39,9 @@ snd-soc-smdk-spdif-objs := smdk_spdif.o
 snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
 snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
 snd-soc-speyside-objs := speyside.o
-snd-soc-speyside-wm8962-objs := speyside_wm8962.o
+snd-soc-tobermory-objs := tobermory.o
+snd-soc-lowland-objs := lowland.o
+snd-soc-littlemill-objs := littlemill.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -60,4 +62,6 @@ obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
 obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
 obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
 obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
-obj-$(CONFIG_SND_SOC_SPEYSIDE_WM8962) += snd-soc-speyside-wm8962.o
+obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
+obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
+obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
index 16521e3ffc0c5af67712c1cdc1cd3c00e4ad501a..7b9bf93e3701edf92bd47b74d39c8d58de4f690e 100644 (file)
@@ -329,12 +329,12 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
+static const 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 = {
+static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
        .hw_params      = s3c_ac97_hw_mic_params,
        .trigger        = s3c_ac97_mic_trigger,
 };
@@ -509,17 +509,7 @@ static struct platform_driver s3c_ac97_driver = {
        },
 };
 
-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_platform_driver(s3c_ac97_driver);
 
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
index a68b2644178477dd7fd6a5c0518498e4ff5da860..427ae0d9817bb95cb09fbab000d6a2d0a35d32c8 100644 (file)
@@ -403,7 +403,6 @@ static u64 dma_mask = DMA_BIT_MASK(32);
 static int dma_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -414,14 +413,14 @@ static int dma_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -458,17 +457,7 @@ static struct platform_driver asoc_dma_driver = {
        .remove = __devexit_p(samsung_asoc_platform_remove),
 };
 
-static int __init samsung_asoc_init(void)
-{
-       return platform_driver_register(&asoc_dma_driver);
-}
-module_init(samsung_asoc_init);
-
-static void __exit samsung_asoc_exit(void)
-{
-       platform_driver_unregister(&asoc_dma_driver);
-}
-module_exit(samsung_asoc_exit);
+module_platform_driver(asoc_dma_driver);
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
index 84f9c3cf7f3e18df691f4074b24bd804c5665e88..c23c2ae91f58e441ae095ba30f7cbadcd9f1d000 100644 (file)
@@ -244,6 +244,7 @@ static struct snd_soc_dai_link goni_dai[] = {
 
 static struct snd_soc_card goni = {
        .name = "goni",
+       .owner = THIS_MODULE,
        .dai_link = goni_dai,
        .num_links = ARRAY_SIZE(goni_dai),
 
index 03cfa5fcdcca9ea64b3696d76436bd6366bb9c4b..6e3257717c54b24c49fa840e8696ccd169612d86 100644 (file)
@@ -215,6 +215,7 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
 
 static struct snd_soc_card h1940_asoc = {
        .name = "h1940",
+       .owner = THIS_MODULE,
        .dai_link = h1940_uda1380_dai,
        .num_links = ARRAY_SIZE(h1940_uda1380_dai),
 
index bff42bf370b9c8849874db4792150fad27328010..87a874dc7a3542d12735d8e9b13a97181e4ab86f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
@@ -881,7 +882,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
                writel(CON_RSTCLR, i2s->addr + I2SCON);
 
        if (i2s->quirks & QUIRK_SEC_DAI)
-               idma_reg_addr_init((void *)i2s->addr,
+               idma_reg_addr_init(i2s->addr,
                                        i2s->sec_dai->idma_playback.dma_addr);
 
 probe_exit:
@@ -923,7 +924,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
        .trigger = i2s_trigger,
        .hw_params = i2s_hw_params,
        .set_fmt = i2s_set_fmt,
@@ -945,7 +946,7 @@ struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
 {
        struct i2s_dai *i2s;
 
-       i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
+       i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL);
        if (i2s == NULL)
                return NULL;
 
@@ -972,10 +973,8 @@ struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
                i2s->pdev = platform_device_register_resndata(NULL,
                                pdev->name, pdev->id + SAMSUNG_I2S_SECOFF,
                                NULL, 0, NULL, 0);
-               if (IS_ERR(i2s->pdev)) {
-                       kfree(i2s);
+               if (IS_ERR(i2s->pdev))
                        return NULL;
-               }
        }
 
        /* Pre-assign snd_soc_dai_set_drvdata */
@@ -1048,7 +1047,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev)
        if (!pri_dai) {
                dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
                ret = -ENOMEM;
-               goto err1;
+               goto err;
        }
 
        pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
@@ -1073,7 +1072,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev)
                if (!sec_dai) {
                        dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
                        ret = -ENOMEM;
-                       goto err2;
+                       goto err;
                }
                sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
                sec_dai->dma_playback.client =
@@ -1092,17 +1091,15 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev)
        if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
                dev_err(&pdev->dev, "Unable to configure gpio\n");
                ret = -EINVAL;
-               goto err3;
+               goto err;
        }
 
        snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
 
+       pm_runtime_enable(&pdev->dev);
+
        return 0;
-err3:
-       kfree(sec_dai);
-err2:
-       kfree(pri_dai);
-err1:
+err:
        release_mem_region(regs_base, resource_size(res));
 
        return ret;
@@ -1111,6 +1108,7 @@ err1:
 static __devexit int samsung_i2s_remove(struct platform_device *pdev)
 {
        struct i2s_dai *i2s, *other;
+       struct resource *res;
 
        i2s = dev_get_drvdata(&pdev->dev);
        other = i2s->pri_dai ? : i2s->sec_dai;
@@ -1119,7 +1117,7 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev)
                other->pri_dai = NULL;
                other->sec_dai = NULL;
        } else {
-               struct resource *res;
+               pm_runtime_disable(&pdev->dev);
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                if (res)
                        release_mem_region(res->start, resource_size(res));
@@ -1128,8 +1126,6 @@ static __devexit int samsung_i2s_remove(struct platform_device *pdev)
        i2s->pri_dai = NULL;
        i2s->sec_dai = NULL;
 
-       kfree(i2s);
-
        snd_soc_unregister_dai(&pdev->dev);
 
        return 0;
@@ -1144,17 +1140,7 @@ static struct platform_driver samsung_i2s_driver = {
        },
 };
 
-static int __init samsung_i2s_init(void)
-{
-       return platform_driver_register(&samsung_i2s_driver);
-}
-module_init(samsung_i2s_init);
-
-static void __exit samsung_i2s_exit(void)
-{
-       platform_driver_unregister(&samsung_i2s_driver);
-}
-module_exit(samsung_i2s_exit);
+module_platform_driver(samsung_i2s_driver);
 
 /* Module information */
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
index c41178efc9084b7c5fe3712bbb2e885f527bded5..c227c3163caeacba809ce7fc0b0b0276062a5008 100644 (file)
@@ -387,7 +387,6 @@ static u64 idma_mask = DMA_BIT_MASK(32);
 static int idma_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -396,21 +395,22 @@ static int idma_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->driver->playback.channels_min)
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = preallocate_idma_buffer(pcm,
                                SNDRV_PCM_STREAM_PLAYBACK);
+       }
 
        return ret;
 }
 
-void idma_reg_addr_init(void *regs, dma_addr_t addr)
+void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
 {
        spin_lock_init(&idma.lock);
        idma.regs = regs;
        idma.lp_tx_addr = addr;
 }
 
-struct snd_soc_platform_driver asoc_idma_platform = {
+static struct snd_soc_platform_driver asoc_idma_platform = {
        .ops = &idma_ops,
        .pcm_new = idma_new,
        .pcm_free = idma_free,
@@ -437,17 +437,7 @@ static struct platform_driver asoc_idma_driver = {
        .remove = __devexit_p(asoc_idma_platform_remove),
 };
 
-static int __init asoc_idma_init(void)
-{
-       return platform_driver_register(&asoc_idma_driver);
-}
-module_init(asoc_idma_init);
-
-static void __exit asoc_idma_exit(void)
-{
-       platform_driver_unregister(&asoc_idma_driver);
-}
-module_exit(asoc_idma_exit);
+module_platform_driver(asoc_idma_driver);
 
 MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
 MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
index 48273216166e42dcd653f02c03f282290e875b4a..8644946973e57a0168c9bd2ce9491c82660ffa6e 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef __SND_SOC_SAMSUNG_IDMA_H_
 #define __SND_SOC_SAMSUNG_IDMA_H_
 
-extern void idma_reg_addr_init(void *regs, dma_addr_t addr);
+extern void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr);
 
 /* dma_state */
 #define LPAM_DMA_STOP  0
index 8e523fd9189e562557b36b39671d9e12b7deefa2..1578663a1faa55de01e5d9110ef41dfe9963f4d4 100644 (file)
@@ -127,6 +127,7 @@ static struct snd_soc_dai_link jive_dai = {
 /* jive audio machine driver */
 static struct snd_soc_card snd_soc_machine_jive = {
        .name           = "Jive",
+       .owner          = THIS_MODULE,
        .dai_link       = &jive_dai,
        .num_links      = 1,
 
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
new file mode 100644 (file)
index 0000000..9dd818b
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Littlemill audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm8994.h"
+
+static int sample_rate = 44100;
+
+static int littlemill_set_bias_level(struct snd_soc_card *card,
+                                         struct snd_soc_dapm_context *dapm,
+                                         enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               /*
+                * If we've not already clocked things via hw_params()
+                * then do so now, otherwise these are noops.
+                */
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+                                                 WM8994_FLL_SRC_MCLK2, 32768,
+                                                 sample_rate * 512);
+                       if (ret < 0) {
+                               pr_err("Failed to start FLL: %d\n", ret);
+                               return ret;
+                       }
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                                    WM8994_SYSCLK_FLL1,
+                                                    sample_rate * 512,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               pr_err("Failed to set SYSCLK: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int littlemill_set_bias_level_post(struct snd_soc_card *card,
+                                              struct snd_soc_dapm_context *dapm,
+                                              enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+                                            32768, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       pr_err("Failed to switch away from FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+                                         0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int littlemill_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       sample_rate = params_rate(params);
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+                                 WM8994_FLL_SRC_MCLK2, 32768,
+                                 sample_rate * 512);
+       if (ret < 0) {
+               pr_err("Failed to start FLL: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                    WM8994_SYSCLK_FLL1,
+                                    sample_rate * 512,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err("Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops littlemill_ops = {
+       .hw_params = littlemill_hw_params,
+};
+
+static struct snd_soc_dai_link littlemill_dai[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8994-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8994-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ops = &littlemill_ops,
+       },
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+       { "Headphone", NULL, "HPOUT1L" },
+       { "Headphone", NULL, "HPOUT1R" },
+
+       { "AMIC", NULL, "MICBIAS1" },   /* Default for AMICBIAS jumper */
+       { "IN1LN", NULL, "AMIC" },
+
+       { "DMIC", NULL, "MICBIAS2" },   /* Default for DMICBIAS jumper */
+       { "DMIC1DAT", NULL, "DMIC" },
+       { "DMIC2DAT", NULL, "DMIC" },
+};
+
+static struct snd_soc_jack littlemill_headset;
+
+static int littlemill_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec = card->rtd[0].codec;
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+                                    32768, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                              SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                              SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                              SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                              &littlemill_headset);
+       if (ret)
+               return ret;
+
+       /* This will check device compatibility itself */
+       wm8958_mic_detect(codec, &littlemill_headset, NULL, NULL);
+
+       return 0;
+}
+
+static struct snd_soc_card littlemill = {
+       .name = "Littlemill",
+       .owner = THIS_MODULE,
+       .dai_link = littlemill_dai,
+       .num_links = ARRAY_SIZE(littlemill_dai),
+
+       .set_bias_level = littlemill_set_bias_level,
+       .set_bias_level_post = littlemill_set_bias_level_post,
+
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
+
+       .late_probe = littlemill_late_probe,
+};
+
+static __devinit int littlemill_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &littlemill;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit littlemill_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver littlemill_driver = {
+       .driver = {
+               .name = "littlemill",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = littlemill_probe,
+       .remove = __devexit_p(littlemill_remove),
+};
+
+module_platform_driver(littlemill_driver);
+
+MODULE_DESCRIPTION("Littlemill audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:littlemill");
index cde38b8e9dc23917551e67b68acbf6b1f8033aac..69c4a5934a4d936c2dc48af9dcf980c987825ed2 100644 (file)
@@ -34,6 +34,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
 
 static struct snd_soc_card ln2440sbc = {
        .name = "LN2440SBC",
+       .owner = THIS_MODULE,
        .dai_link = ln2440sbc_dai,
        .num_links = ARRAY_SIZE(ln2440sbc_dai),
 };
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
new file mode 100644 (file)
index 0000000..4adff93
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Lowland audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm5100.h"
+#include "../codecs/wm9081.h"
+
+#define MCLK1_RATE (44100 * 512)
+#define CLKOUT_RATE (44100 * 256)
+
+static int lowland_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops lowland_ops = {
+       .hw_params = lowland_hw_params,
+};
+
+static struct snd_soc_jack lowland_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin lowland_headset_pins[] = {
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
+       },
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       ret = snd_soc_codec_set_sysclk(codec, WM5100_CLK_SYSCLK,
+                                      WM5100_CLKSRC_MCLK1, MCLK1_RATE,
+                                      SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err("Failed to set SYSCLK clock source: %d\n", ret);
+               return ret;
+       }
+
+       /* Clock OPCLK, used by the other audio components. */
+       ret = snd_soc_codec_set_sysclk(codec, WM5100_CLK_OPCLK, 0,
+                                      CLKOUT_RATE, 0);
+       if (ret < 0) {
+               pr_err("Failed to set OPCLK rate: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_LINEOUT | SND_JACK_HEADSET |
+                              SND_JACK_BTN_0,
+                              &lowland_headset);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&lowland_headset,
+                                   ARRAY_SIZE(lowland_headset_pins),
+                                   lowland_headset_pins);
+       if (ret)
+               return ret;
+
+       wm5100_detect(codec, &lowland_headset);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link lowland_dai[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm5100-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm5100.1-001a",
+               .ops = &lowland_ops,
+               .init = lowland_wm5100_init,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm5100-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .ops = &lowland_ops,
+               .ignore_suspend = 1,
+       },
+};
+
+static int lowland_wm9081_init(struct snd_soc_dapm_context *dapm)
+{
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT");
+
+       /* At any time the WM9081 is active it will have this clock */
+       return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
+                                       CLKOUT_RATE, 0);
+}
+
+static struct snd_soc_aux_dev lowland_aux_dev[] = {
+       {
+               .name = "wm9081",
+               .codec_name = "wm9081.1-006c",
+               .init = lowland_wm9081_init,
+       },
+};
+
+static struct snd_soc_codec_conf lowland_codec_conf[] = {
+       {
+               .dev_name = "wm9081.1-006c",
+               .name_prefix = "Sub",
+       },
+};
+
+static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Main Speaker"),
+       SOC_DAPM_PIN_SWITCH("Main DMIC"),
+       SOC_DAPM_PIN_SWITCH("Main AMIC"),
+       SOC_DAPM_PIN_SWITCH("WM1250 Input"),
+       SOC_DAPM_PIN_SWITCH("WM1250 Output"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+       SND_SOC_DAPM_SPK("Main Speaker", NULL),
+
+       SND_SOC_DAPM_MIC("Main AMIC", NULL),
+       SND_SOC_DAPM_MIC("Main DMIC", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+       { "Sub IN1", NULL, "HPOUT2L" },
+       { "Sub IN2", NULL, "HPOUT2R" },
+
+       { "Main Speaker", NULL, "Sub SPKN" },
+       { "Main Speaker", NULL, "Sub SPKP" },
+       { "Main Speaker", NULL, "SPKDAT1" },
+};
+
+static struct snd_soc_card lowland = {
+       .name = "Lowland",
+       .owner = THIS_MODULE,
+       .dai_link = lowland_dai,
+       .num_links = ARRAY_SIZE(lowland_dai),
+       .aux_dev = lowland_aux_dev,
+       .num_aux_devs = ARRAY_SIZE(lowland_aux_dev),
+       .codec_conf = lowland_codec_conf,
+       .num_configs = ARRAY_SIZE(lowland_codec_conf),
+
+       .controls = controls,
+       .num_controls = ARRAY_SIZE(controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
+};
+
+static __devinit int lowland_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &lowland;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit lowland_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver lowland_driver = {
+       .driver = {
+               .name = "lowland",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = lowland_probe,
+       .remove = __devexit_p(lowland_remove),
+};
+
+module_platform_driver(lowland_driver);
+
+MODULE_DESCRIPTION("Lowland audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lowland");
index 7207189cd21196aa0dc574aec3bed3b88d9869e9..7ac0ba2025c337b5f313996f00a04c52975cb9a5 100644 (file)
@@ -465,6 +465,7 @@ static const struct gpio neo1973_gta02_gpios[] = {};
 
 static struct snd_soc_card neo1973 = {
        .name = "neo1973",
+       .owner = THIS_MODULE,
        .dai_link = neo1973_dai,
        .num_links = ARRAY_SIZE(neo1973_dai),
        .aux_dev = neo1973_aux_devs,
index 05a47cf7f06e9345285fe57d7d1688049c7c23ea..56780206c000be484f2f9651e6be53158794cc7d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
@@ -452,7 +453,7 @@ static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
        return 0;
 }
 
-static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
        .set_sysclk     = s3c_pcm_set_sysclk,
        .set_clkdiv     = s3c_pcm_set_clkdiv,
        .trigger        = s3c_pcm_trigger,
@@ -478,7 +479,7 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
                .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
        }
 
-struct snd_soc_dai_driver s3c_pcm_dai[] = {
+static struct snd_soc_dai_driver s3c_pcm_dai[] = {
        [0] = {
                .name   = "samsung-pcm.0",
                S3C_PCM_DAI_DECLARE,
@@ -488,7 +489,6 @@ struct snd_soc_dai_driver s3c_pcm_dai[] = {
                S3C_PCM_DAI_DECLARE,
        },
 };
-EXPORT_SYMBOL_GPL(s3c_pcm_dai);
 
 static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
@@ -570,12 +570,6 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        }
        clk_enable(pcm->pclk);
 
-       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "failed to get pcm_clock\n");
-               goto err5;
-       }
-
        s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
                                                        + S3C_PCM_RXFIFO;
        s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
@@ -587,6 +581,14 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
        pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
 
+       pm_runtime_enable(&pdev->dev);
+
+       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
+               goto err5;
+       }
+
        return 0;
 
 err5:
@@ -610,6 +612,8 @@ static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
 
        snd_soc_unregister_dai(&pdev->dev);
 
+       pm_runtime_disable(&pdev->dev);
+
        iounmap(pcm->regs);
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -632,17 +636,7 @@ static struct platform_driver s3c_pcm_driver = {
        },
 };
 
-static int __init s3c_pcm_init(void)
-{
-       return platform_driver_register(&s3c_pcm_driver);
-}
-module_init(s3c_pcm_init);
-
-static void __exit s3c_pcm_exit(void)
-{
-       platform_driver_unregister(&s3c_pcm_driver);
-}
-module_exit(s3c_pcm_exit);
+module_platform_driver(s3c_pcm_driver);
 
 /* Module information */
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
index 71b4c029fc352eefe5619b1546af5e54e32a8d32..21e12361a9cd137e1ae595a20c50210dcce9283a 100644 (file)
@@ -114,6 +114,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static struct snd_soc_card rx1950_asoc = {
        .name = "rx1950",
+       .owner = THIS_MODULE,
        .dai_link = rx1950_uda1380_dai,
        .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
 
index 7bbec25e6e158b824561da968d91ee811564858a..72185078ddf8ef6f40a78105a6af09a4f33bf1b4 100644 (file)
@@ -142,7 +142,7 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
+static const struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
        .hw_params      = s3c2412_i2s_hw_params,
 };
 
@@ -184,17 +184,7 @@ static struct platform_driver s3c2412_iis_driver = {
        },
 };
 
-static int __init s3c2412_i2s_init(void)
-{
-       return platform_driver_register(&s3c2412_iis_driver);
-}
-module_init(s3c2412_i2s_init);
-
-static void __exit s3c2412_i2s_exit(void)
-{
-       platform_driver_unregister(&s3c2412_iis_driver);
-}
-module_exit(s3c2412_i2s_exit);
+module_platform_driver(s3c2412_iis_driver);
 
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
index 558c64bbed2e66f0c02d0ecd600605f2bfc1e3fa..c4aa4d412fbf56e94a86b46f3a1775e01d325e1d 100644 (file)
@@ -444,7 +444,7 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
        SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+static const struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
        .trigger        = s3c24xx_i2s_trigger,
        .hw_params      = s3c24xx_i2s_hw_params,
        .set_fmt        = s3c24xx_i2s_set_fmt,
@@ -489,17 +489,7 @@ static struct platform_driver s3c24xx_iis_driver = {
        },
 };
 
-static int __init s3c24xx_i2s_init(void)
-{
-       return platform_driver_register(&s3c24xx_iis_driver);
-}
-module_init(s3c24xx_i2s_init);
-
-static void __exit s3c24xx_i2s_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_iis_driver);
-}
-module_exit(s3c24xx_i2s_exit);
+module_platform_driver(s3c24xx_iis_driver);
 
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
index d125e79baf7f4bd74e2773402312d88183b1dc00..7ace6a87f41b5e673a49f87f1e659be6ea11cd73 100644 (file)
@@ -89,6 +89,7 @@ static struct snd_soc_dai_link simtec_dai_aic33 = {
 /* simtec audio machine driver */
 static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
        .name           = "Simtec-Hermes",
+       .owner          = THIS_MODULE,
        .dai_link       = &simtec_dai_aic33,
        .num_links      = 1,
 
@@ -114,21 +115,9 @@ static struct platform_driver simtec_audio_hermes_platdrv = {
        .remove = __devexit_p(simtec_audio_remove),
 };
 
-MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
-
-static int __init simtec_hermes_modinit(void)
-{
-       return platform_driver_register(&simtec_audio_hermes_platdrv);
-}
-
-static void __exit simtec_hermes_modexit(void)
-{
-       platform_driver_unregister(&simtec_audio_hermes_platdrv);
-}
-
-module_init(simtec_hermes_modinit);
-module_exit(simtec_hermes_modexit);
+module_platform_driver(simtec_audio_hermes_platdrv);
 
+MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
 MODULE_LICENSE("GPL");
index 5e4fd46b7200066d917e5f0a8e00fe9ffa328394..c42d5f00b0e1cc2cdc75bfcd625bc02a35aa7825 100644 (file)
@@ -78,6 +78,7 @@ static struct snd_soc_dai_link simtec_dai_aic23 = {
 /* simtec audio machine driver */
 static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
        .name           = "Simtec",
+       .owner          = THIS_MODULE,
        .dai_link       = &simtec_dai_aic23,
        .num_links      = 1,
 
@@ -92,7 +93,7 @@ static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
        return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
 }
 
-static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
+static struct platform_driver simtec_audio_tlv320aic23_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "s3c24xx-simtec-tlv320aic23",
@@ -102,21 +103,9 @@ static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
        .remove = __devexit_p(simtec_audio_remove),
 };
 
-MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
-
-static int __init simtec_tlv320aic23_modinit(void)
-{
-       return platform_driver_register(&simtec_audio_tlv320aic23_platdrv);
-}
-
-static void __exit simtec_tlv320aic23_modexit(void)
-{
-       platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv);
-}
-
-module_init(simtec_tlv320aic23_modinit);
-module_exit(simtec_tlv320aic23_modexit);
+module_platform_driver(simtec_audio_tlv320aic23_driver);
 
+MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
 MODULE_LICENSE("GPL");
index 548c6ac6e7b06bdc5e9da816836a6bf3a90b7b6a..d731042e51b07db12aff2adc6685d97f3af6e00e 100644 (file)
@@ -229,6 +229,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 
 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
        .name = "S3C24XX_UDA134X",
+       .owner = THIS_MODULE,
        .dai_link = &s3c24xx_uda134x_dai_link,
        .num_links = 1,
 };
@@ -343,19 +344,7 @@ static struct platform_driver s3c24xx_uda134x_driver = {
        },
 };
 
-static int __init s3c24xx_uda134x_init(void)
-{
-       return platform_driver_register(&s3c24xx_uda134x_driver);
-}
-
-static void __exit s3c24xx_uda134x_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_uda134x_driver);
-}
-
-
-module_init(s3c24xx_uda134x_init);
-module_exit(s3c24xx_uda134x_exit);
+module_platform_driver(s3c24xx_uda134x_driver);
 
 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
index a22fc4402802bb36ee20136cfc6e13e622ed60b9..f2dcb424ea255056aa6f3dbe224d9f0bfe14dfe7 100644 (file)
@@ -198,6 +198,7 @@ static struct snd_soc_dai_link smartq_dai[] = {
 
 static struct snd_soc_card snd_soc_smartq = {
        .name = "SmartQ",
+       .owner = THIS_MODULE,
        .dai_link = smartq_dai,
        .num_links = ARRAY_SIZE(smartq_dai),
 
index 8bd1dc5706bf1f423f5d0c7d63a7316c5b9191d0..720ba29bb7e4174e0929a77490f55b7f72c88f09 100644 (file)
@@ -30,6 +30,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
 
 static struct snd_soc_card smdk2443 = {
        .name = "SMDK2443",
+       .owner = THIS_MODULE,
        .dai_link = smdk2443_dai,
        .num_links = ARRAY_SIZE(smdk2443_dai),
 };
index e0fd8ad23552d4fcb8822be2c2d6348d27607890..beaa9c15d6978c64f3899596a7239f829fddb63d 100644 (file)
@@ -160,6 +160,7 @@ static struct snd_soc_dai_link smdk_dai = {
 
 static struct snd_soc_card smdk = {
        .name = "SMDK-S/PDIF",
+       .owner = THIS_MODULE,
        .dai_link = &smdk_dai,
        .num_links = 1,
 };
index 81b447823992c46b68e0faadc7ff8085bd8a9339..bff8758e7f20807e38253a6c202d91d5421c402e 100644 (file)
@@ -203,6 +203,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
 
 static struct snd_soc_card smdk = {
        .name = "SMDK-I2S",
+       .owner = THIS_MODULE,
        .dai_link = smdk_dai,
        .num_links = 2,
 
index 0677473e6b608ef5df677214258c87680687e640..fab5322e9f055002a3acb8a1d6b0bae06f457f38 100644 (file)
@@ -143,6 +143,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
 
 static struct snd_soc_card smdk_pcm = {
        .name = "SMDK-PCM",
+       .owner = THIS_MODULE,
        .dai_link = smdk_dai,
        .num_links = 2,
 };
@@ -188,19 +189,7 @@ static struct platform_driver snd_smdk_driver = {
        .remove = __devexit_p(snd_smdk_remove),
 };
 
-static int __init smdk_audio_init(void)
-{
-       return platform_driver_register(&snd_smdk_driver);
-}
-
-module_init(smdk_audio_init);
-
-static void __exit smdk_audio_exit(void)
-{
-       platform_driver_unregister(&snd_smdk_driver);
-}
-
-module_exit(smdk_audio_exit);
+module_platform_driver(snd_smdk_driver);
 
 MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
index ad9ac42522e2539faf84c6286cc1614573e441f2..8eb309f23d18247983df33970601a8993747c721 100644 (file)
@@ -144,6 +144,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
 
 static struct snd_soc_card smdk = {
        .name = "SMDK-I2S",
+       .owner = THIS_MODULE,
        .dai_link = smdk_dai,
        .num_links = ARRAY_SIZE(smdk_dai),
 };
index da9c2a264d939d47c3ab4f6f5f65b406f7423d69..77ecba9351193c0ad2a8e6c6951449192e7bf3d2 100644 (file)
@@ -124,6 +124,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
 
 static struct snd_soc_card smdk_pcm = {
        .name = "SMDK-PCM",
+       .owner = THIS_MODULE,
        .dai_link = smdk_dai,
        .num_links = 1,
 };
@@ -158,19 +159,7 @@ static struct platform_driver snd_smdk_driver = {
        .remove = __devexit_p(snd_smdk_remove),
 };
 
-static int __init smdk_audio_init(void)
-{
-       return platform_driver_register(&snd_smdk_driver);
-}
-
-module_init(smdk_audio_init);
-
-static void __exit smdk_audio_exit(void)
-{
-       platform_driver_unregister(&snd_smdk_driver);
-}
-
-module_exit(smdk_audio_exit);
+module_platform_driver(snd_smdk_driver);
 
 MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8994 for PCM");
index 31c6daf6d4d02ba632783c711f7e3db563f7ef63..8e26a730fcdc787abb7d758e980d12fe6153f133 100644 (file)
@@ -50,6 +50,7 @@ static struct snd_soc_dai_link smdk_dai = {
 
 static struct snd_soc_card smdk = {
        .name = "SMDK WM9713",
+       .owner = THIS_MODULE,
        .dai_link = &smdk_dai,
        .num_links = 1,
 };
index 468cff1bb1af62b24372a4abcb6a9d9ad4536c78..a5a56a12034554255cbe520313268ab617eef292 100644 (file)
@@ -334,7 +334,7 @@ static int spdif_resume(struct snd_soc_dai *cpu_dai)
 #define spdif_resume NULL
 #endif
 
-static struct snd_soc_dai_ops spdif_dai_ops = {
+static const struct snd_soc_dai_ops spdif_dai_ops = {
        .set_sysclk     = spdif_set_sysclk,
        .trigger        = spdif_trigger,
        .hw_params      = spdif_hw_params,
@@ -483,17 +483,7 @@ static struct platform_driver samsung_spdif_driver = {
        },
 };
 
-static int __init spdif_init(void)
-{
-       return platform_driver_register(&samsung_spdif_driver);
-}
-module_init(spdif_init);
-
-static void __exit spdif_exit(void)
-{
-       platform_driver_unregister(&samsung_spdif_driver);
-}
-module_exit(spdif_exit);
+module_platform_driver(samsung_spdif_driver);
 
 MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
 MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
index 4b8e35410eb1962623cc31882967397747e5b3e7..f9ab7707a3e46674d464be23f36e9775df82169d 100644 (file)
@@ -19,6 +19,7 @@
 #include "../codecs/wm9081.h"
 
 #define WM8996_HPSEL_GPIO 214
+#define MCLK_AUDIO_RATE (512 * 48000)
 
 static int speyside_set_bias_level(struct snd_soc_card *card,
                                   struct snd_soc_dapm_context *dapm,
@@ -67,7 +68,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
                if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
                        ret = snd_soc_dai_set_pll(codec_dai, 0,
                                                  WM8996_FLL_MCLK2,
-                                                 32768, 48000 * 256);
+                                                 32768, MCLK_AUDIO_RATE);
                        if (ret < 0) {
                                pr_err("Failed to start FLL\n");
                                return ret;
@@ -75,7 +76,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
 
                        ret = snd_soc_dai_set_sysclk(codec_dai,
                                                     WM8996_SYSCLK_FLL,
-                                                    48000 * 256,
+                                                    MCLK_AUDIO_RATE,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0)
                                return ret;
@@ -222,11 +223,9 @@ static struct snd_soc_dai_link speyside_dai[] = {
 
 static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
 {
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT");
-
        /* At any time the WM9081 is active it will have this clock */
        return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
-                                       48000 * 256, 0);
+                                       MCLK_AUDIO_RATE, 0);
 }
 
 static struct snd_soc_aux_dev speyside_aux_dev[] = {
@@ -292,6 +291,7 @@ static struct snd_soc_dapm_route audio_paths[] = {
 
 static struct snd_soc_card speyside = {
        .name = "Speyside",
+       .owner = THIS_MODULE,
        .dai_link = speyside_dai,
        .num_links = ARRAY_SIZE(speyside_dai),
        .aux_dev = speyside_aux_dev,
@@ -308,6 +308,7 @@ static struct snd_soc_card speyside = {
        .num_dapm_widgets = ARRAY_SIZE(widgets),
        .dapm_routes = audio_paths,
        .num_dapm_routes = ARRAY_SIZE(audio_paths),
+       .fully_routed = true,
 
        .late_probe = speyside_late_probe,
 };
@@ -348,17 +349,7 @@ static struct platform_driver speyside_driver = {
        .remove = __devexit_p(speyside_remove),
 };
 
-static int __init speyside_audio_init(void)
-{
-       return platform_driver_register(&speyside_driver);
-}
-module_init(speyside_audio_init);
-
-static void __exit speyside_audio_exit(void)
-{
-       platform_driver_unregister(&speyside_driver);
-}
-module_exit(speyside_audio_exit);
+module_platform_driver(speyside_driver);
 
 MODULE_DESCRIPTION("Speyside audio support");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
deleted file mode 100644 (file)
index e3e2716..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Speyside with WM8962 audio support
- *
- * Copyright 2011 Wolfson Microelectronics
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-
-#include "../codecs/wm8962.h"
-
-static int sample_rate = 44100;
-
-static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
-                                         struct snd_soc_dapm_context *dapm,
-                                         enum snd_soc_bias_level level)
-{
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-       int ret;
-
-       if (dapm->dev != codec_dai->dev)
-               return 0;
-
-       switch (level) {
-       case SND_SOC_BIAS_PREPARE:
-               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
-                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
-                                                 WM8962_FLL_MCLK, 32768,
-                                                 sample_rate * 512);
-                       if (ret < 0)
-                               pr_err("Failed to start FLL: %d\n", ret);
-
-                       ret = snd_soc_dai_set_sysclk(codec_dai,
-                                                    WM8962_SYSCLK_FLL,
-                                                    sample_rate * 512,
-                                                    SND_SOC_CLOCK_IN);
-                       if (ret < 0) {
-                               pr_err("Failed to set SYSCLK: %d\n", ret);
-                               return ret;
-                       }
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int speyside_wm8962_set_bias_level_post(struct snd_soc_card *card,
-                                              struct snd_soc_dapm_context *dapm,
-                                              enum snd_soc_bias_level level)
-{
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-       int ret;
-
-       if (dapm->dev != codec_dai->dev)
-               return 0;
-
-       switch (level) {
-       case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
-                                            32768, SND_SOC_CLOCK_IN);
-               if (ret < 0) {
-                       pr_err("Failed to switch away from FLL: %d\n", ret);
-                       return ret;
-               }
-
-               ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
-                                         0, 0, 0);
-               if (ret < 0) {
-                       pr_err("Failed to stop FLL: %d\n", ret);
-                       return ret;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       dapm->bias_level = level;
-
-       return 0;
-}
-
-static int speyside_wm8962_hw_params(struct snd_pcm_substream *substream,
-                             struct snd_pcm_hw_params *params)
-{
-       sample_rate = params_rate(params);
-
-       return 0;
-}
-
-static struct snd_soc_ops speyside_wm8962_ops = {
-       .hw_params = speyside_wm8962_hw_params,
-};
-
-static struct snd_soc_dai_link speyside_wm8962_dai[] = {
-       {
-               .name = "CPU",
-               .stream_name = "CPU",
-               .cpu_dai_name = "samsung-i2s.0",
-               .codec_dai_name = "wm8962",
-               .platform_name = "samsung-audio",
-               .codec_name = "wm8962.1-001a",
-               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
-                               | SND_SOC_DAIFMT_CBM_CFM,
-               .ops = &speyside_wm8962_ops,
-       },
-};
-
-static const struct snd_kcontrol_new controls[] = {
-       SOC_DAPM_PIN_SWITCH("Main Speaker"),
-       SOC_DAPM_PIN_SWITCH("DMIC"),
-};
-
-static struct snd_soc_dapm_widget widgets[] = {
-       SND_SOC_DAPM_HP("Headphone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-
-       SND_SOC_DAPM_MIC("DMIC", NULL),
-       SND_SOC_DAPM_MIC("AMIC", NULL),
-
-       SND_SOC_DAPM_SPK("Main Speaker", NULL),
-};
-
-static struct snd_soc_dapm_route audio_paths[] = {
-       { "Headphone", NULL, "HPOUTL" },
-       { "Headphone", NULL, "HPOUTR" },
-
-       { "Main Speaker", NULL, "SPKOUTL" },
-       { "Main Speaker", NULL, "SPKOUTR" },
-
-       { "Headset Mic", NULL, "MICBIAS" },
-       { "IN4L", NULL, "Headset Mic" },
-       { "IN4R", NULL, "Headset Mic" },
-
-       { "AMIC", NULL, "MICBIAS" },
-       { "IN1L", NULL, "AMIC" },
-       { "IN1R", NULL, "AMIC" },
-
-       { "DMIC", NULL, "MICBIAS" },
-       { "DMICDAT", NULL, "DMIC" },
-};
-
-static struct snd_soc_jack speyside_wm8962_headset;
-
-/* Headset jack detection DAPM pins */
-static struct snd_soc_jack_pin speyside_wm8962_headset_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       },
-       {
-               .pin = "Headphone",
-               .mask = SND_JACK_MICROPHONE,
-       },
-};
-
-static int speyside_wm8962_late_probe(struct snd_soc_card *card)
-{
-       struct snd_soc_codec *codec = card->rtd[0].codec;
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
-       int ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
-                                    32768, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_jack_new(codec, "Headset",
-                              SND_JACK_HEADSET | SND_JACK_BTN_0,
-                              &speyside_wm8962_headset);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&speyside_wm8962_headset,
-                                   ARRAY_SIZE(speyside_wm8962_headset_pins),
-                                   speyside_wm8962_headset_pins);
-       if (ret)
-               return ret;
-
-       wm8962_mic_detect(codec, &speyside_wm8962_headset);
-
-       return 0;
-}
-
-static struct snd_soc_card speyside_wm8962 = {
-       .name = "Speyside WM8962",
-       .dai_link = speyside_wm8962_dai,
-       .num_links = ARRAY_SIZE(speyside_wm8962_dai),
-
-       .set_bias_level = speyside_wm8962_set_bias_level,
-       .set_bias_level_post = speyside_wm8962_set_bias_level_post,
-
-       .controls = controls,
-       .num_controls = ARRAY_SIZE(controls),
-       .dapm_widgets = widgets,
-       .num_dapm_widgets = ARRAY_SIZE(widgets),
-       .dapm_routes = audio_paths,
-       .num_dapm_routes = ARRAY_SIZE(audio_paths),
-
-       .late_probe = speyside_wm8962_late_probe,
-};
-
-static __devinit int speyside_wm8962_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &speyside_wm8962;
-       int ret;
-
-       card->dev = &pdev->dev;
-
-       ret = snd_soc_register_card(card);
-       if (ret) {
-               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
-                       ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int __devexit speyside_wm8962_remove(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
-
-       snd_soc_unregister_card(card);
-
-       return 0;
-}
-
-static struct platform_driver speyside_wm8962_driver = {
-       .driver = {
-               .name = "speyside-wm8962",
-               .owner = THIS_MODULE,
-               .pm = &snd_soc_pm_ops,
-       },
-       .probe = speyside_wm8962_probe,
-       .remove = __devexit_p(speyside_wm8962_remove),
-};
-
-static int __init speyside_wm8962_audio_init(void)
-{
-       return platform_driver_register(&speyside_wm8962_driver);
-}
-module_init(speyside_wm8962_audio_init);
-
-static void __exit speyside_wm8962_audio_exit(void)
-{
-       platform_driver_unregister(&speyside_wm8962_driver);
-}
-module_exit(speyside_wm8962_audio_exit);
-
-MODULE_DESCRIPTION("Speyside WM8962 audio support");
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:speyside-wm8962");
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
new file mode 100644 (file)
index 0000000..9199649
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Tobermory audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm8962.h"
+
+static int sample_rate = 44100;
+
+static int tobermory_set_bias_level(struct snd_soc_card *card,
+                                         struct snd_soc_dapm_context *dapm,
+                                         enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                                 WM8962_FLL_MCLK, 32768,
+                                                 sample_rate * 512);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+
+                       ret = snd_soc_dai_set_sysclk(codec_dai,
+                                                    WM8962_SYSCLK_FLL,
+                                                    sample_rate * 512,
+                                                    SND_SOC_CLOCK_IN);
+                       if (ret < 0) {
+                               pr_err("Failed to set SYSCLK: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int tobermory_set_bias_level_post(struct snd_soc_card *card,
+                                              struct snd_soc_dapm_context *dapm,
+                                              enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                                            32768, SND_SOC_CLOCK_IN);
+               if (ret < 0) {
+                       pr_err("Failed to switch away from FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL,
+                                         0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int tobermory_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       sample_rate = params_rate(params);
+
+       return 0;
+}
+
+static struct snd_soc_ops tobermory_ops = {
+       .hw_params = tobermory_hw_params,
+};
+
+static struct snd_soc_dai_link tobermory_dai[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8962",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8962.1-001a",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ops = &tobermory_ops,
+       },
+};
+
+static const struct snd_kcontrol_new controls[] = {
+       SOC_DAPM_PIN_SWITCH("Main Speaker"),
+       SOC_DAPM_PIN_SWITCH("DMIC"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+       SND_SOC_DAPM_MIC("DMIC", NULL),
+       SND_SOC_DAPM_MIC("AMIC", NULL),
+
+       SND_SOC_DAPM_SPK("Main Speaker", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+       { "Headphone", NULL, "HPOUTL" },
+       { "Headphone", NULL, "HPOUTR" },
+
+       { "Main Speaker", NULL, "SPKOUTL" },
+       { "Main Speaker", NULL, "SPKOUTR" },
+
+       { "Headset Mic", NULL, "MICBIAS" },
+       { "IN4L", NULL, "Headset Mic" },
+       { "IN4R", NULL, "Headset Mic" },
+
+       { "AMIC", NULL, "MICBIAS" },
+       { "IN1L", NULL, "AMIC" },
+       { "IN1R", NULL, "AMIC" },
+
+       { "DMIC", NULL, "MICBIAS" },
+       { "DMICDAT", NULL, "DMIC" },
+};
+
+static struct snd_soc_jack tobermory_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin tobermory_headset_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headphone",
+               .mask = SND_JACK_MICROPHONE,
+       },
+};
+
+static int tobermory_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec = card->rtd[0].codec;
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
+                                    32768, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_jack_new(codec, "Headset",
+                              SND_JACK_HEADSET | SND_JACK_BTN_0,
+                              &tobermory_headset);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&tobermory_headset,
+                                   ARRAY_SIZE(tobermory_headset_pins),
+                                   tobermory_headset_pins);
+       if (ret)
+               return ret;
+
+       wm8962_mic_detect(codec, &tobermory_headset);
+
+       return 0;
+}
+
+static struct snd_soc_card tobermory = {
+       .name = "Tobermory",
+       .owner = THIS_MODULE,
+       .dai_link = tobermory_dai,
+       .num_links = ARRAY_SIZE(tobermory_dai),
+
+       .set_bias_level = tobermory_set_bias_level,
+       .set_bias_level_post = tobermory_set_bias_level_post,
+
+       .controls = controls,
+       .num_controls = ARRAY_SIZE(controls),
+       .dapm_widgets = widgets,
+       .num_dapm_widgets = ARRAY_SIZE(widgets),
+       .dapm_routes = audio_paths,
+       .num_dapm_routes = ARRAY_SIZE(audio_paths),
+       .fully_routed = true,
+
+       .late_probe = tobermory_late_probe,
+};
+
+static __devinit int tobermory_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &tobermory;
+       int ret;
+
+       card->dev = &pdev->dev;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit tobermory_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static struct platform_driver tobermory_driver = {
+       .driver = {
+               .name = "tobermory",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = tobermory_probe,
+       .remove = __devexit_p(tobermory_remove),
+};
+
+module_platform_driver(tobermory_driver);
+
+MODULE_DESCRIPTION("Tobermory audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tobermory");
index db74005f37ce78b69d7dffd873d4bc82775e8a64..7da20186b19e63bdf7efe6372a33b41190e82a2f 100644 (file)
@@ -369,17 +369,7 @@ static struct platform_driver sh7760_pcm_driver = {
        .remove = __devexit_p(sh7760_soc_platform_remove),
 };
 
-static int __init snd_sh7760_pcm_init(void)
-{
-       return platform_driver_register(&sh7760_pcm_driver);
-}
-module_init(snd_sh7760_pcm_init);
-
-static void __exit snd_sh7760_pcm_exit(void)
-{
-       platform_driver_unregister(&sh7760_pcm_driver);
-}
-module_exit(snd_sh7760_pcm_exit);
+module_platform_driver(sh7760_pcm_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
index dff64b95f5dcf11671c282f850ea83af520c365b..97f540aabbdd6c1abd2f1bb51df9af5c1652fb07 100644 (file)
@@ -49,6 +49,7 @@ static struct snd_soc_dai_link fsi_dai_link = {
 };
 
 static struct snd_soc_card fsi_soc_card  = {
+       .owner          = THIS_MODULE,
        .dai_link       = &fsi_dai_link,
        .num_links      = 1,
 };
@@ -58,27 +59,23 @@ static struct platform_device *fsi_snd_device;
 static int fsi_ak4642_probe(struct platform_device *pdev)
 {
        int ret = -ENOMEM;
-       const struct platform_device_id *id_entry;
-       struct fsi_ak4642_data *pdata;
+       struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
 
-       id_entry = pdev->id_entry;
-       if (!id_entry) {
-               dev_err(&pdev->dev, "unknown fsi ak4642\n");
-               return -ENODEV;
+       if (!pinfo) {
+               dev_err(&pdev->dev, "no info for fsi ak4642\n");
+               goto out;
        }
 
-       pdata = (struct fsi_ak4642_data *)id_entry->driver_data;
-
-       fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
+       fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id);
        if (!fsi_snd_device)
                goto out;
 
-       fsi_dai_link.name               = pdata->name;
-       fsi_dai_link.stream_name        = pdata->name;
-       fsi_dai_link.cpu_dai_name       = pdata->cpu_dai;
-       fsi_dai_link.platform_name      = pdata->platform;
-       fsi_dai_link.codec_name         = pdata->codec;
-       fsi_soc_card.name               = pdata->card;
+       fsi_dai_link.name               = pinfo->name;
+       fsi_dai_link.stream_name        = pinfo->name;
+       fsi_dai_link.cpu_dai_name       = pinfo->cpu_dai;
+       fsi_dai_link.platform_name      = pinfo->platform;
+       fsi_dai_link.codec_name         = pinfo->codec;
+       fsi_soc_card.name               = pinfo->card;
 
        platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_snd_device);
@@ -96,114 +93,15 @@ static int fsi_ak4642_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct fsi_ak4642_data fsi_a_ak4642 = {
-       .name           = "AK4642",
-       .card           = "FSIA-AK4642",
-       .cpu_dai        = "fsia-dai",
-       .codec          = "ak4642-codec.0-0012",
-       .platform       = "sh_fsi.0",
-       .id             = FSI_PORT_A,
-};
-
-static struct fsi_ak4642_data fsi_b_ak4642 = {
-       .name           = "AK4642",
-       .card           = "FSIB-AK4642",
-       .cpu_dai        = "fsib-dai",
-       .codec          = "ak4642-codec.0-0012",
-       .platform       = "sh_fsi.0",
-       .id             = FSI_PORT_B,
-};
-
-static struct fsi_ak4642_data fsi_a_ak4643 = {
-       .name           = "AK4643",
-       .card           = "FSIA-AK4643",
-       .cpu_dai        = "fsia-dai",
-       .codec          = "ak4642-codec.0-0013",
-       .platform       = "sh_fsi.0",
-       .id             = FSI_PORT_A,
-};
-
-static struct fsi_ak4642_data fsi_b_ak4643 = {
-       .name           = "AK4643",
-       .card           = "FSIB-AK4643",
-       .cpu_dai        = "fsib-dai",
-       .codec          = "ak4642-codec.0-0013",
-       .platform       = "sh_fsi.0",
-       .id             = FSI_PORT_B,
-};
-
-static struct fsi_ak4642_data fsi2_a_ak4642 = {
-       .name           = "AK4642",
-       .card           = "FSI2A-AK4642",
-       .cpu_dai        = "fsia-dai",
-       .codec          = "ak4642-codec.0-0012",
-       .platform       = "sh_fsi2",
-       .id             = FSI_PORT_A,
-};
-
-static struct fsi_ak4642_data fsi2_b_ak4642 = {
-       .name           = "AK4642",
-       .card           = "FSI2B-AK4642",
-       .cpu_dai        = "fsib-dai",
-       .codec          = "ak4642-codec.0-0012",
-       .platform       = "sh_fsi2",
-       .id             = FSI_PORT_B,
-};
-
-static struct fsi_ak4642_data fsi2_a_ak4643 = {
-       .name           = "AK4643",
-       .card           = "FSI2A-AK4643",
-       .cpu_dai        = "fsia-dai",
-       .codec          = "ak4642-codec.0-0013",
-       .platform       = "sh_fsi2",
-       .id             = FSI_PORT_A,
-};
-
-static struct fsi_ak4642_data fsi2_b_ak4643 = {
-       .name           = "AK4643",
-       .card           = "FSI2B-AK4643",
-       .cpu_dai        = "fsib-dai",
-       .codec          = "ak4642-codec.0-0013",
-       .platform       = "sh_fsi2",
-       .id             = FSI_PORT_B,
-};
-
-static struct platform_device_id fsi_id_table[] = {
-       /* FSI */
-       { "sh_fsi_a_ak4642",    (kernel_ulong_t)&fsi_a_ak4642 },
-       { "sh_fsi_b_ak4642",    (kernel_ulong_t)&fsi_b_ak4642 },
-       { "sh_fsi_a_ak4643",    (kernel_ulong_t)&fsi_a_ak4643 },
-       { "sh_fsi_b_ak4643",    (kernel_ulong_t)&fsi_b_ak4643 },
-
-       /* FSI 2 */
-       { "sh_fsi2_a_ak4642",   (kernel_ulong_t)&fsi2_a_ak4642 },
-       { "sh_fsi2_b_ak4642",   (kernel_ulong_t)&fsi2_b_ak4642 },
-       { "sh_fsi2_a_ak4643",   (kernel_ulong_t)&fsi2_a_ak4643 },
-       { "sh_fsi2_b_ak4643",   (kernel_ulong_t)&fsi2_b_ak4643 },
-       {},
-};
-
 static struct platform_driver fsi_ak4642 = {
        .driver = {
                .name   = "fsi-ak4642-audio",
        },
        .probe          = fsi_ak4642_probe,
        .remove         = fsi_ak4642_remove,
-       .id_table       = fsi_id_table,
 };
 
-static int __init fsi_ak4642_init(void)
-{
-       return platform_driver_register(&fsi_ak4642);
-}
-
-static void __exit fsi_ak4642_exit(void)
-{
-       platform_driver_unregister(&fsi_ak4642);
-}
-
-module_init(fsi_ak4642_init);
-module_exit(fsi_ak4642_exit);
+module_platform_driver(fsi_ak4642);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card");
index f5586b5b0c3b7a135e09468871b272d6bffc158e..1dd3354c7411daff1954240dc6e1901f13ff57eb 100644 (file)
@@ -44,6 +44,7 @@ static struct snd_soc_dai_link fsi_da7210_dai = {
 
 static struct snd_soc_card fsi_soc_card = {
        .name           = "FSI-DA7210",
+       .owner          = THIS_MODULE,
        .dai_link       = &fsi_da7210_dai,
        .num_links      = 1,
 };
index 3ebebe706ad3bf732114cfd06ede04cf412b183d..6e41908323e80b24da3a5c44dd454c643544e777 100644 (file)
@@ -39,6 +39,7 @@ static struct snd_soc_dai_link fsi_dai_link = {
 };
 
 static struct snd_soc_card fsi_soc_card  = {
+       .owner          = THIS_MODULE,
        .dai_link       = &fsi_dai_link,
        .num_links      = 1,
 };
@@ -110,18 +111,7 @@ static struct platform_driver fsi_hdmi = {
        .id_table       = fsi_id_table,
 };
 
-static int __init fsi_hdmi_init(void)
-{
-       return platform_driver_register(&fsi_hdmi);
-}
-
-static void __exit fsi_hdmi_exit(void)
-{
-       platform_driver_unregister(&fsi_hdmi);
-}
-
-module_init(fsi_hdmi_init);
-module_exit(fsi_hdmi_exit);
+module_platform_driver(fsi_hdmi);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
index 3d7016e128f9374d2febb9564f404ed02db6b4db..db6c89a28bda9924a8c96b3e4c3ee85fc9482871 100644 (file)
@@ -32,7 +32,9 @@
 #define REG_DIDT       0x0020
 #define REG_DODT       0x0024
 #define REG_MUTE_ST    0x0028
+#define REG_OUT_DMAC   0x002C
 #define REG_OUT_SEL    0x0030
+#define REG_IN_DMAC    0x0038
 
 /* master register */
 #define MST_CLK_RST    0x0210
@@ -235,13 +237,13 @@ static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data)
 }
 
 #define fsi_reg_write(p, r, d)\
-       __fsi_reg_write((u32)(p->base + REG_##r), d)
+       __fsi_reg_write((p->base + REG_##r), d)
 
 #define fsi_reg_read(p, r)\
-       __fsi_reg_read((u32)(p->base + REG_##r))
+       __fsi_reg_read((p->base + REG_##r))
 
 #define fsi_reg_mask_set(p, r, m, d)\
-       __fsi_reg_mask_set((u32)(p->base + REG_##r), m, d)
+       __fsi_reg_mask_set((p->base + REG_##r), m, d)
 
 #define fsi_master_read(p, r) _fsi_master_read(p, MST_##r)
 #define fsi_core_read(p, r)   _fsi_master_read(p, p->core->r)
@@ -886,11 +888,11 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
                          int is_play,
                          struct device *dev)
 {
+       struct fsi_master *master = fsi_get_master(fsi);
+       int fsi_ver = master->core->ver;
        u32 flags = fsi_get_info_flags(fsi);
        u32 data = 0;
 
-       pm_runtime_get_sync(dev);
-
        /* clock setting */
        if (fsi_is_clk_master(fsi))
                data = DIMD | DOMD;
@@ -920,6 +922,17 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
                fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
        }
 
+       /*
+        * FIXME
+        *
+        * FSI driver assumed that data package is in-back.
+        * FSI2 chip can select it.
+        */
+       if (fsi_ver >= 2) {
+               fsi_reg_write(fsi, OUT_DMAC,    (1 << 4));
+               fsi_reg_write(fsi, IN_DMAC,     (1 << 4));
+       }
+
        /* irq clear */
        fsi_irq_disable(fsi, is_play);
        fsi_irq_clear_status(fsi);
@@ -936,8 +949,6 @@ static void fsi_hw_shutdown(struct fsi_priv *fsi,
 {
        if (fsi_is_clk_master(fsi))
                fsi_set_master_clk(dev, fsi, fsi->rate, 0);
-
-       pm_runtime_put_sync(dev);
 }
 
 static int fsi_dai_startup(struct snd_pcm_substream *substream,
@@ -1081,7 +1092,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static struct snd_soc_dai_ops fsi_dai_ops = {
+static const struct snd_soc_dai_ops fsi_dai_ops = {
        .startup        = fsi_dai_startup,
        .shutdown       = fsi_dai_shutdown,
        .trigger        = fsi_dai_trigger,
@@ -1453,18 +1464,7 @@ static struct platform_driver fsi_driver = {
        .id_table       = fsi_id_table,
 };
 
-static int __init fsi_mobile_init(void)
-{
-       return platform_driver_register(&fsi_driver);
-}
-
-static void __exit fsi_mobile_exit(void)
-{
-       platform_driver_unregister(&fsi_driver);
-}
-
-module_init(fsi_mobile_init);
-module_exit(fsi_mobile_exit);
+module_platform_driver(fsi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip FSI audio driver");
index c87e3ff28a0a02957bbd37c2de21d96b661e569e..3474d7befe5ae537fc6e9862050f5e81dcce9daa 100644 (file)
@@ -266,7 +266,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
 #define AC97_FMTS      \
        SNDRV_PCM_FMTBIT_S16_LE
 
-static struct snd_soc_dai_ops hac_dai_ops = {
+static const struct snd_soc_dai_ops hac_dai_ops = {
        .hw_params      = hac_hw_params,
 };
 
@@ -332,17 +332,7 @@ static struct platform_driver hac_pcm_driver = {
        .remove = __devexit_p(hac_soc_platform_remove),
 };
 
-static int __init sh4_hac_pcm_init(void)
-{
-       return platform_driver_register(&hac_pcm_driver);
-}
-module_init(sh4_hac_pcm_init);
-
-static void __exit sh4_hac_pcm_exit(void)
-{
-       platform_driver_unregister(&hac_pcm_driver);
-}
-module_exit(sh4_hac_pcm_exit);
+module_platform_driver(hac_pcm_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
index 6088a6a3238a1adfc3fa5345004eb2cee1956cc5..9d9ad8d61c0a95b46360c7f71052b133a4db0c2d 100644 (file)
@@ -164,6 +164,7 @@ static struct snd_soc_dai_link migor_dai = {
 /* migor audio machine driver */
 static struct snd_soc_card snd_soc_migor = {
        .name = "Migo-R",
+       .owner = THIS_MODULE,
        .dai_link = &migor_dai,
        .num_links = 1,
 };
index c62ae689c4a157c4373d6957af42d16fcd4dbe29..4a3568a9bf59015cc2e1692edd29ee77d8291c2a 100644 (file)
 
 #define IPSEL 0xFE400034
 
-/* platform specific structs can be declared here */
-extern struct snd_soc_dai_driver sh4_hac_dai[2];
-extern struct snd_soc_platform_driver sh7760_soc_platform;
-
 static struct snd_soc_dai_link sh7760_ac97_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
@@ -32,6 +28,7 @@ static struct snd_soc_dai_link sh7760_ac97_dai = {
 
 static struct snd_soc_card sh7760_ac97_soc_machine  = {
        .name = "SH7760 AC97",
+       .owner = THIS_MODULE,
        .dai_link = &sh7760_ac97_dai,
        .num_links = 1,
 };
index edacfeb13b94e3956589a999aeb78de2e2815635..52d4c17b12325ac079ed8b0cb65950c382290344 100644 (file)
@@ -112,9 +112,6 @@ static void siu_dai_start(struct siu_port *port_info)
 
        dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
 
-       /* Turn on SIU clock */
-       pm_runtime_get_sync(info->dev);
-
        /* Issue software reset to siu */
        siu_write32(base + SIU_SRCTL, 0);
 
@@ -158,9 +155,6 @@ static void siu_dai_stop(struct siu_port *port_info)
 
        /* SIU software reset */
        siu_write32(base + SIU_SRCTL, 0);
-
-       /* Turn off SIU clock */
-       pm_runtime_put_sync(info->dev);
 }
 
 static void siu_dai_spbAselect(struct siu_port *port_info)
@@ -707,7 +701,7 @@ epclkget:
        return ret;
 }
 
-static struct snd_soc_dai_ops siu_dai_ops = {
+static const struct snd_soc_dai_ops siu_dai_ops = {
        .startup        = siu_dai_startup,
        .shutdown       = siu_dai_shutdown,
        .prepare        = siu_dai_prepare,
@@ -852,18 +846,7 @@ static struct platform_driver siu_driver = {
        .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_platform_driver(siu_driver);
 
 MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
 MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
index e0c621c0553b5606afab9530628c94b994f9e847..ff82b56a886093e43c5456b14592452478d5d4a2 100644 (file)
@@ -332,7 +332,7 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
         SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
         SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
 
-static struct snd_soc_dai_ops ssi_dai_ops = {
+static const struct snd_soc_dai_ops ssi_dai_ops = {
        .startup        = ssi_startup,
        .shutdown       = ssi_shutdown,
        .trigger        = ssi_trigger,
@@ -401,17 +401,7 @@ static struct platform_driver sh4_ssi_driver = {
        .remove = __devexit_p(sh4_soc_dai_remove),
 };
 
-static int __init snd_sh4_ssi_init(void)
-{
-       return platform_driver_register(&sh4_ssi_driver);
-}
-module_init(snd_sh4_ssi_init);
-
-static void __exit snd_sh4_ssi_exit(void)
-{
-       platform_driver_unregister(&sh4_ssi_driver);
-}
-module_exit(snd_sh4_ssi_exit);
+module_platform_driver(sh4_ssi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
index 9077aa4b3b4ed975da4430789ff3961810e8df0e..9d56f0218f41688576fec511db272e6484480bdb 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <sound/soc.h>
-#include <linux/lzo.h>
 #include <linux/bitmap.h>
 #include <linux/rbtree.h>
 #include <linux/export.h>
@@ -67,750 +66,6 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
        return -1;
 }
 
-struct snd_soc_rbtree_node {
-       struct rb_node node; /* the actual rbtree node holding this block */
-       unsigned int base_reg; /* base register handled by this block */
-       unsigned int word_size; /* number of bytes needed to represent the register index */
-       void *block; /* block of adjacent registers */
-       unsigned int blklen; /* number of registers available in the block */
-} __attribute__ ((packed));
-
-struct snd_soc_rbtree_ctx {
-       struct rb_root root;
-       struct snd_soc_rbtree_node *cached_rbnode;
-};
-
-static inline void snd_soc_rbtree_get_base_top_reg(
-       struct snd_soc_rbtree_node *rbnode,
-       unsigned int *base, unsigned int *top)
-{
-       *base = rbnode->base_reg;
-       *top = rbnode->base_reg + rbnode->blklen - 1;
-}
-
-static unsigned int snd_soc_rbtree_get_register(
-       struct snd_soc_rbtree_node *rbnode, unsigned int idx)
-{
-       unsigned int val;
-
-       switch (rbnode->word_size) {
-       case 1: {
-               u8 *p = rbnode->block;
-               val = p[idx];
-               return val;
-       }
-       case 2: {
-               u16 *p = rbnode->block;
-               val = p[idx];
-               return val;
-       }
-       default:
-               BUG();
-               break;
-       }
-       return -1;
-}
-
-static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
-                                       unsigned int idx, unsigned int val)
-{
-       switch (rbnode->word_size) {
-       case 1: {
-               u8 *p = rbnode->block;
-               p[idx] = val;
-               break;
-       }
-       case 2: {
-               u16 *p = rbnode->block;
-               p[idx] = val;
-               break;
-       }
-       default:
-               BUG();
-               break;
-       }
-}
-
-static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
-       struct rb_root *root, unsigned int reg)
-{
-       struct rb_node *node;
-       struct snd_soc_rbtree_node *rbnode;
-       unsigned int base_reg, top_reg;
-
-       node = root->rb_node;
-       while (node) {
-               rbnode = container_of(node, struct snd_soc_rbtree_node, node);
-               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
-               if (reg >= base_reg && reg <= top_reg)
-                       return rbnode;
-               else if (reg > top_reg)
-                       node = node->rb_right;
-               else if (reg < base_reg)
-                       node = node->rb_left;
-       }
-
-       return NULL;
-}
-
-static int snd_soc_rbtree_insert(struct rb_root *root,
-                                struct snd_soc_rbtree_node *rbnode)
-{
-       struct rb_node **new, *parent;
-       struct snd_soc_rbtree_node *rbnode_tmp;
-       unsigned int base_reg_tmp, top_reg_tmp;
-       unsigned int base_reg;
-
-       parent = NULL;
-       new = &root->rb_node;
-       while (*new) {
-               rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
-                                         node);
-               /* base and top registers of the current rbnode */
-               snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
-                                               &top_reg_tmp);
-               /* base register of the rbnode to be added */
-               base_reg = rbnode->base_reg;
-               parent = *new;
-               /* if this register has already been inserted, just return */
-               if (base_reg >= base_reg_tmp &&
-                   base_reg <= top_reg_tmp)
-                       return 0;
-               else if (base_reg > top_reg_tmp)
-                       new = &((*new)->rb_right);
-               else if (base_reg < base_reg_tmp)
-                       new = &((*new)->rb_left);
-       }
-
-       /* insert the node into the rbtree */
-       rb_link_node(&rbnode->node, parent, new);
-       rb_insert_color(&rbnode->node, root);
-
-       return 1;
-}
-
-static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
-{
-       struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct rb_node *node;
-       struct snd_soc_rbtree_node *rbnode;
-       unsigned int regtmp;
-       unsigned int val, def;
-       int ret;
-       int i;
-
-       rbtree_ctx = codec->reg_cache;
-       for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
-               rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
-               for (i = 0; i < rbnode->blklen; ++i) {
-                       regtmp = rbnode->base_reg + i;
-                       val = snd_soc_rbtree_get_register(rbnode, i);
-                       def = snd_soc_get_cache_val(codec->reg_def_copy, i,
-                                                   rbnode->word_size);
-                       if (val == def)
-                               continue;
-
-                       WARN_ON(!snd_soc_codec_writable_register(codec, regtmp));
-
-                       codec->cache_bypass = 1;
-                       ret = snd_soc_write(codec, regtmp, val);
-                       codec->cache_bypass = 0;
-                       if (ret)
-                               return ret;
-                       dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
-                               regtmp, val);
-               }
-       }
-
-       return 0;
-}
-
-static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
-                                         unsigned int pos, unsigned int reg,
-                                         unsigned int value)
-{
-       u8 *blk;
-
-       blk = krealloc(rbnode->block,
-                      (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
-       if (!blk)
-               return -ENOMEM;
-
-       /* insert the register value in the correct place in the rbnode block */
-       memmove(blk + (pos + 1) * rbnode->word_size,
-               blk + pos * rbnode->word_size,
-               (rbnode->blklen - pos) * rbnode->word_size);
-
-       /* update the rbnode block, its size and the base register */
-       rbnode->block = blk;
-       rbnode->blklen++;
-       if (!pos)
-               rbnode->base_reg = reg;
-
-       snd_soc_rbtree_set_register(rbnode, pos, value);
-       return 0;
-}
-
-static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
-                                     unsigned int reg, unsigned int value)
-{
-       struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
-       struct rb_node *node;
-       unsigned int val;
-       unsigned int reg_tmp;
-       unsigned int base_reg, top_reg;
-       unsigned int pos;
-       int i;
-       int ret;
-
-       rbtree_ctx = codec->reg_cache;
-       /* look up the required register in the cached rbnode */
-       rbnode = rbtree_ctx->cached_rbnode;
-       if (rbnode) {
-               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
-               if (reg >= base_reg && reg <= top_reg) {
-                       reg_tmp = reg - base_reg;
-                       val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
-                       if (val == value)
-                               return 0;
-                       snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
-                       return 0;
-               }
-       }
-       /* if we can't locate it in the cached rbnode we'll have
-        * to traverse the rbtree looking for it.
-        */
-       rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
-       if (rbnode) {
-               reg_tmp = reg - rbnode->base_reg;
-               val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
-               if (val == value)
-                       return 0;
-               snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
-               rbtree_ctx->cached_rbnode = rbnode;
-       } else {
-               /* bail out early, no need to create the rbnode yet */
-               if (!value)
-                       return 0;
-               /* look for an adjacent register to the one we are about to add */
-               for (node = rb_first(&rbtree_ctx->root); node;
-                    node = rb_next(node)) {
-                       rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
-                       for (i = 0; i < rbnode_tmp->blklen; ++i) {
-                               reg_tmp = rbnode_tmp->base_reg + i;
-                               if (abs(reg_tmp - reg) != 1)
-                                       continue;
-                               /* decide where in the block to place our register */
-                               if (reg_tmp + 1 == reg)
-                                       pos = i + 1;
-                               else
-                                       pos = i;
-                               ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
-                                                                    reg, value);
-                               if (ret)
-                                       return ret;
-                               rbtree_ctx->cached_rbnode = rbnode_tmp;
-                               return 0;
-                       }
-               }
-               /* we did not manage to find a place to insert it in an existing
-                * block so create a new rbnode with a single register in its block.
-                * This block will get populated further if any other adjacent
-                * registers get modified in the future.
-                */
-               rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
-               if (!rbnode)
-                       return -ENOMEM;
-               rbnode->blklen = 1;
-               rbnode->base_reg = reg;
-               rbnode->word_size = codec->driver->reg_word_size;
-               rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
-                                       GFP_KERNEL);
-               if (!rbnode->block) {
-                       kfree(rbnode);
-                       return -ENOMEM;
-               }
-               snd_soc_rbtree_set_register(rbnode, 0, value);
-               snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
-               rbtree_ctx->cached_rbnode = rbnode;
-       }
-
-       return 0;
-}
-
-static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
-                                    unsigned int reg, unsigned int *value)
-{
-       struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct snd_soc_rbtree_node *rbnode;
-       unsigned int base_reg, top_reg;
-       unsigned int reg_tmp;
-
-       rbtree_ctx = codec->reg_cache;
-       /* look up the required register in the cached rbnode */
-       rbnode = rbtree_ctx->cached_rbnode;
-       if (rbnode) {
-               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
-               if (reg >= base_reg && reg <= top_reg) {
-                       reg_tmp = reg - base_reg;
-                       *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
-                       return 0;
-               }
-       }
-       /* if we can't locate it in the cached rbnode we'll have
-        * to traverse the rbtree looking for it.
-        */
-       rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
-       if (rbnode) {
-               reg_tmp = reg - rbnode->base_reg;
-               *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
-               rbtree_ctx->cached_rbnode = rbnode;
-       } else {
-               /* uninitialized registers default to 0 */
-               *value = 0;
-       }
-
-       return 0;
-}
-
-static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
-{
-       struct rb_node *next;
-       struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct snd_soc_rbtree_node *rbtree_node;
-
-       /* if we've already been called then just return */
-       rbtree_ctx = codec->reg_cache;
-       if (!rbtree_ctx)
-               return 0;
-
-       /* free up the rbtree */
-       next = rb_first(&rbtree_ctx->root);
-       while (next) {
-               rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
-               next = rb_next(&rbtree_node->node);
-               rb_erase(&rbtree_node->node, &rbtree_ctx->root);
-               kfree(rbtree_node->block);
-               kfree(rbtree_node);
-       }
-
-       /* release the resources */
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
-
-       return 0;
-}
-
-static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
-{
-       struct snd_soc_rbtree_ctx *rbtree_ctx;
-       unsigned int word_size;
-       unsigned int val;
-       int i;
-       int ret;
-
-       codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
-       if (!codec->reg_cache)
-               return -ENOMEM;
-
-       rbtree_ctx = codec->reg_cache;
-       rbtree_ctx->root = RB_ROOT;
-       rbtree_ctx->cached_rbnode = NULL;
-
-       if (!codec->reg_def_copy)
-               return 0;
-
-       word_size = codec->driver->reg_word_size;
-       for (i = 0; i < codec->driver->reg_cache_size; ++i) {
-               val = snd_soc_get_cache_val(codec->reg_def_copy, i,
-                                           word_size);
-               if (!val)
-                       continue;
-               ret = snd_soc_rbtree_cache_write(codec, i, val);
-               if (ret)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       snd_soc_cache_exit(codec);
-       return ret;
-}
-
-#ifdef CONFIG_SND_SOC_CACHE_LZO
-struct snd_soc_lzo_ctx {
-       void *wmem;
-       void *dst;
-       const void *src;
-       size_t src_len;
-       size_t dst_len;
-       size_t decompressed_size;
-       unsigned long *sync_bmp;
-       int sync_bmp_nbits;
-};
-
-#define LZO_BLOCK_NUM 8
-static int snd_soc_lzo_block_count(void)
-{
-       return LZO_BLOCK_NUM;
-}
-
-static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
-{
-       lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
-       if (!lzo_ctx->wmem)
-               return -ENOMEM;
-       return 0;
-}
-
-static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
-{
-       size_t compress_size;
-       int ret;
-
-       ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
-                              lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
-       if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
-               return -EINVAL;
-       lzo_ctx->dst_len = compress_size;
-       return 0;
-}
-
-static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
-{
-       size_t dst_len;
-       int ret;
-
-       dst_len = lzo_ctx->dst_len;
-       ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
-                                   lzo_ctx->dst, &dst_len);
-       if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
-               return -EINVAL;
-       return 0;
-}
-
-static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
-               struct snd_soc_lzo_ctx *lzo_ctx)
-{
-       int ret;
-
-       lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
-       lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
-       if (!lzo_ctx->dst) {
-               lzo_ctx->dst_len = 0;
-               return -ENOMEM;
-       }
-
-       ret = snd_soc_lzo_compress(lzo_ctx);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
-               struct snd_soc_lzo_ctx *lzo_ctx)
-{
-       int ret;
-
-       lzo_ctx->dst_len = lzo_ctx->decompressed_size;
-       lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
-       if (!lzo_ctx->dst) {
-               lzo_ctx->dst_len = 0;
-               return -ENOMEM;
-       }
-
-       ret = snd_soc_lzo_decompress(lzo_ctx);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
-               unsigned int reg)
-{
-       const struct snd_soc_codec_driver *codec_drv;
-
-       codec_drv = codec->driver;
-       return (reg * codec_drv->reg_word_size) /
-              DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
-}
-
-static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
-               unsigned int reg)
-{
-       const struct snd_soc_codec_driver *codec_drv;
-
-       codec_drv = codec->driver;
-       return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
-                     codec_drv->reg_word_size);
-}
-
-static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
-{
-       return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
-}
-
-static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
-{
-       struct snd_soc_lzo_ctx **lzo_blocks;
-       unsigned int val;
-       int i;
-       int ret;
-
-       lzo_blocks = codec->reg_cache;
-       for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
-               WARN_ON(!snd_soc_codec_writable_register(codec, i));
-               ret = snd_soc_cache_read(codec, i, &val);
-               if (ret)
-                       return ret;
-               codec->cache_bypass = 1;
-               ret = snd_soc_write(codec, i, val);
-               codec->cache_bypass = 0;
-               if (ret)
-                       return ret;
-               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
-                       i, val);
-       }
-
-       return 0;
-}
-
-static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
-                                  unsigned int reg, unsigned int value)
-{
-       struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
-       int ret, blkindex, blkpos;
-       size_t blksize, tmp_dst_len;
-       void *tmp_dst;
-
-       /* index of the compressed lzo block */
-       blkindex = snd_soc_lzo_get_blkindex(codec, reg);
-       /* register index within the decompressed block */
-       blkpos = snd_soc_lzo_get_blkpos(codec, reg);
-       /* size of the compressed block */
-       blksize = snd_soc_lzo_get_blksize(codec);
-       lzo_blocks = codec->reg_cache;
-       lzo_block = lzo_blocks[blkindex];
-
-       /* save the pointer and length of the compressed block */
-       tmp_dst = lzo_block->dst;
-       tmp_dst_len = lzo_block->dst_len;
-
-       /* prepare the source to be the compressed block */
-       lzo_block->src = lzo_block->dst;
-       lzo_block->src_len = lzo_block->dst_len;
-
-       /* decompress the block */
-       ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
-       if (ret < 0) {
-               kfree(lzo_block->dst);
-               goto out;
-       }
-
-       /* write the new value to the cache */
-       if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
-                                 codec->driver->reg_word_size)) {
-               kfree(lzo_block->dst);
-               goto out;
-       }
-
-       /* prepare the source to be the decompressed block */
-       lzo_block->src = lzo_block->dst;
-       lzo_block->src_len = lzo_block->dst_len;
-
-       /* compress the block */
-       ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
-       if (ret < 0) {
-               kfree(lzo_block->dst);
-               kfree(lzo_block->src);
-               goto out;
-       }
-
-       /* set the bit so we know we have to sync this register */
-       set_bit(reg, lzo_block->sync_bmp);
-       kfree(tmp_dst);
-       kfree(lzo_block->src);
-       return 0;
-out:
-       lzo_block->dst = tmp_dst;
-       lzo_block->dst_len = tmp_dst_len;
-       return ret;
-}
-
-static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
-                                 unsigned int reg, unsigned int *value)
-{
-       struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
-       int ret, blkindex, blkpos;
-       size_t blksize, tmp_dst_len;
-       void *tmp_dst;
-
-       *value = 0;
-       /* index of the compressed lzo block */
-       blkindex = snd_soc_lzo_get_blkindex(codec, reg);
-       /* register index within the decompressed block */
-       blkpos = snd_soc_lzo_get_blkpos(codec, reg);
-       /* size of the compressed block */
-       blksize = snd_soc_lzo_get_blksize(codec);
-       lzo_blocks = codec->reg_cache;
-       lzo_block = lzo_blocks[blkindex];
-
-       /* save the pointer and length of the compressed block */
-       tmp_dst = lzo_block->dst;
-       tmp_dst_len = lzo_block->dst_len;
-
-       /* prepare the source to be the compressed block */
-       lzo_block->src = lzo_block->dst;
-       lzo_block->src_len = lzo_block->dst_len;
-
-       /* decompress the block */
-       ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
-       if (ret >= 0)
-               /* fetch the value from the cache */
-               *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
-                                              codec->driver->reg_word_size);
-
-       kfree(lzo_block->dst);
-       /* restore the pointer and length of the compressed block */
-       lzo_block->dst = tmp_dst;
-       lzo_block->dst_len = tmp_dst_len;
-       return 0;
-}
-
-static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
-{
-       struct snd_soc_lzo_ctx **lzo_blocks;
-       int i, blkcount;
-
-       lzo_blocks = codec->reg_cache;
-       if (!lzo_blocks)
-               return 0;
-
-       blkcount = snd_soc_lzo_block_count();
-       /*
-        * the pointer to the bitmap used for syncing the cache
-        * is shared amongst all lzo_blocks.  Ensure it is freed
-        * only once.
-        */
-       if (lzo_blocks[0])
-               kfree(lzo_blocks[0]->sync_bmp);
-       for (i = 0; i < blkcount; ++i) {
-               if (lzo_blocks[i]) {
-                       kfree(lzo_blocks[i]->wmem);
-                       kfree(lzo_blocks[i]->dst);
-               }
-               /* each lzo_block is a pointer returned by kmalloc or NULL */
-               kfree(lzo_blocks[i]);
-       }
-       kfree(lzo_blocks);
-       codec->reg_cache = NULL;
-       return 0;
-}
-
-static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
-{
-       struct snd_soc_lzo_ctx **lzo_blocks;
-       size_t bmp_size;
-       const struct snd_soc_codec_driver *codec_drv;
-       int ret, tofree, i, blksize, blkcount;
-       const char *p, *end;
-       unsigned long *sync_bmp;
-
-       ret = 0;
-       codec_drv = codec->driver;
-
-       /*
-        * If we have not been given a default register cache
-        * then allocate a dummy zero-ed out region, compress it
-        * and remember to free it afterwards.
-        */
-       tofree = 0;
-       if (!codec->reg_def_copy)
-               tofree = 1;
-
-       if (!codec->reg_def_copy) {
-               codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
-               if (!codec->reg_def_copy)
-                       return -ENOMEM;
-       }
-
-       blkcount = snd_soc_lzo_block_count();
-       codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
-                                  GFP_KERNEL);
-       if (!codec->reg_cache) {
-               ret = -ENOMEM;
-               goto err_tofree;
-       }
-       lzo_blocks = codec->reg_cache;
-
-       /*
-        * allocate a bitmap to be used when syncing the cache with
-        * the hardware.  Each time a register is modified, the corresponding
-        * bit is set in the bitmap, so we know that we have to sync
-        * that register.
-        */
-       bmp_size = codec_drv->reg_cache_size;
-       sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
-                          GFP_KERNEL);
-       if (!sync_bmp) {
-               ret = -ENOMEM;
-               goto err;
-       }
-       bitmap_zero(sync_bmp, bmp_size);
-
-       /* allocate the lzo blocks and initialize them */
-       for (i = 0; i < blkcount; ++i) {
-               lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
-                                       GFP_KERNEL);
-               if (!lzo_blocks[i]) {
-                       kfree(sync_bmp);
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               lzo_blocks[i]->sync_bmp = sync_bmp;
-               lzo_blocks[i]->sync_bmp_nbits = bmp_size;
-               /* alloc the working space for the compressed block */
-               ret = snd_soc_lzo_prepare(lzo_blocks[i]);
-               if (ret < 0)
-                       goto err;
-       }
-
-       blksize = snd_soc_lzo_get_blksize(codec);
-       p = codec->reg_def_copy;
-       end = codec->reg_def_copy + codec->reg_size;
-       /* compress the register map and fill the lzo blocks */
-       for (i = 0; i < blkcount; ++i, p += blksize) {
-               lzo_blocks[i]->src = p;
-               if (p + blksize > end)
-                       lzo_blocks[i]->src_len = end - p;
-               else
-                       lzo_blocks[i]->src_len = blksize;
-               ret = snd_soc_lzo_compress_cache_block(codec,
-                                                      lzo_blocks[i]);
-               if (ret < 0)
-                       goto err;
-               lzo_blocks[i]->decompressed_size =
-                       lzo_blocks[i]->src_len;
-       }
-
-       if (tofree) {
-               kfree(codec->reg_def_copy);
-               codec->reg_def_copy = NULL;
-       }
-       return 0;
-err:
-       snd_soc_cache_exit(codec);
-err_tofree:
-       if (tofree) {
-               kfree(codec->reg_def_copy);
-               codec->reg_def_copy = NULL;
-       }
-       return ret;
-}
-#endif
-
 static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
 {
        int i;
@@ -889,26 +144,6 @@ static const struct snd_soc_cache_ops cache_types[] = {
                .write = snd_soc_flat_cache_write,
                .sync = snd_soc_flat_cache_sync
        },
-#ifdef CONFIG_SND_SOC_CACHE_LZO
-       {
-               .id = SND_SOC_LZO_COMPRESSION,
-               .name = "LZO",
-               .init = snd_soc_lzo_cache_init,
-               .exit = snd_soc_lzo_cache_exit,
-               .read = snd_soc_lzo_cache_read,
-               .write = snd_soc_lzo_cache_write,
-               .sync = snd_soc_lzo_cache_sync
-       },
-#endif
-       {
-               .id = SND_SOC_RBTREE_COMPRESSION,
-               .name = "rbtree",
-               .init = snd_soc_rbtree_cache_init,
-               .exit = snd_soc_rbtree_cache_exit,
-               .read = snd_soc_rbtree_cache_read,
-               .write = snd_soc_rbtree_cache_write,
-               .sync = snd_soc_rbtree_cache_sync
-       }
 };
 
 int snd_soc_cache_init(struct snd_soc_codec *codec)
index a25fa63ce9a27501a4f2d4a6334911076200532e..3986520b4677244b9bd592b85f2350889bda5cdf 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -58,8 +59,6 @@ static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
 
-int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
-
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
  * It can be used to eliminate pops between different playback streams, e.g.
@@ -170,8 +169,7 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
 static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_pcm_runtime *rtd =
-                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
 
        return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
 }
@@ -181,8 +179,7 @@ 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_pcm_runtime *rtd =
-                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
 
        return sprintf(buf, "%ld\n", rtd->pmdown_time);
 }
@@ -191,8 +188,7 @@ static ssize_t pmdown_time_set(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct snd_soc_pcm_runtime *rtd =
-                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        int ret;
 
        ret = strict_strtol(buf, 10, &rtd->pmdown_time);
@@ -412,7 +408,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card)
                                                     snd_soc_debugfs_root);
        if (!card->debugfs_card_root) {
                dev_warn(card->dev,
-                        "ASoC: Failed to create codec debugfs directory\n");
+                        "ASoC: Failed to create card debugfs directory\n");
                return;
        }
 
@@ -572,7 +568,7 @@ int snd_soc_suspend(struct device *dev)
                        switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
-                               codec->driver->suspend(codec, PMSG_SUSPEND);
+                               codec->driver->suspend(codec);
                                codec->suspended = 1;
                                codec->cache_sync = 1;
                                break;
@@ -741,7 +737,7 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
 #define snd_soc_resume NULL
 #endif
 
-static struct snd_soc_dai_ops null_dai_ops = {
+static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
 static int soc_bind_dai_link(struct snd_soc_card *card, int num)
@@ -763,10 +759,16 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        }
        /* no, then find CPU DAI from registered DAIs*/
        list_for_each_entry(cpu_dai, &dai_list, list) {
-               if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
-                       rtd->cpu_dai = cpu_dai;
-                       goto find_codec;
+               if (dai_link->cpu_dai_of_node) {
+                       if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
+                               continue;
+               } else {
+                       if (strcmp(cpu_dai->name, dai_link->cpu_dai_name))
+                               continue;
                }
+
+               rtd->cpu_dai = cpu_dai;
+               goto find_codec;
        }
        dev_dbg(card->dev, "CPU DAI %s not registered\n",
                        dai_link->cpu_dai_name);
@@ -779,22 +781,33 @@ find_codec:
 
        /* no, then find CODEC from registered CODECs*/
        list_for_each_entry(codec, &codec_list, list) {
-               if (!strcmp(codec->name, dai_link->codec_name)) {
-                       rtd->codec = codec;
-
-                       /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
-                       list_for_each_entry(codec_dai, &dai_list, list) {
-                               if (codec->dev == codec_dai->dev &&
-                                               !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
-                                       rtd->codec_dai = codec_dai;
-                                       goto find_platform;
-                               }
-                       }
-                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
-                                       dai_link->codec_dai_name);
+               if (dai_link->codec_of_node) {
+                       if (codec->dev->of_node != dai_link->codec_of_node)
+                               continue;
+               } else {
+                       if (strcmp(codec->name, dai_link->codec_name))
+                               continue;
+               }
+
+               rtd->codec = codec;
 
-                       goto find_platform;
+               /*
+                * CODEC found, so find CODEC DAI from registered DAIs from
+                * this CODEC
+                */
+               list_for_each_entry(codec_dai, &dai_list, list) {
+                       if (codec->dev == codec_dai->dev &&
+                               !strcmp(codec_dai->name,
+                                       dai_link->codec_dai_name)) {
+
+                               rtd->codec_dai = codec_dai;
+                               goto find_platform;
+                       }
                }
+               dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                               dai_link->codec_dai_name);
+
+               goto find_platform;
        }
        dev_dbg(card->dev, "CODEC %s not registered\n",
                        dai_link->codec_name);
@@ -806,15 +819,22 @@ find_platform:
 
        /* if there's no platform we match on the empty platform */
        platform_name = dai_link->platform_name;
-       if (!platform_name)
+       if (!platform_name && !dai_link->platform_of_node)
                platform_name = "snd-soc-dummy";
 
        /* no, then find one from the set of registered platforms */
        list_for_each_entry(platform, &platform_list, list) {
-               if (!strcmp(platform->name, platform_name)) {
-                       rtd->platform = platform;
-                       goto out;
+               if (dai_link->platform_of_node) {
+                       if (platform->dev->of_node !=
+                           dai_link->platform_of_node)
+                               continue;
+               } else {
+                       if (strcmp(platform->name, platform_name))
+                               continue;
                }
+
+               rtd->platform = platform;
+               goto out;
        }
 
        dev_dbg(card->dev, "platform %s not registered\n",
@@ -861,9 +881,9 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order)
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
-               device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
-               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
-               device_unregister(&rtd->dev);
+               device_remove_file(rtd->dev, &dev_attr_pmdown_time);
+               device_remove_file(rtd->dev, &dev_attr_codec_reg);
+               device_unregister(rtd->dev);
                rtd->dev_registered = 0;
        }
 
@@ -1038,7 +1058,10 @@ err_probe:
        return ret;
 }
 
-static void rtd_release(struct device *dev) {}
+static void rtd_release(struct device *dev)
+{
+       kfree(dev);
+}
 
 static int soc_post_component_init(struct snd_soc_card *card,
                                   struct snd_soc_codec *codec,
@@ -1081,11 +1104,17 @@ static int soc_post_component_init(struct snd_soc_card *card,
 
        /* register the rtd device */
        rtd->codec = codec;
-       rtd->dev.parent = card->dev;
-       rtd->dev.release = rtd_release;
-       rtd->dev.init_name = name;
+
+       rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!rtd->dev)
+               return -ENOMEM;
+       device_initialize(rtd->dev);
+       rtd->dev->parent = card->dev;
+       rtd->dev->release = rtd_release;
+       rtd->dev->init_name = name;
+       dev_set_drvdata(rtd->dev, rtd);
        mutex_init(&rtd->pcm_mutex);
-       ret = device_register(&rtd->dev);
+       ret = device_add(rtd->dev);
        if (ret < 0) {
                dev_err(card->dev,
                        "asoc: failed to register runtime device: %d\n", ret);
@@ -1094,14 +1123,14 @@ static int soc_post_component_init(struct snd_soc_card *card,
        rtd->dev_registered = 1;
 
        /* add DAPM sysfs entries for this codec */
-       ret = snd_soc_dapm_sys_add(&rtd->dev);
+       ret = snd_soc_dapm_sys_add(rtd->dev);
        if (ret < 0)
                dev_err(codec->dev,
                        "asoc: failed to add codec dapm sysfs entries: %d\n",
                        ret);
 
        /* add codec sysfs entries */
-       ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
+       ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
        if (ret < 0)
                dev_err(codec->dev,
                        "asoc: failed to add codec sysfs files: %d\n", ret);
@@ -1190,7 +1219,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
        if (ret)
                return ret;
 
-       ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
+       ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
        if (ret < 0)
                printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
 
@@ -1288,8 +1317,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
-               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
-               device_unregister(&rtd->dev);
+               device_remove_file(rtd->dev, &dev_attr_codec_reg);
+               device_del(rtd->dev);
                rtd->dev_registered = 0;
        }
 
@@ -1488,6 +1517,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
 
        snd_soc_dapm_new_widgets(&card->dapm);
 
+       if (card->fully_routed)
+               list_for_each_entry(codec, &card->codec_dev_list, card_list)
+                       snd_soc_dapm_auto_nc_codec_pins(codec);
+
        ret = snd_card_register(card->snd_card);
        if (ret < 0) {
                printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
@@ -2818,6 +2851,40 @@ int snd_soc_register_card(struct snd_soc_card *card)
        if (!card->name || !card->dev)
                return -EINVAL;
 
+       for (i = 0; i < card->num_links; i++) {
+               struct snd_soc_dai_link *link = &card->dai_link[i];
+
+               /*
+                * Codec must be specified by 1 of name or OF node,
+                * not both or neither.
+                */
+               if (!!link->codec_name == !!link->codec_of_node) {
+                       dev_err(card->dev,
+                               "Neither/both codec name/of_node are set\n");
+                       return -EINVAL;
+               }
+
+               /*
+                * Platform may be specified by either name or OF node, but
+                * can be left unspecified, and a dummy platform will be used.
+                */
+               if (link->platform_name && link->platform_of_node) {
+                       dev_err(card->dev,
+                               "Both platform name/of_node are set\n");
+                       return -EINVAL;
+               }
+
+               /*
+                * CPU DAI must be specified by 1 of name or OF node,
+                * not both or neither.
+                */
+               if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) {
+                       dev_err(card->dev,
+                               "Neither/both cpu_dai name/of_node are set\n");
+                       return -EINVAL;
+               }
+       }
+
        dev_set_drvdata(card->dev, card);
 
        snd_soc_initialize_card_lists(card);
@@ -3305,6 +3372,87 @@ found:
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
+/* Retrieve a card's name from device tree */
+int snd_soc_of_parse_card_name(struct snd_soc_card *card,
+                              const char *propname)
+{
+       struct device_node *np = card->dev->of_node;
+       int ret;
+
+       ret = of_property_read_string_index(np, propname, 0, &card->name);
+       /*
+        * EINVAL means the property does not exist. This is fine providing
+        * card->name was previously set, which is checked later in
+        * snd_soc_register_card.
+        */
+       if (ret < 0 && ret != -EINVAL) {
+               dev_err(card->dev,
+                       "Property '%s' could not be read: %d\n",
+                       propname, ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name);
+
+int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
+                                  const char *propname)
+{
+       struct device_node *np = card->dev->of_node;
+       int num_routes;
+       struct snd_soc_dapm_route *routes;
+       int i, ret;
+
+       num_routes = of_property_count_strings(np, propname);
+       if (num_routes & 1) {
+               dev_err(card->dev,
+                       "Property '%s's length is not even\n",
+                       propname);
+               return -EINVAL;
+       }
+       num_routes /= 2;
+       if (!num_routes) {
+               dev_err(card->dev,
+                       "Property '%s's length is zero\n",
+                       propname);
+               return -EINVAL;
+       }
+
+       routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes),
+                             GFP_KERNEL);
+       if (!routes) {
+               dev_err(card->dev,
+                       "Could not allocate DAPM route table\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_routes; i++) {
+               ret = of_property_read_string_index(np, propname,
+                       2 * i, &routes[i].sink);
+               if (ret) {
+                       dev_err(card->dev,
+                               "Property '%s' index %d could not be read: %d\n",
+                               propname, 2 * i, ret);
+                       return -EINVAL;
+               }
+               ret = of_property_read_string_index(np, propname,
+                       (2 * i) + 1, &routes[i].source);
+               if (ret) {
+                       dev_err(card->dev,
+                               "Property '%s' index %d could not be read: %d\n",
+                               propname, (2 * i) + 1, ret);
+                       return -EINVAL;
+               }
+       }
+
+       card->num_dapm_routes = num_routes;
+       card->dapm_routes = routes;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing);
+
 static int __init snd_soc_init(void)
 {
 #ifdef CONFIG_DEBUG_FS
index f42e8b9fb17db7baeabaf7152f81123773cdecd0..3ad1f59b80281cfc7c9ace89ae8a30d34317fe7a 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -339,6 +340,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_output:
        case snd_soc_dapm_adc:
        case snd_soc_dapm_input:
+       case snd_soc_dapm_siggen:
        case snd_soc_dapm_dac:
        case snd_soc_dapm_micbias:
        case snd_soc_dapm_vmid:
@@ -772,6 +774,11 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
                        return widget->inputs;
                }
 
+               /* signal generator */
+               if (widget->id == snd_soc_dapm_siggen) {
+                       widget->inputs = snd_soc_dapm_suspend_check(widget);
+                       return widget->inputs;
+               }
        }
 
        list_for_each_entry(path, &widget->sources, list_sink) {
@@ -1200,6 +1207,9 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
        /* If we're off and we're not supposed to be go into STANDBY */
        if (d->bias_level == SND_SOC_BIAS_OFF &&
            d->target_bias_level != SND_SOC_BIAS_OFF) {
+               if (d->dev)
+                       pm_runtime_get_sync(d->dev);
+
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        dev_err(d->dev,
@@ -1239,6 +1249,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
                ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
                if (ret != 0)
                        dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
+
+               if (d->dev)
+                       pm_runtime_put_sync(d->dev);
        }
 
        /* If we just powered up then move to active bias */
@@ -1725,8 +1738,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_pcm_runtime *rtd =
-                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
        struct snd_soc_codec *codec =rtd->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
@@ -1982,6 +1994,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_out_drv:
        case snd_soc_dapm_input:
        case snd_soc_dapm_output:
+       case snd_soc_dapm_siggen:
        case snd_soc_dapm_micbias:
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_pre:
@@ -2947,6 +2960,79 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
+static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
+                                             struct snd_soc_dapm_widget *w)
+{
+       struct snd_soc_dapm_path *p;
+
+       list_for_each_entry(p, &card->paths, list) {
+               if ((p->source == w) || (p->sink == w)) {
+                       dev_dbg(card->dev,
+                           "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
+                           p->source->name, p->source->id, p->source->dapm,
+                           p->sink->name, p->sink->id, p->sink->dapm);
+
+                       /* Connected to something other than the codec */
+                       if (p->source->dapm != p->sink->dapm)
+                               return true;
+                       /*
+                        * Loopback connection from codec external pin to
+                        * codec external pin
+                        */
+                       if (p->sink->id == snd_soc_dapm_input) {
+                               switch (p->source->id) {
+                               case snd_soc_dapm_output:
+                               case snd_soc_dapm_micbias:
+                                       return true;
+                               default:
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return false;
+}
+
+/**
+ * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins
+ * @codec: The codec whose pins should be processed
+ *
+ * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec
+ * which are unused. Pins are used if they are connected externally to the
+ * codec, whether that be to some other device, or a loop-back connection to
+ * the codec itself.
+ */
+void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec)
+{
+       struct snd_soc_card *card = codec->card;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_widget *w;
+
+       dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n",
+               &card->dapm, &codec->dapm);
+
+       list_for_each_entry(w, &card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
+               switch (w->id) {
+               case snd_soc_dapm_input:
+               case snd_soc_dapm_output:
+               case snd_soc_dapm_micbias:
+                       dev_dbg(codec->dev, "Auto NC: Checking widget %s\n",
+                               w->name);
+                       if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
+                               dev_dbg(codec->dev,
+                                       "... Not in map; disabling\n");
+                               snd_soc_dapm_nc_pin(dapm, w->name);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
 /**
  * snd_soc_dapm_free - free dapm resources
  * @dapm: DAPM context
index 6c5ebd38c1b0f050f515dbb2dc1c47acaafc1ba4..ee4353f843eae07a82b7358004d9defb63ae5e96 100644 (file)
@@ -341,10 +341,8 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                                        gpios[i].gpio, ret);
                }
 
-#ifdef CONFIG_GPIO_SYSFS
                /* Expose GPIO value over sysfs for diagnostic purposes */
                gpio_export(gpios[i].gpio, false);
-#endif
 
                /* Update initial jack status */
                snd_soc_jack_gpio_detect(&gpios[i]);
@@ -376,9 +374,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
        int i;
 
        for (i = 0; i < count; i++) {
-#ifdef CONFIG_GPIO_SYSFS
                gpio_unexport(gpios[i].gpio);
-#endif
                free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
                cancel_delayed_work_sync(&gpios[i].work);
                gpio_free(gpios[i].gpio);
index ee15337353fae5f2cf16f5ab86f94d13440dc6bd..cdc860a5ff37ca0fe070bdc9f6f4532e1cd6a7c3 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
@@ -77,6 +78,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
 
+       pm_runtime_get_sync(cpu_dai->dev);
+       pm_runtime_get_sync(codec_dai->dev);
+       pm_runtime_get_sync(platform->dev);
+
        mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
        /* startup the audio subsystem */
@@ -233,6 +238,11 @@ platform_err:
                cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
        mutex_unlock(&rtd->pcm_mutex);
+
+       pm_runtime_put(platform->dev);
+       pm_runtime_put(codec_dai->dev);
+       pm_runtime_put(cpu_dai->dev);
+
        return ret;
 }
 
@@ -319,7 +329,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (unlikely(codec->ignore_pmdown_time)) {
+               if (codec->ignore_pmdown_time ||
+                   rtd->dai_link->ignore_pmdown_time) {
                        /* powered down playback stream now */
                        snd_soc_dapm_stream_event(rtd,
                                codec_dai->driver->playback.stream_name,
@@ -338,6 +349,11 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
        }
 
        mutex_unlock(&rtd->pcm_mutex);
+
+       pm_runtime_put(platform->dev);
+       pm_runtime_put(codec_dai->dev);
+       pm_runtime_put(cpu_dai->dev);
+
        return 0;
 }
 
@@ -582,17 +598,6 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
        return offset;
 }
 
-/* ASoC PCM operations */
-static struct snd_pcm_ops soc_pcm_ops = {
-       .open           = soc_pcm_open,
-       .close          = soc_pcm_close,
-       .hw_params      = soc_pcm_hw_params,
-       .hw_free        = soc_pcm_hw_free,
-       .prepare        = soc_pcm_prepare,
-       .trigger        = soc_pcm_trigger,
-       .pointer        = soc_pcm_pointer,
-};
-
 /* create a new pcm */
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 {
@@ -600,10 +605,19 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        struct snd_soc_platform *platform = rtd->platform;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
 
+       soc_pcm_ops->open       = soc_pcm_open;
+       soc_pcm_ops->close      = soc_pcm_close;
+       soc_pcm_ops->hw_params  = soc_pcm_hw_params;
+       soc_pcm_ops->hw_free    = soc_pcm_hw_free;
+       soc_pcm_ops->prepare    = soc_pcm_prepare;
+       soc_pcm_ops->trigger    = soc_pcm_trigger;
+       soc_pcm_ops->pointer    = soc_pcm_pointer;
+
        /* check client and interface hw capabilities */
        snprintf(new_name, sizeof(new_name), "%s %s-%d",
                        rtd->dai_link->stream_name, codec_dai->name, num);
@@ -627,20 +641,20 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
        rtd->pcm = pcm;
        pcm->private_data = rtd;
        if (platform->driver->ops) {
-               soc_pcm_ops.mmap = platform->driver->ops->mmap;
-               soc_pcm_ops.pointer = platform->driver->ops->pointer;
-               soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
-               soc_pcm_ops.copy = platform->driver->ops->copy;
-               soc_pcm_ops.silence = platform->driver->ops->silence;
-               soc_pcm_ops.ack = platform->driver->ops->ack;
-               soc_pcm_ops.page = platform->driver->ops->page;
+               soc_pcm_ops->mmap = platform->driver->ops->mmap;
+               soc_pcm_ops->pointer = platform->driver->ops->pointer;
+               soc_pcm_ops->ioctl = platform->driver->ops->ioctl;
+               soc_pcm_ops->copy = platform->driver->ops->copy;
+               soc_pcm_ops->silence = platform->driver->ops->silence;
+               soc_pcm_ops->ack = platform->driver->ops->ack;
+               soc_pcm_ops->page = platform->driver->ops->page;
        }
 
        if (playback)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
 
        if (capture)
-               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
 
        if (platform->driver->pcm_new) {
                ret = platform->driver->pcm_new(rtd);
index c6af1fd707f5410a50d9bc6ffaafcf108f76e6a8..ce1b773c351fd00772b5fccdf98688594d099c91 100644 (file)
@@ -47,3 +47,12 @@ config SND_SOC_TEGRA_TRIMSLICE
        help
          Say Y or M here if you want to add support for SoC audio on the
          TrimSlice platform.
+
+config SND_SOC_TEGRA_ALC5632
+       tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
+       depends on SND_SOC_TEGRA && I2C
+       select SND_SOC_TEGRA_I2S
+       select SND_SOC_ALC5632
+       help
+         Say Y or M here if you want to add support for SoC audio on the
+         Toshiba AC100 netbook.
index 4d943b3fe1500393918b1e12a3daa8902c39bf9c..8e584b8fcfba2e5a1c5a5a286bdfd1dda1c714b5 100644 (file)
@@ -14,6 +14,8 @@ obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
 # Tegra machine Support
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-trimslice-objs := trimslice.o
+snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
+obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
new file mode 100644 (file)
index 0000000..4a0e805
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+* tegra_alc5632.c  --  Toshiba AC100(PAZ00) machine ASoC driver
+*
+* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+*
+* Authors:  Leon Romanovsky <leon@leon.nu>
+*           Andrey Danin <danindrey@mail.ru>
+*           Marc Dietrich <marvin24@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 <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/alc5632.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-alc5632"
+
+struct tegra_alc5632 {
+       struct tegra_asoc_utils_data util_data;
+};
+
+static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card);
+       int srate, mclk;
+       int err;
+
+       srate = params_rate(params);
+       mclk = 512 * srate;
+
+       err = tegra_asoc_utils_set_rate(&alc5632->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_alc5632_asoc_ops = {
+       .hw_params = tegra_alc5632_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_alc5632_hs_jack;
+
+static struct snd_soc_jack_pin tegra_alc5632_hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
+static const struct snd_soc_dapm_widget tegra_alc5632_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Int Spk", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route tegra_alc5632_audio_map[] = {
+       /* Internal Speaker */
+       {"Int Spk", NULL, "SPKOUT"},
+       {"Int Spk", NULL, "SPKOUTN"},
+
+       /* Headset Mic */
+       {"MIC1", NULL, "MICBIAS1"},
+       {"MICBIAS1", NULL, "Headset Mic"},
+
+       /* Headset Stereophone */
+       {"Headset Stereophone", NULL, "HPR"},
+       {"Headset Stereophone", NULL, "HPL"},
+};
+
+static const struct snd_kcontrol_new tegra_alc5632_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Int Spk"),
+};
+
+static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
+                        &tegra_alc5632_hs_jack);
+       snd_soc_jack_add_pins(&tegra_alc5632_hs_jack,
+                       ARRAY_SIZE(tegra_alc5632_hs_jack_pins),
+                       tegra_alc5632_hs_jack_pins);
+
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_alc5632_dai = {
+       .name = "ALC5632",
+       .stream_name = "ALC5632 PCM",
+       .codec_name = "alc5632.0-001e",
+       .platform_name = "tegra-pcm-audio",
+       .cpu_dai_name = "tegra-i2s.0",
+       .codec_dai_name = "alc5632-hifi",
+       .init = tegra_alc5632_asoc_init,
+       .ops = &tegra_alc5632_asoc_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S
+                          | SND_SOC_DAIFMT_NB_NF
+                          | SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_alc5632 = {
+       .name = "tegra-alc5632",
+       .owner = THIS_MODULE,
+       .dai_link = &tegra_alc5632_dai,
+       .num_links = 1,
+       .controls = tegra_alc5632_controls,
+       .num_controls = ARRAY_SIZE(tegra_alc5632_controls),
+       .dapm_widgets = tegra_alc5632_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_alc5632_dapm_widgets),
+       .dapm_routes = tegra_alc5632_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(tegra_alc5632_audio_map),
+       .fully_routed = true,
+};
+
+static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &snd_soc_tegra_alc5632;
+       struct tegra_alc5632 *alc5632;
+       int ret;
+
+       alc5632 = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_alc5632), GFP_KERNEL);
+       if (!alc5632) {
+               dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n");
+               return -ENOMEM;
+       }
+
+       ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
+       if (ret)
+               return ret;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, alc5632);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               tegra_asoc_utils_fini(&alc5632->util_data);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&alc5632->util_data);
+
+       return 0;
+}
+
+static struct platform_driver tegra_alc5632_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = tegra_alc5632_probe,
+       .remove = __devexit_p(tegra_alc5632_remove),
+};
+module_platform_driver(tegra_alc5632_driver);
+
+MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
+MODULE_DESCRIPTION("Tegra+ALC5632 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 3b55a44146afc419c99fedd7d834dd826bd738e8..3b3c1ba4d235a2368a0540beddb67b1a54e6320a 100644 (file)
@@ -172,11 +172,11 @@ static int __devinit tegra_das_probe(struct platform_device *pdev)
        if (das)
                return -ENODEV;
 
-       das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL);
+       das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL);
        if (!das) {
                dev_err(&pdev->dev, "Can't allocate tegra_das\n");
                ret = -ENOMEM;
-               goto exit;
+               goto err;
        }
        das->dev = &pdev->dev;
 
@@ -184,22 +184,35 @@ static int __devinit tegra_das_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(&pdev->dev, "No memory resource\n");
                ret = -ENODEV;
-               goto err_free;
+               goto err;
        }
 
-       region = request_mem_region(res->start, resource_size(res),
-                                       pdev->name);
+       region = devm_request_mem_region(&pdev->dev, res->start,
+                                        resource_size(res), pdev->name);
        if (!region) {
                dev_err(&pdev->dev, "Memory region already claimed\n");
                ret = -EBUSY;
-               goto err_free;
+               goto err;
        }
 
-       das->regs = ioremap(res->start, resource_size(res));
+       das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!das->regs) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err_release;
+               goto err;
+       }
+
+       ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1,
+                                          TEGRA_DAS_DAP_SEL_DAC1);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
+               goto err;
+       }
+       ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1,
+                                          TEGRA_DAS_DAC_SEL_DAP1);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
+               goto err;
        }
 
        tegra_das_debug_add(das);
@@ -208,58 +221,41 @@ static int __devinit tegra_das_probe(struct platform_device *pdev)
 
        return 0;
 
-err_release:
-       release_mem_region(res->start, resource_size(res));
-err_free:
-       kfree(das);
+err:
        das = NULL;
-exit:
        return ret;
 }
 
 static int __devexit tegra_das_remove(struct platform_device *pdev)
 {
-       struct resource *res;
-
        if (!das)
                return -ENODEV;
 
-       platform_set_drvdata(pdev, NULL);
-
        tegra_das_debug_remove(das);
 
-       iounmap(das->regs);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(das);
        das = NULL;
 
        return 0;
 }
 
+static const struct of_device_id tegra_das_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra20-das", },
+       {},
+};
+
 static struct platform_driver tegra_das_driver = {
        .probe = tegra_das_probe,
        .remove = __devexit_p(tegra_das_remove),
        .driver = {
                .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = tegra_das_of_match,
        },
 };
-
-static int __init tegra_das_modinit(void)
-{
-       return platform_driver_register(&tegra_das_driver);
-}
-module_init(tegra_das_modinit);
-
-static void __exit tegra_das_modexit(void)
-{
-       platform_driver_unregister(&tegra_das_driver);
-}
-module_exit(tegra_das_modexit);
+module_platform_driver(tegra_das_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra DAS driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_das_of_match);
index 6728fab8c411f05a4a7c10032ba9d0e87aa04c3b..33509de52540bd8c38aea1bbfb121fe20fe238d5 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <mach/iomap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include "tegra_das.h"
 #include "tegra_i2s.h"
 
 #define DRV_NAME "tegra-i2s"
@@ -99,13 +99,11 @@ static const struct file_operations tegra_i2s_debug_fops = {
        .release = single_release,
 };
 
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
+static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
 {
-       char name[] = DRV_NAME ".0";
-
-       snprintf(name, sizeof(name), DRV_NAME".%1d", id);
-       i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root,
-                                               i2s, &tegra_i2s_debug_fops);
+       i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
+                                        snd_soc_debugfs_root, i2s,
+                                        &tegra_i2s_debug_fops);
 }
 
 static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
@@ -306,93 +304,54 @@ static int tegra_i2s_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops tegra_i2s_dai_ops = {
+static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
        .set_fmt        = tegra_i2s_set_fmt,
        .hw_params      = tegra_i2s_hw_params,
        .trigger        = tegra_i2s_trigger,
 };
 
-static struct snd_soc_dai_driver tegra_i2s_dai[] = {
-       {
-               .name = DRV_NAME ".0",
-               .probe = tegra_i2s_probe,
-               .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 = &tegra_i2s_dai_ops,
-               .symmetric_rates = 1,
+static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
+       .probe = tegra_i2s_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
-       {
-               .name = DRV_NAME ".1",
-               .probe = tegra_i2s_probe,
-               .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 = &tegra_i2s_dai_ops,
-               .symmetric_rates = 1,
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
+       .ops = &tegra_i2s_dai_ops,
+       .symmetric_rates = 1,
 };
 
 static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
 {
        struct tegra_i2s * i2s;
        struct resource *mem, *memregion, *dmareq;
+       u32 of_dma[2];
+       u32 dma_ch;
        int ret;
 
-       if ((pdev->id < 0) ||
-               (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) {
-               dev_err(&pdev->dev, "ID %d out of range\n", pdev->id);
-               return -EINVAL;
-       }
-
-       /*
-        * FIXME: Until a codec driver exists for the tegra DAS, hard-code a
-        * 1:1 mapping between audio controllers and audio ports.
-        */
-       ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id,
-                                       TEGRA_DAS_DAP_SEL_DAC1 + pdev->id);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAP connection\n");
-               return ret;
-       }
-       ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id,
-                                       TEGRA_DAS_DAC_SEL_DAP1 + pdev->id);
-       if (ret) {
-               dev_err(&pdev->dev, "Can't set up DAC connection\n");
-               return ret;
-       }
-
-       i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL);
+       i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
        if (!i2s) {
                dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
                ret = -ENOMEM;
-               goto exit;
+               goto err;
        }
        dev_set_drvdata(&pdev->dev, i2s);
 
+       i2s->dai = tegra_i2s_dai_template;
+       i2s->dai.name = dev_name(&pdev->dev);
+
        i2s->clk_i2s = clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2s->clk_i2s)) {
                dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
                ret = PTR_ERR(i2s->clk_i2s);
-               goto err_free;
+               goto err;
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -404,104 +363,93 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
 
        dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!dmareq) {
-               dev_err(&pdev->dev, "No DMA resource\n");
-               ret = -ENODEV;
-               goto err_clk_put;
+               if (of_property_read_u32_array(pdev->dev.of_node,
+                                       "nvidia,dma-request-selector",
+                                       of_dma, 2) < 0) {
+                       dev_err(&pdev->dev, "No DMA resource\n");
+                       ret = -ENODEV;
+                       goto err_clk_put;
+               }
+               dma_ch = of_dma[1];
+       } else {
+               dma_ch = dmareq->start;
        }
 
-       memregion = request_mem_region(mem->start, resource_size(mem),
-                                       DRV_NAME);
+       memregion = devm_request_mem_region(&pdev->dev, mem->start,
+                                           resource_size(mem), DRV_NAME);
        if (!memregion) {
                dev_err(&pdev->dev, "Memory region already claimed\n");
                ret = -EBUSY;
                goto err_clk_put;
        }
 
-       i2s->regs = ioremap(mem->start, resource_size(mem));
+       i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!i2s->regs) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
-               goto err_release;
+               goto err_clk_put;
        }
 
        i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
        i2s->capture_dma_data.wrap = 4;
        i2s->capture_dma_data.width = 32;
-       i2s->capture_dma_data.req_sel = dmareq->start;
+       i2s->capture_dma_data.req_sel = dma_ch;
 
        i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
        i2s->playback_dma_data.wrap = 4;
        i2s->playback_dma_data.width = 32;
-       i2s->playback_dma_data.req_sel = dmareq->start;
+       i2s->playback_dma_data.req_sel = dma_ch;
 
        i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
 
-       ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]);
+       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
-               goto err_unmap;
+               goto err_clk_put;
        }
 
-       tegra_i2s_debug_add(i2s, pdev->id);
+       tegra_i2s_debug_add(i2s);
 
        return 0;
 
-err_unmap:
-       iounmap(i2s->regs);
-err_release:
-       release_mem_region(mem->start, resource_size(mem));
 err_clk_put:
        clk_put(i2s->clk_i2s);
-err_free:
-       kfree(i2s);
-exit:
+err:
        return ret;
 }
 
 static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
 {
        struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
-       struct resource *res;
 
        snd_soc_unregister_dai(&pdev->dev);
 
        tegra_i2s_debug_remove(i2s);
 
-       iounmap(i2s->regs);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
        clk_put(i2s->clk_i2s);
 
-       kfree(i2s);
-
        return 0;
 }
 
+static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra20-i2s", },
+       {},
+};
+
 static struct platform_driver tegra_i2s_driver = {
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = tegra_i2s_of_match,
        },
        .probe = tegra_i2s_platform_probe,
        .remove = __devexit_p(tegra_i2s_platform_remove),
 };
-
-static int __init snd_tegra_i2s_init(void)
-{
-       return platform_driver_register(&tegra_i2s_driver);
-}
-module_init(snd_tegra_i2s_init);
-
-static void __exit snd_tegra_i2s_exit(void)
-{
-       platform_driver_unregister(&tegra_i2s_driver);
-}
-module_exit(snd_tegra_i2s_exit);
+module_platform_driver(tegra_i2s_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra I2S ASoC driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
index 2b38a096f46cfb4427e03646a0fa3a51df53bb6c..15ce1e2e8bde1500d0641a8239eef0cca75e6003 100644 (file)
 #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS  (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
 
 struct tegra_i2s {
+       struct snd_soc_dai_driver dai;
        struct clk *clk_i2s;
        int clk_refs;
        struct tegra_pcm_dma_params capture_dma_data;
index 436def1dfa39fee8b988fcbab0f14a74f277a438..c22431516ab200ebcdc9b2b1b86894afb8cf5a3a 100644 (file)
@@ -330,7 +330,6 @@ static u64 tegra_dma_mask = DMA_BIT_MASK(32);
 static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
        struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
@@ -339,14 +338,14 @@ static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->driver->playback.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
                ret = tegra_pcm_preallocate_dma_buffer(pcm,
                                                SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto err;
        }
 
-       if (dai->driver->capture.channels_min) {
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
                ret = tegra_pcm_preallocate_dma_buffer(pcm,
                                                SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -392,18 +391,7 @@ static struct platform_driver tegra_pcm_driver = {
        .probe = tegra_pcm_platform_probe,
        .remove = __devexit_p(tegra_pcm_platform_remove),
 };
-
-static int __init snd_tegra_pcm_init(void)
-{
-       return platform_driver_register(&tegra_pcm_driver);
-}
-module_init(snd_tegra_pcm_init);
-
-static void __exit snd_tegra_pcm_exit(void)
-{
-       platform_driver_unregister(&tegra_pcm_driver);
-}
-module_exit(snd_tegra_pcm_exit);
+module_platform_driver(tegra_pcm_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
index dd11d0c63474cd6fb8b2b19fea96e4ab07c42829..475428cf270e01eba85cff0a042c2d358669e7aa 100644 (file)
@@ -226,7 +226,7 @@ static int tegra_spdif_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
-static struct snd_soc_dai_ops tegra_spdif_dai_ops = {
+static const struct snd_soc_dai_ops tegra_spdif_dai_ops = {
        .hw_params      = tegra_spdif_hw_params,
        .trigger        = tegra_spdif_trigger,
 };
@@ -352,17 +352,7 @@ static struct platform_driver tegra_spdif_driver = {
        .remove = __devexit_p(tegra_spdif_platform_remove),
 };
 
-static int __init snd_tegra_spdif_init(void)
-{
-       return platform_driver_register(&tegra_spdif_driver);
-}
-module_init(snd_tegra_spdif_init);
-
-static void __exit snd_tegra_spdif_exit(void)
-{
-       platform_driver_unregister(&tegra_spdif_driver);
-}
-module_exit(snd_tegra_spdif_exit);
+module_platform_driver(tegra_spdif_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
index a81cf39257bf2ff8aa68df2b7a9ef408887f0ed7..566655e23b7d18063f8e2e337647eec023fead2a 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include <linux/of_gpio.h>
 
 #include <mach/tegra_wm8903_pdata.h>
 
@@ -59,8 +60,9 @@
 #define GPIO_HP_DET     BIT(4)
 
 struct tegra_wm8903 {
+       struct tegra_wm8903_platform_data pdata;
+       struct platform_device *pcm_dev;
        struct tegra_asoc_utils_data util_data;
-       struct tegra_wm8903_platform_data *pdata;
        int gpio_requested;
 };
 
@@ -160,7 +162,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
        if (!(machine->gpio_requested & GPIO_SPKR_EN))
                return 0;
@@ -177,7 +179,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
        if (!(machine->gpio_requested & GPIO_HP_MUTE))
                return 0;
@@ -201,8 +203,8 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = {
        {"Int Spk", NULL, "RON"},
        {"Int Spk", NULL, "LOP"},
        {"Int Spk", NULL, "LON"},
-       {"Mic Bias", NULL, "Mic Jack"},
-       {"IN1L", NULL, "Mic Bias"},
+       {"Mic Jack", NULL, "MICBIAS"},
+       {"IN1L", NULL, "Mic Jack"},
 };
 
 static const struct snd_soc_dapm_route seaboard_audio_map[] = {
@@ -212,8 +214,8 @@ static const struct snd_soc_dapm_route seaboard_audio_map[] = {
        {"Int Spk", NULL, "RON"},
        {"Int Spk", NULL, "LOP"},
        {"Int Spk", NULL, "LON"},
-       {"Mic Bias", NULL, "Mic Jack"},
-       {"IN1R", NULL, "Mic Bias"},
+       {"Mic Jack", NULL, "MICBIAS"},
+       {"IN1R", NULL, "Mic Jack"},
 };
 
 static const struct snd_soc_dapm_route kaen_audio_map[] = {
@@ -223,8 +225,8 @@ static const struct snd_soc_dapm_route kaen_audio_map[] = {
        {"Int Spk", NULL, "RON"},
        {"Int Spk", NULL, "LOP"},
        {"Int Spk", NULL, "LON"},
-       {"Mic Bias", NULL, "Mic Jack"},
-       {"IN2R", NULL, "Mic Bias"},
+       {"Mic Jack", NULL, "MICBIAS"},
+       {"IN2R", NULL, "Mic Jack"},
 };
 
 static const struct snd_soc_dapm_route aebl_audio_map[] = {
@@ -232,8 +234,8 @@ static const struct snd_soc_dapm_route aebl_audio_map[] = {
        {"Headphone Jack", NULL, "HPOUTL"},
        {"Int Spk", NULL, "LINEOUTR"},
        {"Int Spk", NULL, "LINEOUTL"},
-       {"Mic Bias", NULL, "Mic Jack"},
-       {"IN1R", NULL, "Mic Bias"},
+       {"Mic Jack", NULL, "MICBIAS"},
+       {"IN1R", NULL, "Mic Jack"},
 };
 
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
@@ -246,9 +248,36 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
+       struct device_node *np = card->dev->of_node;
        int ret;
 
+       if (card->dev->platform_data) {
+               memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
+       } else if (np) {
+               /*
+                * This part must be in init() rather than probe() in order to
+                * guarantee that the WM8903 has been probed, and hence its
+                * GPIO controller registered, which is a pre-condition for
+                * of_get_named_gpio() to be able to map the phandles in the
+                * properties to the controller node. Given this, all
+                * pdata handling is in init() for consistency.
+                */
+               pdata->gpio_spkr_en = of_get_named_gpio(np,
+                                               "nvidia,spkr-en-gpios", 0);
+               pdata->gpio_hp_mute = of_get_named_gpio(np,
+                                               "nvidia,hp-mute-gpios", 0);
+               pdata->gpio_hp_det = of_get_named_gpio(np,
+                                               "nvidia,hp-det-gpios", 0);
+               pdata->gpio_int_mic_en = of_get_named_gpio(np,
+                                               "nvidia,int-mic-en-gpios", 0);
+               pdata->gpio_ext_mic_en = of_get_named_gpio(np,
+                                               "nvidia,ext-mic-en-gpios", 0);
+       } else {
+               dev_err(card->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
        if (gpio_is_valid(pdata->gpio_spkr_en)) {
                ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
                if (ret) {
@@ -316,28 +345,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
        wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
                                0);
 
-       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
-
-       /* FIXME: Calculate automatically based on DAPM routes? */
-       if (!machine_is_harmony())
-               snd_soc_dapm_nc_pin(dapm, "IN1L");
-       if (!machine_is_seaboard() && !machine_is_aebl())
-               snd_soc_dapm_nc_pin(dapm, "IN1R");
-       snd_soc_dapm_nc_pin(dapm, "IN2L");
-       if (!machine_is_kaen())
-               snd_soc_dapm_nc_pin(dapm, "IN2R");
-       snd_soc_dapm_nc_pin(dapm, "IN3L");
-       snd_soc_dapm_nc_pin(dapm, "IN3R");
-
-       if (machine_is_aebl()) {
-               snd_soc_dapm_nc_pin(dapm, "LON");
-               snd_soc_dapm_nc_pin(dapm, "RON");
-               snd_soc_dapm_nc_pin(dapm, "ROP");
-               snd_soc_dapm_nc_pin(dapm, "LOP");
-       } else {
-               snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
-               snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
-       }
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
 
        return 0;
 }
@@ -355,6 +363,7 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
 
 static struct snd_soc_card snd_soc_tegra_wm8903 = {
        .name = "tegra-wm8903",
+       .owner = THIS_MODULE,
        .dai_link = &tegra_wm8903_dai,
        .num_links = 1,
 
@@ -362,51 +371,91 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
        .num_controls = ARRAY_SIZE(tegra_wm8903_controls),
        .dapm_widgets = tegra_wm8903_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets),
+       .fully_routed = true,
 };
 
 static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &snd_soc_tegra_wm8903;
        struct tegra_wm8903 *machine;
-       struct tegra_wm8903_platform_data *pdata;
        int ret;
 
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
+       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
                dev_err(&pdev->dev, "No platform data supplied\n");
                return -EINVAL;
        }
 
-       machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL);
+       machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
+                              GFP_KERNEL);
        if (!machine) {
                dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err;
        }
-
-       machine->pdata = pdata;
-
-       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
-       if (ret)
-               goto err_free_machine;
+       machine->pcm_dev = ERR_PTR(-EINVAL);
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
 
-       if (machine_is_harmony()) {
-               card->dapm_routes = harmony_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-       } else if (machine_is_seaboard()) {
-               card->dapm_routes = seaboard_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
-       } else if (machine_is_kaen()) {
-               card->dapm_routes = kaen_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
+       if (pdev->dev.of_node) {
+               ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+               if (ret)
+                       goto err;
+
+               ret = snd_soc_of_parse_audio_routing(card,
+                                                    "nvidia,audio-routing");
+               if (ret)
+                       goto err;
+
+               tegra_wm8903_dai.codec_name = NULL;
+               tegra_wm8903_dai.codec_of_node = of_parse_phandle(
+                               pdev->dev.of_node, "nvidia,audio-codec", 0);
+               if (!tegra_wm8903_dai.codec_of_node) {
+                       dev_err(&pdev->dev,
+                               "Property 'nvidia,audio-codec' missing or invalid\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               tegra_wm8903_dai.cpu_dai_name = NULL;
+               tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle(
+                               pdev->dev.of_node, "nvidia,i2s-controller", 0);
+               if (!tegra_wm8903_dai.cpu_dai_of_node) {
+                       dev_err(&pdev->dev,
+                               "Property 'nvidia,i2s-controller' missing or invalid\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               machine->pcm_dev = platform_device_register_simple(
+                                       "tegra-pcm-audio", -1, NULL, 0);
+               if (IS_ERR(machine->pcm_dev)) {
+                       dev_err(&pdev->dev,
+                               "Can't instantiate tegra-pcm-audio\n");
+                       ret = PTR_ERR(machine->pcm_dev);
+                       goto err;
+               }
        } else {
-               card->dapm_routes = aebl_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+               if (machine_is_harmony()) {
+                       card->dapm_routes = harmony_audio_map;
+                       card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
+               } else if (machine_is_seaboard()) {
+                       card->dapm_routes = seaboard_audio_map;
+                       card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
+               } else if (machine_is_kaen()) {
+                       card->dapm_routes = kaen_audio_map;
+                       card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
+               } else {
+                       card->dapm_routes = aebl_audio_map;
+                       card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
+               }
        }
 
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err_unregister;
+
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
@@ -418,8 +467,10 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&machine->util_data);
-err_free_machine:
-       kfree(machine);
+err_unregister:
+       if (!IS_ERR(machine->pcm_dev))
+               platform_device_unregister(machine->pcm_dev);
+err:
        return ret;
 }
 
@@ -427,7 +478,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = machine->pdata;
+       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
        if (machine->gpio_requested & GPIO_HP_DET)
                snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
@@ -446,35 +497,31 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
        snd_soc_unregister_card(card);
 
        tegra_asoc_utils_fini(&machine->util_data);
-
-       kfree(machine);
+       if (!IS_ERR(machine->pcm_dev))
+               platform_device_unregister(machine->pcm_dev);
 
        return 0;
 }
 
+static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = {
+       { .compatible = "nvidia,tegra-audio-wm8903", },
+       {},
+};
+
 static struct platform_driver tegra_wm8903_driver = {
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_wm8903_of_match,
        },
        .probe = tegra_wm8903_driver_probe,
        .remove = __devexit_p(tegra_wm8903_driver_remove),
 };
-
-static int __init tegra_wm8903_modinit(void)
-{
-       return platform_driver_register(&tegra_wm8903_driver);
-}
-module_init(tegra_wm8903_modinit);
-
-static void __exit tegra_wm8903_modexit(void)
-{
-       platform_driver_unregister(&tegra_wm8903_driver);
-}
-module_exit(tegra_wm8903_modexit);
+module_platform_driver(tegra_wm8903_driver);
 
 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
 MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match);
index b3a7efa6d960c75eed9f764000eea0fd1f8d46fa..2bdfc550cff8a482958042b8d7151d8118d436b1 100644 (file)
@@ -115,18 +115,6 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = {
        {"RLINEIN", NULL, "Line In"},
 };
 
-static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LHPOUT");
-       snd_soc_dapm_nc_pin(dapm, "RHPOUT");
-       snd_soc_dapm_nc_pin(dapm, "MICIN");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
@@ -134,12 +122,12 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .platform_name = "tegra-pcm-audio",
        .cpu_dai_name = "tegra-i2s.0",
        .codec_dai_name = "tlv320aic23-hifi",
-       .init = trimslice_asoc_init,
        .ops = &trimslice_asoc_ops,
 };
 
 static struct snd_soc_card snd_soc_trimslice = {
        .name = "tegra-trimslice",
+       .owner = THIS_MODULE,
        .dai_link = &trimslice_tlv320aic23_dai,
        .num_links = 1,
 
@@ -147,6 +135,7 @@ static struct snd_soc_card snd_soc_trimslice = {
        .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets),
        .dapm_routes = trimslice_audio_map,
        .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map),
+       .fully_routed = true,
 };
 
 static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
@@ -155,15 +144,17 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
        struct tegra_trimslice *trimslice;
        int ret;
 
-       trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL);
+       trimslice = devm_kzalloc(&pdev->dev, sizeof(struct tegra_trimslice),
+                                GFP_KERNEL);
        if (!trimslice) {
                dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err;
        }
 
        ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
        if (ret)
-               goto err_free_trimslice;
+               goto err;
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
@@ -180,8 +171,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
 
 err_fini_utils:
        tegra_asoc_utils_fini(&trimslice->util_data);
-err_free_trimslice:
-       kfree(trimslice);
+err:
        return ret;
 }
 
@@ -194,8 +184,6 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
 
        tegra_asoc_utils_fini(&trimslice->util_data);
 
-       kfree(trimslice);
-
        return 0;
 }
 
@@ -207,18 +195,7 @@ static struct platform_driver tegra_snd_trimslice_driver = {
        .probe = tegra_snd_trimslice_probe,
        .remove = __devexit_p(tegra_snd_trimslice_remove),
 };
-
-static int __init snd_tegra_trimslice_init(void)
-{
-       return platform_driver_register(&tegra_snd_trimslice_driver);
-}
-module_init(snd_tegra_trimslice_init);
-
-static void __exit snd_tegra_trimslice_exit(void)
-{
-       platform_driver_unregister(&tegra_snd_trimslice_driver);
-}
-module_exit(snd_tegra_trimslice_exit);
+module_platform_driver(tegra_snd_trimslice_driver);
 
 MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 MODULE_DESCRIPTION("Trimslice machine ASoC driver");
index a4e3f5501847ec640e2851ce4a786668044405eb..28db4ca997ca2b6c3f768de842ea84f567f4fd25 100644 (file)
@@ -223,18 +223,7 @@ static struct platform_driver txx9aclc_ac97_driver = {
        },
 };
 
-static int __init txx9aclc_ac97_init(void)
-{
-       return platform_driver_register(&txx9aclc_ac97_driver);
-}
-
-static void __exit txx9aclc_ac97_exit(void)
-{
-       platform_driver_unregister(&txx9aclc_ac97_driver);
-}
-
-module_init(txx9aclc_ac97_init);
-module_exit(txx9aclc_ac97_exit);
+module_platform_driver(txx9aclc_ac97_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("TXx9 ACLC AC97 driver");
index 9b5e283af51c68e2611dadbbaeae4cd9db9a9ea6..b056a1431ed41024a6d245374e42ff739eb0e365 100644 (file)
@@ -32,6 +32,7 @@ static struct snd_soc_dai_link txx9aclc_generic_dai = {
 
 static struct snd_soc_card txx9aclc_generic_card = {
        .name           = "Generic TXx9 ACLC Audio",
+       .owner          = THIS_MODULE,
        .dai_link       = &txx9aclc_generic_dai,
        .num_links      = 1,
 };
index 3de99af8cb82ccf6def128632603825e57c9ab77..93931def0dce62b3a5e162d7c759ac82f33745f2 100644 (file)
@@ -438,17 +438,7 @@ static struct platform_driver txx9aclc_pcm_driver = {
        .remove = __devexit_p(txx9aclc_soc_platform_remove),
 };
 
-static int __init snd_txx9aclc_pcm_init(void)
-{
-       return platform_driver_register(&txx9aclc_pcm_driver);
-}
-module_init(snd_txx9aclc_pcm_init);
-
-static void __exit snd_txx9aclc_pcm_exit(void)
-{
-       platform_driver_unregister(&txx9aclc_pcm_driver);
-}
-module_exit(snd_txx9aclc_pcm_exit);
+module_platform_driver(txx9aclc_pcm_driver);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
index f036776380b50d6d3d1f6d452a86a4ecfee3a2c5..b63b3a86d3f40f45eeef765a960b705268dd8d77 100644 (file)
@@ -50,7 +50,7 @@
 
 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_PNP;     /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Sun AMD7930 soundcard.");
index 0e618f82808cc1c590a3a62f5341059c301a2d25..f2eabd3f22fdde3453541b8a72a89da623e3d2ff 100644 (file)
@@ -40,7 +40,7 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 /* Enable this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");
@@ -2118,15 +2118,4 @@ static struct platform_driver cs4231_driver = {
        .remove         = __devexit_p(cs4231_remove),
 };
 
-static int __init cs4231_init(void)
-{
-       return platform_driver_register(&cs4231_driver);
-}
-
-static void __exit cs4231_exit(void)
-{
-       platform_driver_unregister(&cs4231_driver);
-}
-
-module_init(cs4231_init);
-module_exit(cs4231_exit);
+module_platform_driver(cs4231_driver);
index 4a4f1d740330d57b969c67cf1dfe65295f515e37..a6b0deb77746c11646e42dd9f5f6353311e94656 100644 (file)
@@ -80,7 +80,7 @@ MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}");
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 /* Enable this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");
@@ -2697,16 +2697,4 @@ static struct platform_driver dbri_sbus_driver = {
        .remove         = __devexit_p(dbri_remove),
 };
 
-/* Probe for the dbri chip and then attach the driver. */
-static int __init dbri_init(void)
-{
-       return platform_driver_register(&dbri_sbus_driver);
-}
-
-static void __exit dbri_exit(void)
-{
-       platform_driver_unregister(&dbri_sbus_driver);
-}
-
-module_init(dbri_init);
-module_exit(dbri_exit);
+module_platform_driver(dbri_sbus_driver);
index ac2d5e10f1a8c631e31ee00bf9e3c18394e88b65..8af92e3e9c18f9557810f5b71a27ab27f3345c40 100644 (file)
@@ -35,7 +35,7 @@ MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */
 static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
 
index 457fb274ff92d5b7cb31a220fb40f7272e3ccc59..64aed432ae2213dfaca6dba0818ccca8cc38352c 100644 (file)
@@ -55,7 +55,7 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
 
 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_PNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
 static int snd_card_used[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
index 0f6dc0d457bf360174505d717851aed65d5352f9..4a7be7b98331538228a49e13c81faf6b7f8243b7 100644 (file)
@@ -78,14 +78,14 @@ MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");
 
 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_PNP;/* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
 /* Vendor/product IDs for this card */
 static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
 static int nrpacks = 8;                /* max. number of packets per urb */
-static int async_unlink = 1;
+static bool async_unlink = 1;
 static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
-static int ignore_ctl_error;
+static bool ignore_ctl_error;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
index 81c6edecd862356324f93c110aca9b88c9c2562c..08dcce53720bad66499f48709c553b04e6ea6821 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/gfp.h>
 #include <linux/init.h>
+#include <linux/ratelimit.h>
 #include <linux/usb.h>
 #include <linux/usb/audio.h>
 
@@ -458,8 +459,8 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
 
        for (i = 0; i < urb->number_of_packets; i++) {
                cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (urb->iso_frame_desc[i].status) {
-                       snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+               if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
+                       snd_printdd("frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
                        // continue;
                }
                bytes = urb->iso_frame_desc[i].actual_length;
index 89421d176570739c6034c70a3cdd74285a5f394e..e09aba19375cf938eafd28aedec9edf2ea55dbbe 100644 (file)
@@ -209,6 +209,8 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
        return 0;
 }
 
+#define MAX_UAC2_NR_RATES 1024
+
 /*
  * Helper function to walk the array of sample rate triplets reported by
  * the device. The problem is that we need to parse whole array first to
@@ -226,7 +228,7 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
                int min = combine_quad(&data[2 + 12 * i]);
                int max = combine_quad(&data[6 + 12 * i]);
                int res = combine_quad(&data[10 + 12 * i]);
-               int rate;
+               unsigned int rate;
 
                if ((max < 0) || (min < 0) || (res < 0) || (max < min))
                        continue;
@@ -253,6 +255,10 @@ static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets,
                        fp->rates |= snd_pcm_rate_to_rate_bit(rate);
 
                        nr_rates++;
+                       if (nr_rates >= MAX_UAC2_NR_RATES) {
+                               snd_printk(KERN_ERR "invalid uac2 rates\n");
+                               break;
+                       }
 
                        /* avoid endless loop */
                        if (res == 0)
index 4c11da911a14624e4852a0bc7c5177ab1e9f6a29..8b81cb54026f9877d5c83a9a91b95ff1a8abde55 100644 (file)
@@ -52,7 +52,7 @@ MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}");
 
 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 bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 static unsigned int queue_length = 21;
 
 module_param_array(index, int, NULL, 0444);
index 32d2a21f2e3b5a401948d24b81c945e239e8fa4e..8edc5035fc8fc5929b948a765cc463498c0a8a9e 100644 (file)
@@ -269,6 +269,32 @@ YAMAHA_DEVICE(0x105a, NULL),
 YAMAHA_DEVICE(0x105b, NULL),
 YAMAHA_DEVICE(0x105c, NULL),
 YAMAHA_DEVICE(0x105d, NULL),
+{
+       USB_DEVICE(0x0499, 0x1503),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Yamaha", */
+               /* .product_name = "MOX6/MOX8", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_YAMAHA
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
@@ -2336,6 +2362,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+{
+       USB_DEVICE_VENDOR_SPEC(0x0944, 0x0201),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "KORG, Inc.",
+               /* .product_name = "ToneLab ST", */
+               .ifnum = 3,
+               .type = QUIRK_MIDI_STANDARD_INTERFACE,
+       }
+},
+
 /* AKAI devices */
 {
        USB_DEVICE(0x09e8, 0x0062),
index 625f7ca6a8945dde3118f4dd875b50214b4e7d49..c4fd3b1d95927f8eab2b2bfc21d745f3578f94f6 100644 (file)
@@ -37,7 +37,7 @@ 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 */
                                                        /* Enable this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
index c400ade3ff08b8c18d8225a9688b38f9e1c487cc..1e7a47a86605078d2934720f168da85cbf8145ce 100644 (file)
@@ -674,7 +674,7 @@ dotry:
                inurb->transfer_buffer_length =
                        inurb->number_of_packets *
                        inurb->iso_frame_desc[0].length;
-               preempt_disable();
+
                if (u == 0) {
                        int now;
                        struct usb_device *dev = inurb->dev;
@@ -686,19 +686,17 @@ dotry:
                }
                err = usb_submit_urb(inurb, GFP_ATOMIC);
                if (err < 0) {
-                       preempt_enable();
                        snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])"
                                   " returned %i\n", u, err);
                        return err;
                }
                err = usb_submit_urb(outurb, GFP_ATOMIC);
                if (err < 0) {
-                       preempt_enable();
                        snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])"
                                   " returned %i\n", u, err);
                        return err;
                }
-               preempt_enable();
+
                if (inurb->start_frame != outurb->start_frame) {
                        snd_printd(KERN_DEBUG
                                   "u[%i] start_frames differ in:%u out:%u\n",
index 0c738ed3ed389327e0ecd7583eb404361caf3fa4..9af7c1f17413a3cfb4910c56cce7c6a5cc880864 100644 (file)
@@ -154,7 +154,7 @@ MODULE_SUPPORTED_DEVICE("{{TASCAM(0x1604), "NAME_ALLCAPS"(0x8001)(0x8005)(0x8007
 
 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_PNP; /* Enable this card */
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
diff --git a/tools/lguest/.gitignore b/tools/lguest/.gitignore
new file mode 100644 (file)
index 0000000..115587f
--- /dev/null
@@ -0,0 +1 @@
+lguest
diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile
new file mode 100644 (file)
index 0000000..0ac3420
--- /dev/null
@@ -0,0 +1,8 @@
+# This creates the demonstration utility "lguest" which runs a Linux guest.
+# Missing headers?  Add "-I../../../include -I../../../arch/x86/include"
+CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
+
+all: lguest
+
+clean:
+       rm -f lguest
diff --git a/tools/lguest/extract b/tools/lguest/extract
new file mode 100644 (file)
index 0000000..7730bb6
--- /dev/null
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+set -e
+
+PREFIX=$1
+shift
+
+trap 'rm -r $TMPDIR' 0
+TMPDIR=`mktemp -d`
+
+exec 3>/dev/null
+for f; do
+    while IFS="
+" read -r LINE; do
+       case "$LINE" in
+           *$PREFIX:[0-9]*:\**)
+               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
+               if [ -f $TMPDIR/$NUM ]; then
+                   echo "$TMPDIR/$NUM already exits prior to $f"
+                   exit 1
+               fi
+               exec 3>>$TMPDIR/$NUM
+               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
+               /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3
+               ;;
+           *$PREFIX:[0-9]*)
+               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
+               if [ -f $TMPDIR/$NUM ]; then
+                   echo "$TMPDIR/$NUM already exits prior to $f"
+                   exit 1
+               fi
+               exec 3>>$TMPDIR/$NUM
+               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
+               /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3
+               ;;
+           *:\**)
+               /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3
+               echo >&3
+               exec 3>/dev/null
+               ;;
+           *)
+               /bin/echo "$LINE" >&3
+               ;;
+       esac
+    done < $f
+    echo >&3
+    exec 3>/dev/null
+done
+
+LASTFILE=""
+for f in $TMPDIR/*; do
+    if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then
+       LASTFILE=$(cat $TMPDIR/.$(basename $f) )
+       echo "[ $LASTFILE ]"
+    fi
+    cat $f
+done
+
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
new file mode 100644 (file)
index 0000000..f759f4f
--- /dev/null
@@ -0,0 +1,2065 @@
+/*P:100
+ * This is the Launcher code, a simple program which lays out the "physical"
+ * memory for the new Guest by mapping the kernel image and the virtual
+ * devices, then opens /dev/lguest to tell the kernel about the Guest and
+ * control it.
+:*/
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/eventfd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <linux/if_tun.h>
+#include <sys/uio.h>
+#include <termios.h>
+#include <getopt.h>
+#include <assert.h>
+#include <sched.h>
+#include <limits.h>
+#include <stddef.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <linux/virtio_config.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_blk.h>
+#include <linux/virtio_console.h>
+#include <linux/virtio_rng.h>
+#include <linux/virtio_ring.h>
+#include <asm/bootparam.h>
+#include "../../include/linux/lguest_launcher.h"
+/*L:110
+ * We can ignore the 43 include files we need for this program, but I do want
+ * to draw attention to the use of kernel-style types.
+ *
+ * As Linus said, "C is a Spartan language, and so should your naming be."  I
+ * like these abbreviations, so we define them here.  Note that u64 is always
+ * unsigned long long, which works on all Linux systems: this means that we can
+ * use %llu in printf for any u64.
+ */
+typedef unsigned long long u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+/*:*/
+
+#define BRIDGE_PFX "bridge:"
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
+#endif
+/* We can have up to 256 pages for devices. */
+#define DEVICE_PAGES 256
+/* This will occupy 3 pages: it must be a power of 2. */
+#define VIRTQUEUE_NUM 256
+
+/*L:120
+ * verbose is both a global flag and a macro.  The C preprocessor allows
+ * this, and although I wouldn't recommend it, it works quite nicely here.
+ */
+static bool verbose;
+#define verbose(args...) \
+       do { if (verbose) printf(args); } while(0)
+/*:*/
+
+/* The pointer to the start of guest memory. */
+static void *guest_base;
+/* The maximum guest physical address allowed, and maximum possible. */
+static unsigned long guest_limit, guest_max;
+/* The /dev/lguest file descriptor. */
+static int lguest_fd;
+
+/* a per-cpu variable indicating whose vcpu is currently running */
+static unsigned int __thread cpu_id;
+
+/* This is our list of devices. */
+struct device_list {
+       /* Counter to assign interrupt numbers. */
+       unsigned int next_irq;
+
+       /* Counter to print out convenient device numbers. */
+       unsigned int device_num;
+
+       /* The descriptor page for the devices. */
+       u8 *descpage;
+
+       /* A single linked list of devices. */
+       struct device *dev;
+       /* And a pointer to the last device for easy append. */
+       struct device *lastdev;
+};
+
+/* The list of Guest devices, based on command line arguments. */
+static struct device_list devices;
+
+/* The device structure describes a single device. */
+struct device {
+       /* The linked-list pointer. */
+       struct device *next;
+
+       /* The device's descriptor, as mapped into the Guest. */
+       struct lguest_device_desc *desc;
+
+       /* We can't trust desc values once Guest has booted: we use these. */
+       unsigned int feature_len;
+       unsigned int num_vq;
+
+       /* The name of this device, for --verbose. */
+       const char *name;
+
+       /* Any queues attached to this device */
+       struct virtqueue *vq;
+
+       /* Is it operational */
+       bool running;
+
+       /* Device-specific data. */
+       void *priv;
+};
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct virtqueue {
+       struct virtqueue *next;
+
+       /* Which device owns me. */
+       struct device *dev;
+
+       /* The configuration for this queue. */
+       struct lguest_vqconfig config;
+
+       /* The actual ring of buffers. */
+       struct vring vring;
+
+       /* Last available index we saw. */
+       u16 last_avail_idx;
+
+       /* How many are used since we sent last irq? */
+       unsigned int pending_used;
+
+       /* Eventfd where Guest notifications arrive. */
+       int eventfd;
+
+       /* Function for the thread which is servicing this virtqueue. */
+       void (*service)(struct virtqueue *vq);
+       pid_t thread;
+};
+
+/* Remember the arguments to the program so we can "reboot" */
+static char **main_args;
+
+/* The original tty settings to restore on exit. */
+static struct termios orig_term;
+
+/*
+ * We have to be careful with barriers: our devices are all run in separate
+ * threads and so we need to make sure that changes visible to the Guest happen
+ * in precise order.
+ */
+#define wmb() __asm__ __volatile__("" : : : "memory")
+#define mb() __asm__ __volatile__("" : : : "memory")
+
+/*
+ * Convert an iovec element to the given type.
+ *
+ * This is a fairly ugly trick: we need to know the size of the type and
+ * alignment requirement to check the pointer is kosher.  It's also nice to
+ * have the name of the type in case we report failure.
+ *
+ * Typing those three things all the time is cumbersome and error prone, so we
+ * have a macro which sets them all up and passes to the real function.
+ */
+#define convert(iov, type) \
+       ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
+
+static void *_convert(struct iovec *iov, size_t size, size_t align,
+                     const char *name)
+{
+       if (iov->iov_len != size)
+               errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
+       if ((unsigned long)iov->iov_base % align != 0)
+               errx(1, "Bad alignment %p for %s", iov->iov_base, name);
+       return iov->iov_base;
+}
+
+/* Wrapper for the last available index.  Makes it easier to change. */
+#define lg_last_avail(vq)      ((vq)->last_avail_idx)
+
+/*
+ * The virtio configuration space is defined to be little-endian.  x86 is
+ * little-endian too, but it's nice to be explicit so we have these helpers.
+ */
+#define cpu_to_le16(v16) (v16)
+#define cpu_to_le32(v32) (v32)
+#define cpu_to_le64(v64) (v64)
+#define le16_to_cpu(v16) (v16)
+#define le32_to_cpu(v32) (v32)
+#define le64_to_cpu(v64) (v64)
+
+/* Is this iovec empty? */
+static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_iov; i++)
+               if (iov[i].iov_len)
+                       return false;
+       return true;
+}
+
+/* Take len bytes from the front of this iovec. */
+static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_iov; i++) {
+               unsigned int used;
+
+               used = iov[i].iov_len < len ? iov[i].iov_len : len;
+               iov[i].iov_base += used;
+               iov[i].iov_len -= used;
+               len -= used;
+       }
+       assert(len == 0);
+}
+
+/* The device virtqueue descriptors are followed by feature bitmasks. */
+static u8 *get_feature_bits(struct device *dev)
+{
+       return (u8 *)(dev->desc + 1)
+               + dev->num_vq * sizeof(struct lguest_vqconfig);
+}
+
+/*L:100
+ * The Launcher code itself takes us out into userspace, that scary place where
+ * pointers run wild and free!  Unfortunately, like most userspace programs,
+ * it's quite boring (which is why everyone likes to hack on the kernel!).
+ * Perhaps if you make up an Lguest Drinking Game at this point, it will get
+ * you through this section.  Or, maybe not.
+ *
+ * The Launcher sets up a big chunk of memory to be the Guest's "physical"
+ * memory and stores it in "guest_base".  In other words, Guest physical ==
+ * Launcher virtual with an offset.
+ *
+ * This can be tough to get your head around, but usually it just means that we
+ * use these trivial conversion functions when the Guest gives us its
+ * "physical" addresses:
+ */
+static void *from_guest_phys(unsigned long addr)
+{
+       return guest_base + addr;
+}
+
+static unsigned long to_guest_phys(const void *addr)
+{
+       return (addr - guest_base);
+}
+
+/*L:130
+ * Loading the Kernel.
+ *
+ * We start with couple of simple helper routines.  open_or_die() avoids
+ * error-checking code cluttering the callers:
+ */
+static int open_or_die(const char *name, int flags)
+{
+       int fd = open(name, flags);
+       if (fd < 0)
+               err(1, "Failed to open %s", name);
+       return fd;
+}
+
+/* map_zeroed_pages() takes a number of pages. */
+static void *map_zeroed_pages(unsigned int num)
+{
+       int fd = open_or_die("/dev/zero", O_RDONLY);
+       void *addr;
+
+       /*
+        * We use a private mapping (ie. if we write to the page, it will be
+        * copied). We allocate an extra two pages PROT_NONE to act as guard
+        * pages against read/write attempts that exceed allocated space.
+        */
+       addr = mmap(NULL, getpagesize() * (num+2),
+                   PROT_NONE, MAP_PRIVATE, fd, 0);
+
+       if (addr == MAP_FAILED)
+               err(1, "Mmapping %u pages of /dev/zero", num);
+
+       if (mprotect(addr + getpagesize(), getpagesize() * num,
+                    PROT_READ|PROT_WRITE) == -1)
+               err(1, "mprotect rw %u pages failed", num);
+
+       /*
+        * One neat mmap feature is that you can close the fd, and it
+        * stays mapped.
+        */
+       close(fd);
+
+       /* Return address after PROT_NONE page */
+       return addr + getpagesize();
+}
+
+/* Get some more pages for a device. */
+static void *get_pages(unsigned int num)
+{
+       void *addr = from_guest_phys(guest_limit);
+
+       guest_limit += num * getpagesize();
+       if (guest_limit > guest_max)
+               errx(1, "Not enough memory for devices");
+       return addr;
+}
+
+/*
+ * This routine is used to load the kernel or initrd.  It tries mmap, but if
+ * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
+ * it falls back to reading the memory in.
+ */
+static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
+{
+       ssize_t r;
+
+       /*
+        * We map writable even though for some segments are marked read-only.
+        * The kernel really wants to be writable: it patches its own
+        * instructions.
+        *
+        * MAP_PRIVATE means that the page won't be copied until a write is
+        * done to it.  This allows us to share untouched memory between
+        * Guests.
+        */
+       if (mmap(addr, len, PROT_READ|PROT_WRITE,
+                MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
+               return;
+
+       /* pread does a seek and a read in one shot: saves a few lines. */
+       r = pread(fd, addr, len, offset);
+       if (r != len)
+               err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
+}
+
+/*
+ * This routine takes an open vmlinux image, which is in ELF, and maps it into
+ * the Guest memory.  ELF = Embedded Linking Format, which is the format used
+ * by all modern binaries on Linux including the kernel.
+ *
+ * The ELF headers give *two* addresses: a physical address, and a virtual
+ * address.  We use the physical address; the Guest will map itself to the
+ * virtual address.
+ *
+ * We return the starting address.
+ */
+static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
+{
+       Elf32_Phdr phdr[ehdr->e_phnum];
+       unsigned int i;
+
+       /*
+        * Sanity checks on the main ELF header: an x86 executable with a
+        * reasonable number of correctly-sized program headers.
+        */
+       if (ehdr->e_type != ET_EXEC
+           || ehdr->e_machine != EM_386
+           || ehdr->e_phentsize != sizeof(Elf32_Phdr)
+           || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
+               errx(1, "Malformed elf header");
+
+       /*
+        * An ELF executable contains an ELF header and a number of "program"
+        * headers which indicate which parts ("segments") of the program to
+        * load where.
+        */
+
+       /* We read in all the program headers at once: */
+       if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
+               err(1, "Seeking to program headers");
+       if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
+               err(1, "Reading program headers");
+
+       /*
+        * Try all the headers: there are usually only three.  A read-only one,
+        * a read-write one, and a "note" section which we don't load.
+        */
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               /* If this isn't a loadable segment, we ignore it */
+               if (phdr[i].p_type != PT_LOAD)
+                       continue;
+
+               verbose("Section %i: size %i addr %p\n",
+                       i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
+
+               /* We map this section of the file at its physical address. */
+               map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
+                      phdr[i].p_offset, phdr[i].p_filesz);
+       }
+
+       /* The entry point is given in the ELF header. */
+       return ehdr->e_entry;
+}
+
+/*L:150
+ * A bzImage, unlike an ELF file, is not meant to be loaded.  You're supposed
+ * to jump into it and it will unpack itself.  We used to have to perform some
+ * hairy magic because the unpacking code scared me.
+ *
+ * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
+ * a small patch to jump over the tricky bits in the Guest, so now we just read
+ * the funky header so we know where in the file to load, and away we go!
+ */
+static unsigned long load_bzimage(int fd)
+{
+       struct boot_params boot;
+       int r;
+       /* Modern bzImages get loaded at 1M. */
+       void *p = from_guest_phys(0x100000);
+
+       /*
+        * Go back to the start of the file and read the header.  It should be
+        * a Linux boot header (see Documentation/x86/boot.txt)
+        */
+       lseek(fd, 0, SEEK_SET);
+       read(fd, &boot, sizeof(boot));
+
+       /* Inside the setup_hdr, we expect the magic "HdrS" */
+       if (memcmp(&boot.hdr.header, "HdrS", 4) != 0)
+               errx(1, "This doesn't look like a bzImage to me");
+
+       /* Skip over the extra sectors of the header. */
+       lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET);
+
+       /* Now read everything into memory. in nice big chunks. */
+       while ((r = read(fd, p, 65536)) > 0)
+               p += r;
+
+       /* Finally, code32_start tells us where to enter the kernel. */
+       return boot.hdr.code32_start;
+}
+
+/*L:140
+ * Loading the kernel is easy when it's a "vmlinux", but most kernels
+ * come wrapped up in the self-decompressing "bzImage" format.  With a little
+ * work, we can load those, too.
+ */
+static unsigned long load_kernel(int fd)
+{
+       Elf32_Ehdr hdr;
+
+       /* Read in the first few bytes. */
+       if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+               err(1, "Reading kernel");
+
+       /* If it's an ELF file, it starts with "\177ELF" */
+       if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
+               return map_elf(fd, &hdr);
+
+       /* Otherwise we assume it's a bzImage, and try to load it. */
+       return load_bzimage(fd);
+}
+
+/*
+ * This is a trivial little helper to align pages.  Andi Kleen hated it because
+ * it calls getpagesize() twice: "it's dumb code."
+ *
+ * Kernel guys get really het up about optimization, even when it's not
+ * necessary.  I leave this code as a reaction against that.
+ */
+static inline unsigned long page_align(unsigned long addr)
+{
+       /* Add upwards and truncate downwards. */
+       return ((addr + getpagesize()-1) & ~(getpagesize()-1));
+}
+
+/*L:180
+ * An "initial ram disk" is a disk image loaded into memory along with the
+ * kernel which the kernel can use to boot from without needing any drivers.
+ * Most distributions now use this as standard: the initrd contains the code to
+ * load the appropriate driver modules for the current machine.
+ *
+ * Importantly, James Morris works for RedHat, and Fedora uses initrds for its
+ * kernels.  He sent me this (and tells me when I break it).
+ */
+static unsigned long load_initrd(const char *name, unsigned long mem)
+{
+       int ifd;
+       struct stat st;
+       unsigned long len;
+
+       ifd = open_or_die(name, O_RDONLY);
+       /* fstat() is needed to get the file size. */
+       if (fstat(ifd, &st) < 0)
+               err(1, "fstat() on initrd '%s'", name);
+
+       /*
+        * We map the initrd at the top of memory, but mmap wants it to be
+        * page-aligned, so we round the size up for that.
+        */
+       len = page_align(st.st_size);
+       map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
+       /*
+        * Once a file is mapped, you can close the file descriptor.  It's a
+        * little odd, but quite useful.
+        */
+       close(ifd);
+       verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len);
+
+       /* We return the initrd size. */
+       return len;
+}
+/*:*/
+
+/*
+ * Simple routine to roll all the commandline arguments together with spaces
+ * between them.
+ */
+static void concat(char *dst, char *args[])
+{
+       unsigned int i, len = 0;
+
+       for (i = 0; args[i]; i++) {
+               if (i) {
+                       strcat(dst+len, " ");
+                       len++;
+               }
+               strcpy(dst+len, args[i]);
+               len += strlen(args[i]);
+       }
+       /* In case it's empty. */
+       dst[len] = '\0';
+}
+
+/*L:185
+ * This is where we actually tell the kernel to initialize the Guest.  We
+ * saw the arguments it expects when we looked at initialize() in lguest_user.c:
+ * the base of Guest "physical" memory, the top physical page to allow and the
+ * entry point for the Guest.
+ */
+static void tell_kernel(unsigned long start)
+{
+       unsigned long args[] = { LHREQ_INITIALIZE,
+                                (unsigned long)guest_base,
+                                guest_limit / getpagesize(), start };
+       verbose("Guest: %p - %p (%#lx)\n",
+               guest_base, guest_base + guest_limit, guest_limit);
+       lguest_fd = open_or_die("/dev/lguest", O_RDWR);
+       if (write(lguest_fd, args, sizeof(args)) < 0)
+               err(1, "Writing to /dev/lguest");
+}
+/*:*/
+
+/*L:200
+ * Device Handling.
+ *
+ * When the Guest gives us a buffer, it sends an array of addresses and sizes.
+ * We need to make sure it's not trying to reach into the Launcher itself, so
+ * we have a convenient routine which checks it and exits with an error message
+ * if something funny is going on:
+ */
+static void *_check_pointer(unsigned long addr, unsigned int size,
+                           unsigned int line)
+{
+       /*
+        * Check if the requested address and size exceeds the allocated memory,
+        * or addr + size wraps around.
+        */
+       if ((addr + size) > guest_limit || (addr + size) < addr)
+               errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
+       /*
+        * We return a pointer for the caller's convenience, now we know it's
+        * safe to use.
+        */
+       return from_guest_phys(addr);
+}
+/* A macro which transparently hands the line number to the real function. */
+#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
+
+/*
+ * Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end.
+ */
+static unsigned next_desc(struct vring_desc *desc,
+                         unsigned int i, unsigned int max)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc[i].flags & VRING_DESC_F_NEXT))
+               return max;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc[i].next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       wmb();
+
+       if (next >= max)
+               errx(1, "Desc next is %u", next);
+
+       return next;
+}
+
+/*
+ * This actually sends the interrupt for this virtqueue, if we've used a
+ * buffer.
+ */
+static void trigger_irq(struct virtqueue *vq)
+{
+       unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
+
+       /* Don't inform them if nothing used. */
+       if (!vq->pending_used)
+               return;
+       vq->pending_used = 0;
+
+       /* If they don't want an interrupt, don't send one... */
+       if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
+               return;
+       }
+
+       /* Send the Guest an interrupt tell them we used something up. */
+       if (write(lguest_fd, buf, sizeof(buf)) != 0)
+               err(1, "Triggering irq %i", vq->config.irq);
+}
+
+/*
+ * This looks in the virtqueue for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function waits if necessary, and returns the descriptor number found.
+ */
+static unsigned wait_for_vq_desc(struct virtqueue *vq,
+                                struct iovec iov[],
+                                unsigned int *out_num, unsigned int *in_num)
+{
+       unsigned int i, head, max;
+       struct vring_desc *desc;
+       u16 last_avail = lg_last_avail(vq);
+
+       /* There's nothing available? */
+       while (last_avail == vq->vring.avail->idx) {
+               u64 event;
+
+               /*
+                * Since we're about to sleep, now is a good time to tell the
+                * Guest about what we've used up to now.
+                */
+               trigger_irq(vq);
+
+               /* OK, now we need to know about added descriptors. */
+               vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+
+               /*
+                * They could have slipped one in as we were doing that: make
+                * sure it's written, then check again.
+                */
+               mb();
+               if (last_avail != vq->vring.avail->idx) {
+                       vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+                       break;
+               }
+
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
+                       errx(1, "Event read failed?");
+
+               /* We don't need to be notified again. */
+               vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+       }
+
+       /* Check it isn't doing very strange things with descriptor numbers. */
+       if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
+               errx(1, "Guest moved used index from %u to %u",
+                    last_avail, vq->vring.avail->idx);
+
+       /*
+        * Grab the next descriptor number they're advertising, and increment
+        * the index we've seen.
+        */
+       head = vq->vring.avail->ring[last_avail % vq->vring.num];
+       lg_last_avail(vq)++;
+
+       /* If their number is silly, that's a fatal mistake. */
+       if (head >= vq->vring.num)
+               errx(1, "Guest says index %u is available", head);
+
+       /* When we start there are none of either input nor output. */
+       *out_num = *in_num = 0;
+
+       max = vq->vring.num;
+       desc = vq->vring.desc;
+       i = head;
+
+       /*
+        * If this is an indirect entry, then this buffer contains a descriptor
+        * table which we handle as if it's any normal descriptor chain.
+        */
+       if (desc[i].flags & VRING_DESC_F_INDIRECT) {
+               if (desc[i].len % sizeof(struct vring_desc))
+                       errx(1, "Invalid size for indirect buffer table");
+
+               max = desc[i].len / sizeof(struct vring_desc);
+               desc = check_pointer(desc[i].addr, desc[i].len);
+               i = 0;
+       }
+
+       do {
+               /* Grab the first descriptor, and check it's OK. */
+               iov[*out_num + *in_num].iov_len = desc[i].len;
+               iov[*out_num + *in_num].iov_base
+                       = check_pointer(desc[i].addr, desc[i].len);
+               /* If this is an input descriptor, increment that count. */
+               if (desc[i].flags & VRING_DESC_F_WRITE)
+                       (*in_num)++;
+               else {
+                       /*
+                        * If it's an output descriptor, they're all supposed
+                        * to come before any input descriptors.
+                        */
+                       if (*in_num)
+                               errx(1, "Descriptor has out after in");
+                       (*out_num)++;
+               }
+
+               /* If we've got too many, that implies a descriptor loop. */
+               if (*out_num + *in_num > max)
+                       errx(1, "Looped descriptor");
+       } while ((i = next_desc(desc, i, max)) != max);
+
+       return head;
+}
+
+/*
+ * After we've used one of their buffers, we tell the Guest about it.  Sometime
+ * later we'll want to send them an interrupt using trigger_irq(); note that
+ * wait_for_vq_desc() does that for us if it has to wait.
+ */
+static void add_used(struct virtqueue *vq, unsigned int head, int len)
+{
+       struct vring_used_elem *used;
+
+       /*
+        * The virtqueue contains a ring of used buffers.  Get a pointer to the
+        * next entry in that used ring.
+        */
+       used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
+       used->id = head;
+       used->len = len;
+       /* Make sure buffer is written before we update index. */
+       wmb();
+       vq->vring.used->idx++;
+       vq->pending_used++;
+}
+
+/* And here's the combo meal deal.  Supersize me! */
+static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
+{
+       add_used(vq, head, len);
+       trigger_irq(vq);
+}
+
+/*
+ * The Console
+ *
+ * We associate some data with the console for our exit hack.
+ */
+struct console_abort {
+       /* How many times have they hit ^C? */
+       int count;
+       /* When did they start? */
+       struct timeval start;
+};
+
+/* This is the routine which handles console input (ie. stdin). */
+static void console_input(struct virtqueue *vq)
+{
+       int len;
+       unsigned int head, in_num, out_num;
+       struct console_abort *abort = vq->dev->priv;
+       struct iovec iov[vq->vring.num];
+
+       /* Make sure there's a descriptor available. */
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
+       if (out_num)
+               errx(1, "Output buffers in console in queue?");
+
+       /* Read into it.  This is where we usually wait. */
+       len = readv(STDIN_FILENO, iov, in_num);
+       if (len <= 0) {
+               /* Ran out of input? */
+               warnx("Failed to get console input, ignoring console.");
+               /*
+                * For simplicity, dying threads kill the whole Launcher.  So
+                * just nap here.
+                */
+               for (;;)
+                       pause();
+       }
+
+       /* Tell the Guest we used a buffer. */
+       add_used_and_trigger(vq, head, len);
+
+       /*
+        * Three ^C within one second?  Exit.
+        *
+        * This is such a hack, but works surprisingly well.  Each ^C has to
+        * be in a buffer by itself, so they can't be too fast.  But we check
+        * that we get three within about a second, so they can't be too
+        * slow.
+        */
+       if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
+               abort->count = 0;
+               return;
+       }
+
+       abort->count++;
+       if (abort->count == 1)
+               gettimeofday(&abort->start, NULL);
+       else if (abort->count == 3) {
+               struct timeval now;
+               gettimeofday(&now, NULL);
+               /* Kill all Launcher processes with SIGINT, like normal ^C */
+               if (now.tv_sec <= abort->start.tv_sec+1)
+                       kill(0, SIGINT);
+               abort->count = 0;
+       }
+}
+
+/* This is the routine which handles console output (ie. stdout). */
+static void console_output(struct virtqueue *vq)
+{
+       unsigned int head, out, in;
+       struct iovec iov[vq->vring.num];
+
+       /* We usually wait in here, for the Guest to give us something. */
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (in)
+               errx(1, "Input buffers in console output queue?");
+
+       /* writev can return a partial write, so we loop here. */
+       while (!iov_empty(iov, out)) {
+               int len = writev(STDOUT_FILENO, iov, out);
+               if (len <= 0) {
+                       warn("Write to stdout gave %i (%d)", len, errno);
+                       break;
+               }
+               iov_consume(iov, out, len);
+       }
+
+       /*
+        * We're finished with that buffer: if we're going to sleep,
+        * wait_for_vq_desc() will prod the Guest with an interrupt.
+        */
+       add_used(vq, head, 0);
+}
+
+/*
+ * The Network
+ *
+ * Handling output for network is also simple: we get all the output buffers
+ * and write them to /dev/net/tun.
+ */
+struct net_info {
+       int tunfd;
+};
+
+static void net_output(struct virtqueue *vq)
+{
+       struct net_info *net_info = vq->dev->priv;
+       unsigned int head, out, in;
+       struct iovec iov[vq->vring.num];
+
+       /* We usually wait in here for the Guest to give us a packet. */
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (in)
+               errx(1, "Input buffers in net output queue?");
+       /*
+        * Send the whole thing through to /dev/net/tun.  It expects the exact
+        * same format: what a coincidence!
+        */
+       if (writev(net_info->tunfd, iov, out) < 0)
+               warnx("Write to tun failed (%d)?", errno);
+
+       /*
+        * Done with that one; wait_for_vq_desc() will send the interrupt if
+        * all packets are processed.
+        */
+       add_used(vq, head, 0);
+}
+
+/*
+ * Handling network input is a bit trickier, because I've tried to optimize it.
+ *
+ * First we have a helper routine which tells is if from this file descriptor
+ * (ie. the /dev/net/tun device) will block:
+ */
+static bool will_block(int fd)
+{
+       fd_set fdset;
+       struct timeval zero = { 0, 0 };
+       FD_ZERO(&fdset);
+       FD_SET(fd, &fdset);
+       return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
+}
+
+/*
+ * This handles packets coming in from the tun device to our Guest.  Like all
+ * service routines, it gets called again as soon as it returns, so you don't
+ * see a while(1) loop here.
+ */
+static void net_input(struct virtqueue *vq)
+{
+       int len;
+       unsigned int head, out, in;
+       struct iovec iov[vq->vring.num];
+       struct net_info *net_info = vq->dev->priv;
+
+       /*
+        * Get a descriptor to write an incoming packet into.  This will also
+        * send an interrupt if they're out of descriptors.
+        */
+       head = wait_for_vq_desc(vq, iov, &out, &in);
+       if (out)
+               errx(1, "Output buffers in net input queue?");
+
+       /*
+        * If it looks like we'll block reading from the tun device, send them
+        * an interrupt.
+        */
+       if (vq->pending_used && will_block(net_info->tunfd))
+               trigger_irq(vq);
+
+       /*
+        * Read in the packet.  This is where we normally wait (when there's no
+        * incoming network traffic).
+        */
+       len = readv(net_info->tunfd, iov, in);
+       if (len <= 0)
+               warn("Failed to read from tun (%d).", errno);
+
+       /*
+        * Mark that packet buffer as used, but don't interrupt here.  We want
+        * to wait until we've done as much work as we can.
+        */
+       add_used(vq, head, len);
+}
+/*:*/
+
+/* This is the helper to create threads: run the service routine in a loop. */
+static int do_thread(void *_vq)
+{
+       struct virtqueue *vq = _vq;
+
+       for (;;)
+               vq->service(vq);
+       return 0;
+}
+
+/*
+ * When a child dies, we kill our entire process group with SIGTERM.  This
+ * also has the side effect that the shell restores the console for us!
+ */
+static void kill_launcher(int signal)
+{
+       kill(0, SIGTERM);
+}
+
+static void reset_device(struct device *dev)
+{
+       struct virtqueue *vq;
+
+       verbose("Resetting device %s\n", dev->name);
+
+       /* Clear any features they've acked. */
+       memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len);
+
+       /* We're going to be explicitly killing threads, so ignore them. */
+       signal(SIGCHLD, SIG_IGN);
+
+       /* Zero out the virtqueues, get rid of their threads */
+       for (vq = dev->vq; vq; vq = vq->next) {
+               if (vq->thread != (pid_t)-1) {
+                       kill(vq->thread, SIGTERM);
+                       waitpid(vq->thread, NULL, 0);
+                       vq->thread = (pid_t)-1;
+               }
+               memset(vq->vring.desc, 0,
+                      vring_size(vq->config.num, LGUEST_VRING_ALIGN));
+               lg_last_avail(vq) = 0;
+       }
+       dev->running = false;
+
+       /* Now we care if threads die. */
+       signal(SIGCHLD, (void *)kill_launcher);
+}
+
+/*L:216
+ * This actually creates the thread which services the virtqueue for a device.
+ */
+static void create_thread(struct virtqueue *vq)
+{
+       /*
+        * Create stack for thread.  Since the stack grows upwards, we point
+        * the stack pointer to the end of this region.
+        */
+       char *stack = malloc(32768);
+       unsigned long args[] = { LHREQ_EVENTFD,
+                                vq->config.pfn*getpagesize(), 0 };
+
+       /* Create a zero-initialized eventfd. */
+       vq->eventfd = eventfd(0, 0);
+       if (vq->eventfd < 0)
+               err(1, "Creating eventfd");
+       args[2] = vq->eventfd;
+
+       /*
+        * Attach an eventfd to this virtqueue: it will go off when the Guest
+        * does an LHCALL_NOTIFY for this vq.
+        */
+       if (write(lguest_fd, &args, sizeof(args)) != 0)
+               err(1, "Attaching eventfd");
+
+       /*
+        * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so
+        * we get a signal if it dies.
+        */
+       vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
+       if (vq->thread == (pid_t)-1)
+               err(1, "Creating clone");
+
+       /* We close our local copy now the child has it. */
+       close(vq->eventfd);
+}
+
+static void start_device(struct device *dev)
+{
+       unsigned int i;
+       struct virtqueue *vq;
+
+       verbose("Device %s OK: offered", dev->name);
+       for (i = 0; i < dev->feature_len; i++)
+               verbose(" %02x", get_feature_bits(dev)[i]);
+       verbose(", accepted");
+       for (i = 0; i < dev->feature_len; i++)
+               verbose(" %02x", get_feature_bits(dev)
+                       [dev->feature_len+i]);
+
+       for (vq = dev->vq; vq; vq = vq->next) {
+               if (vq->service)
+                       create_thread(vq);
+       }
+       dev->running = true;
+}
+
+static void cleanup_devices(void)
+{
+       struct device *dev;
+
+       for (dev = devices.dev; dev; dev = dev->next)
+               reset_device(dev);
+
+       /* If we saved off the original terminal settings, restore them now. */
+       if (orig_term.c_lflag & (ISIG|ICANON|ECHO))
+               tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+}
+
+/* When the Guest tells us they updated the status field, we handle it. */
+static void update_device_status(struct device *dev)
+{
+       /* A zero status is a reset, otherwise it's a set of flags. */
+       if (dev->desc->status == 0)
+               reset_device(dev);
+       else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+               warnx("Device %s configuration FAILED", dev->name);
+               if (dev->running)
+                       reset_device(dev);
+       } else {
+               if (dev->running)
+                       err(1, "Device %s features finalized twice", dev->name);
+               start_device(dev);
+       }
+}
+
+/*L:215
+ * This is the generic routine we call when the Guest uses LHCALL_NOTIFY.  In
+ * particular, it's used to notify us of device status changes during boot.
+ */
+static void handle_output(unsigned long addr)
+{
+       struct device *i;
+
+       /* Check each device. */
+       for (i = devices.dev; i; i = i->next) {
+               struct virtqueue *vq;
+
+               /*
+                * Notifications to device descriptors mean they updated the
+                * device status.
+                */
+               if (from_guest_phys(addr) == i->desc) {
+                       update_device_status(i);
+                       return;
+               }
+
+               /* Devices should not be used before features are finalized. */
+               for (vq = i->vq; vq; vq = vq->next) {
+                       if (addr != vq->config.pfn*getpagesize())
+                               continue;
+                       errx(1, "Notification on %s before setup!", i->name);
+               }
+       }
+
+       /*
+        * Early console write is done using notify on a nul-terminated string
+        * in Guest memory.  It's also great for hacking debugging messages
+        * into a Guest.
+        */
+       if (addr >= guest_limit)
+               errx(1, "Bad NOTIFY %#lx", addr);
+
+       write(STDOUT_FILENO, from_guest_phys(addr),
+             strnlen(from_guest_phys(addr), guest_limit - addr));
+}
+
+/*L:190
+ * Device Setup
+ *
+ * All devices need a descriptor so the Guest knows it exists, and a "struct
+ * device" so the Launcher can keep track of it.  We have common helper
+ * routines to allocate and manage them.
+ */
+
+/*
+ * The layout of the device page is a "struct lguest_device_desc" followed by a
+ * number of virtqueue descriptors, then two sets of feature bits, then an
+ * array of configuration bytes.  This routine returns the configuration
+ * pointer.
+ */
+static u8 *device_config(const struct device *dev)
+{
+       return (void *)(dev->desc + 1)
+               + dev->num_vq * sizeof(struct lguest_vqconfig)
+               + dev->feature_len * 2;
+}
+
+/*
+ * This routine allocates a new "struct lguest_device_desc" from descriptor
+ * table page just above the Guest's normal memory.  It returns a pointer to
+ * that descriptor.
+ */
+static struct lguest_device_desc *new_dev_desc(u16 type)
+{
+       struct lguest_device_desc d = { .type = type };
+       void *p;
+
+       /* Figure out where the next device config is, based on the last one. */
+       if (devices.lastdev)
+               p = device_config(devices.lastdev)
+                       + devices.lastdev->desc->config_len;
+       else
+               p = devices.descpage;
+
+       /* We only have one page for all the descriptors. */
+       if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
+               errx(1, "Too many devices");
+
+       /* p might not be aligned, so we memcpy in. */
+       return memcpy(p, &d, sizeof(d));
+}
+
+/*
+ * Each device descriptor is followed by the description of its virtqueues.  We
+ * specify how many descriptors the virtqueue is to have.
+ */
+static void add_virtqueue(struct device *dev, unsigned int num_descs,
+                         void (*service)(struct virtqueue *))
+{
+       unsigned int pages;
+       struct virtqueue **i, *vq = malloc(sizeof(*vq));
+       void *p;
+
+       /* First we need some memory for this virtqueue. */
+       pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1)
+               / getpagesize();
+       p = get_pages(pages);
+
+       /* Initialize the virtqueue */
+       vq->next = NULL;
+       vq->last_avail_idx = 0;
+       vq->dev = dev;
+
+       /*
+        * This is the routine the service thread will run, and its Process ID
+        * once it's running.
+        */
+       vq->service = service;
+       vq->thread = (pid_t)-1;
+
+       /* Initialize the configuration. */
+       vq->config.num = num_descs;
+       vq->config.irq = devices.next_irq++;
+       vq->config.pfn = to_guest_phys(p) / getpagesize();
+
+       /* Initialize the vring. */
+       vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);
+
+       /*
+        * Append virtqueue to this device's descriptor.  We use
+        * device_config() to get the end of the device's current virtqueues;
+        * we check that we haven't added any config or feature information
+        * yet, otherwise we'd be overwriting them.
+        */
+       assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
+       memcpy(device_config(dev), &vq->config, sizeof(vq->config));
+       dev->num_vq++;
+       dev->desc->num_vq++;
+
+       verbose("Virtqueue page %#lx\n", to_guest_phys(p));
+
+       /*
+        * Add to tail of list, so dev->vq is first vq, dev->vq->next is
+        * second.
+        */
+       for (i = &dev->vq; *i; i = &(*i)->next);
+       *i = vq;
+}
+
+/*
+ * The first half of the feature bitmask is for us to advertise features.  The
+ * second half is for the Guest to accept features.
+ */
+static void add_feature(struct device *dev, unsigned bit)
+{
+       u8 *features = get_feature_bits(dev);
+
+       /* We can't extend the feature bits once we've added config bytes */
+       if (dev->desc->feature_len <= bit / CHAR_BIT) {
+               assert(dev->desc->config_len == 0);
+               dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1;
+       }
+
+       features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
+}
+
+/*
+ * This routine sets the configuration fields for an existing device's
+ * descriptor.  It only works for the last device, but that's OK because that's
+ * how we use it.
+ */
+static void set_config(struct device *dev, unsigned len, const void *conf)
+{
+       /* Check we haven't overflowed our single page. */
+       if (device_config(dev) + len > devices.descpage + getpagesize())
+               errx(1, "Too many devices");
+
+       /* Copy in the config information, and store the length. */
+       memcpy(device_config(dev), conf, len);
+       dev->desc->config_len = len;
+
+       /* Size must fit in config_len field (8 bits)! */
+       assert(dev->desc->config_len == len);
+}
+
+/*
+ * This routine does all the creation and setup of a new device, including
+ * calling new_dev_desc() to allocate the descriptor and device memory.  We
+ * don't actually start the service threads until later.
+ *
+ * See what I mean about userspace being boring?
+ */
+static struct device *new_device(const char *name, u16 type)
+{
+       struct device *dev = malloc(sizeof(*dev));
+
+       /* Now we populate the fields one at a time. */
+       dev->desc = new_dev_desc(type);
+       dev->name = name;
+       dev->vq = NULL;
+       dev->feature_len = 0;
+       dev->num_vq = 0;
+       dev->running = false;
+
+       /*
+        * Append to device list.  Prepending to a single-linked list is
+        * easier, but the user expects the devices to be arranged on the bus
+        * in command-line order.  The first network device on the command line
+        * is eth0, the first block device /dev/vda, etc.
+        */
+       if (devices.lastdev)
+               devices.lastdev->next = dev;
+       else
+               devices.dev = dev;
+       devices.lastdev = dev;
+
+       return dev;
+}
+
+/*
+ * Our first setup routine is the console.  It's a fairly simple device, but
+ * UNIX tty handling makes it uglier than it could be.
+ */
+static void setup_console(void)
+{
+       struct device *dev;
+
+       /* If we can save the initial standard input settings... */
+       if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
+               struct termios term = orig_term;
+               /*
+                * Then we turn off echo, line buffering and ^C etc: We want a
+                * raw input stream to the Guest.
+                */
+               term.c_lflag &= ~(ISIG|ICANON|ECHO);
+               tcsetattr(STDIN_FILENO, TCSANOW, &term);
+       }
+
+       dev = new_device("console", VIRTIO_ID_CONSOLE);
+
+       /* We store the console state in dev->priv, and initialize it. */
+       dev->priv = malloc(sizeof(struct console_abort));
+       ((struct console_abort *)dev->priv)->count = 0;
+
+       /*
+        * The console needs two virtqueues: the input then the output.  When
+        * they put something the input queue, we make sure we're listening to
+        * stdin.  When they put something in the output queue, we write it to
+        * stdout.
+        */
+       add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
+       add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
+
+       verbose("device %u: console\n", ++devices.device_num);
+}
+/*:*/
+
+/*M:010
+ * Inter-guest networking is an interesting area.  Simplest is to have a
+ * --sharenet=<name> option which opens or creates a named pipe.  This can be
+ * used to send packets to another guest in a 1:1 manner.
+ *
+ * More sophisticated is to use one of the tools developed for project like UML
+ * to do networking.
+ *
+ * Faster is to do virtio bonding in kernel.  Doing this 1:1 would be
+ * completely generic ("here's my vring, attach to your vring") and would work
+ * for any traffic.  Of course, namespace and permissions issues need to be
+ * dealt with.  A more sophisticated "multi-channel" virtio_net.c could hide
+ * multiple inter-guest channels behind one interface, although it would
+ * require some manner of hotplugging new virtio channels.
+ *
+ * Finally, we could use a virtio network switch in the kernel, ie. vhost.
+:*/
+
+static u32 str2ip(const char *ipaddr)
+{
+       unsigned int b[4];
+
+       if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4)
+               errx(1, "Failed to parse IP address '%s'", ipaddr);
+       return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+}
+
+static void str2mac(const char *macaddr, unsigned char mac[6])
+{
+       unsigned int m[6];
+       if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+                  &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6)
+               errx(1, "Failed to parse mac address '%s'", macaddr);
+       mac[0] = m[0];
+       mac[1] = m[1];
+       mac[2] = m[2];
+       mac[3] = m[3];
+       mac[4] = m[4];
+       mac[5] = m[5];
+}
+
+/*
+ * This code is "adapted" from libbridge: it attaches the Host end of the
+ * network device to the bridge device specified by the command line.
+ *
+ * This is yet another James Morris contribution (I'm an IP-level guy, so I
+ * dislike bridging), and I just try not to break it.
+ */
+static void add_to_bridge(int fd, const char *if_name, const char *br_name)
+{
+       int ifidx;
+       struct ifreq ifr;
+
+       if (!*br_name)
+               errx(1, "must specify bridge name");
+
+       ifidx = if_nametoindex(if_name);
+       if (!ifidx)
+               errx(1, "interface %s does not exist!", if_name);
+
+       strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
+       ifr.ifr_name[IFNAMSIZ-1] = '\0';
+       ifr.ifr_ifindex = ifidx;
+       if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
+               err(1, "can't add %s to bridge %s", if_name, br_name);
+}
+
+/*
+ * This sets up the Host end of the network device with an IP address, brings
+ * it up so packets will flow, the copies the MAC address into the hwaddr
+ * pointer.
+ */
+static void configure_device(int fd, const char *tapif, u32 ipaddr)
+{
+       struct ifreq ifr;
+       struct sockaddr_in sin;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strcpy(ifr.ifr_name, tapif);
+
+       /* Don't read these incantations.  Just cut & paste them like I did! */
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(ipaddr);
+       memcpy(&ifr.ifr_addr, &sin, sizeof(sin));
+       if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
+               err(1, "Setting %s interface address", tapif);
+       ifr.ifr_flags = IFF_UP;
+       if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
+               err(1, "Bringing interface %s up", tapif);
+}
+
+static int get_tun_device(char tapif[IFNAMSIZ])
+{
+       struct ifreq ifr;
+       int netfd;
+
+       /* Start with this zeroed.  Messy but sure. */
+       memset(&ifr, 0, sizeof(ifr));
+
+       /*
+        * We open the /dev/net/tun device and tell it we want a tap device.  A
+        * tap device is like a tun device, only somehow different.  To tell
+        * the truth, I completely blundered my way through this code, but it
+        * works now!
+        */
+       netfd = open_or_die("/dev/net/tun", O_RDWR);
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+       strcpy(ifr.ifr_name, "tap%d");
+       if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
+               err(1, "configuring /dev/net/tun");
+
+       if (ioctl(netfd, TUNSETOFFLOAD,
+                 TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0)
+               err(1, "Could not set features for tun device");
+
+       /*
+        * We don't need checksums calculated for packets coming in this
+        * device: trust us!
+        */
+       ioctl(netfd, TUNSETNOCSUM, 1);
+
+       memcpy(tapif, ifr.ifr_name, IFNAMSIZ);
+       return netfd;
+}
+
+/*L:195
+ * Our network is a Host<->Guest network.  This can either use bridging or
+ * routing, but the principle is the same: it uses the "tun" device to inject
+ * packets into the Host as if they came in from a normal network card.  We
+ * just shunt packets between the Guest and the tun device.
+ */
+static void setup_tun_net(char *arg)
+{
+       struct device *dev;
+       struct net_info *net_info = malloc(sizeof(*net_info));
+       int ipfd;
+       u32 ip = INADDR_ANY;
+       bool bridging = false;
+       char tapif[IFNAMSIZ], *p;
+       struct virtio_net_config conf;
+
+       net_info->tunfd = get_tun_device(tapif);
+
+       /* First we create a new network device. */
+       dev = new_device("net", VIRTIO_ID_NET);
+       dev->priv = net_info;
+
+       /* Network devices need a recv and a send queue, just like console. */
+       add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
+       add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
+
+       /*
+        * We need a socket to perform the magic network ioctls to bring up the
+        * tap interface, connect to the bridge etc.  Any socket will do!
+        */
+       ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+       if (ipfd < 0)
+               err(1, "opening IP socket");
+
+       /* If the command line was --tunnet=bridge:<name> do bridging. */
+       if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
+               arg += strlen(BRIDGE_PFX);
+               bridging = true;
+       }
+
+       /* A mac address may follow the bridge name or IP address */
+       p = strchr(arg, ':');
+       if (p) {
+               str2mac(p+1, conf.mac);
+               add_feature(dev, VIRTIO_NET_F_MAC);
+               *p = '\0';
+       }
+
+       /* arg is now either an IP address or a bridge name */
+       if (bridging)
+               add_to_bridge(ipfd, tapif, arg);
+       else
+               ip = str2ip(arg);
+
+       /* Set up the tun device. */
+       configure_device(ipfd, tapif, ip);
+
+       /* Expect Guest to handle everything except UFO */
+       add_feature(dev, VIRTIO_NET_F_CSUM);
+       add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
+       add_feature(dev, VIRTIO_NET_F_GUEST_TSO4);
+       add_feature(dev, VIRTIO_NET_F_GUEST_TSO6);
+       add_feature(dev, VIRTIO_NET_F_GUEST_ECN);
+       add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
+       add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
+       add_feature(dev, VIRTIO_NET_F_HOST_ECN);
+       /* We handle indirect ring entries */
+       add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
+       set_config(dev, sizeof(conf), &conf);
+
+       /* We don't need the socket any more; setup is done. */
+       close(ipfd);
+
+       devices.device_num++;
+
+       if (bridging)
+               verbose("device %u: tun %s attached to bridge: %s\n",
+                       devices.device_num, tapif, arg);
+       else
+               verbose("device %u: tun %s: %s\n",
+                       devices.device_num, tapif, arg);
+}
+/*:*/
+
+/* This hangs off device->priv. */
+struct vblk_info {
+       /* The size of the file. */
+       off64_t len;
+
+       /* The file descriptor for the file. */
+       int fd;
+
+};
+
+/*L:210
+ * The Disk
+ *
+ * The disk only has one virtqueue, so it only has one thread.  It is really
+ * simple: the Guest asks for a block number and we read or write that position
+ * in the file.
+ *
+ * Before we serviced each virtqueue in a separate thread, that was unacceptably
+ * slow: the Guest waits until the read is finished before running anything
+ * else, even if it could have been doing useful work.
+ *
+ * We could have used async I/O, except it's reputed to suck so hard that
+ * characters actually go missing from your code when you try to use it.
+ */
+static void blk_request(struct virtqueue *vq)
+{
+       struct vblk_info *vblk = vq->dev->priv;
+       unsigned int head, out_num, in_num, wlen;
+       int ret;
+       u8 *in;
+       struct virtio_blk_outhdr *out;
+       struct iovec iov[vq->vring.num];
+       off64_t off;
+
+       /*
+        * Get the next request, where we normally wait.  It triggers the
+        * interrupt to acknowledge previously serviced requests (if any).
+        */
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
+
+       /*
+        * Every block request should contain at least one output buffer
+        * (detailing the location on disk and the type of request) and one
+        * input buffer (to hold the result).
+        */
+       if (out_num == 0 || in_num == 0)
+               errx(1, "Bad virtblk cmd %u out=%u in=%u",
+                    head, out_num, in_num);
+
+       out = convert(&iov[0], struct virtio_blk_outhdr);
+       in = convert(&iov[out_num+in_num-1], u8);
+       /*
+        * For historical reasons, block operations are expressed in 512 byte
+        * "sectors".
+        */
+       off = out->sector * 512;
+
+       /*
+        * In general the virtio block driver is allowed to try SCSI commands.
+        * It'd be nice if we supported eject, for example, but we don't.
+        */
+       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
+               fprintf(stderr, "Scsi commands unsupported\n");
+               *in = VIRTIO_BLK_S_UNSUPP;
+               wlen = sizeof(*in);
+       } else if (out->type & VIRTIO_BLK_T_OUT) {
+               /*
+                * Write
+                *
+                * Move to the right location in the block file.  This can fail
+                * if they try to write past end.
+                */
+               if (lseek64(vblk->fd, off, SEEK_SET) != off)
+                       err(1, "Bad seek to sector %llu", out->sector);
+
+               ret = writev(vblk->fd, iov+1, out_num-1);
+               verbose("WRITE to sector %llu: %i\n", out->sector, ret);
+
+               /*
+                * Grr... Now we know how long the descriptor they sent was, we
+                * make sure they didn't try to write over the end of the block
+                * file (possibly extending it).
+                */
+               if (ret > 0 && off + ret > vblk->len) {
+                       /* Trim it back to the correct length */
+                       ftruncate64(vblk->fd, vblk->len);
+                       /* Die, bad Guest, die. */
+                       errx(1, "Write past end %llu+%u", off, ret);
+               }
+
+               wlen = sizeof(*in);
+               *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+       } else if (out->type & VIRTIO_BLK_T_FLUSH) {
+               /* Flush */
+               ret = fdatasync(vblk->fd);
+               verbose("FLUSH fdatasync: %i\n", ret);
+               wlen = sizeof(*in);
+               *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+       } else {
+               /*
+                * Read
+                *
+                * Move to the right location in the block file.  This can fail
+                * if they try to read past end.
+                */
+               if (lseek64(vblk->fd, off, SEEK_SET) != off)
+                       err(1, "Bad seek to sector %llu", out->sector);
+
+               ret = readv(vblk->fd, iov+1, in_num-1);
+               verbose("READ from sector %llu: %i\n", out->sector, ret);
+               if (ret >= 0) {
+                       wlen = sizeof(*in) + ret;
+                       *in = VIRTIO_BLK_S_OK;
+               } else {
+                       wlen = sizeof(*in);
+                       *in = VIRTIO_BLK_S_IOERR;
+               }
+       }
+
+       /* Finished that request. */
+       add_used(vq, head, wlen);
+}
+
+/*L:198 This actually sets up a virtual block device. */
+static void setup_block_file(const char *filename)
+{
+       struct device *dev;
+       struct vblk_info *vblk;
+       struct virtio_blk_config conf;
+
+       /* Creat the device. */
+       dev = new_device("block", VIRTIO_ID_BLOCK);
+
+       /* The device has one virtqueue, where the Guest places requests. */
+       add_virtqueue(dev, VIRTQUEUE_NUM, blk_request);
+
+       /* Allocate the room for our own bookkeeping */
+       vblk = dev->priv = malloc(sizeof(*vblk));
+
+       /* First we open the file and store the length. */
+       vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
+       vblk->len = lseek64(vblk->fd, 0, SEEK_END);
+
+       /* We support FLUSH. */
+       add_feature(dev, VIRTIO_BLK_F_FLUSH);
+
+       /* Tell Guest how many sectors this device has. */
+       conf.capacity = cpu_to_le64(vblk->len / 512);
+
+       /*
+        * Tell Guest not to put in too many descriptors at once: two are used
+        * for the in and out elements.
+        */
+       add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
+       conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
+
+       /* Don't try to put whole struct: we have 8 bit limit. */
+       set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf);
+
+       verbose("device %u: virtblock %llu sectors\n",
+               ++devices.device_num, le64_to_cpu(conf.capacity));
+}
+
+/*L:211
+ * Our random number generator device reads from /dev/random into the Guest's
+ * input buffers.  The usual case is that the Guest doesn't want random numbers
+ * and so has no buffers although /dev/random is still readable, whereas
+ * console is the reverse.
+ *
+ * The same logic applies, however.
+ */
+struct rng_info {
+       int rfd;
+};
+
+static void rng_input(struct virtqueue *vq)
+{
+       int len;
+       unsigned int head, in_num, out_num, totlen = 0;
+       struct rng_info *rng_info = vq->dev->priv;
+       struct iovec iov[vq->vring.num];
+
+       /* First we need a buffer from the Guests's virtqueue. */
+       head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
+       if (out_num)
+               errx(1, "Output buffers in rng?");
+
+       /*
+        * Just like the console write, we loop to cover the whole iovec.
+        * In this case, short reads actually happen quite a bit.
+        */
+       while (!iov_empty(iov, in_num)) {
+               len = readv(rng_info->rfd, iov, in_num);
+               if (len <= 0)
+                       err(1, "Read from /dev/random gave %i", len);
+               iov_consume(iov, in_num, len);
+               totlen += len;
+       }
+
+       /* Tell the Guest about the new input. */
+       add_used(vq, head, totlen);
+}
+
+/*L:199
+ * This creates a "hardware" random number device for the Guest.
+ */
+static void setup_rng(void)
+{
+       struct device *dev;
+       struct rng_info *rng_info = malloc(sizeof(*rng_info));
+
+       /* Our device's privat info simply contains the /dev/random fd. */
+       rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
+
+       /* Create the new device. */
+       dev = new_device("rng", VIRTIO_ID_RNG);
+       dev->priv = rng_info;
+
+       /* The device has one virtqueue, where the Guest places inbufs. */
+       add_virtqueue(dev, VIRTQUEUE_NUM, rng_input);
+
+       verbose("device %u: rng\n", devices.device_num++);
+}
+/* That's the end of device setup. */
+
+/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
+static void __attribute__((noreturn)) restart_guest(void)
+{
+       unsigned int i;
+
+       /*
+        * Since we don't track all open fds, we simply close everything beyond
+        * stderr.
+        */
+       for (i = 3; i < FD_SETSIZE; i++)
+               close(i);
+
+       /* Reset all the devices (kills all threads). */
+       cleanup_devices();
+
+       execv(main_args[0], main_args);
+       err(1, "Could not exec %s", main_args[0]);
+}
+
+/*L:220
+ * Finally we reach the core of the Launcher which runs the Guest, serves
+ * its input and output, and finally, lays it to rest.
+ */
+static void __attribute__((noreturn)) run_guest(void)
+{
+       for (;;) {
+               unsigned long notify_addr;
+               int readval;
+
+               /* We read from the /dev/lguest device to run the Guest. */
+               readval = pread(lguest_fd, &notify_addr,
+                               sizeof(notify_addr), cpu_id);
+
+               /* One unsigned long means the Guest did HCALL_NOTIFY */
+               if (readval == sizeof(notify_addr)) {
+                       verbose("Notify on address %#lx\n", notify_addr);
+                       handle_output(notify_addr);
+               /* ENOENT means the Guest died.  Reading tells us why. */
+               } else if (errno == ENOENT) {
+                       char reason[1024] = { 0 };
+                       pread(lguest_fd, reason, sizeof(reason)-1, cpu_id);
+                       errx(1, "%s", reason);
+               /* ERESTART means that we need to reboot the guest */
+               } else if (errno == ERESTART) {
+                       restart_guest();
+               /* Anything else means a bug or incompatible change. */
+               } else
+                       err(1, "Running guest failed");
+       }
+}
+/*L:240
+ * This is the end of the Launcher.  The good news: we are over halfway
+ * through!  The bad news: the most fiendish part of the code still lies ahead
+ * of us.
+ *
+ * Are you ready?  Take a deep breath and join me in the core of the Host, in
+ * "make Host".
+:*/
+
+static struct option opts[] = {
+       { "verbose", 0, NULL, 'v' },
+       { "tunnet", 1, NULL, 't' },
+       { "block", 1, NULL, 'b' },
+       { "rng", 0, NULL, 'r' },
+       { "initrd", 1, NULL, 'i' },
+       { "username", 1, NULL, 'u' },
+       { "chroot", 1, NULL, 'c' },
+       { NULL },
+};
+static void usage(void)
+{
+       errx(1, "Usage: lguest [--verbose] "
+            "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n"
+            "|--block=<filename>|--initrd=<filename>]...\n"
+            "<mem-in-mb> vmlinux [args...]");
+}
+
+/*L:105 The main routine is where the real work begins: */
+int main(int argc, char *argv[])
+{
+       /* Memory, code startpoint and size of the (optional) initrd. */
+       unsigned long mem = 0, start, initrd_size = 0;
+       /* Two temporaries. */
+       int i, c;
+       /* The boot information for the Guest. */
+       struct boot_params *boot;
+       /* If they specify an initrd file to load. */
+       const char *initrd_name = NULL;
+
+       /* Password structure for initgroups/setres[gu]id */
+       struct passwd *user_details = NULL;
+
+       /* Directory to chroot to */
+       char *chroot_path = NULL;
+
+       /* Save the args: we "reboot" by execing ourselves again. */
+       main_args = argv;
+
+       /*
+        * First we initialize the device list.  We keep a pointer to the last
+        * device, and the next interrupt number to use for devices (1:
+        * remember that 0 is used by the timer).
+        */
+       devices.lastdev = NULL;
+       devices.next_irq = 1;
+
+       /* We're CPU 0.  In fact, that's the only CPU possible right now. */
+       cpu_id = 0;
+
+       /*
+        * We need to know how much memory so we can set up the device
+        * descriptor and memory pages for the devices as we parse the command
+        * line.  So we quickly look through the arguments to find the amount
+        * of memory now.
+        */
+       for (i = 1; i < argc; i++) {
+               if (argv[i][0] != '-') {
+                       mem = atoi(argv[i]) * 1024 * 1024;
+                       /*
+                        * We start by mapping anonymous pages over all of
+                        * guest-physical memory range.  This fills it with 0,
+                        * and ensures that the Guest won't be killed when it
+                        * tries to access it.
+                        */
+                       guest_base = map_zeroed_pages(mem / getpagesize()
+                                                     + DEVICE_PAGES);
+                       guest_limit = mem;
+                       guest_max = mem + DEVICE_PAGES*getpagesize();
+                       devices.descpage = get_pages(1);
+                       break;
+               }
+       }
+
+       /* The options are fairly straight-forward */
+       while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
+               switch (c) {
+               case 'v':
+                       verbose = true;
+                       break;
+               case 't':
+                       setup_tun_net(optarg);
+                       break;
+               case 'b':
+                       setup_block_file(optarg);
+                       break;
+               case 'r':
+                       setup_rng();
+                       break;
+               case 'i':
+                       initrd_name = optarg;
+                       break;
+               case 'u':
+                       user_details = getpwnam(optarg);
+                       if (!user_details)
+                               err(1, "getpwnam failed, incorrect username?");
+                       break;
+               case 'c':
+                       chroot_path = optarg;
+                       break;
+               default:
+                       warnx("Unknown argument %s", argv[optind]);
+                       usage();
+               }
+       }
+       /*
+        * After the other arguments we expect memory and kernel image name,
+        * followed by command line arguments for the kernel.
+        */
+       if (optind + 2 > argc)
+               usage();
+
+       verbose("Guest base is at %p\n", guest_base);
+
+       /* We always have a console device */
+       setup_console();
+
+       /* Now we load the kernel */
+       start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
+
+       /* Boot information is stashed at physical address 0 */
+       boot = from_guest_phys(0);
+
+       /* Map the initrd image if requested (at top of physical memory) */
+       if (initrd_name) {
+               initrd_size = load_initrd(initrd_name, mem);
+               /*
+                * These are the location in the Linux boot header where the
+                * start and size of the initrd are expected to be found.
+                */
+               boot->hdr.ramdisk_image = mem - initrd_size;
+               boot->hdr.ramdisk_size = initrd_size;
+               /* The bootloader type 0xFF means "unknown"; that's OK. */
+               boot->hdr.type_of_loader = 0xFF;
+       }
+
+       /*
+        * The Linux boot header contains an "E820" memory map: ours is a
+        * simple, single region.
+        */
+       boot->e820_entries = 1;
+       boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
+       /*
+        * The boot header contains a command line pointer: we put the command
+        * line after the boot header.
+        */
+       boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
+       /* We use a simple helper to copy the arguments separated by spaces. */
+       concat((char *)(boot + 1), argv+optind+2);
+
+       /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
+       boot->hdr.kernel_alignment = 0x1000000;
+
+       /* Boot protocol version: 2.07 supports the fields for lguest. */
+       boot->hdr.version = 0x207;
+
+       /* The hardware_subarch value of "1" tells the Guest it's an lguest. */
+       boot->hdr.hardware_subarch = 1;
+
+       /* Tell the entry path not to try to reload segment registers. */
+       boot->hdr.loadflags |= KEEP_SEGMENTS;
+
+       /* We tell the kernel to initialize the Guest. */
+       tell_kernel(start);
+
+       /* Ensure that we terminate if a device-servicing child dies. */
+       signal(SIGCHLD, kill_launcher);
+
+       /* If we exit via err(), this kills all the threads, restores tty. */
+       atexit(cleanup_devices);
+
+       /* If requested, chroot to a directory */
+       if (chroot_path) {
+               if (chroot(chroot_path) != 0)
+                       err(1, "chroot(\"%s\") failed", chroot_path);
+
+               if (chdir("/") != 0)
+                       err(1, "chdir(\"/\") failed");
+
+               verbose("chroot done\n");
+       }
+
+       /* If requested, drop privileges */
+       if (user_details) {
+               uid_t u;
+               gid_t g;
+
+               u = user_details->pw_uid;
+               g = user_details->pw_gid;
+
+               if (initgroups(user_details->pw_name, g) != 0)
+                       err(1, "initgroups failed");
+
+               if (setresgid(g, g, g) != 0)
+                       err(1, "setresgid failed");
+
+               if (setresuid(u, u, u) != 0)
+                       err(1, "setresuid failed");
+
+               verbose("Dropping privileges completed\n");
+       }
+
+       /* Finally, run the Guest.  This doesn't return. */
+       run_guest();
+}
+/*:*/
+
+/*M:999
+ * Mastery is done: you now know everything I do.
+ *
+ * But surely you have seen code, features and bugs in your wanderings which
+ * you now yearn to attack?  That is the real game, and I look forward to you
+ * patching and forking lguest into the Your-Name-Here-visor.
+ *
+ * Farewell, and good coding!
+ * Rusty Russell.
+ */
diff --git a/tools/lguest/lguest.txt b/tools/lguest/lguest.txt
new file mode 100644 (file)
index 0000000..bff0c55
--- /dev/null
@@ -0,0 +1,129 @@
+      __
+ (___()'`;  Rusty's Remarkably Unreliable Guide to Lguest
+ /,    /`      - or, A Young Coder's Illustrated Hypervisor
+ \\"--\\    http://lguest.ozlabs.org
+
+Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel,
+for Linux developers and users to experiment with virtualization with the
+minimum of complexity.  Nonetheless, it should have sufficient features to
+make it useful for specific tasks, and, of course, you are encouraged to fork
+and enhance it (see drivers/lguest/README).
+
+Features:
+
+- Kernel module which runs in a normal kernel.
+- Simple I/O model for communication.
+- Simple program to create new guests.
+- Logo contains cute puppies: http://lguest.ozlabs.org
+
+Developer features:
+
+- Fun to hack on.
+- No ABI: being tied to a specific kernel anyway, you can change anything.
+- Many opportunities for improvement or feature implementation.
+
+Running Lguest:
+
+- The easiest way to run lguest is to use same kernel as guest and host.
+  You can configure them differently, but usually it's easiest not to.
+
+  You will need to configure your kernel with the following options:
+
+  "General setup":
+     "Prompt for development and/or incomplete code/drivers" = Y
+        (CONFIG_EXPERIMENTAL=y)
+
+  "Processor type and features":
+     "Paravirtualized guest support" = Y
+        "Lguest guest support" = Y
+     "High Memory Support" = off/4GB
+     "Alignment value to which kernel should be aligned" = 0x100000
+        (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
+         CONFIG_PHYSICAL_ALIGN=0x100000)
+
+  "Device Drivers":
+     "Block devices"
+        "Virtio block driver (EXPERIMENTAL)" = M/Y
+     "Network device support"
+        "Universal TUN/TAP device driver support" = M/Y
+        "Virtio network driver (EXPERIMENTAL)" = M/Y
+           (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m)
+
+  "Virtualization"
+     "Linux hypervisor example code" = M/Y
+        (CONFIG_LGUEST=m)
+
+- A tool called "lguest" is available in this directory: type "make"
+  to build it.  If you didn't build your kernel in-tree, use "make
+  O=<builddir>".
+
+- Create or find a root disk image.  There are several useful ones
+  around, such as the xm-test tiny root image at
+         http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img
+
+  For more serious work, I usually use a distribution ISO image and
+  install it under qemu, then make multiple copies:
+
+         dd if=/dev/zero of=rootfile bs=1M count=2048
+         qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
+
+  Make sure that you install a getty on /dev/hvc0 if you want to log in on the
+  console!
+
+- "modprobe lg" if you built it as a module.
+
+- Run an lguest as root:
+
+      Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \
+        --block=rootfile root=/dev/vda
+
+   Explanation:
+    64: the amount of memory to use, in MB.
+
+    vmlinux: the kernel image found in the top of your build directory.  You
+       can also use a standard bzImage.
+
+    --tunnet=192.168.19.1: configures a "tap" device for networking with this
+       IP address.
+
+    --block=rootfile: a file or block device which becomes /dev/vda
+       inside the guest.
+
+    root=/dev/vda: this (and anything else on the command line) are
+       kernel boot parameters.
+
+- Configuring networking.  I usually have the host masquerade, using
+  "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 >
+  /proc/sys/net/ipv4/ip_forward".  In this example, I would configure
+  eth0 inside the guest at 192.168.19.2.
+
+  Another method is to bridge the tap device to an external interface
+  using --tunnet=bridge:<bridgename>, and perhaps run dhcp on the guest
+  to obtain an IP address.  The bridge needs to be configured first:
+  this option simply adds the tap interface to it.
+
+  A simple example on my system:
+
+    ifconfig eth0 0.0.0.0
+    brctl addbr lg0
+    ifconfig lg0 up
+    brctl addif lg0 eth0
+    dhclient lg0
+
+  Then use --tunnet=bridge:lg0 when launching the guest.
+
+  See:
+  
+    http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
+    
+  for general information on how to get bridging to work.
+
+- Random number generation. Using the --rng option will provide a
+  /dev/hwrng in the guest that will read from the host's /dev/random.
+  Use this option in conjunction with rng-tools (see ../hw_random.txt)
+  to provide entropy to the guest kernel's /dev/random.
+
+There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
+
+Good luck!
+Rusty Russell rusty@rustcorp.com.au.
index 8eb6c489fb152c006d1cd781800cfe7c73059cd8..77f952762426661615d3d0180ab2728010e6069f 100644 (file)
@@ -17,8 +17,8 @@ titan:~> perf list
   kmem:kmem_cache_alloc_node               [Tracepoint event]
   kmem:kfree                               [Tracepoint event]
   kmem:kmem_cache_free                     [Tracepoint event]
-  kmem:mm_page_free_direct                 [Tracepoint event]
-  kmem:mm_pagevec_free                     [Tracepoint event]
+  kmem:mm_page_free                        [Tracepoint event]
+  kmem:mm_page_free_batched                [Tracepoint event]
   kmem:mm_page_alloc                       [Tracepoint event]
   kmem:mm_page_alloc_zone_locked           [Tracepoint event]
   kmem:mm_page_pcpu_drain                  [Tracepoint event]
@@ -29,15 +29,15 @@ measured. For example the page alloc/free properties of a 'hackbench
 run' are:
 
  titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc
- -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10
+ -e kmem:mm_page_free_batched -e kmem:mm_page_free ./hackbench 10
  Time: 0.575
 
  Performance counter stats for './hackbench 10':
 
           13857  kmem:mm_page_pcpu_drain
           27576  kmem:mm_page_alloc
-           6025  kmem:mm_pagevec_free
-          20934  kmem:mm_page_free_direct
+           6025  kmem:mm_page_free_batched
+          20934  kmem:mm_page_free
 
     0.613972165  seconds time elapsed
 
@@ -45,8 +45,8 @@ You can observe the statistical properties as well, by using the
 'repeat the workload N times' feature of perf stat:
 
  titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e
-   kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
-   kmem:mm_page_free_direct ./hackbench 10
+   kmem:mm_page_alloc -e kmem:mm_page_free_batched -e
+   kmem:mm_page_free ./hackbench 10
  Time: 0.627
  Time: 0.644
  Time: 0.564
@@ -57,8 +57,8 @@ You can observe the statistical properties as well, by using the
 
           12920  kmem:mm_page_pcpu_drain    ( +-   3.359% )
           25035  kmem:mm_page_alloc         ( +-   3.783% )
-           6104  kmem:mm_pagevec_free       ( +-   0.934% )
-          18376  kmem:mm_page_free_direct   ( +-   4.941% )
+           6104  kmem:mm_page_free_batched  ( +-   0.934% )
+          18376  kmem:mm_page_free         ( +-   4.941% )
 
     0.643954516  seconds time elapsed   ( +-   2.363% )
 
@@ -158,15 +158,15 @@ Or you can observe the whole system's page allocations for 10
 seconds:
 
 titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e
-kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
-kmem:mm_page_free_direct sleep 10
+kmem:mm_page_alloc -e kmem:mm_page_free_batched -e
+kmem:mm_page_free sleep 10
 
  Performance counter stats for 'sleep 10':
 
          171585  kmem:mm_page_pcpu_drain
          322114  kmem:mm_page_alloc
-          73623  kmem:mm_pagevec_free
-         254115  kmem:mm_page_free_direct
+          73623  kmem:mm_page_free_batched
+         254115  kmem:mm_page_free
 
    10.000591410  seconds time elapsed
 
@@ -174,15 +174,15 @@ Or observe how fluctuating the page allocations are, via statistical
 analysis done over ten 1-second intervals:
 
  titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e
-   kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
-   kmem:mm_page_free_direct sleep 1
+   kmem:mm_page_alloc -e kmem:mm_page_free_batched -e
+   kmem:mm_page_free sleep 1
 
  Performance counter stats for 'sleep 1' (10 runs):
 
           17254  kmem:mm_page_pcpu_drain    ( +-   3.709% )
           34394  kmem:mm_page_alloc         ( +-   4.617% )
-           7509  kmem:mm_pagevec_free       ( +-   4.820% )
-          25653  kmem:mm_page_free_direct   ( +-   3.672% )
+           7509  kmem:mm_page_free_batched  ( +-   4.820% )
+          25653  kmem:mm_page_free         ( +-   3.672% )
 
     1.058135029  seconds time elapsed   ( +-   3.089% )
 
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
new file mode 100644 (file)
index 0000000..4ec8401
--- /dev/null
@@ -0,0 +1,11 @@
+TARGETS = breakpoints
+
+all:
+       for TARGET in $(TARGETS); do \
+               make -C $$TARGET; \
+       done;
+
+clean:
+       for TARGET in $(TARGETS); do \
+               make -C $$TARGET clean; \
+       done;
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
new file mode 100644 (file)
index 0000000..f362722
--- /dev/null
@@ -0,0 +1,20 @@
+# Taken from perf makefile
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
+ifeq ($(ARCH),i386)
+        ARCH := x86
+endif
+ifeq ($(ARCH),x86_64)
+       ARCH := x86
+endif
+
+
+all:
+ifeq ($(ARCH),x86)
+       gcc breakpoint_test.c -o run_test
+else
+       echo "Not an x86 target, can't build breakpoints selftests"
+endif
+
+clean:
+       rm -fr run_test
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c
new file mode 100644 (file)
index 0000000..a0743f3
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
+ *
+ * Licensed under the terms of the GNU GPL License version 2
+ *
+ * Selftests for breakpoints (and more generally the do_debug() path) in x86.
+ */
+
+
+#include <sys/ptrace.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/user.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+
+/* Breakpoint access modes */
+enum {
+       BP_X = 1,
+       BP_RW = 2,
+       BP_W = 4,
+};
+
+static pid_t child_pid;
+
+/*
+ * Ensures the child and parent are always "talking" about
+ * the same test sequence. (ie: that we haven't forgotten
+ * to call check_trapped() somewhere).
+ */
+static int nr_tests;
+
+static void set_breakpoint_addr(void *addr, int n)
+{
+       int ret;
+
+       ret = ptrace(PTRACE_POKEUSER, child_pid,
+                    offsetof(struct user, u_debugreg[n]), addr);
+       if (ret) {
+               perror("Can't set breakpoint addr\n");
+               exit(-1);
+       }
+}
+
+static void toggle_breakpoint(int n, int type, int len,
+                             int local, int global, int set)
+{
+       int ret;
+
+       int xtype, xlen;
+       unsigned long vdr7, dr7;
+
+       switch (type) {
+       case BP_X:
+               xtype = 0;
+               break;
+       case BP_W:
+               xtype = 1;
+               break;
+       case BP_RW:
+               xtype = 3;
+               break;
+       }
+
+       switch (len) {
+       case 1:
+               xlen = 0;
+               break;
+       case 2:
+               xlen = 4;
+               break;
+       case 4:
+               xlen = 0xc;
+               break;
+       case 8:
+               xlen = 8;
+               break;
+       }
+
+       dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
+                    offsetof(struct user, u_debugreg[7]), 0);
+
+       vdr7 = (xlen | xtype) << 16;
+       vdr7 <<= 4 * n;
+
+       if (local) {
+               vdr7 |= 1 << (2 * n);
+               vdr7 |= 1 << 8;
+       }
+       if (global) {
+               vdr7 |= 2 << (2 * n);
+               vdr7 |= 1 << 9;
+       }
+
+       if (set)
+               dr7 |= vdr7;
+       else
+               dr7 &= ~vdr7;
+
+       ret = ptrace(PTRACE_POKEUSER, child_pid,
+                    offsetof(struct user, u_debugreg[7]), dr7);
+       if (ret) {
+               perror("Can't set dr7");
+               exit(-1);
+       }
+}
+
+/* Dummy variables to test read/write accesses */
+static unsigned long long dummy_var[4];
+
+/* Dummy functions to test execution accesses */
+static void dummy_func(void) { }
+static void dummy_func1(void) { }
+static void dummy_func2(void) { }
+static void dummy_func3(void) { }
+
+static void (*dummy_funcs[])(void) = {
+       dummy_func,
+       dummy_func1,
+       dummy_func2,
+       dummy_func3,
+};
+
+static int trapped;
+
+static void check_trapped(void)
+{
+       /*
+        * If we haven't trapped, wake up the parent
+        * so that it notices the failure.
+        */
+       if (!trapped)
+               kill(getpid(), SIGUSR1);
+       trapped = 0;
+
+       nr_tests++;
+}
+
+static void write_var(int len)
+{
+       char *pcval; short *psval; int *pival; long long *plval;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               switch (len) {
+               case 1:
+                       pcval = (char *)&dummy_var[i];
+                       *pcval = 0xff;
+                       break;
+               case 2:
+                       psval = (short *)&dummy_var[i];
+                       *psval = 0xffff;
+                       break;
+               case 4:
+                       pival = (int *)&dummy_var[i];
+                       *pival = 0xffffffff;
+                       break;
+               case 8:
+                       plval = (long long *)&dummy_var[i];
+                       *plval = 0xffffffffffffffffLL;
+                       break;
+               }
+               check_trapped();
+       }
+}
+
+static void read_var(int len)
+{
+       char cval; short sval; int ival; long long lval;
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               switch (len) {
+               case 1:
+                       cval = *(char *)&dummy_var[i];
+                       break;
+               case 2:
+                       sval = *(short *)&dummy_var[i];
+                       break;
+               case 4:
+                       ival = *(int *)&dummy_var[i];
+                       break;
+               case 8:
+                       lval = *(long long *)&dummy_var[i];
+                       break;
+               }
+               check_trapped();
+       }
+}
+
+/*
+ * Do the r/w/x accesses to trigger the breakpoints. And run
+ * the usual traps.
+ */
+static void trigger_tests(void)
+{
+       int len, local, global, i;
+       char val;
+       int ret;
+
+       ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
+       if (ret) {
+               perror("Can't be traced?\n");
+               return;
+       }
+
+       /* Wake up father so that it sets up the first test */
+       kill(getpid(), SIGUSR1);
+
+       /* Test instruction breakpoints */
+       for (local = 0; local < 2; local++) {
+               for (global = 0; global < 2; global++) {
+                       if (!local && !global)
+                               continue;
+
+                       for (i = 0; i < 4; i++) {
+                               dummy_funcs[i]();
+                               check_trapped();
+                       }
+               }
+       }
+
+       /* Test write watchpoints */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               write_var(len);
+                       }
+               }
+       }
+
+       /* Test read/write watchpoints (on read accesses) */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               read_var(len);
+                       }
+               }
+       }
+
+       /* Icebp trap */
+       asm(".byte 0xf1\n");
+       check_trapped();
+
+       /* Int 3 trap */
+       asm("int $3\n");
+       check_trapped();
+
+       kill(getpid(), SIGUSR1);
+}
+
+static void check_success(const char *msg)
+{
+       const char *msg2;
+       int child_nr_tests;
+       int status;
+
+       /* Wait for the child to SIGTRAP */
+       wait(&status);
+
+       msg2 = "Failed";
+
+       if (WSTOPSIG(status) == SIGTRAP) {
+               child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
+                                       &nr_tests, 0);
+               if (child_nr_tests == nr_tests)
+                       msg2 = "Ok";
+               if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
+                       perror("Can't poke\n");
+                       exit(-1);
+               }
+       }
+
+       nr_tests++;
+
+       printf("%s [%s]\n", msg, msg2);
+}
+
+static void launch_instruction_breakpoints(char *buf, int local, int global)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               set_breakpoint_addr(dummy_funcs[i], i);
+               toggle_breakpoint(i, BP_X, 1, local, global, 1);
+               ptrace(PTRACE_CONT, child_pid, NULL, 0);
+               sprintf(buf, "Test breakpoint %d with local: %d global: %d",
+                       i, local, global);
+               check_success(buf);
+               toggle_breakpoint(i, BP_X, 1, local, global, 0);
+       }
+}
+
+static void launch_watchpoints(char *buf, int mode, int len,
+                              int local, int global)
+{
+       const char *mode_str;
+       int i;
+
+       if (mode == BP_W)
+               mode_str = "write";
+       else
+               mode_str = "read";
+
+       for (i = 0; i < 4; i++) {
+               set_breakpoint_addr(&dummy_var[i], i);
+               toggle_breakpoint(i, mode, len, local, global, 1);
+               ptrace(PTRACE_CONT, child_pid, NULL, 0);
+               sprintf(buf, "Test %s watchpoint %d with len: %d local: "
+                       "%d global: %d", mode_str, i, len, local, global);
+               check_success(buf);
+               toggle_breakpoint(i, mode, len, local, global, 0);
+       }
+}
+
+/* Set the breakpoints and check the child successfully trigger them */
+static void launch_tests(void)
+{
+       char buf[1024];
+       int len, local, global, i;
+
+       /* Instruction breakpoints */
+       for (local = 0; local < 2; local++) {
+               for (global = 0; global < 2; global++) {
+                       if (!local && !global)
+                               continue;
+                       launch_instruction_breakpoints(buf, local, global);
+               }
+       }
+
+       /* Write watchpoint */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               launch_watchpoints(buf, BP_W, len,
+                                                  local, global);
+                       }
+               }
+       }
+
+       /* Read-Write watchpoint */
+       for (len = 1; len <= sizeof(long); len <<= 1) {
+               for (local = 0; local < 2; local++) {
+                       for (global = 0; global < 2; global++) {
+                               if (!local && !global)
+                                       continue;
+                               launch_watchpoints(buf, BP_RW, len,
+                                                  local, global);
+                       }
+               }
+       }
+
+       /* Icebp traps */
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success("Test icebp");
+
+       /* Int 3 traps */
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+       check_success("Test int 3 trap");
+
+       ptrace(PTRACE_CONT, child_pid, NULL, 0);
+}
+
+int main(int argc, char **argv)
+{
+       pid_t pid;
+       int ret;
+
+       pid = fork();
+       if (!pid) {
+               trigger_tests();
+               return 0;
+       }
+
+       child_pid = pid;
+
+       wait(NULL);
+
+       launch_tests();
+
+       wait(NULL);
+
+       return 0;
+}
diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests
new file mode 100644 (file)
index 0000000..320718a
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+TARGETS=breakpoints
+
+for TARGET in $TARGETS
+do
+       $TARGET/run_test
+done
index 669bcdd45805a7039473d1acd425effd6d77797c..b4fbc91c41b47dd4ab2a06157594c32b14bdd2aa 100644 (file)
@@ -186,21 +186,12 @@ struct virtqueue {
 #endif
 
 /* Interfaces exported by virtio_ring. */
-int virtqueue_add_buf_gfp(struct virtqueue *vq,
-                         struct scatterlist sg[],
-                         unsigned int out_num,
-                         unsigned int in_num,
-                         void *data,
-                         gfp_t gfp);
-
-static inline int virtqueue_add_buf(struct virtqueue *vq,
-                                   struct scatterlist sg[],
-                                   unsigned int out_num,
-                                   unsigned int in_num,
-                                   void *data)
-{
-       return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
-}
+int virtqueue_add_buf(struct virtqueue *vq,
+                     struct scatterlist sg[],
+                     unsigned int out_num,
+                     unsigned int in_num,
+                     void *data,
+                     gfp_t gfp);
 
 void virtqueue_kick(struct virtqueue *vq);
 
@@ -214,6 +205,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 struct virtqueue *vring_new_virtqueue(unsigned int num,
                                      unsigned int vring_align,
                                      struct virtio_device *vdev,
+                                     bool weak_barriers,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
                                      void (*callback)(struct virtqueue *vq),
index 74d3331bdaf992b10bdf38d630d0dca00cc08360..6bf95f9953640c4671f94be6316383dabb9c5bc8 100644 (file)
@@ -92,7 +92,8 @@ static void vq_info_add(struct vdev_info *dev, int num)
        assert(r >= 0);
        memset(info->ring, 0, vring_size(num, 4096));
        vring_init(&info->vring, num, info->ring, 4096);
-       info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
+       info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev,
+                                      true, info->ring,
                                       vq_notify, vq_callback, "test");
        assert(info->vq);
        info->vq->priv = info;
@@ -160,7 +161,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
                        if (started < bufs) {
                                sg_init_one(&sl, dev->buf, dev->buf_size);
                                r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
-                                                     dev->buf + started);
+                                                     dev->buf + started,
+                                                     GFP_ATOMIC);
                                if (likely(r >= 0)) {
                                        ++started;
                                        virtqueue_kick(vq->vq);