Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Aug 2011 21:18:55 +0000 (14:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 18 Aug 2011 21:18:55 +0000 (14:18 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband:
  IB/iser: Support iSCSI PDU padding
  IBiser: Fix wrong mask when sizeof (dma_addr_t) > sizeof (unsigned long)
  IPoIB: Fix possible NULL dereference in ipoib_start_xmit()

378 files changed:
Documentation/00-INDEX
Documentation/PCI/MSI-HOWTO.txt
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/email-clients.txt
Documentation/filesystems/befs.txt
Documentation/kernel-docs.txt
Documentation/kernel-parameters.txt
Documentation/networking/bonding.txt
Documentation/networking/scaling.txt [new file with mode: 0644]
Documentation/ramoops.txt [new file with mode: 0644]
Documentation/virtual/00-INDEX
Documentation/virtual/lguest/lguest.c
Documentation/virtual/virtio-spec.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/module.c
arch/arm/mach-imx/clock-imx25.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-imx/mach-mx31ads.c
arch/arm/mach-imx/mach-mx31lilly.c
arch/arm/mach-mmp/gplugd.c
arch/arm/mach-mmp/include/mach/mfp-gplugd.h [deleted file]
arch/arm/mach-mmp/include/mach/mfp-pxa168.h
arch/arm/mach-mmp/time.c
arch/arm/mach-mx5/board-cpuimx51.c
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/board-mx51_efikamx.c
arch/arm/mach-mx5/board-mx51_efikasb.c
arch/arm/mach-mx5/clock-mx51-mx53.c
arch/arm/mach-mx5/mx51_efika.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-am3517crane.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/cminst44xx.h
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mm/alignment.c
arch/arm/mm/init.c
arch/arm/mm/proc-arm946.S
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/iomux-mx53.h
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/include/plat/dma.h
arch/arm/plat-omap/include/plat/irqs.h
arch/arm/plat-omap/include/plat/serial.h
arch/arm/plat-omap/iovmm.c
arch/arm/tools/mach-types
arch/ia64/Kconfig
arch/ia64/configs/generic_defconfig
arch/powerpc/include/asm/jump_label.h
arch/powerpc/include/asm/kdump.h
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/iomap.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/perf_callchain.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/io_event_irq.c
arch/powerpc/platforms/pseries/kexec.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/sparc/Kconfig
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/kernel/ds.c
arch/x86/include/asm/desc.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/vsyscall.h
arch/x86/kernel/Makefile
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/paravirt.c
arch/x86/kernel/step.c
arch/x86/kernel/traps.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/vsyscall_emu_64.S
arch/x86/kernel/vsyscall_trace.h [new file with mode: 0644]
arch/x86/kvm/Kconfig
arch/x86/mm/fault.c
arch/x86/vdso/vdso.S
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
drivers/base/power/domain.c
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-spi.c
drivers/base/regmap/regmap.c
drivers/dma/amba-pl08x.c
drivers/edac/i7core_edac.c
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/hwmon/ibmaem.c
drivers/hwmon/pmbus/lm25066.c
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/misc/cb710/core.c
drivers/mmc/card/mmc_test.c
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/tmio_mmc.c
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_dcb.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/can/slcan.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/gianfar_ptp.c
drivers/net/irda/sh_irda.c
drivers/net/irda/sh_sir.c
drivers/net/pcnet32.c
drivers/net/phy/dp83640.c
drivers/net/slip.c
drivers/net/usb/rtl8150.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/wl1251/acx.c
drivers/net/wireless/wl1251/cmd.c
drivers/rtc/interface.c
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
drivers/staging/dt3155v4l/dt3155v4l.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
drivers/staging/gma500/gem_glue.c
drivers/staging/gma500/gem_glue.h
drivers/staging/gma500/mdfld_dsi_dbi.c
drivers/staging/gma500/mdfld_dsi_dbi.h
drivers/staging/gma500/mdfld_dsi_dpi.c
drivers/staging/gma500/mdfld_dsi_output.c
drivers/staging/gma500/medfield.h
drivers/staging/gma500/psb_drv.h
drivers/staging/hv/blkvsc_drv.c
drivers/staging/iio/accel/adis16203_core.c
drivers/staging/iio/accel/adis16204_core.c
drivers/staging/iio/accel/adis16209_core.c
drivers/staging/iio/accel/adis16240_core.c
drivers/staging/iio/gyro/adis16260_core.c
drivers/staging/nvec/TODO
drivers/staging/rtl8192u/r819xU_firmware.c
drivers/staging/rts_pstor/rtsx.c
drivers/staging/rts_pstor/rtsx.h
drivers/staging/solo6x10/core.c
drivers/staging/solo6x10/enc.c
drivers/staging/solo6x10/g723.c
drivers/staging/solo6x10/p2m.c
drivers/staging/solo6x10/solo6x10.h
drivers/staging/speakup/devsynth.c
drivers/staging/zcache/Makefile
drivers/staging/zcache/zcache-main.c [new file with mode: 0644]
drivers/staging/zcache/zcache.c [deleted file]
drivers/usb/class/usbtmc.c
drivers/usb/core/config.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/f_hid.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/tusb6010_omap.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/storage/unusual_devs.h
drivers/xen/xen-selfballoon.c
fs/autofs4/autofs_i.h
fs/autofs4/waitq.c
fs/befs/linuxvfs.c
fs/cifs/cifs_debug.c
fs/cifs/cifsacl.c
fs/cifs/cifsglob.h
fs/cifs/transport.c
fs/compat_ioctl.c
fs/ecryptfs/Kconfig
fs/ecryptfs/keystore.c
fs/ecryptfs/main.c
fs/ecryptfs/read_write.c
fs/exec.c
fs/ext3/namei.c
fs/ext4/namei.c
fs/fat/dir.c
fs/fat/inode.c
fs/jfs/jfs_umount.c
fs/nfs/Kconfig
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_buf.h
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/quota/xfs_dquot.c
fs/xfs/quota/xfs_qm.c
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_btree.c
fs/xfs/xfs_btree.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_dinode.h
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_log.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_rw.c
fs/xfs/xfs_sb.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_vnodeops.c
include/asm-generic/memory_model.h
include/linux/cred.h
include/linux/hash.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/mm.h
include/linux/mmc/host.h
include/linux/netlink.h
include/linux/of.h
include/linux/pm_domain.h
include/linux/rtc.h
include/linux/sched.h
include/linux/socket.h
include/net/inet_sock.h
include/sound/tlv320aic3x.h
include/sound/wm8915.h [deleted file]
include/sound/wm8996.h [new file with mode: 0644]
kernel/Makefile
kernel/cred.c
kernel/fork.c
kernel/irq/generic-chip.c
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/lockdep.c
kernel/power/Kconfig
kernel/printk.c
kernel/sys.c
kernel/trace/Kconfig
mm/highmem.c
mm/memcontrol.c
mm/slub.c
mm/vmalloc.c
net/bridge/br_if.c
net/bridge/br_notify.c
net/bridge/netfilter/ebtables.c
net/core/scm.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv6/syncookies.c
net/netfilter/nf_queue.c
net/netlabel/netlabel_kapi.c
net/sched/sch_prio.c
security/tomoyo/common.c
sound/core/timer.c
sound/oss/pas2_pcm.c
sound/oss/pss.c
sound/pci/Kconfig
sound/pci/asihpi/hpicmn.c
sound/pci/azt3328.c
sound/pci/hda/alc269_quirks.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/rme9652/hdspm.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8915.c [deleted file]
sound/soc/codecs/wm8915.h [deleted file]
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8996.c [new file with mode: 0644]
sound/soc/codecs/wm8996.h [new file with mode: 0644]
sound/soc/codecs/wm_hubs.c
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/rx51.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/idma.c [new file with mode: 0644]
sound/soc/samsung/idma.h [new file with mode: 0644]
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/speyside.c
sound/soc/samsung/speyside_wm8962.c
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_wm8903.c
sound/usb/caiaq/audio.c
sound/usb/caiaq/input.c
sound/usb/endpoint.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/perf/Makefile
tools/perf/builtin-lock.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/util/config.c
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/header.c
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/python.c
tools/perf/util/setup.py
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/ui/browsers/top.c

index 1f89424..65bbd26 100644 (file)
@@ -272,6 +272,8 @@ printk-formats.txt
        - how to get printk format specifiers right
 prio_tree.txt
        - info on radix-priority-search-tree use for indexing vmas.
+ramoops.txt
+       - documentation of the ramoops oops/panic logging module.
 rbtree.txt
        - info on what red-black trees are and what they are for.
 robust-futex-ABI.txt
index 3f5e0b0..53e6fca 100644 (file)
@@ -45,7 +45,7 @@ arrived in memory (this becomes more likely with devices behind PCI-PCI
 bridges).  In order to ensure that all the data has arrived in memory,
 the interrupt handler must read a register on the device which raised
 the interrupt.  PCI transaction ordering rules require that all the data
-arrives in memory before the value can be returned from the register.
+arrive in memory before the value may be returned from the register.
 Using MSIs avoids this problem as the interrupt-generating write cannot
 pass the data writes, so by the time the interrupt is raised, the driver
 knows that all the data has arrived in memory.
@@ -86,13 +86,13 @@ device.
 
 int pci_enable_msi(struct pci_dev *dev)
 
-A successful call will allocate ONE interrupt to the device, regardless
-of how many MSIs the device supports.  The device will be switched from
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device is switched from
 pin-based interrupt mode to MSI mode.  The dev->irq number is changed
-to a new number which represents the message signaled interrupt.
-This function should be called before the driver calls request_irq()
-since enabling MSIs disables the pin-based IRQ and the driver will not
-receive interrupts on the old interrupt.
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
 
 4.2.2 pci_enable_msi_block
 
@@ -111,20 +111,20 @@ the device are in the range dev->irq to dev->irq + count - 1.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to request any more MSI interrupts for
-this device.  If this function returns a positive number, it will be
-less than 'count' and indicate the number of interrupts that could have
-been allocated.  In neither case will the irq value have been
-updated, nor will the device have been switched into MSI mode.
+this device.  If this function returns a positive number, it is
+less than 'count' and indicates the number of interrupts that could have
+been allocated.  In neither case is the irq value updated or the device
+switched into MSI mode.
 
 The device driver must decide what action to take if
-pci_enable_msi_block() returns a value less than the number asked for.
-Some devices can make use of fewer interrupts than the maximum they
-request; in this case the driver should call pci_enable_msi_block()
+pci_enable_msi_block() returns a value less than the number requested.
+For instance, the driver could still make use of fewer interrupts;
+in this case the driver should call pci_enable_msi_block()
 again.  Note that it is not guaranteed to succeed, even when the
 'count' has been reduced to the value returned from a previous call to
 pci_enable_msi_block().  This is because there are multiple constraints
 on the number of vectors that can be allocated; pci_enable_msi_block()
-will return as soon as it finds any constraint that doesn't allow the
+returns as soon as it finds any constraint that doesn't allow the
 call to succeed.
 
 4.2.3 pci_disable_msi
@@ -137,10 +137,10 @@ interrupt number and frees the previously allocated message signaled
 interrupt(s).  The interrupt may subsequently be assigned to another
 device, so drivers should not cache the value of dev->irq.
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI enabled and thus leaking its vector.
 
 4.3 Using MSI-X
 
@@ -155,10 +155,10 @@ struct msix_entry {
 };
 
 This allows for the device to use these interrupts in a sparse fashion;
-for example it could use interrupts 3 and 1027 and allocate only a
+for example, it could use interrupts 3 and 1027 and yet allocate only a
 two-element array.  The driver is expected to fill in the 'entry' value
-in each element of the array to indicate which entries it wants the kernel
-to assign interrupts for.  It is invalid to fill in two entries with the
+in each element of the array to indicate for which entries the kernel
+should assign interrupts; it is invalid to fill in two entries with the
 same number.
 
 4.3.1 pci_enable_msix
@@ -168,10 +168,11 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
 Calling this function asks the PCI subsystem to allocate 'nvec' MSIs.
 The 'entries' argument is a pointer to an array of msix_entry structs
 which should be at least 'nvec' entries in size.  On success, the
-function will return 0 and the device will have been switched into
-MSI-X interrupt mode.  The 'vector' elements in each entry will have
-been filled in with the interrupt number.  The driver should then call
-request_irq() for each 'vector' that it decides to use.
+device is switched into MSI-X mode and the function returns 0.
+The 'vector' member in each entry is populated with the interrupt number;
+the driver should then call request_irq() for each 'vector' that it
+decides to use.  The device driver is responsible for keeping track of the
+interrupts assigned to the MSI-X vectors so it can free them again later.
 
 If this function returns a negative number, it indicates an error and
 the driver should not attempt to allocate any more MSI-X interrupts for
@@ -181,16 +182,14 @@ below.
 
 This function, in contrast with pci_enable_msi(), does not adjust
 dev->irq.  The device will not generate interrupts for this interrupt
-number once MSI-X is enabled.  The device driver is responsible for
-keeping track of the interrupts assigned to the MSI-X vectors so it can
-free them again later.
+number once MSI-X is enabled.
 
 Device drivers should normally call this function once per device
 during the initialization phase.
 
-It is ideal if drivers can cope with a variable number of MSI-X interrupts,
+It is ideal if drivers can cope with a variable number of MSI-X interrupts;
 there are many reasons why the platform may not be able to provide the
-exact number a driver asks for.
+exact number that a driver asks for.
 
 A request loop to achieve that might look like:
 
@@ -212,15 +211,15 @@ static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 
 void pci_disable_msix(struct pci_dev *dev)
 
-This API should be used to undo the effect of pci_enable_msix().  It frees
+This function should be used to undo the effect of pci_enable_msix().  It frees
 the previously allocated message signaled interrupts.  The interrupts may
 subsequently be assigned to another device, so drivers should not cache
 the value of the 'vector' elements over a call to pci_disable_msix().
 
-A device driver must always call free_irq() on the interrupt(s)
-for which it has called request_irq() before calling this function.
-Failure to do so will result in a BUG_ON(), the device will be left with
-MSI enabled and will leak its vector.
+Before calling this function, a device driver must always call free_irq()
+on any interrupt for which it previously called request_irq().
+Failure to do so results in a BUG_ON(), leaving the device with
+MSI-X enabled and thus leaking its vector.
 
 4.3.3 The MSI-X Table
 
@@ -232,10 +231,10 @@ mask or unmask an interrupt, it should call disable_irq() / enable_irq().
 4.4 Handling devices implementing both MSI and MSI-X capabilities
 
 If a device implements both MSI and MSI-X capabilities, it can
-run in either MSI mode or MSI-X mode but not both simultaneously.
+run in either MSI mode or MSI-X mode, but not both simultaneously.
 This is a requirement of the PCI spec, and it is enforced by the
 PCI layer.  Calling pci_enable_msi() when MSI-X is already enabled or
-pci_enable_msix() when MSI is already enabled will result in an error.
+pci_enable_msix() when MSI is already enabled results in an error.
 If a device driver wishes to switch between MSI and MSI-X at runtime,
 it must first quiesce the device, then switch it back to pin-interrupt
 mode, before calling pci_enable_msi() or pci_enable_msix() and resuming
@@ -251,7 +250,7 @@ the MSI-X facilities in preference to the MSI facilities.  As mentioned
 above, MSI-X supports any number of interrupts between 1 and 2048.
 In constrast, MSI is restricted to a maximum of 32 interrupts (and
 must be a power of two).  In addition, the MSI interrupt vectors must
-be allocated consecutively, so the system may not be able to allocate
+be allocated consecutively, so the system might not be able to allocate
 as many vectors for MSI as it could for MSI-X.  On some platforms, MSI
 interrupts must all be targeted at the same set of CPUs whereas MSI-X
 interrupts can all be targeted at different CPUs.
@@ -281,7 +280,7 @@ disabled to enabled and back again.
 
 Using 'lspci -v' (as root) may show some devices with "MSI", "Message
 Signalled Interrupts" or "MSI-X" capabilities.  Each of these capabilities
-has an 'Enable' flag which will be followed with either "+" (enabled)
+has an 'Enable' flag which is followed with either "+" (enabled)
 or "-" (disabled).
 
 
@@ -298,7 +297,7 @@ The PCI stack provides three ways to disable MSIs:
 
 Some host chipsets simply don't support MSIs properly.  If we're
 lucky, the manufacturer knows this and has indicated it in the ACPI
-FADT table.  In this case, Linux will automatically disable MSIs.
+FADT table.  In this case, Linux automatically disables MSIs.
 Some boards don't include this information in the table and so we have
 to detect them ourselves.  The complete list of these is found near the
 quirk_disable_all_msi() function in drivers/pci/quirks.c.
@@ -317,7 +316,7 @@ Some bridges allow you to enable MSIs by changing some bits in their
 PCI configuration space (especially the Hypertransport chipsets such
 as the nVidia nForce and Serverworks HT2000).  As with host chipsets,
 Linux mostly knows about them and automatically enables MSIs if it can.
-If you have a bridge which Linux doesn't yet know about, you can enable
+If you have a bridge unknown to Linux, you can enable
 MSIs in configuration space using whatever method you know works, then
 enable MSIs on that bridge by doing:
 
@@ -327,7 +326,7 @@ where $bridge is the PCI address of the bridge you've enabled (eg
 0000:00:0e.0).
 
 To disable MSIs, echo 0 instead of 1.  Changing this value should be
-done with caution as it can break interrupt handling for all devices
+done with caution as it could break interrupt handling for all devices
 below this bridge.
 
 Again, please notify linux-pci@vger.kernel.org of any bridges that need
@@ -336,7 +335,7 @@ special handling.
 5.3. Disabling MSIs on a single device
 
 Some devices are known to have faulty MSI implementations.  Usually this
-is handled in the individual device driver but occasionally it's necessary
+is handled in the individual device driver, but occasionally it's necessary
 to handle this with a quirk.  Some drivers have an option to disable use
 of MSI.  While this is a convenient workaround for the driver author,
 it is not good practise, and should not be emulated.
@@ -350,7 +349,7 @@ for your machine.  You should also check your .config to be sure you
 have enabled CONFIG_PCI_MSI.
 
 Then, 'lspci -t' gives the list of bridges above a device.  Reading
-/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1)
+/sys/bus/pci/devices/*/msi_bus will tell you whether MSIs are enabled (1)
 or disabled (0).  If 0 is found in any of the msi_bus files belonging
 to bridges between the PCI root and the device, MSIs are disabled.
 
index 319baa8..36d16bb 100644 (file)
@@ -130,7 +130,7 @@ Linux kernel master tree:
        ftp.??.kernel.org:/pub/linux/kernel/...
        ?? == your country code, such as "us", "uk", "fr", etc.
 
-       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git
 
 Linux kernel mailing list:
        linux-kernel@vger.kernel.org
index 569f353..4468ce2 100644 (file)
@@ -303,7 +303,7 @@ patches that are being emailed around.
 
 The sign-off is a simple line at the end of the explanation for the
 patch, which certifies that you wrote it or otherwise have the right to
-pass it on as a open-source patch.  The rules are pretty simple: if you
+pass it on as an open-source patch.  The rules are pretty simple: if you
 can certify the below:
 
         Developer's Certificate of Origin 1.1
index a0b58e2..860c29a 100644 (file)
@@ -199,18 +199,16 @@ to coerce it into behaving.
 
 To beat some sense out of the internal editor, do this:
 
-- Under account settings, composition and addressing, uncheck "Compose
-  messages in HTML format".
-
 - Edit your Thunderbird config settings so that it won't use format=flowed.
   Go to "edit->preferences->advanced->config editor" to bring up the
   thunderbird's registry editor, and set "mailnews.send_plaintext_flowed" to
   "false".
 
-- Enable "preformat" mode: Shft-click on the Write icon to bring up the HTML
-  composer, select "Preformat" from the drop-down box just under the subject
-  line, then close the message without saving.  (This setting also applies to
-  the text composer, but the only control for it is in the HTML composer.)
+- Disable HTML Format: Set "mail.identity.id1.compose_html" to "false".
+
+- Enable "preformat" mode: Set "editor.quotesPreformatted" to "true".
+
+- Enable UTF8: Set "prefs.converted-to-utf8" to "true".
 
 - Install the "toggle wordwrap" extension.  Download the file from:
     https://addons.mozilla.org/thunderbird/addon/2351/
index 6e49c36..da45e6c 100644 (file)
@@ -27,7 +27,7 @@ His original code can still be found at:
 Does anyone know of a more current email address for Makoto? He doesn't
 respond to the address given above...
 
-Current maintainer: Sergey S. Kostyliov <rathamahata@php4.ru>
+This filesystem doesn't have a maintainer.
 
 WHAT IS THIS DRIVER?
 ==================
index 9a86746..0e0734b 100644 (file)
        (including this document itself) have been moved there, and might
        be more up to date than the web version.
 
-     * Name: "Linux Source Driver"
-       URL: http://lsd.linux.cz
-       Keywords: Browsing source code.
-       Description: "Linux Source Driver (LSD) is an application, which
-       can make browsing source codes of Linux kernel easier than you can
-       imagine. You can select between multiple versions of kernel (e.g.
-       0.01, 1.0.0, 2.0.33, 2.0.34pre13, 2.0.0, 2.1.101 etc.). With LSD
-       you can search Linux kernel (fulltext, macros, types, functions
-       and variables) and LSD can generate patches for you on the fly
-       (files, directories or kernel)".
-
      * Name: "Linux Kernel Source Reference"
        Author: Thomas Graichen.
        URL: http://marc.info/?l=linux-kernel&m=96446640102205&w=4
index e279b72..6ca1f5c 100644 (file)
@@ -40,6 +40,7 @@ parameter is applicable:
        ALSA    ALSA sound support is enabled.
        APIC    APIC support is enabled.
        APM     Advanced Power Management support is enabled.
+       ARM     ARM architecture is enabled.
        AVR32   AVR32 architecture is enabled.
        AX25    Appropriate AX.25 support is enabled.
        BLACKFIN Blackfin architecture is enabled.
@@ -49,6 +50,7 @@ parameter is applicable:
        EFI     EFI Partitioning (GPT) is enabled
        EIDE    EIDE/ATAPI support is enabled.
        FB      The frame buffer device is enabled.
+       FTRACE  Function tracing enabled.
        GCOV    GCOV profiling is enabled.
        HW      Appropriate hardware is enabled.
        IA-64   IA-64 architecture is enabled.
@@ -69,6 +71,7 @@ parameter is applicable:
                        Documentation/m68k/kernel-options.txt.
        MCA     MCA bus support is enabled.
        MDA     MDA console support is enabled.
+       MIPS    MIPS architecture is enabled.
        MOUSE   Appropriate mouse support is enabled.
        MSI     Message Signaled Interrupts (PCI).
        MTD     MTD (Memory Technology Device) support is enabled.
@@ -100,7 +103,6 @@ parameter is applicable:
        SPARC   Sparc architecture is enabled.
        SWSUSP  Software suspend (hibernation) is enabled.
        SUSPEND System suspend states are enabled.
-       FTRACE  Function tracing enabled.
        TPM     TPM drivers are enabled.
        TS      Appropriate touchscreen support is enabled.
        UMS     USB Mass Storage support is enabled.
@@ -115,7 +117,7 @@ parameter is applicable:
        X86-64  X86-64 architecture is enabled.
                        More X86-64 boot options can be found in
                        Documentation/x86/x86_64/boot-options.txt .
-       X86     Either 32bit or 64bit x86 (same as X86-32+X86-64)
+       X86     Either 32-bit or 64-bit x86 (same as X86-32+X86-64)
        XEN     Xen support is enabled
 
 In addition, the following text indicates that the option:
@@ -376,7 +378,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        atkbd.softrepeat= [HW]
                        Use software keyboard repeat
 
-       autotest        [IA64]
+       autotest        [IA-64]
 
        baycom_epp=     [HW,AX25]
                        Format: <io>,<mode>
@@ -681,8 +683,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                uart[8250],mmio32,<addr>[,options]
                        Start an early, polled-mode console on the 8250/16550
                        UART at the specified I/O port or MMIO address.
-                       MMIO inter-register address stride is either 8bit (mmio)
-                        or 32bit (mmio32).
+                       MMIO inter-register address stride is either 8-bit
+                       (mmio) or 32-bit (mmio32).
                        The options are the same as for ttyS, above.
 
        earlyprintk=    [X86,SH,BLACKFIN]
@@ -725,7 +727,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        See Documentation/block/as-iosched.txt and
                        Documentation/block/deadline-iosched.txt for details.
 
-       elfcorehdr=     [IA64,PPC,SH,X86]
+       elfcorehdr=     [IA-64,PPC,SH,X86]
                        Specifies physical address of start of kernel core
                        image elf header. Generally kexec loader will
                        pass this option to capture kernel.
@@ -791,7 +793,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        tracer at boot up. function-list is a comma separated
                        list of functions. This list can be changed at run
                        time by the set_ftrace_filter file in the debugfs
-                       tracing directory. 
+                       tracing directory.
 
        ftrace_notrace=[function-list]
                        [FTRACE] Do not trace the functions specified in
@@ -829,7 +831,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        hashdist=       [KNL,NUMA] Large hashes allocated during boot
                        are distributed across NUMA nodes.  Defaults on
-                       for 64bit NUMA, off otherwise.
+                       for 64-bit NUMA, off otherwise.
                        Format: 0 | 1 (for off | on)
 
        hcl=            [IA-64] SGI's Hardware Graph compatibility layer
@@ -998,10 +1000,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        DMA.
                forcedac [x86_64]
                        With this option iommu will not optimize to look
-                       for io virtual address below 32 bit forcing dual
+                       for io virtual address below 32-bit forcing dual
                        address cycle on pci bus for cards supporting greater
-                       than 32 bit addressing. The default is to look
-                       for translation below 32 bit and if not available
+                       than 32-bit addressing. The default is to look
+                       for translation below 32-bit and if not available
                        then look in the higher range.
                strict [Default Off]
                        With this option on every unmap_single operation will
@@ -1017,7 +1019,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        off     disable Interrupt Remapping
                        nosid   disable Source ID checking
 
-       inttest=        [IA64]
+       inttest=        [IA-64]
 
        iomem=          Disable strict checking of access to MMIO memory
                strict  regions from userspace.
@@ -1034,7 +1036,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                nomerge
                forcesac
                soft
-               pt      [x86, IA64]
+               pt      [x86, IA-64]
 
        io7=            [HW] IO7 for Marvel based alpha systems
                        See comment before marvel_specify_io7 in
@@ -1165,7 +1167,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        kvm-amd.npt=    [KVM,AMD] Disable nested paging (virtualized MMU)
                        for all guests.
-                       Default is 1 (enabled) if in 64bit or 32bit-PAE mode
+                       Default is 1 (enabled) if in 64-bit or 32-bit PAE mode.
 
        kvm-intel.ept=  [KVM,Intel] Disable extended page tables
                        (virtualized MMU) support on capable Intel chips.
@@ -1202,10 +1204,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        libata.dma=0      Disable all PATA and SATA DMA
                        libata.dma=1      PATA and SATA Disk DMA only
                        libata.dma=2      ATAPI (CDROM) DMA only
-                       libata.dma=4      Compact Flash DMA only 
+                       libata.dma=4      Compact Flash DMA only
                        Combinations also work, so libata.dma=3 enables DMA
                        for disks and CDROMs, but not CFs.
-       
+
        libata.ignore_hpa=      [LIBATA] Ignore HPA limit
                        libata.ignore_hpa=0       keep BIOS limits (default)
                        libata.ignore_hpa=1       ignore limits, using full disk
@@ -1331,7 +1333,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        ltpc=           [NET]
                        Format: <io>,<irq>,<dma>
 
-       machvec=        [IA64] Force the use of a particular machine-vector
+       machvec=        [IA-64] Force the use of a particular machine-vector
                        (machvec) in a generic kernel.
                        Example: machvec=hpzx1_swiotlb
 
@@ -1734,7 +1736,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nointroute      [IA-64]
 
-       nojitter        [IA64] Disables jitter checking for ITC timers.
+       nojitter        [IA-64] Disables jitter checking for ITC timers.
 
        no-kvmclock     [X86,KVM] Disable paravirtualized KVM clock driver
 
@@ -1800,7 +1802,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nox2apic        [X86-64,APIC] Do not enable x2APIC mode.
 
-       nptcg=          [IA64] Override max number of concurrent global TLB
+       nptcg=          [IA-64] Override max number of concurrent global TLB
                        purges which is reported from either PAL_VM_SUMMARY or
                        SAL PALO.
 
@@ -2077,7 +2079,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: { parport<nr> | timid | 0 }
                        See also Documentation/parport.txt.
 
-       pmtmr=          [X86] Manual setup of pmtmr I/O Port. 
+       pmtmr=          [X86] Manual setup of pmtmr I/O Port.
                        Override pmtimer IOPort with a hex value.
                        e.g. pmtmr=0x508
 
@@ -2635,6 +2637,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                                        medium is write-protected).
                        Example: quirks=0419:aaf5:rl,0421:0433:rc
 
+       user_debug=     [KNL,ARM]
+                       Format: <int>
+                       See arch/arm/Kconfig.debug help text.
+                                1 - undefined instruction events
+                                2 - system calls
+                                4 - invalid data aborts
+                                8 - SIGSEGV faults
+                               16 - SIGBUS faults
+                       Example: user_debug=31
+
        userpte=
                        [X86] Flags controlling user PTE allocations.
 
@@ -2680,6 +2692,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
                        Format: <command>
 
+       vsyscall=       [X86-64]
+                       Controls the behavior of vsyscalls (i.e. calls to
+                       fixed addresses of 0xffffffffff600x00 from legacy
+                       code).  Most statically-linked binaries and older
+                       versions of glibc use these calls.  Because these
+                       functions are at fixed addresses, they make nice
+                       targets for exploits that can control RIP.
+
+                       emulate     [default] Vsyscalls turn into traps and are
+                                   emulated reasonably safely.
+
+                       native      Vsyscalls are native syscall instructions.
+                                   This is a little bit faster than trapping
+                                   and makes a few dynamic recompilers work
+                                   better than they would in emulation mode.
+                                   It also makes exploits much easier to write.
+
+                       none        Vsyscalls don't work at all.  This makes
+                                   them quite hard to use for exploits but
+                                   might break your system.
+
        vt.cur_default= [VT] Default cursor shape.
                        Format: 0xCCBBAA, where AA, BB, and CC are the same as
                        the parameters of the <Esc>[?A;B;Cc escape sequence;
index 5dd960d..91df678 100644 (file)
@@ -238,6 +238,18 @@ ad_select
 
        This option was added in bonding version 3.4.0.
 
+all_slaves_active
+
+       Specifies that duplicate frames (received on inactive ports) should be
+       dropped (0) or delivered (1).
+
+       Normally, bonding will drop duplicate frames (received on inactive
+       ports), which is desirable for most users. But there are some times
+       it is nice to allow duplicate frames to be delivered.
+
+       The default value is 0 (drop duplicate frames received on inactive
+       ports).
+
 arp_interval
 
        Specifies the ARP link monitoring frequency in milliseconds.
@@ -433,6 +445,23 @@ miimon
        determined.  See the High Availability section for additional
        information.  The default value is 0.
 
+min_links
+
+       Specifies the minimum number of links that must be active before
+       asserting carrier. It is similar to the Cisco EtherChannel min-links
+       feature. This allows setting the minimum number of member ports that
+       must be up (link-up state) before marking the bond device as up
+       (carrier on). This is useful for situations where higher level services
+       such as clustering want to ensure a minimum number of low bandwidth
+       links are active before switchover. This option only affect 802.3ad
+       mode.
+
+       The default value is 0. This will cause carrier to be asserted (for
+       802.3ad mode) whenever there is an active aggregator, regardless of the
+       number of available links in that aggregator. Note that, because an
+       aggregator cannot be active without at least one available link,
+       setting this option to 0 or to 1 has the exact same effect.
+
 mode
 
        Specifies one of the bonding policies. The default is
diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt
new file mode 100644 (file)
index 0000000..7254b4b
--- /dev/null
@@ -0,0 +1,371 @@
+Scaling in the Linux Networking Stack
+
+
+Introduction
+============
+
+This document describes a set of complementary techniques in the Linux
+networking stack to increase parallelism and improve performance for
+multi-processor systems.
+
+The following technologies are described:
+
+  RSS: Receive Side Scaling
+  RPS: Receive Packet Steering
+  RFS: Receive Flow Steering
+  Accelerated Receive Flow Steering
+  XPS: Transmit Packet Steering
+
+
+RSS: Receive Side Scaling
+=========================
+
+Contemporary NICs support multiple receive and transmit descriptor queues
+(multi-queue). On reception, a NIC can send different packets to different
+queues to distribute processing among CPUs. The NIC distributes packets by
+applying a filter to each packet that assigns it to one of a small number
+of logical flows. Packets for each flow are steered to a separate receive
+queue, which in turn can be processed by separate CPUs. This mechanism is
+generally known as “Receive-side Scaling” (RSS). The goal of RSS and
+the other scaling techniques to increase performance uniformly.
+Multi-queue distribution can also be used for traffic prioritization, but
+that is not the focus of these techniques.
+
+The filter used in RSS is typically a hash function over the network
+and/or transport layer headers-- for example, a 4-tuple hash over
+IP addresses and TCP ports of a packet. The most common hardware
+implementation of RSS uses a 128-entry indirection table where each entry
+stores a queue number. The receive queue for a packet is determined
+by masking out the low order seven bits of the computed hash for the
+packet (usually a Toeplitz hash), taking this number as a key into the
+indirection table and reading the corresponding value.
+
+Some advanced NICs allow steering packets to queues based on
+programmable filters. For example, webserver bound TCP port 80 packets
+can be directed to their own receive queue. Such “n-tuple” filters can
+be configured from ethtool (--config-ntuple).
+
+==== RSS Configuration
+
+The driver for a multi-queue capable NIC typically provides a kernel
+module parameter for specifying the number of hardware queues to
+configure. In the bnx2x driver, for instance, this parameter is called
+num_queues. A typical RSS configuration would be to have one receive queue
+for each CPU if the device supports enough queues, or otherwise at least
+one for each cache domain at a particular cache level (L1, L2, etc.).
+
+The indirection table of an RSS device, which resolves a queue by masked
+hash, is usually programmed by the driver at initialization. The
+default mapping is to distribute the queues evenly in the table, but the
+indirection table can be retrieved and modified at runtime using ethtool
+commands (--show-rxfh-indir and --set-rxfh-indir). Modifying the
+indirection table could be done to give different queues different
+relative weights.
+
+== RSS IRQ Configuration
+
+Each receive queue has a separate IRQ associated with it. The NIC triggers
+this to notify a CPU when new packets arrive on the given queue. The
+signaling path for PCIe devices uses message signaled interrupts (MSI-X),
+that can route each interrupt to a particular CPU. The active mapping
+of queues to IRQs can be determined from /proc/interrupts. By default,
+an IRQ may be handled on any CPU. Because a non-negligible part of packet
+processing takes place in receive interrupt handling, it is advantageous
+to spread receive interrupts between CPUs. To manually adjust the IRQ
+affinity of each interrupt see Documentation/IRQ-affinity. Some systems
+will be running irqbalance, a daemon that dynamically optimizes IRQ
+assignments and as a result may override any manual settings.
+
+== Suggested Configuration
+
+RSS should be enabled when latency is a concern or whenever receive
+interrupt processing forms a bottleneck. Spreading load between CPUs
+decreases queue length. For low latency networking, the optimal setting
+is to allocate as many queues as there are CPUs in the system (or the
+NIC maximum, if lower). Because the aggregate number of interrupts grows
+with each additional queue, the most efficient high-rate configuration
+is likely the one with the smallest number of receive queues where no
+CPU that processes receive interrupts reaches 100% utilization. Per-cpu
+load can be observed using the mpstat utility.
+
+
+RPS: Receive Packet Steering
+============================
+
+Receive Packet Steering (RPS) is logically a software implementation of
+RSS. Being in software, it is necessarily called later in the datapath.
+Whereas RSS selects the queue and hence CPU that will run the hardware
+interrupt handler, RPS selects the CPU to perform protocol processing
+above the interrupt handler. This is accomplished by placing the packet
+on the desired CPU’s backlog queue and waking up the CPU for processing.
+RPS has some advantages over RSS: 1) it can be used with any NIC,
+2) software filters can easily be added to hash over new protocols,
+3) it does not increase hardware device interrupt rate (although it does
+introduce inter-processor interrupts (IPIs)).
+
+RPS is called during bottom half of the receive interrupt handler, when
+a driver sends a packet up the network stack with netif_rx() or
+netif_receive_skb(). These call the get_rps_cpu() function, which
+selects the queue that should process a packet.
+
+The first step in determining the target CPU for RPS is to calculate a
+flow hash over the packet’s addresses or ports (2-tuple or 4-tuple hash
+depending on the protocol). This serves as a consistent hash of the
+associated flow of the packet. The hash is either provided by hardware
+or will be computed in the stack. Capable hardware can pass the hash in
+the receive descriptor for the packet; this would usually be the same
+hash used for RSS (e.g. computed Toeplitz hash). The hash is saved in
+skb->rx_hash and can be used elsewhere in the stack as a hash of the
+packet’s flow.
+
+Each receive hardware queue has an associated list of CPUs to which
+RPS may enqueue packets for processing. For each received packet,
+an index into the list is computed from the flow hash modulo the size
+of the list. The indexed CPU is the target for processing the packet,
+and the packet is queued to the tail of that CPU’s backlog queue. At
+the end of the bottom half routine, IPIs are sent to any CPUs for which
+packets have been queued to their backlog queue. The IPI wakes backlog
+processing on the remote CPU, and any queued packets are then processed
+up the networking stack.
+
+==== RPS Configuration
+
+RPS requires a kernel compiled with the CONFIG_RPS kconfig symbol (on
+by default for SMP). Even when compiled in, RPS remains disabled until
+explicitly configured. The list of CPUs to which RPS may forward traffic
+can be configured for each receive queue using a sysfs file entry:
+
+ /sys/class/net/<dev>/queues/rx-<n>/rps_cpus
+
+This file implements a bitmap of CPUs. RPS is disabled when it is zero
+(the default), in which case packets are processed on the interrupting
+CPU. Documentation/IRQ-affinity.txt explains how CPUs are assigned to
+the bitmap.
+
+== Suggested Configuration
+
+For a single queue device, a typical RPS configuration would be to set
+the rps_cpus to the CPUs in the same cache domain of the interrupting
+CPU. If NUMA locality is not an issue, this could also be all CPUs in
+the system. At high interrupt rate, it might be wise to exclude the
+interrupting CPU from the map since that already performs much work.
+
+For a multi-queue system, if RSS is configured so that a hardware
+receive queue is mapped to each CPU, then RPS is probably redundant
+and unnecessary. If there are fewer hardware queues than CPUs, then
+RPS might be beneficial if the rps_cpus for each queue are the ones that
+share the same cache domain as the interrupting CPU for that queue.
+
+
+RFS: Receive Flow Steering
+==========================
+
+While RPS steers packets solely based on hash, and thus generally
+provides good load distribution, it does not take into account
+application locality. This is accomplished by Receive Flow Steering
+(RFS). The goal of RFS is to increase datacache hitrate by steering
+kernel processing of packets to the CPU where the application thread
+consuming the packet is running. RFS relies on the same RPS mechanisms
+to enqueue packets onto the backlog of another CPU and to wake up that
+CPU.
+
+In RFS, packets are not forwarded directly by the value of their hash,
+but the hash is used as index into a flow lookup table. This table maps
+flows to the CPUs where those flows are being processed. The flow hash
+(see RPS section above) is used to calculate the index into this table.
+The CPU recorded in each entry is the one which last processed the flow.
+If an entry does not hold a valid CPU, then packets mapped to that entry
+are steered using plain RPS. Multiple table entries may point to the
+same CPU. Indeed, with many flows and few CPUs, it is very likely that
+a single application thread handles flows with many different flow hashes.
+
+rps_sock_table is a global flow table that contains the *desired* CPU for
+flows: the CPU that is currently processing the flow in userspace. Each
+table value is a CPU index that is updated during calls to recvmsg and
+sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
+and tcp_splice_read()).
+
+When the scheduler moves a thread to a new CPU while it has outstanding
+receive packets on the old CPU, packets may arrive out of order. To
+avoid this, RFS uses a second flow table to track outstanding packets
+for each flow: rps_dev_flow_table is a table specific to each hardware
+receive queue of each device. Each table value stores a CPU index and a
+counter. The CPU index represents the *current* CPU onto which packets
+for this flow are enqueued for further kernel processing. Ideally, kernel
+and userspace processing occur on the same CPU, and hence the CPU index
+in both tables is identical. This is likely false if the scheduler has
+recently migrated a userspace thread while the kernel still has packets
+enqueued for kernel processing on the old CPU.
+
+The counter in rps_dev_flow_table values records the length of the current
+CPU's backlog when a packet in this flow was last enqueued. Each backlog
+queue has a head counter that is incremented on dequeue. A tail counter
+is computed as head counter + queue length. In other words, the counter
+in rps_dev_flow_table[i] records the last element in flow i that has
+been enqueued onto the currently designated CPU for flow i (of course,
+entry i is actually selected by hash and multiple flows may hash to the
+same entry i).
+
+And now the trick for avoiding out of order packets: when selecting the
+CPU for packet processing (from get_rps_cpu()) the rps_sock_flow table
+and the rps_dev_flow table of the queue that the packet was received on
+are compared. If the desired CPU for the flow (found in the
+rps_sock_flow table) matches the current CPU (found in the rps_dev_flow
+table), the packet is enqueued onto that CPU’s backlog. If they differ,
+the current CPU is updated to match the desired CPU if one of the
+following is true:
+
+- The current CPU's queue head counter >= the recorded tail counter
+  value in rps_dev_flow[i]
+- The current CPU is unset (equal to NR_CPUS)
+- The current CPU is offline
+
+After this check, the packet is sent to the (possibly updated) current
+CPU. These rules aim to ensure that a flow only moves to a new CPU when
+there are no packets outstanding on the old CPU, as the outstanding
+packets could arrive later than those about to be processed on the new
+CPU.
+
+==== RFS Configuration
+
+RFS is only available if the kconfig symbol CONFIG_RFS is enabled (on
+by default for SMP). The functionality remains disabled until explicitly
+configured. The number of entries in the global flow table is set through:
+
+ /proc/sys/net/core/rps_sock_flow_entries
+
+The number of entries in the per-queue flow table are set through:
+
+ /sys/class/net/<dev>/queues/tx-<n>/rps_flow_cnt
+
+== Suggested Configuration
+
+Both of these need to be set before RFS is enabled for a receive queue.
+Values for both are rounded up to the nearest power of two. The
+suggested flow count depends on the expected number of active connections
+at any given time, which may be significantly less than the number of open
+connections. We have found that a value of 32768 for rps_sock_flow_entries
+works fairly well on a moderately loaded server.
+
+For a single queue device, the rps_flow_cnt value for the single queue
+would normally be configured to the same value as rps_sock_flow_entries.
+For a multi-queue device, the rps_flow_cnt for each queue might be
+configured as rps_sock_flow_entries / N, where N is the number of
+queues. So for instance, if rps_flow_entries is set to 32768 and there
+are 16 configured receive queues, rps_flow_cnt for each queue might be
+configured as 2048.
+
+
+Accelerated RFS
+===============
+
+Accelerated RFS is to RFS what RSS is to RPS: a hardware-accelerated load
+balancing mechanism that uses soft state to steer flows based on where
+the application thread consuming the packets of each flow is running.
+Accelerated RFS should perform better than RFS since packets are sent
+directly to a CPU local to the thread consuming the data. The target CPU
+will either be the same CPU where the application runs, or at least a CPU
+which is local to the application thread’s CPU in the cache hierarchy.
+
+To enable accelerated RFS, the networking stack calls the
+ndo_rx_flow_steer driver function to communicate the desired hardware
+queue for packets matching a particular flow. The network stack
+automatically calls this function every time a flow entry in
+rps_dev_flow_table is updated. The driver in turn uses a device specific
+method to program the NIC to steer the packets.
+
+The hardware queue for a flow is derived from the CPU recorded in
+rps_dev_flow_table. The stack consults a CPU to hardware queue map which
+is maintained by the NIC driver. This is an auto-generated reverse map of
+the IRQ affinity table shown by /proc/interrupts. Drivers can use
+functions in the cpu_rmap (“CPU affinity reverse map”) kernel library
+to populate the map. For each CPU, the corresponding queue in the map is
+set to be one whose processing CPU is closest in cache locality.
+
+==== Accelerated RFS Configuration
+
+Accelerated RFS is only available if the kernel is compiled with
+CONFIG_RFS_ACCEL and support is provided by the NIC device and driver.
+It also requires that ntuple filtering is enabled via ethtool. The map
+of CPU to queues is automatically deduced from the IRQ affinities
+configured for each receive queue by the driver, so no additional
+configuration should be necessary.
+
+== Suggested Configuration
+
+This technique should be enabled whenever one wants to use RFS and the
+NIC supports hardware acceleration.
+
+XPS: Transmit Packet Steering
+=============================
+
+Transmit Packet Steering is a mechanism for intelligently selecting
+which transmit queue to use when transmitting a packet on a multi-queue
+device. To accomplish this, a mapping from CPU to hardware queue(s) is
+recorded. The goal of this mapping is usually to assign queues
+exclusively to a subset of CPUs, where the transmit completions for
+these queues are processed on a CPU within this set. This choice
+provides two benefits. First, contention on the device queue lock is
+significantly reduced since fewer CPUs contend for the same queue
+(contention can be eliminated completely if each CPU has its own
+transmit queue). Secondly, cache miss rate on transmit completion is
+reduced, in particular for data cache lines that hold the sk_buff
+structures.
+
+XPS is configured per transmit queue by setting a bitmap of CPUs that
+may use that queue to transmit. The reverse mapping, from CPUs to
+transmit queues, is computed and maintained for each network device.
+When transmitting the first packet in a flow, the function
+get_xps_queue() is called to select a queue. This function uses the ID
+of the running CPU as a key into the CPU-to-queue lookup table. If the
+ID matches a single queue, that is used for transmission. If multiple
+queues match, one is selected by using the flow hash to compute an index
+into the set.
+
+The queue chosen for transmitting a particular flow is saved in the
+corresponding socket structure for the flow (e.g. a TCP connection).
+This transmit queue is used for subsequent packets sent on the flow to
+prevent out of order (ooo) packets. The choice also amortizes the cost
+of calling get_xps_queues() over all packets in the connection. To avoid
+ooo packets, the queue for a flow can subsequently only be changed if
+skb->ooo_okay is set for a packet in the flow. This flag indicates that
+there are no outstanding packets in the flow, so the transmit queue can
+change without the risk of generating out of order packets. The
+transport layer is responsible for setting ooo_okay appropriately. TCP,
+for instance, sets the flag when all data for a connection has been
+acknowledged.
+
+==== XPS Configuration
+
+XPS is only available if the kconfig symbol CONFIG_XPS is enabled (on by
+default for SMP). The functionality remains disabled until explicitly
+configured. To enable XPS, the bitmap of CPUs that may use a transmit
+queue is configured using the sysfs file entry:
+
+/sys/class/net/<dev>/queues/tx-<n>/xps_cpus
+
+== Suggested Configuration
+
+For a network device with a single transmission queue, XPS configuration
+has no effect, since there is no choice in this case. In a multi-queue
+system, XPS is preferably configured so that each CPU maps onto one queue.
+If there are as many queues as there are CPUs in the system, then each
+queue can also map onto one CPU, resulting in exclusive pairings that
+experience no contention. If there are fewer queues than CPUs, then the
+best CPUs to share a given queue are probably those that share the cache
+with the CPU that processes transmit completions for that queue
+(transmit interrupts).
+
+
+Further Information
+===================
+RPS and RFS were introduced in kernel 2.6.35. XPS was incorporated into
+2.6.38. Original patches were submitted by Tom Herbert
+(therbert@google.com)
+
+Accelerated RFS was introduced in 2.6.35. Original patches were
+submitted by Ben Hutchings (bhutchings@solarflare.com)
+
+Authors:
+Tom Herbert (therbert@google.com)
+Willem de Bruijn (willemb@google.com)
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
new file mode 100644 (file)
index 0000000..8fb1ba7
--- /dev/null
@@ -0,0 +1,76 @@
+Ramoops oops/panic logger
+=========================
+
+Sergiu Iordache <sergiu@chromium.org>
+
+Updated: 8 August 2011
+
+0. Introduction
+
+Ramoops is an oops/panic logger that writes its logs to RAM before the system
+crashes. It works by logging oopses and panics in a circular buffer. Ramoops
+needs a system with persistent RAM so that the content of that area can
+survive after a restart.
+
+1. Ramoops concepts
+
+Ramoops uses a predefined memory area to store the dump. The start and size of
+the memory area are set using two variables:
+  * "mem_address" for the start
+  * "mem_size" for the size. The memory size will be rounded down to a
+  power of two.
+
+The memory area is divided into "record_size" chunks (also rounded down to
+power of two) and each oops/panic writes a "record_size" chunk of
+information.
+
+Dumping both oopses and panics can be done by setting 1 in the "dump_oops"
+variable while setting 0 in that variable dumps only the panics.
+
+The module uses a counter to record multiple dumps but the counter gets reset
+on restart (i.e. new dumps after the restart will overwrite old ones).
+
+2. Setting the parameters
+
+Setting the ramoops parameters can be done in 2 different manners:
+ 1. Use the module parameters (which have the names of the variables described
+ as before).
+ 2. Use a platform device and set the platform data. The parameters can then
+ be set through that platform data. An example of doing that is:
+
+#include <linux/ramoops.h>
+[...]
+
+static struct ramoops_platform_data ramoops_data = {
+        .mem_size               = <...>,
+        .mem_address            = <...>,
+        .record_size            = <...>,
+        .dump_oops              = <...>,
+};
+
+static struct platform_device ramoops_dev = {
+        .name = "ramoops",
+        .dev = {
+                .platform_data = &ramoops_data,
+        },
+};
+
+[... inside a function ...]
+int ret;
+
+ret = platform_device_register(&ramoops_dev);
+if (ret) {
+       printk(KERN_ERR "unable to register platform device\n");
+       return ret;
+}
+
+3. Dump format
+
+The data dump begins with a header, currently defined as "====" followed by a
+timestamp and a new line. The dump then continues with the actual data.
+
+4. Reading the data
+
+The dump data can be read from memory (through /dev/mem or other means).
+Getting the module parameters, which are needed in order to parse the data, can
+be done through /sys/module/ramoops/parameters/* .
index fe0251c..8e60199 100644 (file)
@@ -8,3 +8,6 @@ lguest/
        - Extremely simple hypervisor for experimental/educational use.
 uml/
        - User Mode Linux, builds/runs Linux kernel as a userspace program.
+virtio.txt
+       - Text version of draft virtio spec.
+          See http://ozlabs.org/~rusty/virtio-spec
index 043bd7d..d928c13 100644 (file)
@@ -1996,6 +1996,9 @@ int main(int argc, char *argv[])
        /* 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;
 
diff --git a/Documentation/virtual/virtio-spec.txt b/Documentation/virtual/virtio-spec.txt
new file mode 100644 (file)
index 0000000..a350ae1
--- /dev/null
@@ -0,0 +1,2200 @@
+[Generated file: see http://ozlabs.org/~rusty/virtio-spec/]
+Virtio PCI Card Specification
+v0.9.1 DRAFT
+-
+
+Rusty Russell <rusty@rustcorp.com.au>IBM Corporation (Editor)
+
+2011 August 1.
+
+Purpose and Description
+
+This document describes the specifications of the “virtio” family
+of PCI[LaTeX Command: nomenclature] devices. These are devices
+are found in virtual environments[LaTeX Command: nomenclature],
+yet by design they are not all that different from physical PCI
+devices, and this document treats them as such. This allows the
+guest to use standard PCI drivers and discovery mechanisms.
+
+The purpose of virtio and this specification is that virtual
+environments and guests should have a straightforward, efficient,
+standard and extensible mechanism for virtual devices, rather
+than boutique per-environment or per-OS mechanisms.
+
+  Straightforward: Virtio PCI devices use normal PCI mechanisms
+  of interrupts and DMA which should be familiar to any device
+  driver author. There is no exotic page-flipping or COW
+  mechanism: it's just a PCI device.[footnote:
+This lack of page-sharing implies that the implementation of the
+device (e.g. the hypervisor or host) needs full access to the
+guest memory. Communication with untrusted parties (i.e.
+inter-guest communication) requires copying.
+]
+
+  Efficient: Virtio PCI devices consist of rings of descriptors
+  for input and output, which are neatly separated to avoid cache
+  effects from both guest and device writing to the same cache
+  lines.
+
+  Standard: Virtio PCI makes no assumptions about the environment
+  in which it operates, beyond supporting PCI. In fact the virtio
+  devices specified in the appendices do not require PCI at all:
+  they have been implemented on non-PCI buses.[footnote:
+The Linux implementation further separates the PCI virtio code
+from the specific virtio drivers: these drivers are shared with
+the non-PCI implementations (currently lguest and S/390).
+]
+
+  Extensible: Virtio PCI devices contain feature bits which are
+  acknowledged by the guest operating system during device setup.
+  This allows forwards and backwards compatibility: the device
+  offers all the features it knows about, and the driver
+  acknowledges those it understands and wishes to use.
+
+  Virtqueues
+
+The mechanism for bulk data transport on virtio PCI devices is
+pretentiously called a virtqueue. Each device can have zero or
+more virtqueues: for example, the network device has one for
+transmit and one for receive.
+
+Each virtqueue occupies two or more physically-contiguous pages
+(defined, for the purposes of this specification, as 4096 bytes),
+and consists of three parts:
+
+
++-------------------+-----------------------------------+-----------+
+| Descriptor Table  |   Available Ring     (padding)    | Used Ring |
++-------------------+-----------------------------------+-----------+
+
+
+When the driver wants to send buffers to the device, it puts them
+in one or more slots in the descriptor table, and writes the
+descriptor indices into the available ring. It then notifies the
+device. When the device has finished with the buffers, it writes
+the descriptors into the used ring, and sends an interrupt.
+
+Specification
+
+  PCI Discovery
+
+Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000
+through 0x103F inclusive is a virtio device[footnote:
+The actual value within this range is ignored
+]. The device must also have a Revision ID of 0 to match this
+specification.
+
+The Subsystem Device ID indicates which virtio device is
+supported by the device. The Subsystem Vendor ID should reflect
+the PCI Vendor ID of the environment (it's currently only used
+for informational purposes by the guest).
+
+
++----------------------+--------------------+---------------+
+| Subsystem Device ID  |   Virtio Device    | Specification |
++----------------------+--------------------+---------------+
++----------------------+--------------------+---------------+
+|          1           |   network card     |  Appendix C   |
++----------------------+--------------------+---------------+
+|          2           |   block device     |  Appendix D   |
++----------------------+--------------------+---------------+
+|          3           |      console       |  Appendix E   |
++----------------------+--------------------+---------------+
+|          4           |  entropy source    |  Appendix F   |
++----------------------+--------------------+---------------+
+|          5           | memory ballooning  |  Appendix G   |
++----------------------+--------------------+---------------+
+|          6           |     ioMemory       |       -       |
++----------------------+--------------------+---------------+
+|          9           |   9P transport     |       -       |
++----------------------+--------------------+---------------+
+
+
+  Device Configuration
+
+To configure the device, we use the first I/O region of the PCI
+device. This contains a virtio header followed by a
+device-specific region.
+
+There may be different widths of accesses to the I/O region; the “
+natural” access method for each field in the virtio header must
+be used (i.e. 32-bit accesses for 32-bit fields, etc), but the
+device-specific region can be accessed using any width accesses,
+and should obtain the same results.
+
+Note that this is possible because while the virtio header is PCI
+(i.e. little) endian, the device-specific region is encoded in
+the native endian of the guest (where such distinction is
+applicable).
+
+  Device Initialization Sequence
+
+We start with an overview of device initialization, then expand
+on the details of the device and how each step is preformed.
+
+  Reset the device. This is not required on initial start up.
+
+  The ACKNOWLEDGE status bit is set: we have noticed the device.
+
+  The DRIVER status bit is set: we know how to drive the device.
+
+  Device-specific setup, including reading the Device Feature
+  Bits, discovery of virtqueues for the device, optional MSI-X
+  setup, and reading and possibly writing the virtio
+  configuration space.
+
+  The subset of Device Feature Bits understood by the driver is
+  written to the device.
+
+  The DRIVER_OK status bit is set.
+
+  The device can now be used (ie. buffers added to the
+  virtqueues)[footnote:
+Historically, drivers have used the device before steps 5 and 6.
+This is only allowed if the driver does not use any features
+which would alter this early use of the device.
+]
+
+If any of these steps go irrecoverably wrong, the guest should
+set the FAILED status bit to indicate that it has given up on the
+device (it can reset the device later to restart if desired).
+
+We now cover the fields required for general setup in detail.
+
+  Virtio Header
+
+The virtio header looks as follows:
+
+
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Bits       || 32                  | 32                  | 32       | 16     | 16      | 16      | 8       | 8      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Read/Write || R                   | R+W                 | R+W      | R      | R+W     | R+W     | R+W     | R      |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+| Purpose    || Device              | Guest               | Queue    | Queue  | Queue   | Queue   | Device  | ISR    |
+|            || Features bits 0:31  | Features bits 0:31  | Address  | Size   | Select  | Notify  | Status  | Status |
++------------++---------------------+---------------------+----------+--------+---------+---------+---------+--------+
+
+
+If MSI-X is enabled for the device, two additional fields
+immediately follow this header:
+
+
++------------++----------------+--------+
+| Bits       || 16             | 16     |
+              +----------------+--------+
++------------++----------------+--------+
+| Read/Write || R+W            | R+W    |
++------------++----------------+--------+
+| Purpose    || Configuration  | Queue  |
+| (MSI-X)    || Vector         | Vector |
++------------++----------------+--------+
+
+
+Finally, if feature bits (VIRTIO_F_FEATURES_HI) this is
+immediately followed by two additional fields:
+
+
++------------++----------------------+----------------------
+| Bits       || 32                   | 32
++------------++----------------------+----------------------
+| Read/Write || R                    | R+W
++------------++----------------------+----------------------
+| Purpose    || Device               | Guest
+|            || Features bits 32:63  | Features bits 32:63
++------------++----------------------+----------------------
+
+
+Immediately following these general headers, there may be
+device-specific headers:
+
+
++------------++--------------------+
+| Bits       || Device Specific    |
+              +--------------------+
++------------++--------------------+
+| Read/Write || Device Specific    |
++------------++--------------------+
+| Purpose    || Device Specific... |
+|            ||                    |
++------------++--------------------+
+
+
+  Device Status
+
+The Device Status field is updated by the guest to indicate its
+progress. This provides a simple low-level diagnostic: it's most
+useful to imagine them hooked up to traffic lights on the console
+indicating the status of each device.
+
+The device can be reset by writing a 0 to this field, otherwise
+at least one bit should be set:
+
+  ACKNOWLEDGE (1) Indicates that the guest OS has found the
+  device and recognized it as a valid virtio device.
+
+  DRIVER (2) Indicates that the guest OS knows how to drive the
+  device. Under Linux, drivers can be loadable modules so there
+  may be a significant (or infinite) delay before setting this
+  bit.
+
+  DRIVER_OK (3) Indicates that the driver is set up and ready to
+  drive the device.
+
+  FAILED (8) Indicates that something went wrong in the guest,
+  and it has given up on the device. This could be an internal
+  error, or the driver didn't like the device for some reason, or
+  even a fatal error during device operation. The device must be
+  reset before attempting to re-initialize.
+
+  Feature Bits
+
+The least significant 31 bits of the first configuration field
+indicates the features that the device supports (the high bit is
+reserved, and will be used to indicate the presence of future
+feature bits elsewhere). If more than 31 feature bits are
+supported, the device indicates so by setting feature bit 31 (see
+[cha:Reserved-Feature-Bits]). The bits are allocated as follows:
+
+  0 to 23 Feature bits for the specific device type
+
+  24 to 40 Feature bits reserved for extensions to the queue and
+  feature negotiation mechanisms
+
+  41 to 63 Feature bits reserved for future extensions
+
+For example, feature bit 0 for a network device (i.e. Subsystem
+Device ID 1) indicates that the device supports checksumming of
+packets.
+
+The feature bits are negotiated: the device lists all the
+features it understands in the Device Features field, and the
+guest writes the subset that it understands into the Guest
+Features field. The only way to renegotiate is to reset the
+device.
+
+In particular, new fields in the device configuration header are
+indicated by offering a feature bit, so the guest can check
+before accessing that part of the configuration space.
+
+This allows for forwards and backwards compatibility: if the
+device is enhanced with a new feature bit, older guests will not
+write that feature bit back to the Guest Features field and it
+can go into backwards compatibility mode. Similarly, if a guest
+is enhanced with a feature that the device doesn't support, it
+will not see that feature bit in the Device Features field and
+can go into backwards compatibility mode (or, for poor
+implementations, set the FAILED Device Status bit).
+
+Access to feature bits 32 to 63 is enabled by Guest by setting
+feature bit 31. If this bit is unset, Device must assume that all
+feature bits > 31 are unset.
+
+  Configuration/Queue Vectors
+
+When MSI-X capability is present and enabled in the device
+(through standard PCI configuration space) 4 bytes at byte offset
+20 are used to map configuration change and queue interrupts to
+MSI-X vectors. In this case, the ISR Status field is unused, and
+device specific configuration starts at byte offset 24 in virtio
+header structure. When MSI-X capability is not enabled, device
+specific configuration starts at byte offset 20 in virtio header.
+
+Writing a valid MSI-X Table entry number, 0 to 0x7FF, to one of
+Configuration/Queue Vector registers, maps interrupts triggered
+by the configuration change/selected queue events respectively to
+the corresponding MSI-X vector. To disable interrupts for a
+specific event type, unmap it by writing a special NO_VECTOR
+value:
+
+/* Vector value used to disable MSI for queue */
+
+#define VIRTIO_MSI_NO_VECTOR            0xffff
+
+Reading these registers returns vector mapped to a given event,
+or NO_VECTOR if unmapped. All queue and configuration change
+events are unmapped by default.
+
+Note that mapping an event to vector might require allocating
+internal device resources, and might fail. Devices report such
+failures by returning the NO_VECTOR value when the relevant
+Vector field is read. After mapping an event to vector, the
+driver must verify success by reading the Vector field value: on
+success, the previously written value is returned, and on
+failure, NO_VECTOR is returned. If a mapping failure is detected,
+the driver can retry mapping with fewervectors, or disable MSI-X.
+
+  Virtqueue Configuration
+
+As a device can have zero or more virtqueues for bulk data
+transport (for example, the network driver has two), the driver
+needs to configure them as part of the device-specific
+configuration.
+
+This is done as follows, for each virtqueue a device has:
+
+  Write the virtqueue index (first queue is 0) to the Queue
+  Select field.
+
+  Read the virtqueue size from the Queue Size field, which is
+  always a power of 2. This controls how big the virtqueue is
+  (see below). If this field is 0, the virtqueue does not exist.
+
+  Allocate and zero virtqueue in contiguous physical memory, on a
+  4096 byte alignment. Write the physical address, divided by
+  4096 to the Queue Address field.[footnote:
+The 4096 is based on the x86 page size, but it's also large
+enough to ensure that the separate parts of the virtqueue are on
+separate cache lines.
+]
+
+  Optionally, if MSI-X capability is present and enabled on the
+  device, select a vector to use to request interrupts triggered
+  by virtqueue events. Write the MSI-X Table entry number
+  corresponding to this vector in Queue Vector field. Read the
+  Queue Vector field: on success, previously written value is
+  returned; on failure, NO_VECTOR value is returned.
+
+The Queue Size field controls the total number of bytes required
+for the virtqueue according to the following formula:
+
+#define ALIGN(x) (((x) + 4095) & ~4095)
+
+static inline unsigned vring_size(unsigned int qsz)
+
+{
+
+     return ALIGN(sizeof(struct vring_desc)*qsz + sizeof(u16)*(2
++ qsz))
+
+          + ALIGN(sizeof(struct vring_used_elem)*qsz);
+
+}
+
+This currently wastes some space with padding, but also allows
+future extensions. The virtqueue layout structure looks like this
+(qsz is the Queue Size field, which is a variable, so this code
+won't compile):
+
+struct vring {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[qsz];
+
+
+
+    /* A ring of available descriptor heads with free-running
+index. */
+
+    struct vring_avail avail;
+
+
+
+    // Padding to the next 4096 boundary.
+
+    char pad[];
+
+
+
+    // A ring of used descriptor heads with free-running index.
+
+    struct vring_used used;
+
+};
+
+  A Note on Virtqueue Endianness
+
+Note that the endian of these fields and everything else in the
+virtqueue is the native endian of the guest, not little-endian as
+PCI normally is. This makes for simpler guest code, and it is
+assumed that the host already has to be deeply aware of the guest
+endian so such an “endian-aware” device is not a significant
+issue.
+
+  Descriptor Table
+
+The descriptor table refers to the buffers the guest is using for
+the device. The addresses are physical addresses, and the buffers
+can be chained via the next field. Each descriptor describes a
+buffer which is read-only or write-only, but a chain of
+descriptors can contain both read-only and write-only buffers.
+
+No descriptor chain may be more than 2^32 bytes long in total.struct vring_desc {
+
+    /* Address (guest-physical). */
+
+    u64 addr;
+
+    /* Length. */
+
+    u32 len;
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT   1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE     2
+
+/* This means the buffer contains a list of buffer descriptors.
+*/
+
+#define VRING_DESC_F_INDIRECT   4
+
+    /* The flags as indicated above. */
+
+    u16 flags;
+
+    /* Next field if flags & NEXT */
+
+    u16 next;
+
+};
+
+The number of descriptors in the table is specified by the Queue
+Size field for this virtqueue.
+
+  <sub:Indirect-Descriptors>Indirect Descriptors
+
+Some devices benefit by concurrently dispatching a large number
+of large requests. The VIRTIO_RING_F_INDIRECT_DESC feature can be
+used to allow this (see [cha:Reserved-Feature-Bits]). To increase
+ring capacity it is possible to store a table of indirect
+descriptors anywhere in memory, and insert a descriptor in main
+virtqueue (with flags&INDIRECT on) that refers to memory buffer
+containing this indirect descriptor table; fields addr and len
+refer to the indirect table address and length in bytes,
+respectively. The indirect table layout structure looks like this
+(len is the length of the descriptor that refers to this table,
+which is a variable, so this code won't compile):
+
+struct indirect_descriptor_table {
+
+    /* The actual descriptors (16 bytes each) */
+
+    struct vring_desc desc[len / 16];
+
+};
+
+The first indirect descriptor is located at start of the indirect
+descriptor table (index 0), additional indirect descriptors are
+chained by next field. An indirect descriptor without next field
+(with flags&NEXT off) signals the end of the indirect descriptor
+table, and transfers control back to the main virtqueue. An
+indirect descriptor can not refer to another indirect descriptor
+table (flags&INDIRECT must be off). A single indirect descriptor
+table can include both read-only and write-only descriptors;
+write-only flag (flags&WRITE) in the descriptor that refers to it
+is ignored.
+
+  Available Ring
+
+The available ring refers to what descriptors we are offering the
+device: it refers to the head of a descriptor chain. The “flags”
+field is currently 0 or 1: 1 indicating that we do not need an
+interrupt when the device consumes a descriptor from the
+available ring. Alternatively, the guest can ask the device to
+delay interrupts until an entry with an index specified by the “
+used_event” field is written in the used ring (equivalently,
+until the idx field in the used ring will reach the value
+used_event + 1). The method employed by the device is controlled
+by the VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). This interrupt suppression is merely an optimization; it may
+not suppress interrupts entirely.
+
+The “idx” field indicates where we would put the next descriptor
+entry (modulo the ring size). This starts at 0, and increases.
+
+struct vring_avail {
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+   u16 flags;
+
+   u16 idx;
+
+   u16 ring[qsz]; /* qsz is the Queue Size field read from device
+*/
+
+   u16 used_event;
+
+};
+
+  Used Ring
+
+The used ring is where the device returns buffers once it is done
+with them. The flags field can be used by the device to hint that
+no notification is necessary when the guest adds to the available
+ring. Alternatively, the “avail_event” field can be used by the
+device to hint that no notification is necessary until an entry
+with an index specified by the “avail_event” is written in the
+available ring (equivalently, until the idx field in the
+available ring will reach the value avail_event + 1). The method
+employed by the device is controlled by the guest through the
+VIRTIO_RING_F_EVENT_IDX feature bit (see [cha:Reserved-Feature-Bits]
+). [footnote:
+These fields are kept here because this is the only part of the
+virtqueue written by the device
+].
+
+Each entry in the ring is a pair: the head entry of the
+descriptor chain describing the buffer (this matches an entry
+placed in the available ring by the guest earlier), and the total
+of bytes written into the buffer. The latter is extremely useful
+for guests using untrusted buffers: if you do not know exactly
+how much has been written by the device, you usually have to zero
+the buffer to ensure no data leakage occurs.
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+    /* Index of start of used descriptor chain. */
+
+    u32 id;
+
+    /* Total length of the descriptor chain which was used
+(written to) */
+
+    u32 len;
+
+};
+
+
+
+struct vring_used {
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+    u16 flags;
+
+    u16 idx;
+
+    struct vring_used_elem ring[qsz];
+
+    u16 avail_event;
+
+};
+
+  Helpers for Managing Virtqueues
+
+The Linux Kernel Source code contains the definitions above and
+helper routines in a more usable form, in
+include/linux/virtio_ring.h. This was explicitly licensed by IBM
+and Red Hat under the (3-clause) BSD license so that it can be
+freely used by all other projects, and is reproduced (with slight
+variation to remove Linux assumptions) in Appendix A.
+
+  Device Operation
+
+There are two parts to device operation: supplying new buffers to
+the device, and processing used buffers from the device. As an
+example, the virtio network device has two virtqueues: the
+transmit virtqueue and the receive virtqueue. The driver adds
+outgoing (read-only) packets to the transmit virtqueue, and then
+frees them after they are used. Similarly, incoming (write-only)
+buffers are added to the receive virtqueue, and processed after
+they are used.
+
+  Supplying Buffers to The Device
+
+Actual transfer of buffers from the guest OS to the device
+operates as follows:
+
+  Place the buffer(s) into free descriptor(s).
+
+  If there are no free descriptors, the guest may choose to
+    notify the device even if notifications are suppressed (to
+    reduce latency).[footnote:
+The Linux drivers do this only for read-only buffers: for
+write-only buffers, it is assumed that the driver is merely
+trying to keep the receive buffer ring full, and no notification
+of this expected condition is necessary.
+]
+
+  Place the id of the buffer in the next ring entry of the
+  available ring.
+
+  The steps (1) and (2) may be performed repeatedly if batching
+  is possible.
+
+  A memory barrier should be executed to ensure the device sees
+  the updated descriptor table and available ring before the next
+  step.
+
+  The available “idx” field should be increased by the number of
+  entries added to the available ring.
+
+  A memory barrier should be executed to ensure that we update
+  the idx field before checking for notification suppression.
+
+  If notifications are not suppressed, the device should be
+  notified of the new buffers.
+
+Note that the above code does not take precautions against the
+available ring buffer wrapping around: this is not possible since
+the ring buffer is the same size as the descriptor table, so step
+(1) will prevent such a condition.
+
+In addition, the maximum queue size is 32768 (it must be a power
+of 2 which fits in 16 bits), so the 16-bit “idx” value can always
+distinguish between a full and empty buffer.
+
+Here is a description of each stage in more detail.
+
+  Placing Buffers Into The Descriptor Table
+
+A buffer consists of zero or more read-only physically-contiguous
+elements followed by zero or more physically-contiguous
+write-only elements (it must have at least one element). This
+algorithm maps it into the descriptor table:
+
+  for each buffer element, b:
+
+  Get the next free descriptor table entry, d
+
+  Set d.addr to the physical address of the start of b
+
+  Set d.len to the length of b.
+
+  If b is write-only, set d.flags to VRING_DESC_F_WRITE,
+    otherwise 0.
+
+  If there is a buffer element after this:
+
+    Set d.next to the index of the next free descriptor element.
+
+    Set the VRING_DESC_F_NEXT bit in d.flags.
+
+In practice, the d.next fields are usually used to chain free
+descriptors, and a separate count kept to check there are enough
+free descriptors before beginning the mappings.
+
+  Updating The Available Ring
+
+The head of the buffer we mapped is the first d in the algorithm
+above. A naive implementation would do the following:
+
+avail->ring[avail->idx % qsz] = head;
+
+However, in general we can add many descriptors before we update
+the “idx” field (at which point they become visible to the
+device), so we keep a counter of how many we've added:
+
+avail->ring[(avail->idx + added++) % qsz] = head;
+
+  Updating The Index Field
+
+Once the idx field of the virtqueue is updated, the device will
+be able to access the descriptor entries we've created and the
+memory they refer to. This is why a memory barrier is generally
+used before the idx update, to ensure it sees the most up-to-date
+copy.
+
+The idx field always increments, and we let it wrap naturally at
+65536:
+
+avail->idx += added;
+
+  <sub:Notifying-The-Device>Notifying The Device
+
+Device notification occurs by writing the 16-bit virtqueue index
+of this virtqueue to the Queue Notify field of the virtio header
+in the first I/O region of the PCI device. This can be expensive,
+however, so the device can suppress such notifications if it
+doesn't need them. We have to be careful to expose the new idx
+value before checking the suppression flag: it's OK to notify
+gratuitously, but not to omit a required notification. So again,
+we use a memory barrier here before reading the flags or the
+avail_event field.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated, and if
+the VRING_USED_F_NOTIFY flag is not set, we go ahead and write to
+the PCI configuration space.
+
+If the VIRTIO_F_RING_EVENT_IDX feature is negotiated, we read the
+avail_event field in the available ring structure. If the
+available index crossed_the avail_event field value since the
+last notification, we go ahead and write to the PCI configuration
+space. The avail_event field wraps naturally at 65536 as well:
+
+(u16)(new_idx - avail_event - 1) < (u16)(new_idx - old_idx)
+
+  <sub:Receiving-Used-Buffers>Receiving Used Buffers From The
+  Device
+
+Once the device has used a buffer (read from or written to it, or
+parts of both, depending on the nature of the virtqueue and the
+device), it sends an interrupt, following an algorithm very
+similar to the algorithm used for the driver to send the device a
+buffer:
+
+  Write the head descriptor number to the next field in the used
+  ring.
+
+  Update the used ring idx.
+
+  Determine whether an interrupt is necessary:
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is not negotiated: check
+    if f the VRING_AVAIL_F_NO_INTERRUPT flag is not set in avail-
+    >flags
+
+  If the VIRTIO_F_RING_EVENT_IDX feature is negotiated: check
+    whether the used index crossed the used_event field value
+    since the last update. The used_event field wraps naturally
+    at 65536 as well:(u16)(new_idx - used_event - 1) < (u16)(new_idx - old_idx)
+
+  If an interrupt is necessary:
+
+  If MSI-X capability is disabled:
+
+    Set the lower bit of the ISR Status field for the device.
+
+    Send the appropriate PCI interrupt for the device.
+
+  If MSI-X capability is enabled:
+
+    Request the appropriate MSI-X interrupt message for the
+      device, Queue Vector field sets the MSI-X Table entry
+      number.
+
+    If Queue Vector field value is NO_VECTOR, no interrupt
+      message is requested for this event.
+
+The guest interrupt handler should:
+
+  If MSI-X capability is disabled: read the ISR Status field,
+  which will reset it to zero. If the lower bit is zero, the
+  interrupt was not for this device. Otherwise, the guest driver
+  should look through the used rings of each virtqueue for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+  If MSI-X capability is enabled: look through the used rings of
+  each virtqueue mapped to the specific MSI-X vector for the
+  device, to see if any progress has been made by the device
+  which requires servicing.
+
+For each ring, guest should then disable interrupts by writing
+VRING_AVAIL_F_NO_INTERRUPT flag in avail structure, if required.
+It can then process used ring entries finally enabling interrupts
+by clearing the VRING_AVAIL_F_NO_INTERRUPT flag or updating the
+EVENT_IDX field in the available structure, Guest should then
+execute a memory barrier, and then recheck the ring empty
+condition. This is necessary to handle the case where, after the
+last check and before enabling interrupts, an interrupt has been
+suppressed by the device:
+
+vring_disable_interrupts(vq);
+
+for (;;) {
+
+    if (vq->last_seen_used != vring->used.idx) {
+
+               vring_enable_interrupts(vq);
+
+               mb();
+
+               if (vq->last_seen_used != vring->used.idx)
+
+                       break;
+
+    }
+
+    struct vring_used_elem *e =
+vring.used->ring[vq->last_seen_used%vsz];
+
+    process_buffer(e);
+
+    vq->last_seen_used++;
+
+}
+
+  Dealing With Configuration Changes
+
+Some virtio PCI devices can change the device configuration
+state, as reflected in the virtio header in the PCI configuration
+space. In this case:
+
+  If MSI-X capability is disabled: an interrupt is delivered and
+  the second highest bit is set in the ISR Status field to
+  indicate that the driver should re-examine the configuration
+  space.Note that a single interrupt can indicate both that one
+  or more virtqueue has been used and that the configuration
+  space has changed: even if the config bit is set, virtqueues
+  must be scanned.
+
+  If MSI-X capability is enabled: an interrupt message is
+  requested. The Configuration Vector field sets the MSI-X Table
+  entry number to use. If Configuration Vector field value is
+  NO_VECTOR, no interrupt message is requested for this event.
+
+Creating New Device Types
+
+Various considerations are necessary when creating a new device
+type:
+
+  How Many Virtqueues?
+
+It is possible that a very simple device will operate entirely
+through its configuration space, but most will need at least one
+virtqueue in which it will place requests. A device with both
+input and output (eg. console and network devices described here)
+need two queues: one which the driver fills with buffers to
+receive input, and one which the driver places buffers to
+transmit output.
+
+  What Configuration Space Layout?
+
+Configuration space is generally used for rarely-changing or
+initialization-time parameters. But it is a limited resource, so
+it might be better to use a virtqueue to update configuration
+information (the network device does this for filtering,
+otherwise the table in the config space could potentially be very
+large).
+
+Note that this space is generally the guest's native endian,
+rather than PCI's little-endian.
+
+  What Device Number?
+
+Currently device numbers are assigned quite freely: a simple
+request mail to the author of this document or the Linux
+virtualization mailing list[footnote:
+
+https://lists.linux-foundation.org/mailman/listinfo/virtualization
+] will be sufficient to secure a unique one.
+
+Meanwhile for experimental drivers, use 65535 and work backwards.
+
+  How many MSI-X vectors?
+
+Using the optional MSI-X capability devices can speed up
+interrupt processing by removing the need to read ISR Status
+register by guest driver (which might be an expensive operation),
+reducing interrupt sharing between devices and queues within the
+device, and handling interrupts from multiple CPUs. However, some
+systems impose a limit (which might be as low as 256) on the
+total number of MSI-X vectors that can be allocated to all
+devices. Devices and/or device drivers should take this into
+account, limiting the number of vectors used unless the device is
+expected to cause a high volume of interrupts. Devices can
+control the number of vectors used by limiting the MSI-X Table
+Size or not presenting MSI-X capability in PCI configuration
+space. Drivers can control this by mapping events to as small
+number of vectors as possible, or disabling MSI-X capability
+altogether.
+
+  Message Framing
+
+The descriptors used for a buffer should not effect the semantics
+of the message, except for the total length of the buffer. For
+example, a network buffer consists of a 10 byte header followed
+by the network packet. Whether this is presented in the ring
+descriptor chain as (say) a 10 byte buffer and a 1514 byte
+buffer, or a single 1524 byte buffer, or even three buffers,
+should have no effect.
+
+In particular, no implementation should use the descriptor
+boundaries to determine the size of any header in a request.[footnote:
+The current qemu device implementations mistakenly insist that
+the first descriptor cover the header in these cases exactly, so
+a cautious driver should arrange it so.
+]
+
+  Device Improvements
+
+Any change to configuration space, or new virtqueues, or
+behavioural changes, should be indicated by negotiation of a new
+feature bit. This establishes clarity[footnote:
+Even if it does mean documenting design or implementation
+mistakes!
+] and avoids future expansion problems.
+
+Clusters of functionality which are always implemented together
+can use a single bit, but if one feature makes sense without the
+others they should not be gratuitously grouped together to
+conserve feature bits. We can always extend the spec when the
+first person needs more than 24 feature bits for their device.
+
+[LaTeX Command: printnomenclature]
+
+Appendix A: virtio_ring.h
+
+#ifndef VIRTIO_RING_H
+
+#define VIRTIO_RING_H
+
+/* An interface for efficient virtio implementation.
+
+ *
+
+ * This header is BSD licensed so anyone can use the definitions
+
+ * to implement compatible drivers/servers.
+
+ *
+
+ * Copyright 2007, 2009, IBM Corporation
+
+ * Copyright 2011, Red Hat, Inc
+
+ * All rights reserved.
+
+ *
+
+ * Redistribution and use in source and binary forms, with or
+without
+
+ * modification, are permitted provided that the following
+conditions
+
+ * are met:
+
+ * 1. Redistributions of source code must retain the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer.
+
+ * 2. Redistributions in binary form must reproduce the above
+copyright
+
+ *    notice, this list of conditions and the following
+disclaimer in the
+
+ *    documentation and/or other materials provided with the
+distribution.
+
+ * 3. Neither the name of IBM nor the names of its contributors
+
+ *    may be used to endorse or promote products derived from
+this software
+
+ *    without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS ``AS IS'' AND
+
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE
+
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE
+
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE
+LIABLE
+
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL
+
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS
+
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION)
+
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT
+
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY
+
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF
+
+ * SUCH DAMAGE.
+
+ */
+
+
+
+/* This marks a buffer as continuing via the next field. */
+
+#define VRING_DESC_F_NEXT       1
+
+/* This marks a buffer as write-only (otherwise read-only). */
+
+#define VRING_DESC_F_WRITE      2
+
+
+
+/* The Host uses this in used->flags to advise the Guest: don't
+kick me
+
+ * when you add a buffer.  It's unreliable, so it's simply an
+
+ * optimization.  Guest will still kick if it's out of buffers.
+*/
+
+#define VRING_USED_F_NO_NOTIFY  1
+
+/* The Guest uses this in avail->flags to advise the Host: don't
+
+ * interrupt me when you consume a buffer.  It's unreliable, so
+it's
+
+ * simply an optimization.  */
+
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+
+
+/* Virtio ring descriptors: 16 bytes.
+
+ * These can chain together via "next". */
+
+struct vring_desc {
+
+        /* Address (guest-physical). */
+
+        uint64_t addr;
+
+        /* Length. */
+
+        uint32_t len;
+
+        /* The flags as indicated above. */
+
+        uint16_t flags;
+
+        /* We chain unused descriptors via this, too */
+
+        uint16_t next;
+
+};
+
+
+
+struct vring_avail {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        uint16_t ring[];
+
+        uint16_t used_event;
+
+};
+
+
+
+/* u32 is used here for ids for padding reasons. */
+
+struct vring_used_elem {
+
+        /* Index of start of used descriptor chain. */
+
+        uint32_t id;
+
+        /* Total length of the descriptor chain which was written
+to. */
+
+        uint32_t len;
+
+};
+
+
+
+struct vring_used {
+
+        uint16_t flags;
+
+        uint16_t idx;
+
+        struct vring_used_elem ring[];
+
+        uint16_t avail_event;
+
+};
+
+
+
+struct vring {
+
+        unsigned int num;
+
+
+
+        struct vring_desc *desc;
+
+        struct vring_avail *avail;
+
+        struct vring_used *used;
+
+};
+
+
+
+/* The standard layout for the ring is a continuous chunk of
+memory which
+
+ * looks like this.  We assume num is a power of 2.
+
+ *
+
+ * struct vring {
+
+ *      // The actual descriptors (16 bytes each)
+
+ *      struct vring_desc desc[num];
+
+ *
+
+ *      // A ring of available descriptor heads with free-running
+index.
+
+ *      __u16 avail_flags;
+
+ *      __u16 avail_idx;
+
+ *      __u16 available[num];
+
+ *
+
+ *      // Padding to the next align boundary.
+
+ *      char pad[];
+
+ *
+
+ *      // A ring of used descriptor heads with free-running
+index.
+
+ *      __u16 used_flags;
+
+ *      __u16 EVENT_IDX;
+
+ *      struct vring_used_elem used[num];
+
+ * };
+
+ * Note: for virtio PCI, align is 4096.
+
+ */
+
+static inline void vring_init(struct vring *vr, unsigned int num,
+void *p,
+
+                              unsigned long align)
+
+{
+
+        vr->num = num;
+
+        vr->desc = p;
+
+        vr->avail = p + num*sizeof(struct vring_desc);
+
+        vr->used = (void *)(((unsigned long)&vr->avail->ring[num]
+
+                              + align-1)
+
+                            & ~(align - 1));
+
+}
+
+
+
+static inline unsigned vring_size(unsigned int num, unsigned long
+align)
+
+{
+
+        return ((sizeof(struct vring_desc)*num +
+sizeof(uint16_t)*(2+num)
+
+                 + align - 1) & ~(align - 1))
+
+                + sizeof(uint16_t)*3 + sizeof(struct
+vring_used_elem)*num;
+
+}
+
+
+
+static inline int vring_need_event(uint16_t event_idx, uint16_t
+new_idx, uint16_t old_idx)
+
+{
+
+         return (uint16_t)(new_idx - event_idx - 1) <
+(uint16_t)(new_idx - old_idx);
+
+}
+
+#endif /* VIRTIO_RING_H */
+
+<cha:Reserved-Feature-Bits>Appendix B: Reserved Feature Bits
+
+Currently there are five device-independent feature bits defined:
+
+  VIRTIO_F_NOTIFY_ON_EMPTY (24) Negotiating this feature
+  indicates that the driver wants an interrupt if the device runs
+  out of available descriptors on a virtqueue, even though
+  interrupts are suppressed using the VRING_AVAIL_F_NO_INTERRUPT
+  flag or the used_event field. An example of this is the
+  networking driver: it doesn't need to know every time a packet
+  is transmitted, but it does need to free the transmitted
+  packets a finite time after they are transmitted. It can avoid
+  using a timer if the device interrupts it when all the packets
+  are transmitted.
+
+  VIRTIO_F_RING_INDIRECT_DESC (28) Negotiating this feature
+  indicates that the driver can use descriptors with the
+  VRING_DESC_F_INDIRECT flag set, as described in [sub:Indirect-Descriptors]
+  .
+
+  VIRTIO_F_RING_EVENT_IDX(29) This feature enables the used_event
+  and the avail_event fields. If set, it indicates that the
+  device should ignore the flags field in the available ring
+  structure. Instead, the used_event field in this structure is
+  used by guest to suppress device interrupts. Further, the
+  driver should ignore the flags field in the used ring
+  structure. Instead, the avail_event field in this structure is
+  used by the device to suppress notifications. If unset, the
+  driver should ignore the used_event field; the device should
+  ignore the avail_event field; the flags field is used
+
+  VIRTIO_F_BAD_FEATURE(30) This feature should never be
+  negotiated by the guest; doing so is an indication that the
+  guest is faulty[footnote:
+An experimental virtio PCI driver contained in Linux version
+2.6.25 had this problem, and this feature bit can be used to
+detect it.
+]
+
+  VIRTIO_F_FEATURES_HIGH(31) This feature indicates that the
+  device supports feature bits 32:63. If unset, feature bits
+  32:63 are unset.
+
+Appendix C: Network Device
+
+The virtio network device is a virtual ethernet card, and is the
+most complex of the devices supported so far by virtio. It has
+enhanced rapidly and demonstrates clearly how support for new
+features should be added to an existing device. Empty buffers are
+placed in one virtqueue for receiving packets, and outgoing
+packets are enqueued into another for transmission in that order.
+A third command queue is used to control advanced filtering
+features.
+
+  Configuration
+
+  Subsystem Device ID 1
+
+  Virtqueues 0:receiveq. 1:transmitq. 2:controlq[footnote:
+Only if VIRTIO_NET_F_CTRL_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_NET_F_CSUM (0) Device handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_GUEST_CSUM (1) Guest handles packets with partial
+    checksum
+
+  VIRTIO_NET_F_MAC (5) Device has given MAC address.
+
+  VIRTIO_NET_F_GSO (6) (Deprecated) device handles packets with
+    any GSO type.[footnote:
+It was supposed to indicate segmentation offload support, but
+upon further investigation it became clear that multiple bits
+were required.
+]
+
+  VIRTIO_NET_F_GUEST_TSO4 (7) Guest can receive TSOv4.
+
+  VIRTIO_NET_F_GUEST_TSO6 (8) Guest can receive TSOv6.
+
+  VIRTIO_NET_F_GUEST_ECN (9) Guest can receive TSO with ECN.
+
+  VIRTIO_NET_F_GUEST_UFO (10) Guest can receive UFO.
+
+  VIRTIO_NET_F_HOST_TSO4 (11) Device can receive TSOv4.
+
+  VIRTIO_NET_F_HOST_TSO6 (12) Device can receive TSOv6.
+
+  VIRTIO_NET_F_HOST_ECN (13) Device can receive TSO with ECN.
+
+  VIRTIO_NET_F_HOST_UFO (14) Device can receive UFO.
+
+  VIRTIO_NET_F_MRG_RXBUF (15) Guest can merge receive buffers.
+
+  VIRTIO_NET_F_STATUS (16) Configuration status field is
+    available.
+
+  VIRTIO_NET_F_CTRL_VQ (17) Control channel is available.
+
+  VIRTIO_NET_F_CTRL_RX (18) Control channel RX mode support.
+
+  VIRTIO_NET_F_CTRL_VLAN (19) Control channel VLAN filtering.
+
+  Device configuration layout Two configuration fields are
+  currently defined. The mac address field always exists (though
+  is only valid if VIRTIO_NET_F_MAC is set), and the status field
+  only exists if VIRTIO_NET_F_STATUS is set. Only one bit is
+  currently defined for the status field: VIRTIO_NET_S_LINK_UP. #define VIRTIO_NET_S_LINK_UP   1
+
+
+
+struct virtio_net_config {
+
+    u8 mac[6];
+
+    u16 status;
+
+};
+
+  Device Initialization
+
+  The initialization routine should identify the receive and
+  transmission virtqueues.
+
+  If the VIRTIO_NET_F_MAC feature bit is set, the configuration
+  space “mac” entry indicates the “physical” address of the the
+  network card, otherwise a private MAC address should be
+  assigned. All guests are expected to negotiate this feature if
+  it is set.
+
+  If the VIRTIO_NET_F_CTRL_VQ feature bit is negotiated, identify
+  the control virtqueue.
+
+  If the VIRTIO_NET_F_STATUS feature bit is negotiated, the link
+  status can be read from the bottom bit of the “status” config
+  field. Otherwise, the link should be assumed active.
+
+  The receive virtqueue should be filled with receive buffers.
+  This is described in detail below in “Setting Up Receive
+  Buffers”.
+
+  A driver can indicate that it will generate checksumless
+  packets by negotating the VIRTIO_NET_F_CSUM feature. This “
+  checksum offload” is a common feature on modern network cards.
+
+  If that feature is negotiated, a driver can use TCP or UDP
+  segmentation offload by negotiating the VIRTIO_NET_F_HOST_TSO4
+  (IPv4 TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP) and
+  VIRTIO_NET_F_HOST_UFO (UDP fragmentation) features. It should
+  not send TCP packets requiring segmentation offload which have
+  the Explicit Congestion Notification bit set, unless the
+  VIRTIO_NET_F_HOST_ECN feature is negotiated.[footnote:
+This is a common restriction in real, older network cards.
+]
+
+  The converse features are also available: a driver can save the
+  virtual device some work by negotiating these features.[footnote:
+For example, a network packet transported between two guests on
+the same system may not require checksumming at all, nor
+segmentation, if both guests are amenable.
+] The VIRTIO_NET_F_GUEST_CSUM feature indicates that partially
+  checksummed packets can be received, and if it can do that then
+  the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
+  VIRTIO_NET_F_GUEST_UFO and VIRTIO_NET_F_GUEST_ECN are the input
+  equivalents of the features described above. See “Receiving
+  Packets” below.
+
+  Device Operation
+
+Packets are transmitted by placing them in the transmitq, and
+buffers for incoming packets are placed in the receiveq. In each
+case, the packet itself is preceeded by a header:
+
+struct virtio_net_hdr {
+
+#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1
+
+       u8 flags;
+
+#define VIRTIO_NET_HDR_GSO_NONE        0
+
+#define VIRTIO_NET_HDR_GSO_TCPV4       1
+
+#define VIRTIO_NET_HDR_GSO_UDP          3
+
+#define VIRTIO_NET_HDR_GSO_TCPV6       4
+
+#define VIRTIO_NET_HDR_GSO_ECN      0x80
+
+       u8 gso_type;
+
+       u16 hdr_len;
+
+       u16 gso_size;
+
+       u16 csum_start;
+
+       u16 csum_offset;
+
+/* Only if VIRTIO_NET_F_MRG_RXBUF: */
+
+       u16 num_buffers
+
+};
+
+The controlq is used to control device features such as
+filtering.
+
+  Packet Transmission
+
+Transmitting a single packet is simple, but varies depending on
+the different features the driver negotiated.
+
+  If the driver negotiated VIRTIO_NET_F_CSUM, and the packet has
+  not been fully checksummed, then the virtio_net_hdr's fields
+  are set as follows. Otherwise, the packet must be fully
+  checksummed, and flags is zero.
+
+  flags has the VIRTIO_NET_HDR_F_NEEDS_CSUM set,
+
+  <ite:csum_start-is-set>csum_start is set to the offset within
+    the packet to begin checksumming, and
+
+  csum_offset indicates how many bytes after the csum_start the
+    new (16 bit ones' complement) checksum should be placed.[footnote:
+For example, consider a partially checksummed TCP (IPv4) packet.
+It will have a 14 byte ethernet header and 20 byte IP header
+followed by the TCP header (with the TCP checksum field 16 bytes
+into that header). csum_start will be 14+20 = 34 (the TCP
+checksum includes the header), and csum_offset will be 16. The
+value in the TCP checksum field will be the sum of the TCP pseudo
+header, so that replacing it by the ones' complement checksum of
+the TCP header and body will give the correct result.
+]
+
+  <enu:If-the-driver>If the driver negotiated
+  VIRTIO_NET_F_HOST_TSO4, TSO6 or UFO, and the packet requires
+  TCP segmentation or UDP fragmentation, then the “gso_type”
+  field is set to VIRTIO_NET_HDR_GSO_TCPV4, TCPV6 or UDP.
+  (Otherwise, it is set to VIRTIO_NET_HDR_GSO_NONE). In this
+  case, packets larger than 1514 bytes can be transmitted: the
+  metadata indicates how to replicate the packet header to cut it
+  into smaller packets. The other gso fields are set:
+
+  hdr_len is a hint to the device as to how much of the header
+    needs to be kept to copy into each packet, usually set to the
+    length of the headers, including the transport header.[footnote:
+Due to various bugs in implementations, this field is not useful
+as a guarantee of the transport header size.
+]
+
+  gso_size is the size of the packet beyond that header (ie.
+    MSS).
+
+  If the driver negotiated the VIRTIO_NET_F_HOST_ECN feature, the
+    VIRTIO_NET_HDR_GSO_ECN bit may be set in “gso_type” as well,
+    indicating that the TCP packet has the ECN bit set.[footnote:
+This case is not handled by some older hardware, so is called out
+specifically in the protocol.
+]
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  the num_buffers field is set to zero.
+
+  The header and packet are added as one output buffer to the
+  transmitq, and the device is notified of the new entry (see [sub:Notifying-The-Device]
+  ).[footnote:
+Note that the header will be two bytes longer for the
+VIRTIO_NET_F_MRG_RXBUF case.
+]
+
+  Packet Transmission Interrupt
+
+Often a driver will suppress transmission interrupts using the
+VRING_AVAIL_F_NO_INTERRUPT flag (see [sub:Receiving-Used-Buffers]
+) and check for used packets in the transmit path of following
+packets. However, it will still receive interrupts if the
+VIRTIO_F_NOTIFY_ON_EMPTY feature is negotiated, indicating that
+the transmission queue is completely emptied.
+
+The normal behavior in this interrupt handler is to retrieve and
+new descriptors from the used ring and free the corresponding
+headers and packets.
+
+  Setting Up Receive Buffers
+
+It is generally a good idea to keep the receive virtqueue as
+fully populated as possible: if it runs out, network performance
+will suffer.
+
+If the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6 or
+VIRTIO_NET_F_GUEST_UFO features are used, the Guest will need to
+accept packets of up to 65550 bytes long (the maximum size of a
+TCP or UDP packet, plus the 14 byte ethernet header), otherwise
+1514 bytes. So unless VIRTIO_NET_F_MRG_RXBUF is negotiated, every
+buffer in the receive queue needs to be at least this length [footnote:
+Obviously each one can be split across multiple descriptor
+elements.
+].
+
+If VIRTIO_NET_F_MRG_RXBUF is negotiated, each buffer must be at
+least the size of the struct virtio_net_hdr.
+
+  Packet Receive Interrupt
+
+When a packet is copied into a buffer in the receiveq, the
+optimal path is to disable further interrupts for the receiveq
+(see [sub:Receiving-Used-Buffers]) and process packets until no
+more are found, then re-enable them.
+
+Processing packet involves:
+
+  If the driver negotiated the VIRTIO_NET_F_MRG_RXBUF feature,
+  then the “num_buffers” field indicates how many descriptors
+  this packet is spread over (including this one). This allows
+  receipt of large packets without having to allocate large
+  buffers. In this case, there will be at least “num_buffers” in
+  the used ring, and they should be chained together to form a
+  single packet. The other buffers will not begin with a struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_MRG_RXBUF feature was not negotiated, or
+  the “num_buffers” field is one, then the entire packet will be
+  contained within this buffer, immediately following the struct
+  virtio_net_hdr.
+
+  If the VIRTIO_NET_F_GUEST_CSUM feature was negotiated, the
+  VIRTIO_NET_HDR_F_NEEDS_CSUM bit in the “flags” field may be
+  set: if so, the checksum on the packet is incomplete and the “
+  csum_start” and “csum_offset” fields indicate how to calculate
+  it (see [ite:csum_start-is-set]).
+
+  If the VIRTIO_NET_F_GUEST_TSO4, TSO6 or UFO options were
+  negotiated, then the “gso_type” may be something other than
+  VIRTIO_NET_HDR_GSO_NONE, and the “gso_size” field indicates the
+  desired MSS (see [enu:If-the-driver]).Control Virtqueue
+
+The driver uses the control virtqueue (if VIRTIO_NET_F_VTRL_VQ is
+negotiated) to send commands to manipulate various features of
+the device which would not easily map into the configuration
+space.
+
+All commands are of the following form:
+
+struct virtio_net_ctrl {
+
+       u8 class;
+
+       u8 command;
+
+       u8 command-specific-data[];
+
+       u8 ack;
+
+};
+
+
+
+/* ack values */
+
+#define VIRTIO_NET_OK     0
+
+#define VIRTIO_NET_ERR    1
+
+The class, command and command-specific-data are set by the
+driver, and the device sets the ack byte. There is little it can
+do except issue a diagnostic if the ack byte is not
+VIRTIO_NET_OK.
+
+  Packet Receive Filtering
+
+If the VIRTIO_NET_F_CTRL_RX feature is negotiated, the driver can
+send control commands for promiscuous mode, multicast receiving,
+and filtering of MAC addresses.
+
+Note that in general, these commands are best-effort: unwanted
+packets may still arrive.
+
+  Setting Promiscuous Mode
+
+#define VIRTIO_NET_CTRL_RX    0
+
+ #define VIRTIO_NET_CTRL_RX_PROMISC      0
+
+ #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+
+The class VIRTIO_NET_CTRL_RX has two commands:
+VIRTIO_NET_CTRL_RX_PROMISC turns promiscuous mode on and off, and
+VIRTIO_NET_CTRL_RX_ALLMULTI turns all-multicast receive on and
+off. The command-specific-data is one byte containing 0 (off) or
+1 (on).
+
+  Setting MAC Address Filtering
+
+struct virtio_net_ctrl_mac {
+
+       u32 entries;
+
+       u8 macs[entries][ETH_ALEN];
+
+};
+
+
+
+#define VIRTIO_NET_CTRL_MAC    1
+
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+
+The device can filter incoming packets by any number of
+destination MAC addresses.[footnote:
+Since there are no guarentees, it can use a hash filter
+orsilently switch to allmulti or promiscuous mode if it is given
+too many addresses.
+] This table is set using the class VIRTIO_NET_CTRL_MAC and the
+command VIRTIO_NET_CTRL_MAC_TABLE_SET. The command-specific-data
+is two variable length tables of 6-byte MAC addresses. The first
+table contains unicast addresses, and the second contains
+multicast addresses.
+
+  VLAN Filtering
+
+If the driver negotiates the VIRTION_NET_F_CTRL_VLAN feature, it
+can control a VLAN filter table in the device.
+
+#define VIRTIO_NET_CTRL_VLAN       2
+
+ #define VIRTIO_NET_CTRL_VLAN_ADD             0
+
+ #define VIRTIO_NET_CTRL_VLAN_DEL             1
+
+Both the VIRTIO_NET_CTRL_VLAN_ADD and VIRTIO_NET_CTRL_VLAN_DEL
+command take a 16-bit VLAN id as the command-specific-data.
+
+Appendix D: Block Device
+
+The virtio block device is a simple virtual block device (ie.
+disk). Read and write requests (and other exotic requests) are
+placed in the queue, and serviced (probably out of order) by the
+device except where noted.
+
+  Configuration
+
+  Subsystem Device ID 2
+
+  Virtqueues 0:requestq.
+
+  Feature bits
+
+  VIRTIO_BLK_F_BARRIER (0) Host supports request barriers.
+
+  VIRTIO_BLK_F_SIZE_MAX (1) Maximum size of any single segment is
+    in “size_max”.
+
+  VIRTIO_BLK_F_SEG_MAX (2) Maximum number of segments in a
+    request is in “seg_max”.
+
+  VIRTIO_BLK_F_GEOMETRY (4) Disk-style geometry specified in “
+    geometry”.
+
+  VIRTIO_BLK_F_RO (5) Device is read-only.
+
+  VIRTIO_BLK_F_BLK_SIZE (6) Block size of disk is in “blk_size”.
+
+  VIRTIO_BLK_F_SCSI (7) Device supports scsi packet commands.
+
+  VIRTIO_BLK_F_FLUSH (9) Cache flush command support.
+
+
+
+  Device configuration layout The capacity of the device
+  (expressed in 512-byte sectors) is always present. The
+  availability of the others all depend on various feature bits
+  as indicated above. struct virtio_blk_config {
+
+       u64 capacity;
+
+       u32 size_max;
+
+       u32 seg_max;
+
+       struct virtio_blk_geometry {
+
+               u16 cylinders;
+
+               u8 heads;
+
+               u8 sectors;
+
+       } geometry;
+
+       u32 blk_size;
+
+
+
+};
+
+  Device Initialization
+
+  The device size should be read from the “capacity”
+  configuration field. No requests should be submitted which goes
+  beyond this limit.
+
+  If the VIRTIO_BLK_F_BLK_SIZE feature is negotiated, the
+  blk_size field can be read to determine the optimal sector size
+  for the driver to use. This does not effect the units used in
+  the protocol (always 512 bytes), but awareness of the correct
+  value can effect performance.
+
+  If the VIRTIO_BLK_F_RO feature is set by the device, any write
+  requests will fail.
+
+
+
+  Device Operation
+
+The driver queues requests to the virtqueue, and they are used by
+the device (not necessarily in order). Each request is of form:
+
+struct virtio_blk_req {
+
+
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+       char data[][512];
+
+       u8 status;
+
+};
+
+If the device has VIRTIO_BLK_F_SCSI feature, it can also support
+scsi packet command requests, each of these requests is of form:struct virtio_scsi_pc_req {
+
+       u32 type;
+
+       u32 ioprio;
+
+       u64 sector;
+
+    char cmd[];
+
+       char data[][512];
+
+#define SCSI_SENSE_BUFFERSIZE   96
+
+    u8 sense[SCSI_SENSE_BUFFERSIZE];
+
+    u32 errors;
+
+    u32 data_len;
+
+    u32 sense_len;
+
+    u32 residual;
+
+       u8 status;
+
+};
+
+The type of the request is either a read (VIRTIO_BLK_T_IN), a
+write (VIRTIO_BLK_T_OUT), a scsi packet command
+(VIRTIO_BLK_T_SCSI_CMD or VIRTIO_BLK_T_SCSI_CMD_OUT[footnote:
+the SCSI_CMD and SCSI_CMD_OUT types are equivalent, the device
+does not distinguish between them
+]) or a flush (VIRTIO_BLK_T_FLUSH or VIRTIO_BLK_T_FLUSH_OUT[footnote:
+the FLUSH and FLUSH_OUT types are equivalent, the device does not
+distinguish between them
+]). If the device has VIRTIO_BLK_F_BARRIER feature the high bit
+(VIRTIO_BLK_T_BARRIER) indicates that this request acts as a
+barrier and that all preceeding requests must be complete before
+this one, and all following requests must not be started until
+this is complete. Note that a barrier does not flush caches in
+the underlying backend device in host, and thus does not serve as
+data consistency guarantee. Driver must use FLUSH request to
+flush the host cache.
+
+#define VIRTIO_BLK_T_IN           0
+
+#define VIRTIO_BLK_T_OUT          1
+
+#define VIRTIO_BLK_T_SCSI_CMD     2
+
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+
+#define VIRTIO_BLK_T_FLUSH        4
+
+#define VIRTIO_BLK_T_FLUSH_OUT    5
+
+#define VIRTIO_BLK_T_BARRIER    0x80000000
+
+The ioprio field is a hint about the relative priorities of
+requests to the device: higher numbers indicate more important
+requests.
+
+The sector number indicates the offset (multiplied by 512) where
+the read or write is to occur. This field is unused and set to 0
+for scsi packet commands and for flush commands.
+
+The cmd field is only present for scsi packet command requests,
+and indicates the command to perform. This field must reside in a
+single, separate read-only buffer; command length can be derived
+from the length of this buffer.
+
+Note that these first three (four for scsi packet commands)
+fields are always read-only: the data field is either read-only
+or write-only, depending on the request. The size of the read or
+write can be derived from the total size of the request buffers.
+
+The sense field is only present for scsi packet command requests,
+and indicates the buffer for scsi sense data.
+
+The data_len field is only present for scsi packet command
+requests, this field is deprecated, and should be ignored by the
+driver. Historically, devices copied data length there.
+
+The sense_len field is only present for scsi packet command
+requests and indicates the number of bytes actually written to
+the sense buffer.
+
+The residual field is only present for scsi packet command
+requests and indicates the residual size, calculated as data
+length - number of bytes actually transferred.
+
+The final status byte is written by the device: either
+VIRTIO_BLK_S_OK for success, VIRTIO_BLK_S_IOERR for host or guest
+error or VIRTIO_BLK_S_UNSUPP for a request unsupported by host:#define VIRTIO_BLK_S_OK        0
+
+#define VIRTIO_BLK_S_IOERR     1
+
+#define VIRTIO_BLK_S_UNSUPP    2
+
+Historically, devices assumed that the fields type, ioprio and
+sector reside in a single, separate read-only buffer; the fields
+errors, data_len, sense_len and residual reside in a single,
+separate write-only buffer; the sense field in a separate
+write-only buffer of size 96 bytes, by itself; the fields errors,
+data_len, sense_len and residual in a single write-only buffer;
+and the status field is a separate read-only buffer of size 1
+byte, by itself.
+
+Appendix E: Console Device
+
+The virtio console device is a simple device for data input and
+output. A device may have one or more ports. Each port has a pair
+of input and output virtqueues. Moreover, a device has a pair of
+control IO virtqueues. The control virtqueues are used to
+communicate information between the device and the driver about
+ports being opened and closed on either side of the connection,
+indication from the host about whether a particular port is a
+console port, adding new ports, port hot-plug/unplug, etc., and
+indication from the guest about whether a port or a device was
+successfully added, port open/close, etc.. For data IO, one or
+more empty buffers are placed in the receive queue for incoming
+data and outgoing characters are placed in the transmit queue.
+
+  Configuration
+
+  Subsystem Device ID 3
+
+  Virtqueues 0:receiveq(port0). 1:transmitq(port0), 2:control
+  receiveq[footnote:
+Ports 2 onwards only if VIRTIO_CONSOLE_F_MULTIPORT is set
+], 3:control transmitq, 4:receiveq(port1), 5:transmitq(port1),
+  ...
+
+  Feature bits
+
+  VIRTIO_CONSOLE_F_SIZE (0) Configuration cols and rows fields
+    are valid.
+
+  VIRTIO_CONSOLE_F_MULTIPORT(1) Device has support for multiple
+    ports; configuration fields nr_ports and max_nr_ports are
+    valid and control virtqueues will be used.
+
+  Device configuration layout The size of the console is supplied
+  in the configuration space if the VIRTIO_CONSOLE_F_SIZE feature
+  is set. Furthermore, if the VIRTIO_CONSOLE_F_MULTIPORT feature
+  is set, the maximum number of ports supported by the device can
+  be fetched.struct virtio_console_config {
+
+       u16 cols;
+
+       u16 rows;
+
+
+
+       u32 max_nr_ports;
+
+};
+
+  Device Initialization
+
+  If the VIRTIO_CONSOLE_F_SIZE feature is negotiated, the driver
+  can read the console dimensions from the configuration fields.
+
+  If the VIRTIO_CONSOLE_F_MULTIPORT feature is negotiated, the
+  driver can spawn multiple ports, not all of which may be
+  attached to a console. Some could be generic ports. In this
+  case, the control virtqueues are enabled and according to the
+  max_nr_ports configuration-space value, the appropriate number
+  of virtqueues are created. A control message indicating the
+  driver is ready is sent to the host. The host can then send
+  control messages for adding new ports to the device. After
+  creating and initializing each port, a
+  VIRTIO_CONSOLE_PORT_READY control message is sent to the host
+  for that port so the host can let us know of any additional
+  configuration options set for that port.
+
+  The receiveq for each port is populated with one or more
+  receive buffers.
+
+  Device Operation
+
+  For output, a buffer containing the characters is placed in the
+  port's transmitq.[footnote:
+Because this is high importance and low bandwidth, the current
+Linux implementation polls for the buffer to be used, rather than
+waiting for an interrupt, simplifying the implementation
+significantly. However, for generic serial ports with the
+O_NONBLOCK flag set, the polling limitation is relaxed and the
+consumed buffers are freed upon the next write or poll call or
+when a port is closed or hot-unplugged.
+]
+
+  When a buffer is used in the receiveq (signalled by an
+  interrupt), the contents is the input to the port associated
+  with the virtqueue for which the notification was received.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_SIZE feature, a
+  configuration change interrupt may occur. The updated size can
+  be read from the configuration fields.
+
+  If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT
+  feature, active ports are announced by the host using the
+  VIRTIO_CONSOLE_PORT_ADD control message. The same message is
+  used for port hot-plug as well.
+
+  If the host specified a port `name', a sysfs attribute is
+  created with the name filled in, so that udev rules can be
+  written that can create a symlink from the port's name to the
+  char device for port discovery by applications in the guest.
+
+  Changes to ports' state are effected by control messages.
+  Appropriate action is taken on the port indicated in the
+  control message. The layout of the structure of the control
+  buffer and the events associated are:struct virtio_console_control {
+
+       uint32_t id;    /* Port number */
+
+       uint16_t event; /* The kind of control event */
+
+       uint16_t value; /* Extra information for the event */
+
+};
+
+
+
+/* Some events for the internal messages (control packets) */
+
+
+
+#define VIRTIO_CONSOLE_DEVICE_READY     0
+
+#define VIRTIO_CONSOLE_PORT_ADD         1
+
+#define VIRTIO_CONSOLE_PORT_REMOVE      2
+
+#define VIRTIO_CONSOLE_PORT_READY       3
+
+#define VIRTIO_CONSOLE_CONSOLE_PORT     4
+
+#define VIRTIO_CONSOLE_RESIZE           5
+
+#define VIRTIO_CONSOLE_PORT_OPEN        6
+
+#define VIRTIO_CONSOLE_PORT_NAME        7
+
+Appendix F: Entropy Device
+
+The virtio entropy device supplies high-quality randomness for
+guest use.
+
+  Configuration
+
+  Subsystem Device ID 4
+
+  Virtqueues 0:requestq.
+
+  Feature bits None currently defined
+
+  Device configuration layout None currently defined.
+
+  Device Initialization
+
+  The virtqueue is initialized
+
+  Device Operation
+
+When the driver requires random bytes, it places the descriptor
+of one or more buffers in the queue. It will be completely filled
+by random data by the device.
+
+Appendix G: Memory Balloon Device
+
+The virtio memory balloon device is a primitive device for
+managing guest memory: the device asks for a certain amount of
+memory, and the guest supplies it (or withdraws it, if the device
+has more than it asks for). This allows the guest to adapt to
+changes in allowance of underlying physical memory. If the
+feature is negotiated, the device can also be used to communicate
+guest memory statistics to the host.
+
+  Configuration
+
+  Subsystem Device ID 5
+
+  Virtqueues 0:inflateq. 1:deflateq. 2:statsq.[footnote:
+Only if VIRTIO_BALLON_F_STATS_VQ set
+]
+
+  Feature bits
+
+  VIRTIO_BALLOON_F_MUST_TELL_HOST (0) Host must be told before
+    pages from the balloon are used.
+
+  VIRTIO_BALLOON_F_STATS_VQ (1) A virtqueue for reporting guest
+    memory statistics is present.
+
+  Device configuration layout Both fields of this configuration
+  are always available. Note that they are little endian, despite
+  convention that device fields are guest endian:struct virtio_balloon_config {
+
+       u32 num_pages;
+
+       u32 actual;
+
+};
+
+  Device Initialization
+
+  The inflate and deflate virtqueues are identified.
+
+  If the VIRTIO_BALLOON_F_STATS_VQ feature bit is negotiated:
+
+  Identify the stats virtqueue.
+
+  Add one empty buffer to the stats virtqueue and notify the
+    host.
+
+Device operation begins immediately.
+
+  Device Operation
+
+  Memory Ballooning The device is driven by the receipt of a
+  configuration change interrupt.
+
+  The “num_pages” configuration field is examined. If this is
+  greater than the “actual” number of pages, memory must be given
+  to the balloon. If it is less than the “actual” number of
+  pages, memory may be taken back from the balloon for general
+  use.
+
+  To supply memory to the balloon (aka. inflate):
+
+  The driver constructs an array of addresses of unused memory
+    pages. These addresses are divided by 4096[footnote:
+This is historical, and independent of the guest page size
+] and the descriptor describing the resulting 32-bit array is
+    added to the inflateq.
+
+  To remove memory from the balloon (aka. deflate):
+
+  The driver constructs an array of addresses of memory pages it
+    has previously given to the balloon, as described above. This
+    descriptor is added to the deflateq.
+
+  If the VIRTIO_BALLOON_F_MUST_TELL_HOST feature is set, the
+    guest may not use these requested pages until that descriptor
+    in the deflateq has been used by the device.
+
+  Otherwise, the guest may begin to re-use pages previously given
+    to the balloon before the device has acknowledged their
+    withdrawl. [footnote:
+In this case, deflation advice is merely a courtesy
+]
+
+  In either case, once the device has completed the inflation or
+  deflation, the “actual” field of the configuration should be
+  updated to reflect the new number of pages in the balloon.[footnote:
+As updates to configuration space are not atomic, this field
+isn't particularly reliable, but can be used to diagnose buggy
+guests.
+]
+
+  Memory Statistics
+
+The stats virtqueue is atypical because communication is driven
+by the device (not the driver). The channel becomes active at
+driver initialization time when the driver adds an empty buffer
+and notifies the device. A request for memory statistics proceeds
+as follows:
+
+  The device pushes the buffer onto the used ring and sends an
+  interrupt.
+
+  The driver pops the used buffer and discards it.
+
+  The driver collects memory statistics and writes them into a
+  new buffer.
+
+  The driver adds the buffer to the virtqueue and notifies the
+  device.
+
+  The device pops the buffer (retaining it to initiate a
+  subsequent request) and consumes the statistics.
+
+  Memory Statistics Format Each statistic consists of a 16 bit
+  tag and a 64 bit value. Both quantities are represented in the
+  native endian of the guest. All statistics are optional and the
+  driver may choose which ones to supply. To guarantee backwards
+  compatibility, unsupported statistics should be omitted.
+
+  struct virtio_balloon_stat {
+
+#define VIRTIO_BALLOON_S_SWAP_IN  0
+
+#define VIRTIO_BALLOON_S_SWAP_OUT 1
+
+#define VIRTIO_BALLOON_S_MAJFLT   2
+
+#define VIRTIO_BALLOON_S_MINFLT   3
+
+#define VIRTIO_BALLOON_S_MEMFREE  4
+
+#define VIRTIO_BALLOON_S_MEMTOT   5
+
+       u16 tag;
+
+       u64 val;
+
+} __attribute__((packed));
+
+  Tags
+
+  VIRTIO_BALLOON_S_SWAP_IN The amount of memory that has been
+  swapped in (in bytes).
+
+  VIRTIO_BALLOON_S_SWAP_OUT The amount of memory that has been
+  swapped out to disk (in bytes).
+
+  VIRTIO_BALLOON_S_MAJFLT The number of major page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MINFLT The number of minor page faults that
+  have occurred.
+
+  VIRTIO_BALLOON_S_MEMFREE The amount of memory not being used
+  for any purpose (in bytes).
+
+  VIRTIO_BALLOON_S_MEMTOT The total amount of memory available
+  (in bytes).
+
index 51d42fb..1d445f5 100644 (file)
@@ -3905,9 +3905,9 @@ F:        arch/powerpc/platforms/powermac/
 F:     drivers/macintosh/
 
 LINUX FOR POWERPC EMBEDDED MPC5XXX
-M:     Grant Likely <grant.likely@secretlab.ca>
+M:     Anatolij Gustschin <agust@denx.de>
 L:     linuxppc-dev@lists.ozlabs.org
-T:     git git://git.secretlab.ca/git/linux-2.6.git
+T:     git git://git.denx.de/linux-2.6-agust.git
 S:     Maintained
 F:     arch/powerpc/platforms/512x/
 F:     arch/powerpc/platforms/52xx/
@@ -4604,7 +4604,7 @@ F:        arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
 F:     arch/arm/mach-omap2/clockdomain44xx.c
 
 OMAP AUDIO SUPPORT
-M:     Jarkko Nikula <jhnikula@gmail.com>
+M:     Jarkko Nikula <jarkko.nikula@bitmer.com>
 L:     alsa-devel@alsa-project.org (subscribers-only)
 L:     linux-omap@vger.kernel.org
 S:     Maintained
@@ -7357,7 +7357,7 @@ THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/LKML/list/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 S:     Buried alive in reporters
 F:     *
 F:     */
index b4ca4e1..3241d41 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
 PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
-NAME = Sneaky Weasel
+EXTRAVERSION = -rc2
+NAME = Wet Seal
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
index 2c71a8f..5ebc5d9 100644 (file)
@@ -195,8 +195,7 @@ config VECTORS_BASE
          The base address of exception vectors.
 
 config ARM_PATCH_PHYS_VIRT
-       bool "Patch physical to virtual translations at runtime (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       bool "Patch physical to virtual translations at runtime"
        depends on !XIP_KERNEL && MMU
        depends on !ARCH_REALVIEW || !SPARSEMEM
        help
index 7fa3bb0..a087838 100644 (file)
@@ -195,10 +195,10 @@ ENTRY(iwmmxt_task_disable)
 
        @ enable access to CP0 and CP1
        XSC(mrc p15, 0, r4, c15, c1, 0)
-       XSC(orr r4, r4, #0xf)
+       XSC(orr r4, r4, #0x3)
        XSC(mcr p15, 0, r4, c15, c1, 0)
        PJ4(mrc p15, 0, r4, c1, c0, 2)
-       PJ4(orr r4, r4, #0x3)
+       PJ4(orr r4, r4, #0xf)
        PJ4(mcr p15, 0, r4, c1, c0, 2)
 
        mov     r0, #0                          @ nothing to load
@@ -313,7 +313,7 @@ ENTRY(iwmmxt_task_switch)
        teq     r2, r3                          @ next task owns it?
        movne   pc, lr                          @ no: leave Concan disabled
 
-1:     @ flip Conan access
+1:     @ flip Concan access
        XSC(eor r1, r1, #0x3)
        XSC(mcr p15, 0, r1, c15, c1, 0)
        PJ4(eor r1, r1, #0xf)
index 05b3776..cc2020c 100644 (file)
@@ -323,7 +323,11 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 #endif
        s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
        if (s && !is_smp())
+#ifdef CONFIG_SMP_ON_UP
                fixup_smp((void *)s->sh_addr, s->sh_size);
+#else
+               return -EINVAL;
+#endif
        return 0;
 }
 
index 0fc7ba5..e63e235 100644 (file)
@@ -331,6 +331,9 @@ int __init mx25_clocks_init(void)
        __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0),
                        CRM_BASE + 0x64);
 
+       /* Clock source for gpt is ahb_div */
+       __raw_writel(__raw_readl(CRM_BASE+0x64) & ~(1 << 5), CRM_BASE + 0x64);
+
        mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
 
        return 0;
index 6707de0..6778f81 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/delay.h>
+#include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -196,6 +197,17 @@ static struct pca953x_platform_data visstrim_m10_pca9555_pdata = {
        .invert = 0,
 };
 
+static struct aic32x4_pdata visstrim_m10_aic32x4_pdata = {
+       .power_cfg = AIC32X4_PWR_MICBIAS_2075_LDOIN |
+                    AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE |
+                    AIC32X4_PWR_AIC32X4_LDO_ENABLE |
+                    AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 |
+                    AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED,
+       .micpga_routing = AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K |
+                        AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K,
+       .swapdacs = false,
+};
+
 static struct i2c_board_info visstrim_m10_i2c_devices[] = {
        {
                I2C_BOARD_INFO("pca9555", 0x20),
@@ -203,6 +215,7 @@ static struct i2c_board_info visstrim_m10_i2c_devices[] = {
        },
        {
                I2C_BOARD_INFO("tlv320aic32x4", 0x18),
+               .platform_data = &visstrim_m10_aic32x4_pdata,
        }
 };
 
index 0ce4947..29ca890 100644 (file)
@@ -468,7 +468,7 @@ static struct i2c_board_info __initdata mx31ads_i2c1_devices[] = {
 #endif
 };
 
-static void mxc_init_i2c(void)
+static void __init mxc_init_i2c(void)
 {
        i2c_register_board_info(1, mx31ads_i2c1_devices,
                                ARRAY_SIZE(mx31ads_i2c1_devices));
@@ -486,7 +486,7 @@ static unsigned int ssi_pins[] = {
        MX31_PIN_STXD5__STXD5,
 };
 
-static void mxc_init_audio(void)
+static void __init mxc_init_audio(void)
 {
        imx31_add_imx_ssi(0, NULL);
        mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
index 750368d..126913a 100644 (file)
@@ -192,7 +192,7 @@ static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
        .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
 };
 
-static void lilly1131_usb_init(void)
+static void __init lilly1131_usb_init(void)
 {
        imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
 
index c070c24..98e25d9 100644 (file)
 #include <mach/gpio.h>
 #include <mach/pxa168.h>
 #include <mach/mfp-pxa168.h>
-#include <mach/mfp-gplugd.h>
 
 #include "common.h"
 
 static unsigned long gplugd_pin_config[] __initdata = {
        /* UART3 */
-       GPIO8_UART3_SOUT,
-       GPIO9_UART3_SIN,
-       GPI1O_UART3_CTS,
-       GPI11_UART3_RTS,
+       GPIO8_UART3_TXD,
+       GPIO9_UART3_RXD,
+       GPIO1O_UART3_CTS,
+       GPIO11_UART3_RTS,
+
+       /* USB OTG PEN */
+       GPIO18_GPIO,
 
        /* MMC2 */
        GPIO28_MMC2_CMD,
@@ -109,6 +111,12 @@ static unsigned long gplugd_pin_config[] __initdata = {
        GPIO105_CI2C_SDA,
        GPIO106_CI2C_SCL,
 
+       /* SPI NOR Flash on SSP2 */
+       GPIO107_SSP2_RXD,
+       GPIO108_SSP2_TXD,
+       GPIO110_GPIO,     /* SPI_CSn */
+       GPIO111_SSP2_CLK,
+
        /* Select JTAG */
        GPIO109_GPIO,
 
@@ -154,7 +162,7 @@ static void __init select_disp_freq(void)
                                "frequency\n");
        } else {
                gpio_direction_output(35, 1);
-               gpio_free(104);
+               gpio_free(35);
        }
 
        if (unlikely(gpio_request(85, "DISP_FREQ_SEL_2"))) {
@@ -162,7 +170,7 @@ static void __init select_disp_freq(void)
                                "frequency\n");
        } else {
                gpio_direction_output(85, 0);
-               gpio_free(104);
+               gpio_free(85);
        }
 }
 
diff --git a/arch/arm/mach-mmp/include/mach/mfp-gplugd.h b/arch/arm/mach-mmp/include/mach/mfp-gplugd.h
deleted file mode 100644 (file)
index b8cf38d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/mfp-gplugd.h
- *
- *   MFP definitions used in gplugD
- *
- * This program is free software; you can 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 __MACH_MFP_GPLUGD_H
-#define __MACH_MFP_GPLUGD_H
-
-#include <plat/mfp.h>
-#include <mach/mfp.h>
-
-/* UART3 */
-#define GPIO8_UART3_SOUT       MFP_CFG(GPIO8, AF2)
-#define GPIO9_UART3_SIN        MFP_CFG(GPIO9, AF2)
-#define GPI1O_UART3_CTS        MFP_CFG(GPIO10, AF2)
-#define GPI11_UART3_RTS        MFP_CFG(GPIO11, AF2)
-
-/* MMC2 */
-#define        GPIO28_MMC2_CMD         MFP_CFG_DRV(GPIO28, AF6, FAST)
-#define        GPIO29_MMC2_CLK         MFP_CFG_DRV(GPIO29, AF6, FAST)
-#define        GPIO30_MMC2_DAT0        MFP_CFG_DRV(GPIO30, AF6, FAST)
-#define        GPIO31_MMC2_DAT1        MFP_CFG_DRV(GPIO31, AF6, FAST)
-#define        GPIO32_MMC2_DAT2        MFP_CFG_DRV(GPIO32, AF6, FAST)
-#define        GPIO33_MMC2_DAT3        MFP_CFG_DRV(GPIO33, AF6, FAST)
-
-/* I2S */
-#undef GPIO114_I2S_FRM
-#undef GPIO115_I2S_BCLK
-
-#define GPIO114_I2S_FRM                MFP_CFG_DRV(GPIO114, AF1, FAST)
-#define GPIO115_I2S_BCLK        MFP_CFG_DRV(GPIO115, AF1, FAST)
-#define GPIO116_I2S_TXD         MFP_CFG_DRV(GPIO116, AF1, FAST)
-
-/* MMC4 */
-#define GPIO125_MMC4_DAT3       MFP_CFG_DRV(GPIO125, AF7, FAST)
-#define GPIO126_MMC4_DAT2       MFP_CFG_DRV(GPIO126, AF7, FAST)
-#define GPIO127_MMC4_DAT1       MFP_CFG_DRV(GPIO127, AF7, FAST)
-#define GPIO0_2_MMC4_DAT0       MFP_CFG_DRV(GPIO0_2, AF7, FAST)
-#define GPIO1_2_MMC4_CMD        MFP_CFG_DRV(GPIO1_2, AF7, FAST)
-#define GPIO2_2_MMC4_CLK        MFP_CFG_DRV(GPIO2_2, AF7, FAST)
-
-/* OTG GPIO */
-#define GPIO_USB_OTG_PEN        18
-#define GPIO_USB_OIDIR          20
-
-/* Other GPIOs are 35, 84, 85 */
-#endif /* __MACH_MFP_GPLUGD_H */
index 8c78232..92aaa3c 100644 (file)
 #define GPIO33_CF_nCD2         MFP_CFG(GPIO33, AF3)
 
 /* UART */
+#define GPIO8_UART3_TXD                MFP_CFG(GPIO8, AF2)
+#define GPIO9_UART3_RXD                MFP_CFG(GPIO9, AF2)
+#define GPIO1O_UART3_CTS       MFP_CFG(GPIO10, AF2)
+#define GPIO11_UART3_RTS       MFP_CFG(GPIO11, AF2)
 #define GPIO88_UART2_TXD       MFP_CFG(GPIO88, AF2)
 #define GPIO89_UART2_RXD       MFP_CFG(GPIO89, AF2)
 #define GPIO107_UART1_TXD      MFP_CFG_DRV(GPIO107, AF1, FAST)
 #define GPIO53_MMC1_CD         MFP_CFG(GPIO53, AF1)
 #define GPIO46_MMC1_WP         MFP_CFG(GPIO46, AF1)
 
+/* MMC2 */
+#define        GPIO28_MMC2_CMD         MFP_CFG_DRV(GPIO28, AF6, FAST)
+#define        GPIO29_MMC2_CLK         MFP_CFG_DRV(GPIO29, AF6, FAST)
+#define        GPIO30_MMC2_DAT0        MFP_CFG_DRV(GPIO30, AF6, FAST)
+#define        GPIO31_MMC2_DAT1        MFP_CFG_DRV(GPIO31, AF6, FAST)
+#define        GPIO32_MMC2_DAT2        MFP_CFG_DRV(GPIO32, AF6, FAST)
+#define        GPIO33_MMC2_DAT3        MFP_CFG_DRV(GPIO33, AF6, FAST)
+
+/* MMC4 */
+#define GPIO125_MMC4_DAT3       MFP_CFG_DRV(GPIO125, AF7, FAST)
+#define GPIO126_MMC4_DAT2       MFP_CFG_DRV(GPIO126, AF7, FAST)
+#define GPIO127_MMC4_DAT1       MFP_CFG_DRV(GPIO127, AF7, FAST)
+#define GPIO0_2_MMC4_DAT0       MFP_CFG_DRV(GPIO0_2, AF7, FAST)
+#define GPIO1_2_MMC4_CMD        MFP_CFG_DRV(GPIO1_2, AF7, FAST)
+#define GPIO2_2_MMC4_CLK        MFP_CFG_DRV(GPIO2_2, AF7, FAST)
+
 /* LCD */
 #define GPIO84_LCD_CS          MFP_CFG(GPIO84, AF1)
 #define GPIO60_LCD_DD0         MFP_CFG(GPIO60, AF1)
 #define GPIO106_CI2C_SCL       MFP_CFG(GPIO106, AF1)
 
 /* I2S */
-#define GPIO113_I2S_MCLK       MFP_CFG(GPIO113,AF6)
-#define GPIO114_I2S_FRM                MFP_CFG(GPIO114,AF1)
-#define GPIO115_I2S_BCLK       MFP_CFG(GPIO115,AF1)
-#define GPIO116_I2S_RXD                MFP_CFG(GPIO116,AF2)
-#define GPIO117_I2S_TXD                MFP_CFG(GPIO117,AF2)
+#define GPIO113_I2S_MCLK       MFP_CFG(GPIO113, AF6)
+#define GPIO114_I2S_FRM                MFP_CFG(GPIO114, AF1)
+#define GPIO115_I2S_BCLK       MFP_CFG(GPIO115, AF1)
+#define GPIO116_I2S_RXD                MFP_CFG(GPIO116, AF2)
+#define GPIO116_I2S_TXD         MFP_CFG(GPIO116, AF1)
+#define GPIO117_I2S_TXD                MFP_CFG(GPIO117, AF2)
 
 /* PWM */
 #define GPIO96_PWM3_OUT                MFP_CFG(GPIO96, AF1)
 #define GPIO101_MII_MDIO       MFP_CFG(GPIO101, AF5)
 #define GPIO103_RX_DV          MFP_CFG(GPIO103, AF5)
 
+/* SSP2 */
+#define GPIO107_SSP2_RXD       MFP_CFG(GPIO107, AF4)
+#define GPIO108_SSP2_TXD       MFP_CFG(GPIO108, AF4)
+#define GPIO111_SSP2_CLK       MFP_CFG(GPIO111, AF4)
+#define GPIO112_SSP2_FRM       MFP_CFG(GPIO112, AF4)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
index 99833b9..4e91ee6 100644 (file)
@@ -51,12 +51,12 @@ static inline uint32_t timer_read(void)
 {
        int delay = 100;
 
-       __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(0));
+       __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1));
 
        while (delay--)
                cpu_relax();
 
-       return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(0));
+       return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
 }
 
 unsigned long long notrace sched_clock(void)
@@ -75,28 +75,51 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *c = dev_id;
 
-       /* disable and clear pending interrupt status */
-       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
-       __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_ICR(0));
+       /*
+        * Clear pending interrupt status.
+        */
+       __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
+
+       /*
+        * Disable timer 0.
+        */
+       __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+
        c->event_handler(c);
+
        return IRQ_HANDLED;
 }
 
 static int timer_set_next_event(unsigned long delta,
                                struct clock_event_device *dev)
 {
-       unsigned long flags, next;
+       unsigned long flags;
 
        local_irq_save(flags);
 
-       /* clear pending interrupt status and enable */
+       /*
+        * Disable timer 0.
+        */
+       __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+
+       /*
+        * Clear and enable timer match 0 interrupt.
+        */
        __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
        __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
 
-       next = timer_read() + delta;
-       __raw_writel(next, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+       /*
+        * Setup new clockevent timer value.
+        */
+       __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+
+       /*
+        * Enable timer 0.
+        */
+       __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER);
 
        local_irq_restore(flags);
+
        return 0;
 }
 
@@ -145,23 +168,26 @@ static struct clocksource cksrc = {
 static void __init timer_config(void)
 {
        uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
-       uint32_t cer = __raw_readl(TIMERS_VIRT_BASE + TMR_CER);
-       uint32_t cmr = __raw_readl(TIMERS_VIRT_BASE + TMR_CMR);
 
-       __raw_writel(cer & ~0x1, TIMERS_VIRT_BASE + TMR_CER); /* disable */
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */
 
-       ccr &= (cpu_is_mmp2()) ? TMR_CCR_CS_0(0) : TMR_CCR_CS_0(3);
+       ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
+               (TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
        __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
 
-       /* free-running mode */
-       __raw_writel(cmr | 0x01, TIMERS_VIRT_BASE + TMR_CMR);
+       /* set timer 0 to periodic mode, and timer 1 to free-running mode */
+       __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR);
 
-       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* free-running */
+       __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */
        __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0));  /* clear status */
        __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
 
-       /* enable timer counter */
-       __raw_writel(cer | 0x01, TIMERS_VIRT_BASE + TMR_CER);
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */
+       __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1));  /* clear status */
+       __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1));
+
+       /* enable timer 1 counter */
+       __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER);
 }
 
 static struct irqaction timer_irq = {
index 7c893fa..68934ea 100644 (file)
@@ -81,7 +81,7 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
        }, {
                .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000),
-               .irq = irq_to_gpio(CPUIMX51_QUARTD_GPIO),
+               .irq = gpio_to_irq(CPUIMX51_QUARTD_GPIO),
                .irqflags = IRQF_TRIGGER_HIGH,
                .uartclk = CPUIMX51_QUART_XTAL,
                .regshift = CPUIMX51_QUART_REGSHIFT,
index e400b09..11b0ff6 100644 (file)
@@ -369,7 +369,7 @@ static void __init mx51_babbage_init(void)
                                        ARRAY_SIZE(mx51babbage_pads));
 
        imx51_add_imx_uart(0, &uart_pdata);
-       imx51_add_imx_uart(1, &uart_pdata);
+       imx51_add_imx_uart(1, NULL);
        imx51_add_imx_uart(2, &uart_pdata);
 
        babbage_fec_reset();
index f70700d..551daf8 100644 (file)
@@ -108,9 +108,9 @@ static void __init mx51_efikamx_board_id(void)
        gpio_request(EFIKAMX_PCBID2, "pcbid2");
        gpio_direction_input(EFIKAMX_PCBID2);
 
-       id = gpio_get_value(EFIKAMX_PCBID0);
-       id |= gpio_get_value(EFIKAMX_PCBID1) << 1;
-       id |= gpio_get_value(EFIKAMX_PCBID2) << 2;
+       id = gpio_get_value(EFIKAMX_PCBID0) ? 1 : 0;
+       id |= (gpio_get_value(EFIKAMX_PCBID1) ? 1 : 0) << 1;
+       id |= (gpio_get_value(EFIKAMX_PCBID2) ? 1 : 0) << 2;
 
        switch (id) {
        case 7:
index 2e4d9d3..8a9bca2 100644 (file)
@@ -156,23 +156,24 @@ static struct gpio_keys_button mx51_efikasb_keys[] = {
        {
                .code = KEY_POWER,
                .gpio = EFIKASB_PWRKEY,
-               .type = EV_PWR,
+               .type = EV_KEY,
                .desc = "Power Button",
                .wakeup = 1,
-               .debounce_interval = 10, /* ms */
+               .active_low = 1,
        },
        {
                .code = SW_LID,
                .gpio = EFIKASB_LID,
                .type = EV_SW,
                .desc = "Lid Switch",
+               .active_low = 1,
        },
        {
-               /* SW_RFKILLALL vs KEY_RFKILL ? */
-               .code = SW_RFKILL_ALL,
+               .code = KEY_RFKILL,
                .gpio = EFIKASB_RFKILL,
-               .type = EV_SW,
+               .type = EV_KEY,
                .desc = "rfkill",
+               .active_low = 1,
        },
 };
 
@@ -224,8 +225,8 @@ static void __init mx51_efikasb_board_id(void)
        gpio_request(EFIKASB_PCBID1, "pcb id1");
        gpio_direction_input(EFIKASB_PCBID1);
 
-       id = gpio_get_value(EFIKASB_PCBID0);
-       id |= gpio_get_value(EFIKASB_PCBID1) << 1;
+       id = gpio_get_value(EFIKASB_PCBID0) ? 1 : 0;
+       id |= (gpio_get_value(EFIKASB_PCBID1) ? 1 : 0) << 1;
 
        switch (id) {
        default:
index 7f20308..f7bf996 100644 (file)
@@ -271,7 +271,11 @@ static int _clk_pll_enable(struct clk *clk)
        int i = 0;
 
        pllbase = _get_pll_base(clk);
-       reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
+       reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+       if (reg & MXC_PLL_DP_CTL_UPEN)
+               return 0;
+
+       reg |= MXC_PLL_DP_CTL_UPEN;
        __raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
 
        /* Wait for lock */
index 4435e03..c920945 100644 (file)
@@ -186,7 +186,7 @@ static int initialize_usbh1_port(struct platform_device *pdev)
 
        mdelay(10);
 
-       return mx51_initialize_usb_hw(0, MXC_EHCI_ITC_NO_THRESHOLD);
+       return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_ITC_NO_THRESHOLD);
 }
 
 static struct mxc_usbh_platform_data usbh1_config = {
index 4ae6257..57b66d5 100644 (file)
@@ -7,7 +7,6 @@ config ARCH_OMAP2PLUS_TYPICAL
        default y
        select AEABI
        select REGULATOR
-       select PM
        select PM_RUNTIME
        select VFP
        select NEON if ARCH_OMAP3 || ARCH_OMAP4
index 5f2b55f..933e935 100644 (file)
@@ -45,8 +45,6 @@ static struct omap_board_config_kernel am3517_crane_config[] __initdata = {
 static struct omap_board_mux board_mux[] __initdata = {
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
-#else
-#define board_mux      NULL
 #endif
 
 static void __init am3517_crane_init_early(void)
index 32f5f89..3ae16b4 100644 (file)
@@ -491,23 +491,22 @@ static void __init beagle_opp_init(void)
 
        /* Custom OPP enabled for all xM versions */
        if (cpu_is_omap3630()) {
-               struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
-               struct omap_hwmod *dh = omap_hwmod_lookup("iva");
-               struct device *dev;
+               struct device *mpu_dev, *iva_dev;
 
-               if (!mh || !dh) {
+               mpu_dev = omap2_get_mpuss_device();
+               iva_dev = omap2_get_iva_device();
+
+               if (!mpu_dev || !iva_dev) {
                        pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
-                               __func__, mh, dh);
+                               __func__, mpu_dev, iva_dev);
                        return;
                }
                /* Enable MPU 1GHz and lower opps */
-               dev = &mh->od->pdev.dev;
-               r = opp_enable(dev, 800000000);
+               r = opp_enable(mpu_dev, 800000000);
                /* TODO: MPU 1GHz needs SR and ABB */
 
                /* Enable IVA 800MHz and lower opps */
-               dev = &dh->od->pdev.dev;
-               r |= opp_enable(dev, 660000000);
+               r |= opp_enable(iva_dev, 660000000);
                /* TODO: DSP 800MHz needs SR and ABB */
                if (r) {
                        pr_err("%s: failed to enable higher opp %d\n",
@@ -516,10 +515,8 @@ static void __init beagle_opp_init(void)
                         * Cleanup - disable the higher freqs - we dont care
                         * about the results
                         */
-                       dev = &mh->od->pdev.dev;
-                       opp_disable(dev, 800000000);
-                       dev = &dh->od->pdev.dev;
-                       opp_disable(dev, 660000000);
+                       opp_disable(mpu_dev, 800000000);
+                       opp_disable(iva_dev, 660000000);
                }
        }
        return;
index f2ea645..a018a73 100644 (file)
@@ -18,13 +18,36 @@ extern void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs);
 extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs);
 
 extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
-extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
+
+# ifdef CONFIG_ARCH_OMAP4
+extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
+                                        u16 clkctrl_offs);
 
 extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
                                       u16 clkctrl_offs);
 extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
                                        u16 clkctrl_offs);
 
+# else
+
+static inline int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
+                                       u16 clkctrl_offs)
+{
+       return 0;
+}
+
+static inline void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
+                               s16 cdoffs, u16 clkctrl_offs)
+{
+}
+
+static inline void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
+                                u16 clkctrl_offs)
+{
+}
+
+# endif
+
 /*
  * In an ideal world, we would not export these low-level functions,
  * but this will probably take some time to fix properly
index c7fb22a..655e948 100644 (file)
@@ -821,11 +821,10 @@ static void __init omap_mux_set_cmdline_signals(void)
        if (!omap_mux_options)
                return;
 
-       options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL);
+       options = kstrdup(omap_mux_options, GFP_KERNEL);
        if (!options)
                return;
 
-       strcpy(options, omap_mux_options);
        next_opt = options;
 
        while ((token = strsep(&next_opt, ",")) != NULL) {
@@ -855,24 +854,19 @@ static int __init omap_mux_copy_names(struct omap_mux *src,
 
        for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
                if (src->muxnames[i]) {
-                       dst->muxnames[i] =
-                               kmalloc(strlen(src->muxnames[i]) + 1,
-                                       GFP_KERNEL);
+                       dst->muxnames[i] = kstrdup(src->muxnames[i],
+                                                  GFP_KERNEL);
                        if (!dst->muxnames[i])
                                goto free;
-                       strcpy(dst->muxnames[i], src->muxnames[i]);
                }
        }
 
 #ifdef CONFIG_DEBUG_FS
        for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
                if (src->balls[i]) {
-                       dst->balls[i] =
-                               kmalloc(strlen(src->balls[i]) + 1,
-                                       GFP_KERNEL);
+                       dst->balls[i] = kstrdup(src->balls[i], GFP_KERNEL);
                        if (!dst->balls[i])
                                goto free;
-                       strcpy(dst->balls[i], src->balls[i]);
                }
        }
 #endif
index 2ce2fb7..34c01a7 100644 (file)
@@ -621,7 +621,7 @@ void sr_disable(struct voltagedomain *voltdm)
                        sr_v2_disable(sr);
        }
 
-       pm_runtime_put_sync(&sr->pdev->dev);
+       pm_runtime_put_sync_suspend(&sr->pdev->dev);
 }
 
 /**
@@ -860,6 +860,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_irq_safe(&pdev->dev);
 
        sr_info->pdev = pdev;
        sr_info->srid = pdev->id;
index e964072..cf1de7d 100644 (file)
@@ -293,7 +293,8 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
        pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
                gptimer_id, clksrc.rate);
 
-       __omap_dm_timer_load_start(clksrc.io_base, OMAP_TIMER_CTRL_ST, 0, 1);
+       __omap_dm_timer_load_start(clksrc.io_base,
+                       OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
        init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
 
        if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
index 2543342..daa056e 100644 (file)
@@ -48,14 +48,7 @@ void __init omap_pmic_init(int bus, u32 clkrate,
        omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1);
 }
 
-static struct twl4030_usb_data omap4_usb_pdata = {
-       .phy_init       = omap4430_phy_init,
-       .phy_exit       = omap4430_phy_exit,
-       .phy_power      = omap4430_phy_power,
-       .phy_set_clock  = omap4430_phy_set_clk,
-       .phy_suspend    = omap4430_phy_suspend,
-};
-
+#if defined(CONFIG_ARCH_OMAP3)
 static struct twl4030_usb_data omap3_usb_pdata = {
        .usb_mode       = T2_USB_MODE_ULPI,
 };
@@ -122,6 +115,45 @@ static struct regulator_init_data omap3_vpll2_idata = {
        .consumer_supplies              = omap3_vpll2_supplies,
 };
 
+void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
+                                 u32 pdata_flags, u32 regulators_flags)
+{
+       if (!pmic_data->irq_base)
+               pmic_data->irq_base = TWL4030_IRQ_BASE;
+       if (!pmic_data->irq_end)
+               pmic_data->irq_end = TWL4030_IRQ_END;
+
+       /* Common platform data configurations */
+       if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
+               pmic_data->usb = &omap3_usb_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
+               pmic_data->bci = &omap3_bci_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc)
+               pmic_data->madc = &omap3_madc_pdata;
+
+       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
+               pmic_data->audio = &omap3_audio_pdata;
+
+       /* Common regulator configurations */
+       if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
+               pmic_data->vdac = &omap3_vdac_idata;
+
+       if (regulators_flags & TWL_COMMON_REGULATOR_VPLL2 && !pmic_data->vpll2)
+               pmic_data->vpll2 = &omap3_vpll2_idata;
+}
+#endif /* CONFIG_ARCH_OMAP3 */
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct twl4030_usb_data omap4_usb_pdata = {
+       .phy_init       = omap4430_phy_init,
+       .phy_exit       = omap4430_phy_exit,
+       .phy_power      = omap4430_phy_power,
+       .phy_set_clock  = omap4430_phy_set_clk,
+       .phy_suspend    = omap4430_phy_suspend,
+};
+
 static struct regulator_init_data omap4_vdac_idata = {
        .constraints = {
                .min_uV                 = 1800000,
@@ -273,32 +305,4 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
            !pmic_data->clk32kg)
                pmic_data->clk32kg = &omap4_clk32kg_idata;
 }
-
-void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
-                                 u32 pdata_flags, u32 regulators_flags)
-{
-       if (!pmic_data->irq_base)
-               pmic_data->irq_base = TWL4030_IRQ_BASE;
-       if (!pmic_data->irq_end)
-               pmic_data->irq_end = TWL4030_IRQ_END;
-
-       /* Common platform data configurations */
-       if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
-               pmic_data->usb = &omap3_usb_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
-               pmic_data->bci = &omap3_bci_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_MADC && !pmic_data->madc)
-               pmic_data->madc = &omap3_madc_pdata;
-
-       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
-               pmic_data->audio = &omap3_audio_pdata;
-
-       /* Common regulator configurations */
-       if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
-               pmic_data->vdac = &omap3_vdac_idata;
-
-       if (regulators_flags & TWL_COMMON_REGULATOR_VPLL2 && !pmic_data->vpll2)
-               pmic_data->vpll2 = &omap3_vpll2_idata;
-}
+#endif /* CONFIG_ARCH_OMAP4 */
index 9026249..af0c2fe 100644 (file)
@@ -65,7 +65,7 @@
 #include <plat/iic.h>
 #include <plat/pm.h>
 
-#include <sound/wm8915.h>
+#include <sound/wm8996.h>
 #include <sound/wm8962.h>
 #include <sound/wm9081.h>
 
@@ -614,7 +614,7 @@ static struct wm831x_pdata glenfarclas_pmic_pdata __initdata = {
        .disable_touch = true,
 };
 
-static struct wm8915_retune_mobile_config wm8915_retune[] = {
+static struct wm8996_retune_mobile_config wm8996_retune[] = {
        {
                .name = "Sub LPF",
                .rate = 48000,
@@ -635,12 +635,12 @@ static struct wm8915_retune_mobile_config wm8915_retune[] = {
        },
 };
 
-static struct wm8915_pdata wm8915_pdata __initdata = {
+static struct wm8996_pdata wm8996_pdata __initdata = {
        .ldo_ena = S3C64XX_GPN(7),
        .gpio_base = CODEC_GPIO_BASE,
        .micdet_def = 1,
-       .inl_mode = WM8915_DIFFERRENTIAL_1,
-       .inr_mode = WM8915_DIFFERRENTIAL_1,
+       .inl_mode = WM8996_DIFFERRENTIAL_1,
+       .inr_mode = WM8996_DIFFERRENTIAL_1,
 
        .irq_flags = IRQF_TRIGGER_RISING,
 
@@ -652,8 +652,8 @@ static struct wm8915_pdata wm8915_pdata __initdata = {
                0x020e, /* GPIO5 == CLKOUT */
        },
 
-       .retune_mobile_cfgs = wm8915_retune,
-       .num_retune_mobile_cfgs = ARRAY_SIZE(wm8915_retune),
+       .retune_mobile_cfgs = wm8996_retune,
+       .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune),
 };
 
 static struct wm8962_pdata wm8962_pdata __initdata = {
@@ -679,8 +679,8 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
          .platform_data = &glenfarclas_pmic_pdata },
 
        { I2C_BOARD_INFO("wm1250-ev1", 0x27) },
-       { I2C_BOARD_INFO("wm8915", 0x1a),
-         .platform_data = &wm8915_pdata,
+       { I2C_BOARD_INFO("wm8996", 0x1a),
+         .platform_data = &wm8996_pdata,
          .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
        },
        { I2C_BOARD_INFO("wm9081", 0x6c),
index 964c6c3..dd39fee 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mach-types.h>
 
 #include <mach/nanoengine.h>
+#include <mach/hardware.h>
 
 static DEFINE_SPINLOCK(nano_lock);
 
index be7c638..cfbcf8b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 
+#include <asm/system.h>
 #include <asm/unaligned.h>
 
 #include "fault.h"
@@ -95,6 +96,33 @@ static const char *usermode_action[] = {
        "signal+warn"
 };
 
+/* Return true if and only if the ARMv6 unaligned access model is in use. */
+static bool cpu_is_v6_unaligned(void)
+{
+       return cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U);
+}
+
+static int safe_usermode(int new_usermode, bool warn)
+{
+       /*
+        * ARMv6 and later CPUs can perform unaligned accesses for
+        * most single load and store instructions up to word size.
+        * LDM, STM, LDRD and STRD still need to be handled.
+        *
+        * Ignoring the alignment fault is not an option on these
+        * CPUs since we spin re-faulting the instruction without
+        * making any progress.
+        */
+       if (cpu_is_v6_unaligned() && !(new_usermode & (UM_FIXUP | UM_SIGNAL))) {
+               new_usermode |= UM_FIXUP;
+
+               if (warn)
+                       printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU.  Defaulting to fixup mode.\n");
+       }
+
+       return new_usermode;
+}
+
 static int alignment_proc_show(struct seq_file *m, void *v)
 {
        seq_printf(m, "User:\t\t%lu\n", ai_user);
@@ -125,7 +153,7 @@ static ssize_t alignment_proc_write(struct file *file, const char __user *buffer
                if (get_user(mode, buffer))
                        return -EFAULT;
                if (mode >= '0' && mode <= '5')
-                       ai_usermode = mode - '0';
+                       ai_usermode = safe_usermode(mode - '0', true);
        }
        return count;
 }
@@ -886,9 +914,16 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (ai_usermode & UM_FIXUP)
                goto fixup;
 
-       if (ai_usermode & UM_SIGNAL)
-               force_sig(SIGBUS, current);
-       else {
+       if (ai_usermode & UM_SIGNAL) {
+               siginfo_t si;
+
+               si.si_signo = SIGBUS;
+               si.si_errno = 0;
+               si.si_code = BUS_ADRALN;
+               si.si_addr = (void __user *)addr;
+
+               force_sig_info(si.si_signo, &si, current);
+       } else {
                /*
                 * We're about to disable the alignment trap and return to
                 * user space.  But if an interrupt occurs before actually
@@ -926,20 +961,11 @@ static int __init alignment_init(void)
                return -ENOMEM;
 #endif
 
-       /*
-        * ARMv6 and later CPUs can perform unaligned accesses for
-        * most single load and store instructions up to word size.
-        * LDM, STM, LDRD and STRD still need to be handled.
-        *
-        * Ignoring the alignment fault is not an option on these
-        * CPUs since we spin re-faulting the instruction without
-        * making any progress.
-        */
-       if (cpu_architecture() >= CPU_ARCH_ARMv6 && (cr_alignment & CR_U)) {
+       if (cpu_is_v6_unaligned()) {
                cr_alignment &= ~CR_A;
                cr_no_alignment &= ~CR_A;
                set_cr(cr_alignment);
-               ai_usermode = UM_FIXUP;
+               ai_usermode = safe_usermode(ai_usermode, false);
        }
 
        hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
index 2fee782..91bca35 100644 (file)
@@ -441,7 +441,7 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s)
 static inline void poison_init_mem(void *s, size_t count)
 {
        u32 *p = (u32 *)s;
-       while ((count = count - 4))
+       for (; count != 0; count -= 4)
                *p++ = 0xe7fddef0;
 }
 
index f8f7ea3..683af3a 100644 (file)
@@ -410,6 +410,7 @@ __arm946_proc_info:
        .long   0x41009460
        .long   0xff00fff0
        .long   0
+       .long   0
        b       __arm946_setup
        .long   cpu_arch_name
        .long   cpu_elf_name
@@ -418,6 +419,6 @@ __arm946_proc_info:
        .long   arm946_processor_functions
        .long   0
        .long   0
-       .long   arm940_cache_fns
+       .long   arm946_cache_fns
        .size   __arm946_proc_info, . - __arm946_proc_info
 
index 91fc7cd..e4dde91 100644 (file)
 #define UART_PADDR     MX51_UART1_BASE_ADDR
 #endif
 
+/* iMX50/53 have same addresses, but not iMX51 */
+#if defined(CONFIG_SOC_IMX50) || defined(CONFIG_SOC_IMX53)
+#ifdef UART_PADDR
+#error "CONFIG_DEBUG_LL is incompatible with multiple archs"
+#endif
+#define UART_PADDR     MX53_UART1_BASE_ADDR
+#endif
+
 #define UART_VADDR     IMX_IO_ADDRESS(UART_PADDR)
 
                .macro  addruart, rp, rv
index 9440b9e..5408fd1 100644 (file)
@@ -30,6 +30,9 @@
 #define MX53_SDHC_PAD_CTRL     (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
                                PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_HIGH | \
                                PAD_CTL_SRE_FAST)
+#define PAD_CTRL_I2C   (PAD_CTL_SRE_FAST | PAD_CTL_ODE | PAD_CTL_PKE | \
+                       PAD_CTL_PUE | PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP \
+                       | PAD_CTL_HYS)
 
 #define _MX53_PAD_GPIO_19__KPP_COL_5           IOMUX_PAD(0x348, 0x20, 0, 0x840, 0, 0)
 #define _MX53_PAD_GPIO_19__GPIO4_5             IOMUX_PAD(0x348, 0x20, 1, 0x0, 0, 0)
 #define MX53_PAD_KEY_COL3__GPIO4_12            (_MX53_PAD_KEY_COL3__GPIO4_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__USBOH3_H2_DP                (_MX53_PAD_KEY_COL3__USBOH3_H2_DP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__SPDIF_IN1           (_MX53_PAD_KEY_COL3__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_KEY_COL3__I2C2_SCL            (_MX53_PAD_KEY_COL3__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__I2C2_SCL            (_MX53_PAD_KEY_COL3__I2C2_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_KEY_COL3__ECSPI1_SS3          (_MX53_PAD_KEY_COL3__ECSPI1_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__FEC_CRS             (_MX53_PAD_KEY_COL3__FEC_CRS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK            (_MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__GPIO4_13            (_MX53_PAD_KEY_ROW3__GPIO4_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__USBOH3_H2_DM                (_MX53_PAD_KEY_ROW3__USBOH3_H2_DM | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK            (_MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_KEY_ROW3__I2C2_SDA            (_MX53_PAD_KEY_ROW3__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__I2C2_SDA            (_MX53_PAD_KEY_ROW3__I2C2_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_KEY_ROW3__OSC32K_32K_OUT              (_MX53_PAD_KEY_ROW3__OSC32K_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__CCM_PLL4_BYP                (_MX53_PAD_KEY_ROW3__CCM_PLL4_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0         (_MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__KPP_COL_7          (_MX53_PAD_CSI0_DAT8__KPP_COL_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__ECSPI2_SCLK                (_MX53_PAD_CSI0_DAT8__ECSPI2_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC            (_MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_CSI0_DAT8__I2C1_SDA           (_MX53_PAD_CSI0_DAT8__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__I2C1_SDA           (_MX53_PAD_CSI0_DAT8__I2C1_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37           (_MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT8__TPIU_TRACE_5               (_MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9               (_MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__KPP_ROW_7          (_MX53_PAD_CSI0_DAT9__KPP_ROW_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__ECSPI2_MOSI                (_MX53_PAD_CSI0_DAT9__ECSPI2_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR           (_MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_CSI0_DAT9__I2C1_SCL           (_MX53_PAD_CSI0_DAT9__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__I2C1_SCL           (_MX53_PAD_CSI0_DAT9__I2C1_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38           (_MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT9__TPIU_TRACE_6               (_MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10             (_MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK              (_MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS             (_MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_EB2__ECSPI1_SS0           (_MX53_PAD_EIM_EB2__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_EB2__I2C2_SCL             (_MX53_PAD_EIM_EB2__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__I2C2_SCL             (_MX53_PAD_EIM_EB2__I2C2_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D16__EMI_WEIM_D_16                (_MX53_PAD_EIM_D16__EMI_WEIM_D_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__GPIO3_16             (_MX53_PAD_EIM_D16__GPIO3_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__IPU_DI0_PIN5         (_MX53_PAD_EIM_D16__IPU_DI0_PIN5 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK           (_MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D16__ECSPI1_SCLK          (_MX53_PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D16__I2C2_SDA             (_MX53_PAD_EIM_D16__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__I2C2_SDA             (_MX53_PAD_EIM_D16__I2C2_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D17__EMI_WEIM_D_17                (_MX53_PAD_EIM_D17__EMI_WEIM_D_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__GPIO3_17             (_MX53_PAD_EIM_D17__GPIO3_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__IPU_DI0_PIN6         (_MX53_PAD_EIM_D17__IPU_DI0_PIN6 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN           (_MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D17__ECSPI1_MISO          (_MX53_PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D17__I2C3_SCL             (_MX53_PAD_EIM_D17__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__I2C3_SCL             (_MX53_PAD_EIM_D17__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D18__EMI_WEIM_D_18                (_MX53_PAD_EIM_D18__EMI_WEIM_D_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__GPIO3_18             (_MX53_PAD_EIM_D18__GPIO3_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__IPU_DI0_PIN7         (_MX53_PAD_EIM_D18__IPU_DI0_PIN7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO           (_MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D18__ECSPI1_MOSI          (_MX53_PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D18__I2C3_SDA             (_MX53_PAD_EIM_D18__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__I2C3_SDA             (_MX53_PAD_EIM_D18__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D18__IPU_DI1_D0_CS                (_MX53_PAD_EIM_D18__IPU_DI1_D0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D19__EMI_WEIM_D_19                (_MX53_PAD_EIM_D19__EMI_WEIM_D_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D19__GPIO3_19             (_MX53_PAD_EIM_D19__GPIO3_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__IPU_DI0_PIN17                (_MX53_PAD_EIM_D21__IPU_DI0_PIN17 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK           (_MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D21__CSPI_SCLK            (_MX53_PAD_EIM_D21__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D21__I2C1_SCL             (_MX53_PAD_EIM_D21__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__I2C1_SCL             (_MX53_PAD_EIM_D21__I2C1_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D21__USBOH3_USBOTG_OC             (_MX53_PAD_EIM_D21__USBOH3_USBOTG_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D22__EMI_WEIM_D_22                (_MX53_PAD_EIM_D22__EMI_WEIM_D_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D22__GPIO3_22             (_MX53_PAD_EIM_D22__GPIO3_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__UART2_CTS            (_MX53_PAD_EIM_D28__UART2_CTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
 #define MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO           (_MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__CSPI_MOSI            (_MX53_PAD_EIM_D28__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_EIM_D28__I2C1_SDA             (_MX53_PAD_EIM_D28__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__I2C1_SDA             (_MX53_PAD_EIM_D28__I2C1_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_EIM_D28__IPU_EXT_TRIG         (_MX53_PAD_EIM_D28__IPU_EXT_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D28__IPU_DI0_PIN13                (_MX53_PAD_EIM_D28__IPU_DI0_PIN13 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_EIM_D29__EMI_WEIM_D_29                (_MX53_PAD_EIM_D29__EMI_WEIM_D_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_9__SCC_FAIL_STATE                (_MX53_PAD_GPIO_9__SCC_FAIL_STATE | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__ESAI1_HCKR            (_MX53_PAD_GPIO_3__ESAI1_HCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__GPIO1_3               (_MX53_PAD_GPIO_3__GPIO1_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_3__I2C3_SCL              (_MX53_PAD_GPIO_3__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__I2C3_SCL              (_MX53_PAD_GPIO_3__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_3__DPLLIP1_TOG_EN                (_MX53_PAD_GPIO_3__DPLLIP1_TOG_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__CCM_CLKO2             (_MX53_PAD_GPIO_3__CCM_CLKO2 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0            (_MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_3__MLB_MLBCLK            (_MX53_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__ESAI1_SCKT            (_MX53_PAD_GPIO_6__ESAI1_SCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__GPIO1_6               (_MX53_PAD_GPIO_6__GPIO1_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_6__I2C3_SDA              (_MX53_PAD_GPIO_6__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__I2C3_SDA              (_MX53_PAD_GPIO_6__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_6__CCM_CCM_OUT_0         (_MX53_PAD_GPIO_6__CCM_CCM_OUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__CSU_CSU_INT_DEB               (_MX53_PAD_GPIO_6__CSU_CSU_INT_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1            (_MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__CCM_CLKO              (_MX53_PAD_GPIO_5__CCM_CLKO | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2           (_MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4            (_MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_5__I2C3_SCL              (_MX53_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__I2C3_SCL              (_MX53_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_5__CCM_PLL1_BYP          (_MX53_PAD_GPIO_5__CCM_PLL1_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_7__ESAI1_TX4_RX1         (_MX53_PAD_GPIO_7__ESAI1_TX4_RX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_7__GPIO1_7               (_MX53_PAD_GPIO_7__GPIO1_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT             (_MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1         (_MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_16__SPDIF_IN1            (_MX53_PAD_GPIO_16__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX53_PAD_GPIO_16__I2C3_SDA             (_MX53_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__I2C3_SDA             (_MX53_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(PAD_CTRL_I2C))
 #define MX53_PAD_GPIO_16__SJC_DE_B             (_MX53_PAD_GPIO_16__SJC_DE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_17__ESAI1_TX0            (_MX53_PAD_GPIO_17__ESAI1_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
 #define MX53_PAD_GPIO_17__GPIO7_12             (_MX53_PAD_GPIO_17__GPIO7_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
index 6e6735f..bb8f4a6 100644 (file)
@@ -13,6 +13,7 @@ config ARCH_OMAP1
        bool "TI OMAP1"
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
+       select GENERIC_IRQ_CHIP
        help
          "Systems based on omap7xx, omap15xx or omap16xx"
 
index d1c916f..dc562a5 100644 (file)
 
 #define OMAP36XX_DMA_UART4_TX          81      /* S_DMA_80 */
 #define OMAP36XX_DMA_UART4_RX          82      /* S_DMA_81 */
+
+/* Only for AM35xx */
+#define AM35XX_DMA_UART4_TX            54
+#define AM35XX_DMA_UART4_RX            55
+
 /*----------------------------------------------------------------------------*/
 
 #define OMAP1_DMA_TOUT_IRQ             (1 << 0)
index 926d25c..30e1071 100644 (file)
 #define INT_35XX_EMAC_C0_TX_PULSE_IRQ  69
 #define INT_35XX_EMAC_C0_MISC_PULSE_IRQ        70
 #define INT_35XX_USBOTG_IRQ            71
+#define INT_35XX_UART4                 84
 #define INT_35XX_CCDC_VD0_IRQ          88
 #define INT_35XX_CCDC_VD1_IRQ          92
 #define INT_35XX_CCDC_VD2_IRQ          93
index 2723f91..de3b10c 100644 (file)
@@ -56,6 +56,9 @@
 #define TI816X_UART2_BASE      0x48022000
 #define TI816X_UART3_BASE      0x48024000
 
+/* AM3505/3517 UART4 */
+#define AM35XX_UART4_BASE      0x4809E000      /* Only on AM3505/3517 */
+
 /* External port on Zoom2/3 */
 #define ZOOM_UART_BASE         0x10000000
 #define ZOOM_UART_VIRT         0xfa400000
index c60737c..79e7fed 100644 (file)
@@ -423,9 +423,6 @@ static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, u32 da,
 {
        unsigned int i;
        struct scatterlist *sg;
-       void *va;
-
-       va = phys_to_virt(pa);
 
        for_each_sg(sgt->sgl, sg, sgt->nents, i) {
                unsigned bytes;
index 3b3776d..fff68d0 100644 (file)
@@ -910,7 +910,7 @@ omapl138_case_a3    MACH_OMAPL138_CASE_A3   OMAPL138_CASE_A3        3280
 uemd                   MACH_UEMD               UEMD                    3281
 ccwmx51mut             MACH_CCWMX51MUT         CCWMX51MUT              3282
 rockhopper             MACH_ROCKHOPPER         ROCKHOPPER              3283
-nookcolor              MACH_NOOKCOLOR          NOOKCOLOR               3284
+encore                 MACH_ENCORE             ENCORE                  3284
 hkdkc100               MACH_HKDKC100           HKDKC100                3285
 ts42xx                 MACH_TS42XX             TS42XX                  3286
 aebl                   MACH_AEBL               AEBL                    3287
index 1248547..3ff7785 100644 (file)
@@ -162,7 +162,6 @@ config IA64_GENERIC
        select ACPI_NUMA
        select SWIOTLB
        select PCI_MSI
-       select DMAR
        help
          This selects the system type of your hardware.  A "generic" kernel
          will run on any supported IA-64 system.  However, if you configure
index 1d7bca0..0e5cd14 100644 (file)
@@ -234,3 +234,4 @@ CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_T10DIF=y
 CONFIG_MISC_DEVICES=y
+CONFIG_DMAR=y
index 1f780b9..938986e 100644 (file)
@@ -22,7 +22,6 @@ static __always_inline bool arch_static_branch(struct jump_label_key *key)
        asm goto("1:\n\t"
                 "nop\n\t"
                 ".pushsection __jump_table,  \"aw\"\n\t"
-                ".align 4\n\t"
                 JUMP_ENTRY_TYPE "1b, %l[l_yes], %c0\n\t"
                 ".popsection \n\t"
                 : :  "i" (key) : : l_yes);
@@ -41,7 +40,6 @@ struct jump_entry {
        jump_label_t code;
        jump_label_t target;
        jump_label_t key;
-       jump_label_t pad;
 };
 
 #endif /* _ASM_POWERPC_JUMP_LABEL_H */
index 6857af5..bffd062 100644 (file)
@@ -3,17 +3,7 @@
 
 #include <asm/page.h>
 
-/*
- * If CONFIG_RELOCATABLE is enabled we can place the kdump kernel anywhere.
- * To keep enough space in the RMO for the first stage kernel on 64bit, we
- * place it at 64MB. If CONFIG_RELOCATABLE is not enabled we must place
- * the second stage at 32MB.
- */
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC64)
-#define KDUMP_KERNELBASE       0x4000000
-#else
 #define KDUMP_KERNELBASE       0x2000000
-#endif
 
 /* How many bytes to reserve at zero for kdump. The reserve limit should
  * be greater or equal to the trampoline's end address.
index e8aaf6f..559da19 100644 (file)
 #define PV_970         0x0039
 #define PV_POWER5      0x003A
 #define PV_POWER5p     0x003B
-#define PV_POWER7      0x003F
 #define PV_970FX       0x003C
 #define PV_POWER6      0x003E
 #define PV_POWER7      0x003F
 #define mtmsrd(v)      __mtmsrd((v), 0)
 #define mtmsr(v)       mtmsrd(v)
 #else
-#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v) : "memory")
+#define mtmsr(v)       asm volatile("mtmsr %0" : \
+                                    : "r" ((unsigned long)(v)) \
+                                    : "memory")
 #endif
 
 #define mfspr(rn)      ({unsigned long rval; \
                        asm volatile("mfspr %0," __stringify(rn) \
                                : "=r" (rval)); rval;})
-#define mtspr(rn, v)   asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v)\
+#define mtspr(rn, v)   asm volatile("mtspr " __stringify(rn) ",%0" : \
+                                    : "r" ((unsigned long)(v)) \
                                     : "memory")
 
 #ifdef __powerpc64__
index 9fb9332..fa44ff5 100644 (file)
@@ -2051,7 +2051,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
 
 static struct cpu_spec the_cpu_spec;
 
-static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
+static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
+                                              struct cpu_spec *s)
 {
        struct cpu_spec *t = &the_cpu_spec;
        struct cpu_spec old;
@@ -2114,6 +2115,8 @@ static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
                t->cpu_setup(offset, t);
        }
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
+
+       return t;
 }
 
 struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
@@ -2124,10 +2127,8 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr)
        s = PTRRELOC(s);
 
        for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) {
-               if ((pvr & s->pvr_mask) == s->pvr_value) {
-                       setup_cpu_spec(offset, s);
-                       return s;
-               }
+               if ((pvr & s->pvr_mask) == s->pvr_value)
+                       return setup_cpu_spec(offset, s);
        }
 
        BUG();
index 1577434..b25f632 100644 (file)
@@ -117,6 +117,7 @@ void ioport_unmap(void __iomem *addr)
 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);
@@ -146,3 +147,4 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
 
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
+#endif /* CONFIG_PCI */
index 6658a15..9ce1672 100644 (file)
@@ -136,12 +136,16 @@ void __init reserve_crashkernel(void)
        crashk_res.start = KDUMP_KERNELBASE;
 #else
        if (!crashk_res.start) {
+#ifdef CONFIG_PPC64
                /*
-                * unspecified address, choose a region of specified size
-                * can overlap with initrd (ignoring corruption when retained)
-                * ppc64 requires kernel and some stacks to be in first segemnt
+                * On 64bit we split the RMO in half but cap it at half of
+                * a small SLB (128MB) since the crash kernel needs to place
+                * itself and some stacks to be in the first segment.
                 */
+               crashk_res.start = min(0x80000000ULL, (ppc64_rma_size / 2));
+#else
                crashk_res.start = KDUMP_KERNELBASE;
+#endif
        }
 
        crash_base = PAGE_ALIGN(crashk_res.start);
index d05ae42..564c1d8 100644 (file)
@@ -154,8 +154,12 @@ static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
            ((unsigned long)ptr & 7))
                return -EFAULT;
 
-       if (!__get_user_inatomic(*ret, ptr))
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
                return 0;
+       }
+       pagefault_enable();
 
        return read_user_stack_slow(ptr, ret, 8);
 }
@@ -166,8 +170,12 @@ static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
            ((unsigned long)ptr & 3))
                return -EFAULT;
 
-       if (!__get_user_inatomic(*ret, ptr))
+       pagefault_disable();
+       if (!__get_user_inatomic(*ret, ptr)) {
+               pagefault_enable();
                return 0;
+       }
+       pagefault_enable();
 
        return read_user_stack_slow(ptr, ret, 4);
 }
@@ -294,11 +302,17 @@ static inline int current_is_64bit(void)
  */
 static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
 {
+       int rc;
+
        if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
            ((unsigned long)ptr & 3))
                return -EFAULT;
 
-       return __get_user_inatomic(*ret, ptr);
+       pagefault_disable();
+       rc = __get_user_inatomic(*ret, ptr);
+       pagefault_enable();
+
+       return rc;
 }
 
 static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
index c016033..a909f4e 100644 (file)
@@ -1020,7 +1020,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
        }
        if (addr == 0)
                return 0;
-       RELOC(alloc_bottom) = addr;
+       RELOC(alloc_bottom) = addr + size;
 
        prom_debug(" -> %x\n", addr);
        prom_debug("  alloc_bottom : %x\n", RELOC(alloc_bottom));
@@ -1830,11 +1830,13 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
                if (room > DEVTREE_CHUNK_SIZE)
                        room = DEVTREE_CHUNK_SIZE;
                if (room < PAGE_SIZE)
-                       prom_panic("No memory for flatten_device_tree (no room)");
+                       prom_panic("No memory for flatten_device_tree "
+                                  "(no room)\n");
                chunk = alloc_up(room, 0);
                if (chunk == 0)
-                       prom_panic("No memory for flatten_device_tree (claim failed)");
-               *mem_end = RELOC(alloc_top);
+                       prom_panic("No memory for flatten_device_tree "
+                                  "(claim failed)\n");
+               *mem_end = chunk + room;
        }
 
        ret = (void *)*mem_start;
@@ -2042,7 +2044,7 @@ static void __init flatten_device_tree(void)
 
        /*
         * Check how much room we have between alloc top & bottom (+/- a
-        * few pages), crop to 4Mb, as this is our "chuck" size
+        * few pages), crop to 1MB, as this is our "chunk" size
         */
        room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
        if (room > DEVTREE_CHUNK_SIZE)
@@ -2053,7 +2055,7 @@ static void __init flatten_device_tree(void)
        mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
        if (mem_start == 0)
                prom_panic("Can't allocate initial device-tree chunk\n");
-       mem_end = RELOC(alloc_top);
+       mem_end = mem_start + room;
 
        /* Get root of tree */
        root = call_prom("peer", 1, 1, (phandle)0);
index 6dd3358..de29501 100644 (file)
@@ -1251,7 +1251,7 @@ BEGIN_FTR_SECTION
        reg = 0
        .rept   32
        li      r6,reg*16+VCPU_VSRS
-       stxvd2x reg,r6,r3
+       STXVD2X(reg,r6,r3)
        reg = reg + 1
        .endr
 FTR_SECTION_ELSE
@@ -1313,7 +1313,7 @@ BEGIN_FTR_SECTION
        reg = 0
        .rept   32
        li      r7,reg*16+VCPU_VSRS
-       lxvd2x  reg,r7,r4
+       LXVD2X(reg,r7,r4)
        reg = reg + 1
        .endr
 FTR_SECTION_ELSE
index d0af7fb..b9ba861 100644 (file)
@@ -24,7 +24,7 @@ source "arch/powerpc/platforms/wsp/Kconfig"
 
 config KVM_GUEST
        bool "KVM Guest support"
-       default y
+       default n
        ---help---
          This option enables various optimizations for running under the KVM
          hypervisor. Overhead for the kernel when not running inside KVM should
index e919007..0e86563 100644 (file)
@@ -181,7 +181,7 @@ static void dtl_stop(struct dtl *dtl)
 
        lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
 
-       unregister_dtl(hwcpu, __pa(dtl->buf));
+       unregister_dtl(hwcpu);
 }
 
 static u64 dtl_current_index(struct dtl *dtl)
index bc02885..83a3ca2 100644 (file)
@@ -135,7 +135,7 @@ static void pseries_mach_cpu_die(void)
                get_lppaca()->idle = 0;
 
                if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) {
-                       unregister_slb_shadow(hwcpu, __pa(get_slb_shadow()));
+                       unregister_slb_shadow(hwcpu);
 
                        /*
                         * Call to start_secondary_resume() will not return.
@@ -150,7 +150,7 @@ static void pseries_mach_cpu_die(void)
        WARN_ON(get_preferred_offline_state(cpu) != CPU_STATE_OFFLINE);
 
        set_cpu_current_state(cpu, CPU_STATE_OFFLINE);
-       unregister_slb_shadow(hwcpu, __pa(get_slb_shadow()));
+       unregister_slb_shadow(hwcpu);
        rtas_stop_self();
 
        /* Should never get here... */
index c829e60..2c4dd1f 100644 (file)
@@ -212,17 +212,15 @@ static int __init ioei_init(void)
        struct device_node *np;
 
        ioei_check_exception_token = rtas_token("check-exception");
-       if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) {
-               pr_warning("IO Event IRQ not supported on this system !\n");
+       if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE)
                return -ENODEV;
-       }
+
        np = of_find_node_by_path("/event-sources/ibm,io-events");
        if (np) {
                request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
+               pr_info("IBM I/O event interrupts enabled\n");
                of_node_put(np);
        } else {
-               pr_err("io_event_irq: No ibm,io-events on system! "
-                      "IO Event interrupt disabled.\n");
                return -ENODEV;
        }
        return 0;
index 54cf3a4..7d94bdc 100644 (file)
@@ -25,20 +25,30 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
 {
        /* Don't risk a hypervisor call if we're crashing */
        if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
-               unsigned long addr;
+               int ret;
+               int cpu = smp_processor_id();
+               int hwcpu = hard_smp_processor_id();
 
-               addr = __pa(get_slb_shadow());
-               if (unregister_slb_shadow(hard_smp_processor_id(), addr))
-                       printk("SLB shadow buffer deregistration of "
-                              "cpu %u (hw_cpu_id %d) failed\n",
-                              smp_processor_id(),
-                              hard_smp_processor_id());
+               if (get_lppaca()->dtl_enable_mask) {
+                       ret = unregister_dtl(hwcpu);
+                       if (ret) {
+                               pr_err("WARNING: DTL deregistration for cpu "
+                                      "%d (hw %d) failed with %d\n",
+                                      cpu, hwcpu, ret);
+                       }
+               }
+
+               ret = unregister_slb_shadow(hwcpu);
+               if (ret) {
+                       pr_err("WARNING: SLB shadow buffer deregistration "
+                              "for cpu %d (hw %d) failed with %d\n",
+                              cpu, hwcpu, ret);
+               }
 
-               addr = __pa(get_lppaca());
-               if (unregister_vpa(hard_smp_processor_id(), addr)) {
-                       printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
-                                       "failed\n", smp_processor_id(),
-                                       hard_smp_processor_id());
+               ret = unregister_vpa(hwcpu);
+               if (ret) {
+                       pr_err("WARNING: VPA deregistration for cpu %d "
+                              "(hw %d) failed with %d\n", cpu, hwcpu, ret);
                }
        }
 }
index f7205d3..c9a29da 100644 (file)
@@ -67,9 +67,8 @@ void vpa_init(int cpu)
        ret = register_vpa(hwcpu, addr);
 
        if (ret) {
-               printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
-                               "cpu %d (hw %d) of area %lx returns %ld\n",
-                               cpu, hwcpu, addr, ret);
+               pr_err("WARNING: VPA registration for cpu %d (hw %d) of area "
+                      "%lx failed with %ld\n", cpu, hwcpu, addr, ret);
                return;
        }
        /*
@@ -80,10 +79,9 @@ void vpa_init(int cpu)
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                ret = register_slb_shadow(hwcpu, addr);
                if (ret)
-                       printk(KERN_ERR
-                              "WARNING: vpa_init: SLB shadow buffer "
-                              "registration for cpu %d (hw %d) of area %lx "
-                              "returns %ld\n", cpu, hwcpu, addr, ret);
+                       pr_err("WARNING: SLB shadow buffer registration for "
+                              "cpu %d (hw %d) of area %lx failed with %ld\n",
+                              cpu, hwcpu, addr, ret);
        }
 
        /*
@@ -100,8 +98,9 @@ void vpa_init(int cpu)
                dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
                ret = register_dtl(hwcpu, __pa(dtl));
                if (ret)
-                       pr_warn("DTL registration failed for cpu %d (%ld)\n",
-                               cpu, ret);
+                       pr_err("WARNING: DTL registration of cpu %d (hw %d) "
+                              "failed with %ld\n", smp_processor_id(),
+                              hwcpu, ret);
                lppaca_of(cpu).dtl_enable_mask = 2;
        }
 }
@@ -204,7 +203,7 @@ static void pSeries_lpar_hptab_clear(void)
                unsigned long ptel;
        } ptes[4];
        long lpar_rc;
-       int i, j;
+       unsigned long i, j;
 
        /* Read in batches of 4,
         * invalidate only valid entries not in the VRMA
index 4bf2120..41c24c1 100644 (file)
@@ -53,9 +53,9 @@ static inline long vpa_call(unsigned long flags, unsigned long cpu,
        return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
 }
 
-static inline long unregister_vpa(unsigned long cpu, unsigned long vpa)
+static inline long unregister_vpa(unsigned long cpu)
 {
-       return vpa_call(0x5, cpu, vpa);
+       return vpa_call(0x5, cpu, 0);
 }
 
 static inline long register_vpa(unsigned long cpu, unsigned long vpa)
@@ -63,9 +63,9 @@ static inline long register_vpa(unsigned long cpu, unsigned long vpa)
        return vpa_call(0x1, cpu, vpa);
 }
 
-static inline long unregister_slb_shadow(unsigned long cpu, unsigned long vpa)
+static inline long unregister_slb_shadow(unsigned long cpu)
 {
-       return vpa_call(0x7, cpu, vpa);
+       return vpa_call(0x7, cpu, 0);
 }
 
 static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
@@ -73,9 +73,9 @@ static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
        return vpa_call(0x3, cpu, vpa);
 }
 
-static inline long unregister_dtl(unsigned long cpu, unsigned long vpa)
+static inline long unregister_dtl(unsigned long cpu)
 {
-       return vpa_call(0x6, cpu, vpa);
+       return vpa_call(0x6, cpu, 0);
 }
 
 static inline long register_dtl(unsigned long cpu, unsigned long vpa)
index d00e529..0969fd9 100644 (file)
@@ -324,8 +324,9 @@ static int alloc_dispatch_logs(void)
        dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
        ret = register_dtl(hard_smp_processor_id(), __pa(dtl));
        if (ret)
-               pr_warn("DTL registration failed for boot cpu %d (%d)\n",
-                       smp_processor_id(), ret);
+               pr_err("WARNING: DTL registration of cpu %d (hw %d) failed "
+                      "with %d\n", smp_processor_id(),
+                      hard_smp_processor_id(), ret);
        get_paca()->lppaca_ptr->dtl_enable_mask = 2;
 
        return 0;
index a59ba96..dbfe96b 100644 (file)
@@ -655,8 +655,6 @@ struct ppc4xx_pciex_hwops
 
 static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
 
-#ifdef CONFIG_44x
-
 static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
                                           unsigned int sdr_offset,
                                           unsigned int mask,
@@ -688,6 +686,7 @@ static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port)
        return 0;
 }
 
+
 static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
 {
        printk(KERN_INFO "PCIE%d: Checking link...\n", port->index);
@@ -718,6 +717,8 @@ static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port)
                printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
 }
 
+#ifdef CONFIG_44x
+
 /* Check various reset bits of the 440SPe PCIe core */
 static int __init ppc440spe_pciex_check_reset(struct device_node *np)
 {
index 42c67be..1a6f20d 100644 (file)
@@ -55,6 +55,7 @@ config SPARC64
        select PERF_USE_VMALLOC
        select IRQ_PREFLOW_FASTEOI
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select HAVE_C_RECORDMCOUNT
 
 config ARCH_DEFCONFIG
        string
index 5f5b8bf..bcc98fc 100644 (file)
@@ -131,6 +131,15 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
        *(volatile __u32 *)&lp->lock = ~0U;
 }
 
+static void inline arch_write_unlock(arch_rwlock_t *lock)
+{
+       __asm__ __volatile__(
+"      st              %%g0, [%0]"
+       : /* no outputs */
+       : "r" (lock)
+       : "memory");
+}
+
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
        unsigned int val;
@@ -175,8 +184,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw)
        res; \
 })
 
-#define arch_write_unlock(rw)  do { (rw)->lock = 0; } while(0)
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_read_lock_flags(rw, flags)   arch_read_lock(rw)
 #define arch_write_lock_flags(rw, flags)  arch_write_lock(rw)
index 073936a..9689176 100644 (file)
@@ -210,14 +210,8 @@ static int inline arch_write_trylock(arch_rwlock_t *lock)
        return result;
 }
 
-#define arch_read_lock(p)      arch_read_lock(p)
 #define arch_read_lock_flags(p, f) arch_read_lock(p)
-#define arch_read_trylock(p)   arch_read_trylock(p)
-#define arch_read_unlock(p)    arch_read_unlock(p)
-#define arch_write_lock(p)     arch_write_lock(p)
 #define arch_write_lock_flags(p, f) arch_write_lock(p)
-#define arch_write_unlock(p)   arch_write_unlock(p)
-#define arch_write_trylock(p)  arch_write_trylock(p)
 
 #define arch_read_can_lock(rw)         (!((rw)->lock & 0x80000000UL))
 #define arch_write_can_lock(rw)        (!(rw)->lock)
index 490e541..7429b47 100644 (file)
@@ -1256,13 +1256,14 @@ static int __init ds_init(void)
 {
        unsigned long hv_ret, major, minor;
 
-       hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
-       if (hv_ret == HV_EOK) {
-               pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
-                       major, minor);
-               reboot_data_supported = 1;
+       if (tlb_type == hypervisor) {
+               hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
+               if (hv_ret == HV_EOK) {
+                       pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
+                               major, minor);
+                       reboot_data_supported = 1;
+               }
        }
-
        kthread_run(ds_thread, NULL, "kldomd");
 
        return vio_register_driver(&ds_driver);
index 7b439d9..41935fa 100644 (file)
@@ -27,8 +27,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
 
        desc->base2             = (info->base_addr & 0xff000000) >> 24;
        /*
-        * Don't allow setting of the lm bit. It is useless anyway
-        * because 64bit system calls require __USER_CS:
+        * Don't allow setting of the lm bit. It would confuse
+        * user_64bit_mode and would get overridden by sysret anyway.
         */
        desc->l                 = 0;
 }
index f9a3209..7e50f06 100644 (file)
@@ -17,7 +17,6 @@
  *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
  *  Vectors  32 ... 127 : device interrupts
  *  Vector  128         : legacy int80 syscall interface
- *  Vector  204         : legacy x86_64 vsyscall emulation
  *  Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts
  *  Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
  *
@@ -51,9 +50,6 @@
 #ifdef CONFIG_X86_32
 # define SYSCALL_VECTOR                        0x80
 #endif
-#ifdef CONFIG_X86_64
-# define VSYSCALL_EMU_VECTOR           0xcc
-#endif
 
 /*
  * Vectors 0x30-0x3f are used for ISA interrupts.
index 2c76521..8e8b9a4 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <asm/desc_defs.h>
 #include <asm/kmap_types.h>
+#include <asm/pgtable_types.h>
 
 struct page;
 struct thread_struct;
@@ -63,6 +64,11 @@ struct paravirt_callee_save {
 struct pv_info {
        unsigned int kernel_rpl;
        int shared_kernel_pmd;
+
+#ifdef CONFIG_X86_64
+       u16 extra_user_64bit_cs;  /* __USER_CS if none */
+#endif
+
        int paravirt_enabled;
        const char *name;
 };
index 94e7618..3566454 100644 (file)
@@ -131,6 +131,9 @@ struct pt_regs {
 #ifdef __KERNEL__
 
 #include <linux/init.h>
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt_types.h>
+#endif
 
 struct cpuinfo_x86;
 struct task_struct;
@@ -187,6 +190,22 @@ static inline int v8086_mode(struct pt_regs *regs)
 #endif
 }
 
+#ifdef CONFIG_X86_64
+static inline bool user_64bit_mode(struct pt_regs *regs)
+{
+#ifndef CONFIG_PARAVIRT
+       /*
+        * On non-paravirt systems, this is the only long mode CPL 3
+        * selector.  We do not allow long mode selectors in the LDT.
+        */
+       return regs->cs == __USER_CS;
+#else
+       /* Headers are too twisted for this to go in paravirt.h. */
+       return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
+#endif
+}
+#endif
+
 /*
  * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode
  * when it traps.  The previous stack will be directly underneath the saved
index 2bae0a5..0012d09 100644 (file)
@@ -40,7 +40,6 @@ asmlinkage void alignment_check(void);
 asmlinkage void machine_check(void);
 #endif /* CONFIG_X86_MCE */
 asmlinkage void simd_coprocessor_error(void);
-asmlinkage void emulate_vsyscall(void);
 
 dotraplinkage void do_divide_error(struct pt_regs *, long);
 dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +66,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long);
 dotraplinkage void do_machine_check(struct pt_regs *, long);
 #endif
 dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
-dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
index 705bf13..d92641c 100644 (file)
@@ -681,6 +681,8 @@ __SYSCALL(__NR_syncfs, sys_syncfs)
 __SYSCALL(__NR_sendmmsg, sys_sendmmsg)
 #define __NR_setns                             308
 __SYSCALL(__NR_setns, sys_setns)
+#define __NR_getcpu                            309
+__SYSCALL(__NR_getcpu, sys_getcpu)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 6010707..eaea1d3 100644 (file)
@@ -27,6 +27,12 @@ extern struct timezone sys_tz;
 
 extern void map_vsyscall(void);
 
+/*
+ * Called on instruction fetch fault in vsyscall page.
+ * Returns true if handled.
+ */
+extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_VSYSCALL_H */
index 0410557..82f2912 100644 (file)
@@ -17,19 +17,6 @@ CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_early_printk.o = -pg
 endif
 
-#
-# vsyscalls (which work on the user stack) should have
-# no stack-protector checks:
-#
-nostackp := $(call cc-option, -fno-stack-protector)
-CFLAGS_vsyscall_64.o   := $(PROFILING) -g0 $(nostackp)
-CFLAGS_hpet.o          := $(nostackp)
-CFLAGS_paravirt.o      := $(nostackp)
-GCOV_PROFILE_vsyscall_64.o     := n
-GCOV_PROFILE_hpet.o            := n
-GCOV_PROFILE_tsc.o             := n
-GCOV_PROFILE_paravirt.o                := n
-
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o
index 45fbb8f..f88af2c 100644 (file)
@@ -1590,6 +1590,7 @@ static __init int intel_pmu_init(void)
                break;
 
        case 42: /* SandyBridge */
+       case 45: /* SandyBridge, "Romely-EP" */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
index e13329d..6419bb0 100644 (file)
@@ -1111,7 +1111,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
 zeroentry coprocessor_error do_coprocessor_error
 errorentry alignment_check do_alignment_check
 zeroentry simd_coprocessor_error do_simd_coprocessor_error
-zeroentry emulate_vsyscall do_emulate_vsyscall
 
 
        /* Reload gs selector with exception handling */
index 613a793..d90272e 100644 (file)
@@ -307,6 +307,10 @@ struct pv_info pv_info = {
        .paravirt_enabled = 0,
        .kernel_rpl = 0,
        .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */
+
+#ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = __USER_CS,
+#endif
 };
 
 struct pv_init_ops pv_init_ops = {
index 7977f0c..c346d11 100644 (file)
@@ -74,7 +74,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
 
 #ifdef CONFIG_X86_64
                case 0x40 ... 0x4f:
-                       if (regs->cs != __USER_CS)
+                       if (!user_64bit_mode(regs))
                                /* 32-bit mode: register increment */
                                return 0;
                        /* 64-bit mode: REX prefix */
index 9682ec5..6913369 100644 (file)
@@ -872,12 +872,6 @@ void __init trap_init(void)
        set_bit(SYSCALL_VECTOR, used_vectors);
 #endif
 
-#ifdef CONFIG_X86_64
-       BUG_ON(test_bit(VSYSCALL_EMU_VECTOR, used_vectors));
-       set_system_intr_gate(VSYSCALL_EMU_VECTOR, &emulate_vsyscall);
-       set_bit(VSYSCALL_EMU_VECTOR, used_vectors);
-#endif
-
        /*
         * Should be a barrier for any external CPU state:
         */
index 4aa9c54..0f703f1 100644 (file)
@@ -71,7 +71,6 @@ PHDRS {
        text PT_LOAD FLAGS(5);          /* R_E */
        data PT_LOAD FLAGS(6);          /* RW_ */
 #ifdef CONFIG_X86_64
-       user PT_LOAD FLAGS(5);          /* R_E */
 #ifdef CONFIG_SMP
        percpu PT_LOAD FLAGS(6);        /* RW_ */
 #endif
@@ -154,44 +153,16 @@ SECTIONS
 
 #ifdef CONFIG_X86_64
 
-#define VSYSCALL_ADDR (-10*1024*1024)
-
-#define VLOAD_OFFSET (VSYSCALL_ADDR - __vsyscall_0 + LOAD_OFFSET)
-#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
-
-#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0)
-#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
-
-       . = ALIGN(4096);
-       __vsyscall_0 = .;
-
-       . = VSYSCALL_ADDR;
-       .vsyscall : AT(VLOAD(.vsyscall)) {
-               *(.vsyscall_0)
-
-               . = 1024;
-               *(.vsyscall_1)
-
-               . = 2048;
-               *(.vsyscall_2)
-
-               . = 4096;  /* Pad the whole page. */
-       } :user =0xcc
-       . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE);
-
-#undef VSYSCALL_ADDR
-#undef VLOAD_OFFSET
-#undef VLOAD
-#undef VVIRT_OFFSET
-#undef VVIRT
-
+       . = ALIGN(PAGE_SIZE);
        __vvar_page = .;
 
        .vvar : AT(ADDR(.vvar) - LOAD_OFFSET) {
+               /* work around gold bug 13023 */
+               __vvar_beginning_hack = .;
 
-             /* Place all vvars at the offsets in asm/vvar.h. */
-#define EMIT_VVAR(name, offset)                \
-               . = offset;             \
+               /* Place all vvars at the offsets in asm/vvar.h. */
+#define EMIT_VVAR(name, offset)                        \
+               . = __vvar_beginning_hack + offset;     \
                *(.vvar_ ## name)
 #define __VVAR_KERNEL_LDS
 #include <asm/vvar.h>
index dda7dff..18ae83d 100644 (file)
@@ -18,9 +18,6 @@
  *  use the vDSO.
  */
 
-/* Disable profiling for userspace code: */
-#define DISABLE_BRANCH_PROFILING
-
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/vgtod.h>
 #include <asm/traps.h>
 
+#define CREATE_TRACE_POINTS
+#include "vsyscall_trace.h"
+
 DEFINE_VVAR(int, vgetcpu_mode);
 DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
 {
        .lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
 };
 
+static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
+
+static int __init vsyscall_setup(char *str)
+{
+       if (str) {
+               if (!strcmp("emulate", str))
+                       vsyscall_mode = EMULATE;
+               else if (!strcmp("native", str))
+                       vsyscall_mode = NATIVE;
+               else if (!strcmp("none", str))
+                       vsyscall_mode = NONE;
+               else
+                       return -EINVAL;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+early_param("vsyscall", vsyscall_setup);
+
 void update_vsyscall_tz(void)
 {
        unsigned long flags;
@@ -100,7 +121,7 @@ static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
 
        printk("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
               level, tsk->comm, task_pid_nr(tsk),
-              message, regs->ip - 2, regs->cs,
+              message, regs->ip, regs->cs,
               regs->sp, regs->ax, regs->si, regs->di);
 }
 
@@ -118,46 +139,39 @@ static int addr_to_vsyscall_nr(unsigned long addr)
        return nr;
 }
 
-void dotraplinkage do_emulate_vsyscall(struct pt_regs *regs, long error_code)
+bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 {
        struct task_struct *tsk;
        unsigned long caller;
        int vsyscall_nr;
        long ret;
 
-       local_irq_enable();
-
        /*
-        * Real 64-bit user mode code has cs == __USER_CS.  Anything else
-        * is bogus.
+        * No point in checking CS -- the only way to get here is a user mode
+        * trap to a high address, which means that we're in 64-bit user code.
         */
-       if (regs->cs != __USER_CS) {
-               /*
-                * If we trapped from kernel mode, we might as well OOPS now
-                * instead of returning to some random address and OOPSing
-                * then.
-                */
-               BUG_ON(!user_mode(regs));
 
-               /* Compat mode and non-compat 32-bit CS should both segfault. */
-               warn_bad_vsyscall(KERN_WARNING, regs,
-                                 "illegal int 0xcc from 32-bit mode");
-               goto sigsegv;
+       WARN_ON_ONCE(address != regs->ip);
+
+       if (vsyscall_mode == NONE) {
+               warn_bad_vsyscall(KERN_INFO, regs,
+                                 "vsyscall attempted with vsyscall=none");
+               return false;
        }
 
-       /*
-        * x86-ism here: regs->ip points to the instruction after the int 0xcc,
-        * and int 0xcc is two bytes long.
-        */
-       vsyscall_nr = addr_to_vsyscall_nr(regs->ip - 2);
+       vsyscall_nr = addr_to_vsyscall_nr(address);
+
+       trace_emulate_vsyscall(vsyscall_nr);
+
        if (vsyscall_nr < 0) {
                warn_bad_vsyscall(KERN_WARNING, regs,
-                                 "illegal int 0xcc (exploit attempt?)");
+                                 "misaligned vsyscall (exploit attempt or buggy program) -- look up the vsyscall kernel parameter if you need a workaround");
                goto sigsegv;
        }
 
        if (get_user(caller, (unsigned long __user *)regs->sp) != 0) {
-               warn_bad_vsyscall(KERN_WARNING, regs, "int 0xcc with bad stack (exploit attempt?)");
+               warn_bad_vsyscall(KERN_WARNING, regs,
+                                 "vsyscall with bad stack (exploit attempt?)");
                goto sigsegv;
        }
 
@@ -202,13 +216,11 @@ void dotraplinkage do_emulate_vsyscall(struct pt_regs *regs, long error_code)
        regs->ip = caller;
        regs->sp += 8;
 
-       local_irq_disable();
-       return;
+       return true;
 
 sigsegv:
-       regs->ip -= 2;  /* The faulting instruction should be the int 0xcc. */
        force_sig(SIGSEGV, current);
-       local_irq_disable();
+       return true;
 }
 
 /*
@@ -256,15 +268,21 @@ cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
 
 void __init map_vsyscall(void)
 {
-       extern char __vsyscall_0;
-       unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
+       extern char __vsyscall_page;
+       unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
        extern char __vvar_page;
        unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page);
 
-       /* Note that VSYSCALL_MAPPED_PAGES must agree with the code below. */
-       __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
+       __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall,
+                    vsyscall_mode == NATIVE
+                    ? PAGE_KERNEL_VSYSCALL
+                    : PAGE_KERNEL_VVAR);
+       BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_FIRST_PAGE) !=
+                    (unsigned long)VSYSCALL_START);
+
        __set_fixmap(VVAR_PAGE, physaddr_vvar_page, PAGE_KERNEL_VVAR);
-       BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) != (unsigned long)VVAR_ADDRESS);
+       BUILD_BUG_ON((unsigned long)__fix_to_virt(VVAR_PAGE) !=
+                    (unsigned long)VVAR_ADDRESS);
 }
 
 static int __init vsyscall_init(void)
index ffa845e..c9596a9 100644 (file)
@@ -7,21 +7,31 @@
  */
 
 #include <linux/linkage.h>
+
 #include <asm/irq_vectors.h>
+#include <asm/page_types.h>
+#include <asm/unistd_64.h>
+
+__PAGE_ALIGNED_DATA
+       .globl __vsyscall_page
+       .balign PAGE_SIZE, 0xcc
+       .type __vsyscall_page, @object
+__vsyscall_page:
+
+       mov $__NR_gettimeofday, %rax
+       syscall
+       ret
 
-/* The unused parts of the page are filled with 0xcc by the linker script. */
+       .balign 1024, 0xcc
+       mov $__NR_time, %rax
+       syscall
+       ret
 
-.section .vsyscall_0, "a"
-ENTRY(vsyscall_0)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_0)
+       .balign 1024, 0xcc
+       mov $__NR_getcpu, %rax
+       syscall
+       ret
 
-.section .vsyscall_1, "a"
-ENTRY(vsyscall_1)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_1)
+       .balign 4096, 0xcc
 
-.section .vsyscall_2, "a"
-ENTRY(vsyscall_2)
-       int $VSYSCALL_EMU_VECTOR
-END(vsyscall_2)
+       .size __vsyscall_page, 4096
diff --git a/arch/x86/kernel/vsyscall_trace.h b/arch/x86/kernel/vsyscall_trace.h
new file mode 100644 (file)
index 0000000..a8b2ede
--- /dev/null
@@ -0,0 +1,29 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM vsyscall
+
+#if !defined(__VSYSCALL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __VSYSCALL_TRACE_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(emulate_vsyscall,
+
+           TP_PROTO(int nr),
+
+           TP_ARGS(nr),
+
+           TP_STRUCT__entry(__field(int, nr)),
+
+           TP_fast_assign(
+                          __entry->nr = nr;
+                          ),
+
+           TP_printk("nr = %d", __entry->nr)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../arch/x86/kernel
+#define TRACE_INCLUDE_FILE vsyscall_trace
+#include <trace/define_trace.h>
index 988724b..ff5790d 100644 (file)
@@ -22,6 +22,8 @@ config KVM
        depends on HAVE_KVM
        # for device assignment:
        depends on PCI
+       # for TASKSTATS/TASK_DELAY_ACCT:
+       depends on NET
        select PREEMPT_NOTIFIERS
        select MMU_NOTIFIER
        select ANON_INODES
@@ -31,6 +33,7 @@ config KVM
        select KVM_ASYNC_PF
        select USER_RETURN_NOTIFIER
        select KVM_MMIO
+       select TASKSTATS
        select TASK_DELAY_ACCT
        ---help---
          Support hosting fully virtualized guest machines using hardware
index 4d09df0..0d17c8c 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/traps.h>                 /* dotraplinkage, ...           */
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
 #include <asm/kmemcheck.h>             /* kmemcheck_*(), ...           */
+#include <asm/vsyscall.h>
 
 /*
  * Page fault error code bits:
@@ -105,7 +106,7 @@ check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr,
                 * but for now it's good enough to assume that long
                 * mode only uses well known segments or kernel.
                 */
-               return (!user_mode(regs)) || (regs->cs == __USER_CS);
+               return (!user_mode(regs) || user_64bit_mode(regs));
 #endif
        case 0x60:
                /* 0x64 thru 0x67 are valid prefixes in all modes. */
@@ -720,6 +721,18 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                if (is_errata100(regs, address))
                        return;
 
+#ifdef CONFIG_X86_64
+               /*
+                * Instruction fetch faults in the vsyscall page might need
+                * emulation.
+                */
+               if (unlikely((error_code & PF_INSTR) &&
+                            ((address & ~0xfff) == VSYSCALL_START))) {
+                       if (emulate_vsyscall(regs, address))
+                               return;
+               }
+#endif
+
                if (unlikely(show_unhandled_signals))
                        show_signal_msg(regs, error_code, address, tsk);
 
index 1b979c1..01f5e3b 100644 (file)
@@ -9,6 +9,7 @@ __PAGE_ALIGNED_DATA
 vdso_start:
        .incbin "arch/x86/vdso/vdso.so"
 vdso_end:
+       .align PAGE_SIZE /* extra data here leaks to userspace. */
 
 .previous
 
index 974a528..e2345af 100644 (file)
@@ -951,6 +951,10 @@ static const struct pv_info xen_info __initconst = {
        .paravirt_enabled = 1,
        .shared_kernel_pmd = 0,
 
+#ifdef CONFIG_X86_64
+       .extra_user_64bit_cs = FLAT_USER_CS64,
+#endif
+
        .name = "Xen",
 };
 
index f987bde..8cce339 100644 (file)
@@ -1916,6 +1916,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 # endif
 #else
        case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
+       case VVAR_PAGE:
 #endif
        case FIX_TEXT_POKE0:
        case FIX_TEXT_POKE1:
@@ -1956,7 +1957,8 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #ifdef CONFIG_X86_64
        /* Replicate changes to map the vsyscall page into the user
           pagetable vsyscall mapping. */
-       if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) {
+       if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) ||
+           idx == VVAR_PAGE) {
                unsigned long vaddr = __fix_to_virt(idx);
                set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
        }
index e18566a..1c37457 100644 (file)
@@ -460,6 +460,21 @@ static int pm_genpd_runtime_resume(struct device *dev)
        return 0;
 }
 
+/**
+ * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
+ */
+void pm_genpd_poweroff_unused(void)
+{
+       struct generic_pm_domain *genpd;
+
+       mutex_lock(&gpd_list_lock);
+
+       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
+               genpd_queue_power_off_work(genpd);
+
+       mutex_unlock(&gpd_list_lock);
+}
+
 #else
 
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
@@ -1255,18 +1270,3 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        list_add(&genpd->gpd_list_node, &gpd_list);
        mutex_unlock(&gpd_list_lock);
 }
-
-/**
- * pm_genpd_poweroff_unused - Power off all PM domains with no devices in use.
- */
-void pm_genpd_poweroff_unused(void)
-{
-       struct generic_pm_domain *genpd;
-
-       mutex_lock(&gpd_list_lock);
-
-       list_for_each_entry(genpd, &gpd_list, gpd_list_node)
-               genpd_queue_power_off_work(genpd);
-
-       mutex_unlock(&gpd_list_lock);
-}
index c2231ff..c4f7a45 100644 (file)
@@ -113,3 +113,4 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
 }
 EXPORT_SYMBOL_GPL(regmap_init_i2c);
 
+MODULE_LICENSE("GPL");
index 4deba06..f839694 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 static int regmap_spi_write(struct device *dev, const void *data, size_t count)
 {
@@ -70,3 +71,5 @@ struct regmap *regmap_init_spi(struct spi_device *spi,
        return regmap_init(&spi->dev, &regmap_spi, config);
 }
 EXPORT_SYMBOL_GPL(regmap_init_spi);
+
+MODULE_LICENSE("GPL");
index cf3565c..0eef4da 100644 (file)
@@ -317,7 +317,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                u8[0] |= map->bus->read_flag_mask;
 
        ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
-                            val, map->format.val_bytes);
+                            val, val_len);
        if (ret != 0)
                return ret;
 
index 196a737..be21e3f 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
index 04f1e7c..f6cf448 100644 (file)
@@ -1670,7 +1670,7 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
        char *type, *optype, *err, *msg;
        unsigned long error = m->status & 0x1ff0000l;
        u32 optypenum = (m->status >> 4) & 0x07;
-       u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+       u32 core_err_cnt = (m->status >> 38) & 0x7fff;
        u32 dimm = (m->misc >> 16) & 0x3;
        u32 channel = (m->misc >> 18) & 0x3;
        u32 syndrome = m->misc >> 32;
index e6ad3bb..4799393 100644 (file)
@@ -216,15 +216,33 @@ struct inbound_phy_packet_event {
        struct fw_cdev_event_phy_packet phy_packet;
 };
 
-static inline void __user *u64_to_uptr(__u64 value)
+#ifdef CONFIG_COMPAT
+static void __user *u64_to_uptr(u64 value)
+{
+       if (is_compat_task())
+               return compat_ptr(value);
+       else
+               return (void __user *)(unsigned long)value;
+}
+
+static u64 uptr_to_u64(void __user *ptr)
+{
+       if (is_compat_task())
+               return ptr_to_compat(ptr);
+       else
+               return (u64)(unsigned long)ptr;
+}
+#else
+static inline void __user *u64_to_uptr(u64 value)
 {
        return (void __user *)(unsigned long)value;
 }
 
-static inline __u64 uptr_to_u64(void __user *ptr)
+static inline u64 uptr_to_u64(void __user *ptr)
 {
-       return (__u64)(unsigned long)ptr;
+       return (u64)(unsigned long)ptr;
 }
+#endif /* CONFIG_COMPAT */
 
 static int fw_device_op_open(struct inode *inode, struct file *file)
 {
index bcf792f..57cd3a4 100644 (file)
@@ -2179,8 +2179,13 @@ static int ohci_enable(struct fw_card *card,
                        ohci_driver_name, ohci)) {
                fw_error("Failed to allocate interrupt %d.\n", dev->irq);
                pci_disable_msi(dev);
-               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-                                 ohci->config_rom, ohci->config_rom_bus);
+
+               if (config_rom) {
+                       dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                         ohci->next_config_rom,
+                                         ohci->next_config_rom_bus);
+                       ohci->next_config_rom = NULL;
+               }
                return -EIO;
        }
 
index a8ab626..3c395a5 100644 (file)
@@ -499,7 +499,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        seq_printf(m, "Interrupts received: %d\n",
                   atomic_read(&dev_priv->irq_received));
        for (i = 0; i < I915_NUM_RINGS; i++) {
-               if (IS_GEN6(dev)) {
+               if (IS_GEN6(dev) || IS_GEN7(dev)) {
                        seq_printf(m, "Graphics Interrupt mask (%s):    %08x\n",
                                   dev_priv->ring[i].name,
                                   I915_READ_IMR(&dev_priv->ring[i]));
index feb4f16..7916bd9 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <drm/intel-gtt.h>
+#include <linux/backlight.h>
 
 /* General customization:
  */
@@ -690,6 +691,7 @@ typedef struct drm_i915_private {
        int child_dev_num;
        struct child_device_config *child_dev;
        struct drm_connector *int_lvds_connector;
+       struct drm_connector *int_edp_connector;
 
        bool mchbar_need_disable;
 
@@ -723,6 +725,8 @@ typedef struct drm_i915_private {
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 
+       struct backlight_device *backlight;
+
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
index 02f96fd..9cbb0cd 100644 (file)
@@ -2058,8 +2058,10 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
 
-
-       dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
+       else
+               dev->driver->get_vblank_timestamp = NULL;
        dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
 
        if (IS_IVYBRIDGE(dev)) {
index d1331f7..5baaef4 100644 (file)
 #define   ADPA_PIPE_SELECT_MASK        (1<<30)
 #define   ADPA_PIPE_A_SELECT   0
 #define   ADPA_PIPE_B_SELECT   (1<<30)
+#define   ADPA_PIPE_SELECT(pipe) ((pipe) << 30)
 #define   ADPA_USE_VGA_HVPOLARITY (1<<15)
 #define   ADPA_SETS_HVPOLARITY 0
 #define   ADPA_VSYNC_CNTL_DISABLE (1<<11)
 /* Selects pipe B for LVDS data.  Must be set on pre-965. */
 #define   LVDS_PIPEB_SELECT            (1 << 30)
 #define   LVDS_PIPE_MASK               (1 << 30)
+#define   LVDS_PIPE(pipe)              ((pipe) << 30)
 /* LVDS dithering flag on 965/g4x platform */
 #define   LVDS_ENABLE_DITHER           (1 << 25)
 /* LVDS sync polarity flags. Set to invert (i.e. negative) */
 #define   LVDS_B0B3_POWER_DOWN         (0 << 2)
 #define   LVDS_B0B3_POWER_UP           (3 << 2)
 
-#define LVDS_PIPE_ENABLED(V, P) \
-       (((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN))
-
 /* Video Data Island Packet control */
 #define VIDEO_DIP_DATA         0x61178
 #define VIDEO_DIP_CTL          0x61170
 #define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)
 #define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
 
-#define ADPA_PIPE_ENABLED(V, P) \
-       (((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE))
-
 /* or SDVOB */
 #define HDMIB   0xe1140
 #define  PORT_ENABLE    (1 << 31)
 #define  TRANSCODER_A   (0)
 #define  TRANSCODER_B   (1 << 30)
+#define  TRANSCODER(pipe)      ((pipe) << 30)
 #define  TRANSCODER_MASK   (1 << 30)
 #define  COLOR_FORMAT_8bpc      (0)
 #define  COLOR_FORMAT_12bpc     (3 << 26)
 #define  HSYNC_ACTIVE_HIGH      (1 << 3)
 #define  PORT_DETECTED          (1 << 2)
 
-#define HDMI_PIPE_ENABLED(V, P) \
-       (((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE))
-
 /* PCH SDVOB multiplex with HDMIB */
 #define PCH_SDVOB      HDMIB
 
 #define  PORT_TRANS_B_SEL_CPT  (1<<29)
 #define  PORT_TRANS_C_SEL_CPT  (2<<29)
 #define  PORT_TRANS_SEL_MASK   (3<<29)
+#define  PORT_TRANS_SEL_CPT(pipe)      ((pipe) << 29)
 
 #define TRANS_DP_CTL_A         0xe0300
 #define TRANS_DP_CTL_B         0xe1300
index 87677d6..f107423 100644 (file)
@@ -871,7 +871,8 @@ int i915_restore_state(struct drm_device *dev)
        }
        mutex_unlock(&dev->struct_mutex);
 
-       intel_init_clock_gating(dev);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
index 35364e6..ee1d701 100644 (file)
@@ -980,8 +980,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
             pipe_name(pipe));
 }
 
-static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
-                           int reg, u32 port_sel, u32 val)
+static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
+                           enum pipe pipe, u32 port_sel, u32 val)
 {
        if ((val & DP_PORT_EN) == 0)
                return false;
@@ -998,11 +998,58 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
        return true;
 }
 
+static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & PORT_ENABLE) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & LVDS_PORT_EN) == 0)
+               return false;
+
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
+                       return false;
+       }
+       return true;
+}
+
+static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
+                             enum pipe pipe, u32 val)
+{
+       if ((val & ADPA_DAC_ENABLE) == 0)
+               return false;
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
+                       return false;
+       } else {
+               if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
+                       return false;
+       }
+       return true;
+}
+
 static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
                                   enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val),
+       WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -1011,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
                                     enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       WARN(HDMI_PIPE_ENABLED(val, pipe),
+       WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
 }
@@ -1028,13 +1075,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       WARN(ADPA_PIPE_ENABLED(val, pipe),
+       WARN(adpa_pipe_enabled(dev_priv, val, pipe),
             "PCH VGA enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       WARN(LVDS_PIPE_ENABLED(val, pipe),
+       WARN(lvds_pipe_enabled(dev_priv, val, pipe),
             "PCH LVDS enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
 
@@ -1360,7 +1407,7 @@ static void disable_pch_dp(struct drm_i915_private *dev_priv,
                           enum pipe pipe, int reg, u32 port_sel)
 {
        u32 val = I915_READ(reg);
-       if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) {
+       if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
                DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
                I915_WRITE(reg, val & ~DP_PORT_EN);
        }
@@ -1370,7 +1417,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
                             enum pipe pipe, int reg)
 {
        u32 val = I915_READ(reg);
-       if (HDMI_PIPE_ENABLED(val, pipe)) {
+       if (hdmi_pipe_enabled(dev_priv, val, pipe)) {
                DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
                              reg, pipe);
                I915_WRITE(reg, val & ~PORT_ENABLE);
@@ -1392,12 +1439,13 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
 
        reg = PCH_ADPA;
        val = I915_READ(reg);
-       if (ADPA_PIPE_ENABLED(val, pipe))
+       if (adpa_pipe_enabled(dev_priv, val, pipe))
                I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
 
        reg = PCH_LVDS;
        val = I915_READ(reg);
-       if (LVDS_PIPE_ENABLED(val, pipe)) {
+       if (lvds_pipe_enabled(dev_priv, val, pipe)) {
+               DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
                I915_WRITE(reg, val & ~LVDS_PORT_EN);
                POSTING_READ(reg);
                udelay(100);
@@ -5049,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static void ironlake_update_pch_refclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_crtc *crtc;
+       struct intel_encoder *encoder;
+       struct intel_encoder *has_edp_encoder = NULL;
+       u32 temp;
+       bool has_lvds = false;
+
+       /* We need to take the global config into account */
+       list_for_each_entry(crtc, &mode_config->crtc_list, head) {
+               if (!crtc->enabled)
+                       continue;
+
+               list_for_each_entry(encoder, &mode_config->encoder_list,
+                                   base.head) {
+                       if (encoder->base.crtc != crtc)
+                               continue;
+
+                       switch (encoder->type) {
+                       case INTEL_OUTPUT_LVDS:
+                               has_lvds = true;
+                       case INTEL_OUTPUT_EDP:
+                               has_edp_encoder = encoder;
+                               break;
+                       }
+               }
+       }
+
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+       temp &= ~DREF_SSC_SOURCE_MASK;
+       temp |= DREF_SSC_SOURCE_ENABLE;
+       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+       POSTING_READ(PCH_DREF_CONTROL);
+       udelay(200);
+
+       if (has_edp_encoder) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       temp |= DREF_SSC1_ENABLE;
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
+               }
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Enable CPU source on CPU attached eDP */
+               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       if (intel_panel_use_ssc(dev_priv))
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else {
+                       /* Enable SSC on PCH eDP if needed */
+                       if (intel_panel_use_ssc(dev_priv)) {
+                               DRM_ERROR("enabling SSC on PCH\n");
+                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                       }
+               }
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
+}
+
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode,
@@ -5244,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
                             &m_n);
 
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       temp = I915_READ(PCH_DREF_CONTROL);
-       /* Always enable nonspread source */
-       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-       temp &= ~DREF_SSC_SOURCE_MASK;
-       temp |= DREF_SSC_SOURCE_ENABLE;
-       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-       POSTING_READ(PCH_DREF_CONTROL);
-       udelay(200);
-
-       if (has_edp_encoder) {
-               if (intel_panel_use_ssc(dev_priv)) {
-                       temp |= DREF_SSC1_ENABLE;
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
-
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
-               }
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-               /* Enable CPU source on CPU attached eDP */
-               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       if (intel_panel_use_ssc(dev_priv))
-                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                       else
-                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-               } else {
-                       /* Enable SSC on PCH eDP if needed */
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               DRM_ERROR("enabling SSC on PCH\n");
-                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                       }
-               }
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-       }
+       ironlake_update_pch_refclk(dev);
 
        fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
        if (has_reduced_clock)
index 0feae90..44fef5e 100644 (file)
@@ -1841,6 +1841,11 @@ done:
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
+       struct drm_device *dev = connector->dev;
+
+       if (intel_dpd_is_edp(dev))
+               intel_panel_destroy_backlight(dev);
+
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
        kfree(connector);
@@ -2072,6 +2077,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                                        DRM_MODE_TYPE_PREFERRED;
                        }
                }
+               dev_priv->int_edp_connector = connector;
+               intel_panel_setup_backlight(dev);
        }
 
        intel_dp_add_properties(intel_dp, connector);
index 7b330e7..0b2ee9d 100644 (file)
@@ -297,9 +297,10 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
-extern void intel_panel_setup_backlight(struct drm_device *dev);
+extern int intel_panel_setup_backlight(struct drm_device *dev);
 extern void intel_panel_enable_backlight(struct drm_device *dev);
 extern void intel_panel_disable_backlight(struct drm_device *dev);
+extern void intel_panel_destroy_backlight(struct drm_device *dev);
 extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
 
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
index 2e8ddfc..31da77f 100644 (file)
@@ -72,14 +72,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
@@ -94,17 +96,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)
                DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
                              intel_lvds->pfit_control,
                              intel_lvds->pfit_pgm_ratios);
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-               } else {
-                       I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
-                       I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
-                       intel_lvds->pfit_dirty = false;
-               }
+
+               I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+               I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+               intel_lvds->pfit_dirty = false;
        }
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
        POSTING_READ(lvds_reg);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power on\n");
 
        intel_panel_enable_backlight(dev);
 }
@@ -113,24 +114,25 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)
 {
        struct drm_device *dev = intel_lvds->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 ctl_reg, lvds_reg;
+       u32 ctl_reg, lvds_reg, stat_reg;
 
        if (HAS_PCH_SPLIT(dev)) {
                ctl_reg = PCH_PP_CONTROL;
                lvds_reg = PCH_LVDS;
+               stat_reg = PCH_PP_STATUS;
        } else {
                ctl_reg = PP_CONTROL;
                lvds_reg = LVDS;
+               stat_reg = PP_STATUS;
        }
 
        intel_panel_disable_backlight(dev);
 
        I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+       if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000))
+               DRM_ERROR("timed out waiting for panel to power off\n");
 
        if (intel_lvds->pfit_control) {
-               if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
-                       DRM_ERROR("timed out waiting for panel to power off\n");
-
                I915_WRITE(PFIT_CONTROL, 0);
                intel_lvds->pfit_dirty = true;
        }
@@ -398,53 +400,21 @@ out:
 
 static void intel_lvds_prepare(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* We try to do the minimum that is necessary in order to unlock
-        * the registers for mode setting.
-        *
-        * On Ironlake, this is quite simple as we just set the unlock key
-        * and ignore all subtleties. (This may cause some issues...)
-        *
+       /*
         * Prior to Ironlake, we must disable the pipe if we want to adjust
         * the panel fitter. However at all other times we can just reset
         * the registers regardless.
         */
-
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PCH_PP_CONTROL,
-                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
-       } else if (intel_lvds->pfit_dirty) {
-               I915_WRITE(PP_CONTROL,
-                          (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
-                          & ~POWER_TARGET_ON);
-       } else {
-               I915_WRITE(PP_CONTROL,
-                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
-       }
+       if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty)
+               intel_lvds_disable(intel_lvds);
 }
 
 static void intel_lvds_commit(struct drm_encoder *encoder)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-       /* Undo any unlocking done in prepare to prevent accidental
-        * adjustment of the registers.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               u32 val = I915_READ(PCH_PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PCH_PP_CONTROL, val & 0x3);
-       } else {
-               u32 val = I915_READ(PP_CONTROL);
-               if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
-                       I915_WRITE(PP_CONTROL, val & 0x3);
-       }
-
        /* Always do a full power on as we do not know what state
         * we were left in.
         */
@@ -582,6 +552,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       intel_panel_destroy_backlight(dev);
+
        if (dev_priv->lid_notifier.notifier_call)
                acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
        drm_sysfs_connector_remove(connector);
@@ -1040,6 +1012,19 @@ out:
                pwm = I915_READ(BLC_PWM_PCH_CTL1);
                pwm |= PWM_PCH_ENABLE;
                I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PCH_PP_CONTROL,
+                          I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+       } else {
+               /*
+                * Unlock registers and just
+                * leave them unlocked
+                */
+               I915_WRITE(PP_CONTROL,
+                          I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
        }
        dev_priv->lid_notifier.notifier_call = intel_lid_notify;
        if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
@@ -1049,6 +1034,9 @@ out:
        /* keep the LVDS connector */
        dev_priv->int_lvds_connector = connector;
        drm_sysfs_connector_add(connector);
+
+       intel_panel_setup_backlight(dev);
+
        return true;
 
 failed:
index b7c5ddb..b8e8158 100644 (file)
@@ -227,7 +227,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
        asle->aslc = asle_stat;
 }
 
-/* Only present on Ironlake+ */
 void intel_opregion_gse_intr(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index 05f500c..a9e0c7b 100644 (file)
@@ -277,7 +277,7 @@ void intel_panel_enable_backlight(struct drm_device *dev)
        dev_priv->backlight_enabled = true;
 }
 
-void intel_panel_setup_backlight(struct drm_device *dev)
+static void intel_panel_init_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -309,3 +309,73 @@ intel_panel_detect(struct drm_device *dev)
 
        return connector_status_unknown;
 }
+
+#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
+static int intel_panel_update_status(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       intel_panel_set_backlight(dev, bd->props.brightness);
+       return 0;
+}
+
+static int intel_panel_get_brightness(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       return intel_panel_get_backlight(dev);
+}
+
+static const struct backlight_ops intel_panel_bl_ops = {
+       .update_status = intel_panel_update_status,
+       .get_brightness = intel_panel_get_brightness,
+};
+
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct backlight_properties props;
+       struct drm_connector *connector;
+
+       intel_panel_init_backlight(dev);
+
+       if (dev_priv->int_lvds_connector)
+               connector = dev_priv->int_lvds_connector;
+       else if (dev_priv->int_edp_connector)
+               connector = dev_priv->int_edp_connector;
+       else
+               return -ENODEV;
+
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = intel_panel_get_max_backlight(dev);
+       dev_priv->backlight =
+               backlight_device_register("intel_backlight",
+                                         &connector->kdev, dev,
+                                         &intel_panel_bl_ops, &props);
+
+       if (IS_ERR(dev_priv->backlight)) {
+               DRM_ERROR("Failed to register backlight: %ld\n",
+                         PTR_ERR(dev_priv->backlight));
+               dev_priv->backlight = NULL;
+               return -ENODEV;
+       }
+       dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (dev_priv->backlight)
+               backlight_device_unregister(dev_priv->backlight);
+}
+#else
+int intel_panel_setup_backlight(struct drm_device *dev)
+{
+       intel_panel_init_backlight(dev);
+       return 0;
+}
+
+void intel_panel_destroy_backlight(struct drm_device *dev)
+{
+       return;
+}
+#endif
index 645b84b..7ad43c6 100644 (file)
@@ -613,6 +613,18 @@ static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
        return true;
 }
 
+bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
+{
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
+       if (!radeon_dp_get_link_status(radeon_connector, link_status))
+               return false;
+       if (dp_channel_eq_ok(link_status, dig->dp_lane_count))
+               return false;
+       return true;
+}
+
 struct radeon_dp_link_train_info {
        struct radeon_device *rdev;
        struct drm_encoder *encoder;
index 14dce9f..fb5fa08 100644 (file)
@@ -743,7 +743,7 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
                    !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
                    !evergreen_check_latency_hiding(&wm) ||
                    (rdev->disp_priority == 2)) {
-                       DRM_INFO("force priority to high\n");
+                       DRM_DEBUG_KMS("force priority to high\n");
                        priority_a_cnt |= PRIORITY_ALWAYS_ON;
                        priority_b_cnt |= PRIORITY_ALWAYS_ON;
                }
index 6d6b5f1..7f65940 100644 (file)
@@ -60,18 +60,20 @@ void radeon_connector_hotplug(struct drm_connector *connector)
 
        radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
 
-       /* powering up/down the eDP panel generates hpd events which
-        * can interfere with modesetting.
-        */
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+       /* if the connector is already off, don't turn it back on */
+       if (connector->dpms != DRM_MODE_DPMS_ON)
                return;
 
-       /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
-       if (rdev->family >= CHIP_R600) {
-               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+       /* just deal with DP (not eDP) here. */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+               int saved_dpms = connector->dpms;
+
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+                   radeon_dp_needs_link_train(radeon_connector))
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                else
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               connector->dpms = saved_dpms;
        }
 }
 
@@ -474,11 +476,19 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+       struct drm_display_mode *t, *mode;
+
+       /* If the EDID preferred mode doesn't match the native mode, use it */
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
+               if (mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       if (mode->hdisplay != native_mode->hdisplay ||
+                           mode->vdisplay != native_mode->vdisplay)
+                               memcpy(native_mode, mode, sizeof(*mode));
+               }
+       }
 
        /* Try to get native mode details from EDID if necessary */
        if (!native_mode->clock) {
-               struct drm_display_mode *t, *mode;
-
                list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
                        if (mode->hdisplay == native_mode->hdisplay &&
                            mode->vdisplay == native_mode->vdisplay) {
@@ -489,6 +499,7 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
                        }
                }
        }
+
        if (!native_mode->clock) {
                DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
                radeon_encoder->rmx_type = RMX_OFF;
index 440e6ec..a3b011b 100644 (file)
@@ -32,6 +32,7 @@
 #include <drm/radeon_drm.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/efi.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "atom.h"
@@ -348,6 +349,9 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
+       if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+               return false;
+
        /* first check CRTCs */
        if (ASIC_IS_DCE41(rdev)) {
                reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
index b293487..319d85d 100644 (file)
@@ -2323,6 +2323,9 @@ radeon_add_atom_encoder(struct drm_device *dev,
        default:
                encoder->possible_crtcs = 0x3;
                break;
+       case 4:
+               encoder->possible_crtcs = 0xf;
+               break;
        case 6:
                encoder->possible_crtcs = 0x3f;
                break;
index d09031c..68820f5 100644 (file)
@@ -479,6 +479,7 @@ extern void radeon_dp_set_link_config(struct drm_connector *connector,
                                      struct drm_display_mode *mode);
 extern void radeon_dp_link_train(struct drm_encoder *encoder,
                                 struct drm_connector *connector);
+extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
index 1a409c5..c316294 100644 (file)
@@ -432,13 +432,15 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
        aem_send_message(ipmi);
 
        res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
-       if (!res)
-               return -ETIMEDOUT;
+       if (!res) {
+               res = -ETIMEDOUT;
+               goto out;
+       }
 
        if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
            memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) {
-               kfree(rs_resp);
-               return -ENOENT;
+               res = -ENOENT;
+               goto out;
        }
 
        switch (size) {
@@ -463,8 +465,11 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
                break;
        }
        }
+       res = 0;
 
-       return 0;
+out:
+       kfree(rs_resp);
+       return res;
 }
 
 /* Update AEM energy registers */
index d4bc114..ac254fb 100644 (file)
@@ -161,6 +161,17 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
        return ret;
 }
 
+static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
+{
+       if (page > 1)
+               return -EINVAL;
+
+       if (page == 0)
+               return pmbus_write_byte(client, 0, value);
+
+       return 0;
+}
+
 static int lm25066_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
@@ -204,6 +215,7 @@ static int lm25066_probe(struct i2c_client *client,
 
        info->read_word_data = lm25066_read_word_data;
        info->write_word_data = lm25066_write_word_data;
+       info->write_byte = lm25066_write_byte;
 
        switch (id->driver_data) {
        case lm25066:
index 0808d98..a6ae20f 100644 (file)
@@ -325,6 +325,7 @@ struct pmbus_driver_info {
        int (*read_word_data)(struct i2c_client *client, int page, int reg);
        int (*write_word_data)(struct i2c_client *client, int page, int reg,
                               u16 word);
+       int (*write_byte)(struct i2c_client *client, int page, u8 value);
        /*
         * The identify function determines supported PMBus functionality.
         * This function is only necessary if a chip driver supports multiple
index 5c1b6cf..a561c3a 100644 (file)
@@ -182,6 +182,24 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
 }
 EXPORT_SYMBOL_GPL(pmbus_write_byte);
 
+/*
+ * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if
+ * a device specific mapping funcion exists and calls it if necessary.
+ */
+static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->write_byte) {
+               status = info->write_byte(client, page, value);
+               if (status != -ENODATA)
+                       return status;
+       }
+       return pmbus_write_byte(client, page, value);
+}
+
 int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
 {
        int rv;
@@ -281,7 +299,7 @@ static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
 
 static void pmbus_clear_fault_page(struct i2c_client *client, int page)
 {
-       pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+       _pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
 }
 
 void pmbus_clear_faults(struct i2c_client *client)
index efec413..68cd05b 100644 (file)
@@ -33,7 +33,7 @@ EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
 static int __devinit cb710_pci_configure(struct pci_dev *pdev)
 {
        unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
-       struct pci_dev *pdev0 = pci_get_slot(pdev->bus, devfn);
+       struct pci_dev *pdev0;
        u32 val;
 
        cb710_pci_update_config_reg(pdev, 0x48,
@@ -43,6 +43,7 @@ static int __devinit cb710_pci_configure(struct pci_dev *pdev)
        if (val & 0x80000000)
                return 0;
 
+       pdev0 = pci_get_slot(pdev->bus, devfn);
        if (!pdev0)
                return -ENODEV;
 
index 006a5e9..2bf229a 100644 (file)
@@ -224,7 +224,7 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
 static int mmc_test_busy(struct mmc_command *cmd)
 {
        return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
-               (R1_CURRENT_STATE(cmd->resp[0]) == 7);
+               (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
 }
 
 /*
@@ -2900,7 +2900,7 @@ static const struct file_operations mmc_test_fops_testlist = {
        .release        = single_release,
 };
 
-static void mmc_test_free_file_test(struct mmc_card *card)
+static void mmc_test_free_dbgfs_file(struct mmc_card *card)
 {
        struct mmc_test_dbgfs_file *df, *dfs;
 
@@ -2917,34 +2917,21 @@ static void mmc_test_free_file_test(struct mmc_card *card)
        mutex_unlock(&mmc_test_lock);
 }
 
-static int mmc_test_register_file_test(struct mmc_card *card)
+static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
+       const char *name, mode_t mode, const struct file_operations *fops)
 {
        struct dentry *file = NULL;
        struct mmc_test_dbgfs_file *df;
-       int ret = 0;
-
-       mutex_lock(&mmc_test_lock);
-
-       if (card->debugfs_root)
-               file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
-                       card->debugfs_root, card, &mmc_test_fops_test);
-
-       if (IS_ERR_OR_NULL(file)) {
-               dev_err(&card->dev,
-                       "Can't create test. Perhaps debugfs is disabled.\n");
-               ret = -ENODEV;
-               goto err;
-       }
 
        if (card->debugfs_root)
-               file = debugfs_create_file("testlist", S_IRUGO,
-                       card->debugfs_root, card, &mmc_test_fops_testlist);
+               file = debugfs_create_file(name, mode, card->debugfs_root,
+                       card, fops);
 
        if (IS_ERR_OR_NULL(file)) {
                dev_err(&card->dev,
-                       "Can't create testlist. Perhaps debugfs is disabled.\n");
-               ret = -ENODEV;
-               goto err;
+                       "Can't create %s. Perhaps debugfs is disabled.\n",
+                       name);
+               return -ENODEV;
        }
 
        df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
@@ -2952,14 +2939,31 @@ static int mmc_test_register_file_test(struct mmc_card *card)
                debugfs_remove(file);
                dev_err(&card->dev,
                        "Can't allocate memory for internal usage.\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        df->card = card;
        df->file = file;
 
        list_add(&df->link, &mmc_test_file_test);
+       return 0;
+}
+
+static int mmc_test_register_dbgfs_file(struct mmc_card *card)
+{
+       int ret;
+
+       mutex_lock(&mmc_test_lock);
+
+       ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO,
+               &mmc_test_fops_test);
+       if (ret)
+               goto err;
+
+       ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
+               &mmc_test_fops_testlist);
+       if (ret)
+               goto err;
 
 err:
        mutex_unlock(&mmc_test_lock);
@@ -2974,7 +2978,7 @@ static int mmc_test_probe(struct mmc_card *card)
        if (!mmc_card_mmc(card) && !mmc_card_sd(card))
                return -ENODEV;
 
-       ret = mmc_test_register_file_test(card);
+       ret = mmc_test_register_dbgfs_file(card);
        if (ret)
                return ret;
 
@@ -2986,7 +2990,7 @@ static int mmc_test_probe(struct mmc_card *card)
 static void mmc_test_remove(struct mmc_card *card)
 {
        mmc_test_free_result(card);
-       mmc_test_free_file_test(card);
+       mmc_test_free_dbgfs_file(card);
 }
 
 static struct mmc_driver mmc_driver = {
@@ -3006,7 +3010,7 @@ static void __exit mmc_test_exit(void)
 {
        /* Clear stalled data if card is still plugged */
        mmc_test_free_result(NULL);
-       mmc_test_free_file_test(NULL);
+       mmc_test_free_dbgfs_file(NULL);
 
        mmc_unregister_driver(&mmc_driver);
 }
index 89bdeae..91a0a74 100644 (file)
@@ -1502,7 +1502,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        goto out;
                }
        } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-                R1_CURRENT_STATE(cmd.resp[0]) == 7);
+                R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
 out:
        return err;
 }
index aa7d1d7..5700b1c 100644 (file)
@@ -259,7 +259,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
 
        card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-       if (card->ext_csd.rev > 5) {
+       if (card->ext_csd.rev > 6) {
                printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n",
                        mmc_hostname(card->host), card->ext_csd.rev);
                err = -EINVAL;
index 845ce7c..770c3d0 100644 (file)
@@ -407,7 +407,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                        break;
                if (mmc_host_is_spi(card->host))
                        break;
-       } while (R1_CURRENT_STATE(status) == 7);
+       } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
        if (mmc_host_is_spi(card->host)) {
                if (status & R1_SPI_ILLEGAL_COMMAND)
index 77f0b6b..ff0f714 100644 (file)
@@ -62,7 +62,7 @@ struct idmac_desc {
 
        u32             des1;   /* Buffer sizes */
 #define IDMAC_SET_BUFFER1_SIZE(d, s) \
-       ((d)->des1 = ((d)->des1 & 0x03ffc000) | ((s) & 0x3fff))
+       ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
 
        u32             des2;   /* buffer 1 physical address */
 
@@ -699,7 +699,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
        /* DDR mode set */
-       if (ios->ddr) {
+       if (ios->timing == MMC_TIMING_UHS_DDR50) {
                regs = mci_readl(slot->host, UHS_REG);
                regs |= (0x1 << slot->id) << 16;
                mci_writel(slot->host, UHS_REG, regs);
@@ -1646,7 +1646,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
-               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
 #ifdef CONFIG_MMC_DW_IDMAC
        mmc->max_segs = host->ring_size;
index 9ebfb4b..0e9780f 100644 (file)
@@ -27,6 +27,7 @@
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 
+#define        SDHCI_CTRL_D3CD                 0x08
 /* VENDOR SPEC register */
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
@@ -141,13 +142,32 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
        struct esdhc_platform_data *boarddata = &imx_data->boarddata;
-
-       if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-                       && (boarddata->cd_type == ESDHC_CD_GPIO)))
-               /*
-                * these interrupts won't work with a custom card_detect gpio
-                */
-               val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+       u32 data;
+
+       if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
+               if (boarddata->cd_type == ESDHC_CD_GPIO)
+                       /*
+                        * These interrupts won't work with a custom
+                        * card_detect gpio (only applied to mx25/35)
+                        */
+                       val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+               if (val & SDHCI_INT_CARD_INT) {
+                       /*
+                        * Clear and then set D3CD bit to avoid missing the
+                        * card interrupt.  This is a eSDHC controller problem
+                        * so we need to apply the following workaround: clear
+                        * and set D3CD bit will make eSDHC re-sample the card
+                        * interrupt. In case a card interrupt was lost,
+                        * re-sample it by the following steps.
+                        */
+                       data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
+                       data &= ~SDHCI_CTRL_D3CD;
+                       writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
+                       data |= SDHCI_CTRL_D3CD;
+                       writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
+               }
+       }
 
        if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
                                && (reg == SDHCI_INT_STATUS)
@@ -217,8 +237,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
                 */
                return;
        case SDHCI_HOST_CONTROL:
-               /* FSL messed up here, so we can just keep those two */
-               new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+               /* FSL messed up here, so we can just keep those three */
+               new_val = val & (SDHCI_CTRL_LED | \
+                               SDHCI_CTRL_4BITBUS | \
+                               SDHCI_CTRL_D3CD);
                /* ensure the endianess */
                new_val |= ESDHC_HOST_CONTROL_LE;
                /* DMA mode bits are shifted */
index 4198dbb..fc7e4a5 100644 (file)
@@ -195,7 +195,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        clk_enable(clk);
 
        host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
-               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
+               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
+               | SDHCI_QUIRK_32BIT_ADMA_SIZE;
 
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
index 460ffaf..2bd7bf4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/module.h>
 
 #include <linux/mmc/host.h>
 
@@ -502,6 +503,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        /* This host supports the Auto CMD12 */
        host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
 
+       /* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
+       host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
+
        if (pdata->cd_type == S3C_SDHCI_CD_NONE ||
            pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
index c31a334..0e02cc1 100644 (file)
@@ -628,12 +628,11 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
        /* timeout in us */
        if (!data)
                target_timeout = cmd->cmd_timeout_ms * 1000;
-       else
-               target_timeout = data->timeout_ns / 1000 +
-                       data->timeout_clks / host->clock;
-
-       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-               host->timeout_clk = host->clock / 1000;
+       else {
+               target_timeout = data->timeout_ns / 1000;
+               if (host->clock)
+                       target_timeout += data->timeout_clks / host->clock;
+       }
 
        /*
         * Figure out needed cycles.
@@ -645,7 +644,6 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
         *     =>
         *     (1) / (2) > 2^6
         */
-       BUG_ON(!host->timeout_clk);
        count = 0;
        current_timeout = (1 << 13) * 1000 / host->timeout_clk;
        while (current_timeout < target_timeout) {
@@ -1867,9 +1865,6 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        del_timer(&host->timer);
 
-       if (host->version >= SDHCI_SPEC_300)
-               del_timer(&host->tuning_timer);
-
        mrq = host->mrq;
 
        /*
@@ -2461,22 +2456,6 @@ int sdhci_add_host(struct sdhci_host *host)
                host->max_clk = host->ops->get_max_clock(host);
        }
 
-       host->timeout_clk =
-               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-       if (host->timeout_clk == 0) {
-               if (host->ops->get_timeout_clock) {
-                       host->timeout_clk = host->ops->get_timeout_clock(host);
-               } else if (!(host->quirks &
-                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
-                       printk(KERN_ERR
-                              "%s: Hardware doesn't specify timeout clock "
-                              "frequency.\n", mmc_hostname(mmc));
-                       return -ENODEV;
-               }
-       }
-       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
-               host->timeout_clk *= 1000;
-
        /*
         * In case of Host Controller v3.00, find out whether clock
         * multiplier is supported.
@@ -2509,10 +2488,26 @@ int sdhci_add_host(struct sdhci_host *host)
        } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
+       host->timeout_clk =
+               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+       if (host->timeout_clk == 0) {
+               if (host->ops->get_timeout_clock) {
+                       host->timeout_clk = host->ops->get_timeout_clock(host);
+               } else if (!(host->quirks &
+                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+                       printk(KERN_ERR
+                              "%s: Hardware doesn't specify timeout clock "
+                              "frequency.\n", mmc_hostname(mmc));
+                       return -ENODEV;
+               }
+       }
+       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
+               host->timeout_clk *= 1000;
+
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
-               mmc->max_discard_to = (1 << 27) / (mmc->f_max / 1000);
-       else
-               mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+               host->timeout_clk = mmc->f_max / 1000;
+
+       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
index 8d185de..44a9668 100644 (file)
@@ -27,7 +27,6 @@
 static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
-       struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
        ret = tmio_mmc_host_suspend(&dev->dev);
@@ -42,7 +41,6 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
 static int tmio_mmc_resume(struct platform_device *dev)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
-       struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
index d724a18..37e5790 100644 (file)
@@ -63,8 +63,9 @@ static inline void bnx2x_bz_fp(struct bnx2x *bp, int index)
        fp->disable_tpa = ((bp->flags & TPA_ENABLE_FLAG) == 0);
 
 #ifdef BCM_CNIC
-       /* We don't want TPA on FCoE, FWD and OOO L2 rings */
-       bnx2x_fcoe(bp, disable_tpa) = 1;
+       /* We don't want TPA on an FCoE L2 ring */
+       if (IS_FCOE_FP(fp))
+               fp->disable_tpa = 1;
 #endif
 }
 
@@ -1404,10 +1405,9 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct bnx2x *bp = netdev_priv(dev);
+
 #ifdef BCM_CNIC
-       if (NO_FCOE(bp))
-               return skb_tx_hash(dev, skb);
-       else {
+       if (!NO_FCOE(bp)) {
                struct ethhdr *hdr = (struct ethhdr *)skb->data;
                u16 ether_type = ntohs(hdr->h_proto);
 
@@ -1424,8 +1424,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
                        return bnx2x_fcoe_tx(bp, txq_index);
        }
 #endif
-       /* Select a none-FCoE queue:  if FCoE is enabled, exclude FCoE L2 ring
-        */
+       /* select a non-FCoE queue */
        return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
 }
 
@@ -1448,6 +1447,28 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
        bp->num_queues += NON_ETH_CONTEXT_USE;
 }
 
+/**
+ * bnx2x_set_real_num_queues - configure netdev->real_num_[tx,rx]_queues
+ *
+ * @bp:                Driver handle
+ *
+ * We currently support for at most 16 Tx queues for each CoS thus we will
+ * allocate a multiple of 16 for ETH L2 rings according to the value of the
+ * bp->max_cos.
+ *
+ * If there is an FCoE L2 queue the appropriate Tx queue will have the next
+ * index after all ETH L2 indices.
+ *
+ * If the actual number of Tx queues (for each CoS) is less than 16 then there
+ * will be the holes at the end of each group of 16 ETh L2 indices (0..15,
+ * 16..31,...) with indicies that are not coupled with any real Tx queue.
+ *
+ * The proper configuration of skb->queue_mapping is handled by
+ * bnx2x_select_queue() and __skb_tx_hash().
+ *
+ * bnx2x_setup_tc() takes care of the proper TC mappings so that __skb_tx_hash()
+ * will return a proper Tx index if TC is enabled (netdev->num_tc > 0).
+ */
 static inline int bnx2x_set_real_num_queues(struct bnx2x *bp)
 {
        int rc, tx, rx;
index a4ea35f..a1e004a 100644 (file)
@@ -920,7 +920,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 
 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 {
-       if (!CHIP_IS_E1x(bp)) {
+       if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3(bp)) {
                bp->dcb_state = dcb_on;
                bp->dcbx_enabled = dcbx_enabled;
        } else {
index 1507091..f74582a 100644 (file)
@@ -5798,6 +5798,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
 
        DP(BNX2X_MSG_MCP, "starting common init  func %d\n", BP_ABS_FUNC(bp));
 
+       /*
+        * take the UNDI lock to protect undi_unload flow from accessing
+        * registers while we're resetting the chip
+        */
+       bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+
        bnx2x_reset_common(bp);
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff);
 
@@ -5808,6 +5814,8 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
        }
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val);
 
+       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI);
+
        bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON);
 
        if (!CHIP_IS_E1x(bp)) {
@@ -10251,10 +10259,17 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        /* clean indirect addresses */
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
                               PCICFG_VENDOR_ID_OFFSET);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0);
-       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0);
+       /* Clean the following indirect addresses for all functions since it
+        * is not used by the driver.
+        */
+       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
+       REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
 
        /*
         * Enable internal target-read (in case we are probed after PF FLR).
index 27b5ecb..40266c1 100644 (file)
 /* [R 6] Debug only: Number of used entries in the data FIFO */
 #define PXP2_REG_HST_DATA_FIFO_STATUS                           0x12047c
 /* [R 7] Debug only: Number of used entries in the header FIFO */
-#define PXP2_REG_HST_HEADER_FIFO_STATUS                         0x120478
-#define PXP2_REG_PGL_ADDR_88_F0                                 0x120534
-#define PXP2_REG_PGL_ADDR_8C_F0                                 0x120538
-#define PXP2_REG_PGL_ADDR_90_F0                                 0x12053c
-#define PXP2_REG_PGL_ADDR_94_F0                                 0x120540
+#define PXP2_REG_HST_HEADER_FIFO_STATUS                                 0x120478
+#define PXP2_REG_PGL_ADDR_88_F0                                         0x120534
+/* [R 32] GRC address for configuration access to PCIE config address 0x88.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_88_F1                                         0x120544
+#define PXP2_REG_PGL_ADDR_8C_F0                                         0x120538
+/* [R 32] GRC address for configuration access to PCIE config address 0x8c.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_8C_F1                                         0x120548
+#define PXP2_REG_PGL_ADDR_90_F0                                         0x12053c
+/* [R 32] GRC address for configuration access to PCIE config address 0x90.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_90_F1                                         0x12054c
+#define PXP2_REG_PGL_ADDR_94_F0                                         0x120540
+/* [R 32] GRC address for configuration access to PCIE config address 0x94.
+ * any write to this PCIE address will cause a GRC write access to the
+ * address that's in t this register */
+#define PXP2_REG_PGL_ADDR_94_F1                                         0x120550
 #define PXP2_REG_PGL_CONTROL0                                   0x120490
 #define PXP2_REG_PGL_CONTROL1                                   0x120514
 #define PXP2_REG_PGL_DEBUG                                      0x120520
index f523f1c..4b70b7e 100644 (file)
@@ -197,7 +197,7 @@ static void slc_bump(struct slcan *sl)
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        memcpy(skb_put(skb, sizeof(struct can_frame)),
               &cf, sizeof(struct can_frame));
-       netif_rx(skb);
+       netif_rx_ni(skb);
 
        sl->dev->stats.rx_packets++;
        sl->dev->stats.rx_bytes += cf.can_dlc;
index 480f259..536b3a5 100644 (file)
@@ -2085,7 +2085,8 @@ struct e1000_info e1000_82574_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
        .flags2                   = FLAG2_CHECK_PHY_HANG
-                                 | FLAG2_DISABLE_ASPM_L0S,
+                                 | FLAG2_DISABLE_ASPM_L0S
+                                 | FLAG2_NO_DISABLE_RX,
        .pba                    = 32,
        .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
@@ -2104,7 +2105,8 @@ struct e1000_info e1000_82583_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_JUMBO_FRAMES
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
-       .flags2                 = FLAG2_DISABLE_ASPM_L0S,
+       .flags2                 = FLAG2_DISABLE_ASPM_L0S
+                                 | FLAG2_NO_DISABLE_RX,
        .pba                    = 32,
        .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
index 638d175..35916f4 100644 (file)
@@ -453,6 +453,7 @@ struct e1000_info {
 #define FLAG2_DISABLE_ASPM_L0S            (1 << 7)
 #define FLAG2_DISABLE_AIM                 (1 << 8)
 #define FLAG2_CHECK_PHY_HANG              (1 << 9)
+#define FLAG2_NO_DISABLE_RX               (1 << 10)
 
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
index 06d88f3..6a0526a 100644 (file)
@@ -1206,7 +1206,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
        rx_ring->next_to_clean = 0;
 
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
        ew32(RDBAH, ((u64) rx_ring->dma >> 32));
        ew32(RDLEN, rx_ring->size);
index 7898a67..0893ab1 100644 (file)
@@ -190,7 +190,8 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
        /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */
        if (!((nvm_data & NVM_COMPAT_LOM) ||
              (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_DUAL) ||
-             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)))
+             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) ||
+             (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES)))
                goto out;
 
        ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
@@ -200,10 +201,10 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
                goto out;
        }
 
-       if (nvm_alt_mac_addr_offset == 0xFFFF) {
+       if ((nvm_alt_mac_addr_offset == 0xFFFF) ||
+           (nvm_alt_mac_addr_offset == 0x0000))
                /* There is no Alternate MAC Address */
                goto out;
-       }
 
        if (hw->bus.func == E1000_FUNC_1)
                nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
index ab4be80..362f703 100644 (file)
@@ -56,7 +56,7 @@
 
 #define DRV_EXTRAVERSION "-k"
 
-#define DRV_VERSION "1.3.16" DRV_EXTRAVERSION
+#define DRV_VERSION "1.4.4" DRV_EXTRAVERSION
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -2915,7 +2915,8 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 
        /* disable receives while setting up the descriptors */
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        e1e_flush();
        usleep_range(10000, 20000);
 
@@ -3394,7 +3395,8 @@ void e1000e_down(struct e1000_adapter *adapter)
 
        /* disable receives in the hardware */
        rctl = er32(RCTL);
-       ew32(RCTL, rctl & ~E1000_RCTL_EN);
+       if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
+               ew32(RCTL, rctl & ~E1000_RCTL_EN);
        /* flush and sleep below */
 
        netif_stop_queue(netdev);
@@ -3403,6 +3405,7 @@ void e1000e_down(struct e1000_adapter *adapter)
        tctl = er32(TCTL);
        tctl &= ~E1000_TCTL_EN;
        ew32(TCTL, tctl);
+
        /* flush both disables and wait for them to finish */
        e1e_flush();
        usleep_range(10000, 20000);
index 1c97861..f67b8ae 100644 (file)
@@ -193,14 +193,9 @@ static void set_alarm(struct etsects *etsects)
 /* Caller must hold etsects->lock. */
 static void set_fipers(struct etsects *etsects)
 {
-       u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
-
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl & (~TE));
-       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       set_alarm(etsects);
        gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
        gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
-       set_alarm(etsects);
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|TE);
 }
 
 /*
@@ -511,7 +506,7 @@ static int gianfar_ptp_probe(struct platform_device *dev)
        gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
        gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
        set_alarm(etsects);
-       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE|FRD);
 
        spin_unlock_irqrestore(&etsects->lock, flags);
 
index 4488bd5..8266067 100644 (file)
@@ -22,6 +22,8 @@
  *  - DMA transfer support
  *  - FIFO mode support
  */
+#include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
index 52a7c86..ed7d7d6 100644 (file)
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/io.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -511,7 +513,7 @@ static void sh_sir_tx(struct sh_sir_self *self, int phase)
 
 static int sh_sir_read_data(struct sh_sir_self *self)
 {
-       u16 val;
+       u16 val = 0;
        int timeout = 1024;
 
        while (timeout--) {
index 8b3090d..80b6f36 100644 (file)
@@ -82,7 +82,7 @@ static int cards_found;
 /*
  * VLB I/O addresses
  */
-static unsigned int pcnet32_portlist[] __initdata =
+static unsigned int pcnet32_portlist[] =
     { 0x300, 0x320, 0x340, 0x360, 0 };
 
 static int pcnet32_debug;
index 2cd8dc5..cb6e0b4 100644 (file)
@@ -34,8 +34,7 @@
 #define PAGESEL                0x13
 #define LAYER4         0x02
 #define LAYER2         0x01
-#define MAX_RXTS       4
-#define MAX_TXTS       4
+#define MAX_RXTS       64
 #define N_EXT_TS       1
 #define PSF_PTPVER     2
 #define PSF_EVNT       0x4000
@@ -218,7 +217,7 @@ static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
        rxts->seqid = p->seqid;
        rxts->msgtype = (p->msgtype >> 12) & 0xf;
        rxts->hash = p->msgtype & 0x0fff;
-       rxts->tmo = jiffies + HZ;
+       rxts->tmo = jiffies + 2;
 }
 
 static u64 phy2txts(struct phy_txts *p)
index f11b3f3..4c61753 100644 (file)
@@ -367,7 +367,7 @@ static void sl_bump(struct slip *sl)
        memcpy(skb_put(skb, count), sl->rbuff, count);
        skb_reset_mac_header(skb);
        skb->protocol = htons(ETH_P_IP);
-       netif_rx(skb);
+       netif_rx_ni(skb);
        dev->stats.rx_packets++;
 }
 
index 041fb7d..ef3b236 100644 (file)
@@ -977,7 +977,6 @@ static void rtl8150_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
        if (dev) {
                set_bit(RTL8150_UNPLUG, &dev->flags);
-               tasklet_disable(&dev->tl);
                tasklet_kill(&dev->tl);
                unregister_netdev(dev->netdev);
                unlink_all_urbs(dev);
index f54dff4..c3119a6 100644 (file)
@@ -1735,6 +1735,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf)
 
        if (dma_mapping_error(ah->dev, bf->skbaddr)) {
                ATH5K_ERR(ah, "beacon DMA mapping failed\n");
+               dev_kfree_skb_any(skb);
+               bf->skb = NULL;
                return -EIO;
        }
 
@@ -1819,8 +1821,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        ath5k_txbuf_free_skb(ah, avf->bbuf);
        avf->bbuf->skb = skb;
        ret = ath5k_beacon_setup(ah, avf->bbuf);
-       if (ret)
-               avf->bbuf->skb = NULL;
 out:
        return ret;
 }
@@ -1840,6 +1840,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
        struct ath5k_vif *avf;
        struct ath5k_buf *bf;
        struct sk_buff *skb;
+       int err;
 
        ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_BEACON, "in beacon_send\n");
 
@@ -1888,11 +1889,6 @@ ath5k_beacon_send(struct ath5k_hw *ah)
 
        avf = (void *)vif->drv_priv;
        bf = avf->bbuf;
-       if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
-                    ah->opmode == NL80211_IFTYPE_MONITOR)) {
-               ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
-               return;
-       }
 
        /*
         * Stop any current dma and put the new frame on the queue.
@@ -1906,8 +1902,17 @@ ath5k_beacon_send(struct ath5k_hw *ah)
 
        /* refresh the beacon for AP or MESH mode */
        if (ah->opmode == NL80211_IFTYPE_AP ||
-           ah->opmode == NL80211_IFTYPE_MESH_POINT)
-               ath5k_beacon_update(ah->hw, vif);
+           ah->opmode == NL80211_IFTYPE_MESH_POINT) {
+               err = ath5k_beacon_update(ah->hw, vif);
+               if (err)
+                       return;
+       }
+
+       if (unlikely(bf->skb == NULL || ah->opmode == NL80211_IFTYPE_STATION ||
+                    ah->opmode == NL80211_IFTYPE_MONITOR)) {
+               ATH5K_WARN(ah, "bf=%p bf_skb=%p\n", bf, bf->skb);
+               return;
+       }
 
        trace_ath5k_tx(ah, bf->skb, &ah->txqs[ah->bhalq]);
 
index d109c25..c34bef1 100644 (file)
@@ -307,7 +307,7 @@ static const struct ar9300_eeprom ar9300_default = {
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-                { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
@@ -884,7 +884,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-                { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
@@ -2040,7 +2040,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-               { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+               { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
@@ -3734,7 +3734,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
                                }
                        } else {
                                reg_pmu_set = (5 << 1) | (7 << 4) |
-                                             (1 << 8) | (2 << 14) |
+                                             (2 << 8) | (2 << 14) |
                                              (6 << 17) | (1 << 20) |
                                              (3 << 24) | (1 << 28);
                        }
index 6de3f0b..5c59042 100644 (file)
 #define AR_PHY_TPC_11_B1         (AR_SM1_BASE + 0x220)
 #define AR_PHY_PDADC_TAB_1       (AR_SM1_BASE + 0x240)
 #define AR_PHY_TX_IQCAL_STATUS_B1   (AR_SM1_BASE + 0x48c)
-#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i)    (AR_SM_BASE + 0x450 + ((_i) << 2))
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i)    (AR_SM1_BASE + 0x450 + ((_i) << 2))
 
 /*
  * Channel 2 Register Map
index 83cba22..481e534 100644 (file)
@@ -795,9 +795,23 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
        u32 tmp;
        u16 mmio_base;
 
-       tmp = b43_read32(dev, SSB_TMSHIGH);
-       if (tmp & SSB_TMSHIGH_DMA64)
-               return DMA_BIT_MASK(64);
+       switch (dev->dev->bus_type) {
+#ifdef CONFIG_B43_BCMA
+       case B43_BUS_BCMA:
+               tmp = bcma_aread32(dev->dev->bdev, BCMA_IOST);
+               if (tmp & BCMA_IOST_DMA64)
+                       return DMA_BIT_MASK(64);
+               break;
+#endif
+#ifdef CONFIG_B43_SSB
+       case B43_BUS_SSB:
+               tmp = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
+               if (tmp & SSB_TMSHIGH_DMA64)
+                       return DMA_BIT_MASK(64);
+               break;
+#endif
+       }
+
        mmio_base = b43_dmacontroller_base(0, 0);
        b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
        tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
index 5075593..9395631 100644 (file)
@@ -921,6 +921,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c16) },
        /* Draytek */
        { USB_DEVICE(0x07fa, 0x7712) },
+       /* DVICO */
+       { USB_DEVICE(0x0fe9, 0xb307) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7711) },
        { USB_DEVICE(0x7392, 0x7717) },
index 6a93939..0baeb89 100644 (file)
@@ -2420,6 +2420,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00d8) },
        { USB_DEVICE(0x0411, 0x00d9) },
+       { USB_DEVICE(0x0411, 0x00e6) },
        { USB_DEVICE(0x0411, 0x00f4) },
        { USB_DEVICE(0x0411, 0x0116) },
        { USB_DEVICE(0x0411, 0x0119) },
index 942f7a3..ef63c0d 100644 (file)
@@ -281,6 +281,8 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817d, rtl92cu_hal_cfg)},
        /* 8188CE-VAU USB minCard (b/g mode only) */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817e, rtl92cu_hal_cfg)},
+       /* 8188RU in Alfa AWUS036NHR */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
        /* 8188 Combo for BC4 */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
@@ -303,20 +305,23 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
        /* HP - Lite-On ,8188CUS Slim Combo */
        {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
        {RTL_USB_DEVICE(0x2001, 0x3308, rtl92cu_hal_cfg)}, /*D-Link - Alpha*/
        {RTL_USB_DEVICE(0x2019, 0xab2a, rtl92cu_hal_cfg)}, /*Planex - Abocom*/
        {RTL_USB_DEVICE(0x2019, 0xed17, rtl92cu_hal_cfg)}, /*PCI - Edimax*/
        {RTL_USB_DEVICE(0x20f4, 0x648b, rtl92cu_hal_cfg)}, /*TRENDnet - Cameo*/
        {RTL_USB_DEVICE(0x7392, 0x7811, rtl92cu_hal_cfg)}, /*Edimax - Edimax*/
-       {RTL_USB_DEVICE(0x3358, 0x13d3, rtl92cu_hal_cfg)}, /*Azwave 8188CE-VAU*/
+       {RTL_USB_DEVICE(0x13d3, 0x3358, rtl92cu_hal_cfg)}, /*Azwave 8188CE-VAU*/
        /* Russian customer -Azwave (8188CE-VAU  b/g mode only) */
-       {RTL_USB_DEVICE(0x3359, 0x13d3, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(0x13d3, 0x3359, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(0x4855, 0x0090, rtl92cu_hal_cfg)}, /* Feixun */
+       {RTL_USB_DEVICE(0x4855, 0x0091, rtl92cu_hal_cfg)}, /* NetweeN-Feixun */
+       {RTL_USB_DEVICE(0x9846, 0x9041, rtl92cu_hal_cfg)}, /* Netgear Cameo */
 
        /****** 8192CU ********/
        {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/
        {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
-       {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Abocom -Abocom*/
        {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
        {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
index ef8370e..ad87a1a 100644 (file)
@@ -140,8 +140,6 @@ int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
        auth->sleep_auth = sleep_auth;
 
        ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
-       if (ret < 0)
-               return ret;
 
 out:
        kfree(auth);
@@ -681,10 +679,8 @@ int wl1251_acx_cca_threshold(struct wl1251 *wl)
 
        ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
                                   detection, sizeof(*detection));
-       if (ret < 0) {
+       if (ret < 0)
                wl1251_warning("failed to set cca threshold: %d", ret);
-               return ret;
-       }
 
 out:
        kfree(detection);
index 81f164b..d14d69d 100644 (file)
@@ -241,7 +241,7 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
        if (ret < 0) {
                wl1251_error("tx %s cmd for channel %d failed",
                             enable ? "start" : "stop", channel);
-               return ret;
+               goto out;
        }
 
        wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
index 3195dbd..44e91e5 100644 (file)
@@ -639,7 +639,7 @@ EXPORT_SYMBOL_GPL(rtc_irq_unregister);
 static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
 {
        /*
-        * We unconditionally cancel the timer here, because otherwise
+        * We always cancel the timer here first, because otherwise
         * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
         * when we manage to start the timer before the callback
         * returns HRTIMER_RESTART.
@@ -708,7 +708,7 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
        int err = 0;
        unsigned long flags;
 
-       if (freq <= 0 || freq > 5000)
+       if (freq <= 0 || freq > RTC_MAX_FREQ)
                return -EINVAL;
 retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
index c01c0cb..b99a11a 100644 (file)
@@ -812,7 +812,7 @@ int AthCreateCommandList(struct ps_cmd_packet **HciPacketList, u32 *numPackets)
     for(count = 0; count < Patch_Count; count++) {
 
         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing Patch Buffer %d \r\n",count));
-        kfree(RamPatch[Patch_Count].Data);
+       kfree(RamPatch[count].Data);
     }
 
     for(count = 0; count < Tag_Count; count++) {
index fe02d22..05aa41c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf2-dma-contig.h>
index 627a98b..9e728b3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
+#include <asm/io.h>
 #include <asm/uaccess.h>
 #include "ft1000.h"
 
index 779ac1a..daac121 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm.h>
 
-/**
- * Initialize an already allocated GEM object of the specified size with
- * no GEM provided backing store. Instead the caller is responsible for
- * backing the object and handling it.
- */
-int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size)
-{
-       BUG_ON((size & (PAGE_SIZE - 1)) != 0);
-
-       obj->dev = dev;
-       obj->filp = NULL;
-
-       kref_init(&obj->refcount);
-       atomic_set(&obj->handle_count, 0);
-       obj->size = size;
-
-       return 0;
-}
-
 void drm_gem_object_release_wrap(struct drm_gem_object *obj)
 {
        /* Remove the list map if one is present */
@@ -51,8 +31,7 @@ void drm_gem_object_release_wrap(struct drm_gem_object *obj)
                kfree(list->map);
                list->map = NULL;
        }
-       if (obj->filp)
-               drm_gem_object_release(obj);
+       drm_gem_object_release(obj);
 }
 
 /**
index a0f2bc4..ce5ce30 100644 (file)
@@ -1,4 +1,2 @@
 extern void drm_gem_object_release_wrap(struct drm_gem_object *obj);
-extern int drm_gem_private_object_init(struct drm_device *dev,
-                       struct drm_gem_object *obj, size_t size);
 extern int gem_create_mmap_offset(struct drm_gem_object *obj);
index 02e17c9..fd211f3 100644 (file)
@@ -711,10 +711,11 @@ struct mdfld_dsi_encoder *mdfld_dsi_dbi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dbi_output->base.base;
+       /* Review this if we ever get MIPI-HDMI bridges or similar */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder, p_funcs->encoder_helper_funcs);
 
        /* Attach to given connector */
index dc6242c..f0fa986 100644 (file)
@@ -42,9 +42,6 @@
 #include "mdfld_dsi_output.h"
 #include "mdfld_output.h"
 
-#define DRM_MODE_ENCODER_MIPI  5
-
-
 /*
  * DBI encoder which inherits from mdfld_dsi_encoder
  */
index 6e03a91..e685f12 100644 (file)
@@ -777,10 +777,15 @@ struct mdfld_dsi_encoder *mdfld_dsi_dpi_init(struct drm_device *dev,
        /* Create drm encoder object */
        connector = &dsi_connector->base.base;
        encoder = &dpi_output->base.base;
+       /*
+        * On existing hardware this will be a panel of some form,
+        * if future devices also have HDMI bridges this will need
+        * revisiting
+        */
        drm_encoder_init(dev,
                        encoder,
                        p_funcs->encoder_funcs,
-                       DRM_MODE_ENCODER_MIPI);
+                       DRM_MODE_ENCODER_LVDS);
        drm_encoder_helper_add(encoder,
                                p_funcs->encoder_helper_funcs);
        
index 7536095..9050c0f 100644 (file)
@@ -955,7 +955,9 @@ void mdfld_dsi_output_init(struct drm_device *dev,
        psb_output->type = (pipe == 0) ? INTEL_OUTPUT_MIPI : INTEL_OUTPUT_MIPI2;
 
        connector = &psb_output->base;
-       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, DRM_MODE_CONNECTOR_MIPI);
+       /* Revisit type if MIPI/HDMI bridges ever appear on Medfield */
+       drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs,
+                                               DRM_MODE_CONNECTOR_LVDS);
        drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs);
        
        connector->display_info.subpixel_order = SubPixelHorizontalRGB;
index 38165e8..09e9687 100644 (file)
@@ -21,8 +21,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#define DRM_MODE_ENCODER_MIPI  5
-
 /* Medfield DSI controller registers */
 
 #define MIPIA_DEVICE_READY_REG                         0xb000
index 72f487a..fd4732d 100644 (file)
@@ -35,7 +35,6 @@
 
 /* Append new drm mode definition here, align with libdrm definition */
 #define DRM_MODE_SCALE_NO_SCALE        2
-#define DRM_MODE_CONNECTOR_MIPI         15
 
 enum {
        CHIP_PSB_8108 = 0,              /* Poulsbo */
index 3612574..d286b22 100644 (file)
@@ -325,7 +325,7 @@ static int blkvsc_do_operation(struct block_device_context *blkdev,
 
        page_buf = alloc_page(GFP_KERNEL);
        if (!page_buf) {
-               kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+               kmem_cache_free(blkdev->request_pool, blkvsc_req);
                return -ENOMEM;
        }
 
@@ -422,7 +422,7 @@ cleanup:
 
        __free_page(page_buf);
 
-       kmem_cache_free(blkvsc_req->dev->request_pool, blkvsc_req);
+       kmem_cache_free(blkdev->request_pool, blkvsc_req);
 
        return ret;
 }
index bf19888..cf5d15d 100644 (file)
@@ -311,13 +311,17 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16203_addresses[chan->address][0];
                ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16203_ERROR_ACTIVE) {
                        ret = adis16203_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index cfd09b3..3e2b626 100644 (file)
@@ -341,13 +341,17 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16204_addresses[chan->address][0];
                ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16204_ERROR_ACTIVE) {
                        ret = adis16204_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 55f3a7b..bec1fa8 100644 (file)
@@ -337,13 +337,17 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16209_addresses[chan->address][0];
                ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16209_ERROR_ACTIVE) {
                        ret = adis16209_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 4a4eafc..aee8b69 100644 (file)
@@ -370,13 +370,17 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16240_addresses[chan->address][0];
                ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16240_ERROR_ACTIVE) {
                        ret = adis16240_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 05797f4..f2d43cf 100644 (file)
@@ -446,13 +446,17 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
                mutex_lock(&indio_dev->mlock);
                addr = adis16260_addresses[chan->address][0];
                ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&indio_dev->mlock);
                        return ret;
+               }
 
                if (val16 & ADIS16260_ERROR_ACTIVE) {
                        ret = adis16260_check_status(indio_dev);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&indio_dev->mlock);
                                return ret;
+                       }
                }
                val16 = val16 & ((1 << chan->scan_type.realbits) - 1);
                if (chan->scan_type.sign == 's')
index 77b47f7..649d6b7 100644 (file)
@@ -4,5 +4,7 @@ ToDo list (incomplete, unordered)
        - add compile as module support
        - move nvec devices to mfd cells?
        - adjust to kernel style
-
-
+       - fix clk usage
+         should not be using clk_get_sys(), but clk_get(&pdev->dev, conn)
+         where conn is either NULL if the device only has one clock, or
+         the device specific name if it has multiple clocks.
index 6766f46..4bb5fff 100644 (file)
@@ -399,10 +399,7 @@ download_firmware_fail:
 
 }
 
-
-
-
-
-
-
+MODULE_FIRMWARE("RTL8192U/boot.img");
+MODULE_FIRMWARE("RTL8192U/main.img");
+MODULE_FIRMWARE("RTL8192U/data.img");
 
index 5ff59f2..16c73fb 100644 (file)
@@ -66,12 +66,6 @@ static int msi_en;
 module_param(msi_en, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(msi_en, "enable msi");
 
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
-
 static irqreturn_t rtsx_interrupt(int irq, void *dev_id);
 
 /***********************************************************************
@@ -192,7 +186,7 @@ static int queuecommand_lck(struct scsi_cmnd *srb,
        /* enqueue the command and wake up the control thread */
        srb->scsi_done = done;
        chip->srb = srb;
-       up(&(dev->sema));
+       complete(&dev->cmnd_ready);
 
        return 0;
 }
@@ -475,7 +469,7 @@ static int rtsx_control_thread(void *__dev)
        current->flags |= PF_NOFREEZE;
 
        for (;;) {
-               if (down_interruptible(&dev->sema))
+               if (wait_for_completion_interruptible(&dev->cmnd_ready))
                        break;
 
                /* lock the device pointers */
@@ -557,8 +551,6 @@ SkipForAbort:
                mutex_unlock(&dev->dev_mutex);
        } /* for (;;) */
 
-       scsi_host_put(host);
-
        /* notify the exit routine that we're actually exiting now
         *
         * complete()/wait_for_completion() is similar to up()/down(),
@@ -573,7 +565,7 @@ SkipForAbort:
         * This is important in preemption kernels, which transfer the flow
         * of execution immediately upon a complete().
         */
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->control_exit, 0);
 }
 
 
@@ -581,7 +573,6 @@ static int rtsx_polling_thread(void *__dev)
 {
        struct rtsx_dev *dev = (struct rtsx_dev *)__dev;
        struct rtsx_chip *chip = dev->chip;
-       struct Scsi_Host *host = rtsx_to_host(dev);
        struct sd_info *sd_card = &(chip->sd_card);
        struct xd_info *xd_card = &(chip->xd_card);
        struct ms_info *ms_card = &(chip->ms_card);
@@ -621,8 +612,7 @@ static int rtsx_polling_thread(void *__dev)
                mutex_unlock(&dev->dev_mutex);
        }
 
-       scsi_host_put(host);
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->polling_exit, 0);
 }
 
 /*
@@ -699,29 +689,38 @@ static void rtsx_release_resources(struct rtsx_dev *dev)
 {
        printk(KERN_INFO "-- %s\n", __func__);
 
+       /* Tell the control thread to exit.  The SCSI host must
+        * already have been removed so it won't try to queue
+        * any more commands.
+        */
+       printk(KERN_INFO "-- sending exit command to thread\n");
+       complete(&dev->cmnd_ready);
+       if (dev->ctl_thread)
+               wait_for_completion(&dev->control_exit);
+       if (dev->polling_thread)
+               wait_for_completion(&dev->polling_exit);
+
+       wait_timeout(200);
+
        if (dev->rtsx_resv_buf) {
-               dma_free_coherent(&(dev->pci->dev), HOST_CMDS_BUF_LEN,
+               dma_free_coherent(&(dev->pci->dev), RTSX_RESV_BUF_LEN,
                                dev->rtsx_resv_buf, dev->rtsx_resv_buf_addr);
                dev->chip->host_cmds_ptr = NULL;
                dev->chip->host_sg_tbl_ptr = NULL;
        }
 
-       pci_disable_device(dev->pci);
-       pci_release_regions(dev->pci);
-
-       if (dev->irq > 0) {
+       if (dev->irq > 0)
                free_irq(dev->irq, (void *)dev);
-       }
-       if (dev->chip->msi_en) {
+       if (dev->chip->msi_en)
                pci_disable_msi(dev->pci);
-       }
+       if (dev->remap_addr)
+               iounmap(dev->remap_addr);
 
-       /* Tell the control thread to exit.  The SCSI host must
-        * already have been removed so it won't try to queue
-        * any more commands.
-        */
-       printk(KERN_INFO "-- sending exit command to thread\n");
-       up(&dev->sema);
+       pci_disable_device(dev->pci);
+       pci_release_regions(dev->pci);
+
+       rtsx_release_chip(dev->chip);
+       kfree(dev->chip);
 }
 
 /* First stage of disconnect processing: stop all commands and remove
@@ -739,6 +738,7 @@ static void quiesce_and_remove_host(struct rtsx_dev *dev)
        scsi_unlock(host);
        mutex_unlock(&dev->dev_mutex);
        wake_up(&dev->delay_wait);
+       wait_for_completion(&dev->scanning_done);
 
        /* Wait some time to let other threads exist */
        wait_timeout(100);
@@ -793,8 +793,7 @@ static int rtsx_scan_thread(void *__dev)
                /* Should we unbind if no devices were detected? */
        }
 
-       scsi_host_put(rtsx_to_host(dev));
-       complete_and_exit(&threads_gone, 0);
+       complete_and_exit(&dev->scanning_done, 0);
 }
 
 static void rtsx_init_options(struct rtsx_chip *chip)
@@ -941,8 +940,11 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
 
        spin_lock_init(&dev->reg_lock);
        mutex_init(&(dev->dev_mutex));
-       sema_init(&(dev->sema), 0);
+       init_completion(&dev->cmnd_ready);
+       init_completion(&dev->control_exit);
+       init_completion(&dev->polling_exit);
        init_completion(&(dev->notify));
+       init_completion(&dev->scanning_done);
        init_waitqueue_head(&dev->delay_wait);
 
        dev->pci = pci;
@@ -992,28 +994,22 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
        pci_set_master(pci);
        synchronize_irq(dev->irq);
 
-       err = scsi_add_host(host, &pci->dev);
-       if (err) {
-               printk(KERN_ERR "Unable to add the scsi host\n");
-               goto errout;
-       }
-
        rtsx_init_chip(dev->chip);
 
        /* Start up our control thread */
-       th = kthread_create(rtsx_control_thread, dev, CR_DRIVER_NAME);
+       th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME);
        if (IS_ERR(th)) {
                printk(KERN_ERR "Unable to start control thread\n");
                err = PTR_ERR(th);
                goto errout;
        }
+       dev->ctl_thread = th;
 
-       /* Take a reference to the host for the control thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
-       wake_up_process(th);
+       err = scsi_add_host(host, &pci->dev);
+       if (err) {
+               printk(KERN_ERR "Unable to add the scsi host\n");
+               goto errout;
+       }
 
        /* Start up the thread for delayed SCSI-device scanning */
        th = kthread_create(rtsx_scan_thread, dev, "rtsx-scan");
@@ -1024,28 +1020,17 @@ static int __devinit rtsx_probe(struct pci_dev *pci, const struct pci_device_id
                goto errout;
        }
 
-       /* Take a reference to the host for the scanning thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
        wake_up_process(th);
 
        /* Start up the thread for polling thread */
-       th = kthread_create(rtsx_polling_thread, dev, "rtsx-polling");
+       th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling");
        if (IS_ERR(th)) {
                printk(KERN_ERR "Unable to start the device-polling thread\n");
                quiesce_and_remove_host(dev);
                err = PTR_ERR(th);
                goto errout;
        }
-
-       /* Take a reference to the host for the polling thread and
-        * count it among all the threads we have launched.  Then
-        * start it up. */
-       scsi_host_get(rtsx_to_host(dev));
-       atomic_inc(&total_threads);
-       wake_up_process(th);
+       dev->polling_thread = th;
 
        pci_set_drvdata(pci, dev);
 
@@ -1108,16 +1093,6 @@ static void __exit rtsx_exit(void)
 
        pci_unregister_driver(&driver);
 
-       /* Don't return until all of our control and scanning threads
-        * have exited.  Since each thread signals threads_gone as its
-        * last act, we have to call wait_for_completion the right number
-        * of times.
-        */
-       while (atomic_read(&total_threads) > 0) {
-               wait_for_completion(&threads_gone);
-               atomic_dec(&total_threads);
-       }
-
        printk(KERN_INFO "%s module exit\n", CR_DRIVER_NAME);
 }
 
index 247615b..86e47c2 100644 (file)
@@ -112,9 +112,16 @@ struct rtsx_dev {
        /* locks */
        spinlock_t              reg_lock;
 
+       struct task_struct      *ctl_thread;     /* the control thread   */
+       struct task_struct      *polling_thread; /* the polling thread   */
+
        /* mutual exclusion and synchronization structures */
-       struct semaphore        sema;            /* to sleep thread on      */
+       struct completion       cmnd_ready;      /* to sleep thread on      */
+       struct completion       control_exit;    /* control thread exit     */
+       struct completion       polling_exit;    /* polling thread exit     */
        struct completion       notify;          /* thread begin/end        */
+       struct completion       scanning_done;   /* wait for scan thread    */
+
        wait_queue_head_t       delay_wait;      /* wait during scan, reset */
        struct mutex            dev_mutex;
 
index 7677994..f974f64 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 #include <linux/videodev2.h>
 #include "solo6x10.h"
 #include "tw28.h"
index 285f7f3..de50259 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include "solo6x10.h"
 #include "osd-font.h"
 
index bd8eb92..59274bf 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mempool.h>
 #include <linux/poll.h>
 #include <linux/kthread.h>
+#include <linux/slab.h>
 #include <linux/freezer.h>
 #include <sound/core.h>
 #include <sound/initval.h>
index 5717eab..56210f0 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include "solo6x10.h"
 
index 17c06bd..abee721 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #include <linux/atomic.h>
 #include <linux/videodev2.h>
index 39dc586..940769e 100644 (file)
@@ -18,13 +18,14 @@ static ssize_t speakup_file_write(struct file *fp, const char *buffer,
 {
        size_t count = nbytes;
        const char *ptr = buffer;
-       int bytes;
+       size_t bytes;
        unsigned long flags;
        u_char buf[256];
+
        if (synth == NULL)
                return -ENODEV;
        while (count > 0) {
-               bytes = min_t(size_t, count, sizeof(buf));
+               bytes = min(count, sizeof(buf));
                if (copy_from_user(buf, ptr, bytes))
                        return -EFAULT;
                count -= bytes;
index f5ec64f..60daa27 100644 (file)
@@ -1,3 +1,3 @@
-zcache-y       :=      tmem.o
+zcache-y       :=      zcache-main.o tmem.o
 
 obj-$(CONFIG_ZCACHE)   +=      zcache.o
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
new file mode 100644 (file)
index 0000000..855a5bb
--- /dev/null
@@ -0,0 +1,2003 @@
+/*
+ * zcache.c
+ *
+ * Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp.
+ * Copyright (c) 2010,2011, Nitin Gupta
+ *
+ * Zcache provides an in-kernel "host implementation" for transcendent memory
+ * and, thus indirectly, for cleancache and frontswap.  Zcache includes two
+ * page-accessible memory [1] interfaces, both utilizing lzo1x compression:
+ * 1) "compression buddies" ("zbud") is used for ephemeral pages
+ * 2) xvmalloc is used for persistent pages.
+ * Xvmalloc (based on the TLSF allocator) has very low fragmentation
+ * so maximizes space efficiency, while zbud allows pairs (and potentially,
+ * in the future, more than a pair of) compressed pages to be closely linked
+ * so that reclaiming can be done via the kernel's physical-page-oriented
+ * "shrinker" interface.
+ *
+ * [1] For a definition of page-accessible memory (aka PAM), see:
+ *   http://marc.info/?l=linux-mm&m=127811271605009
+ */
+
+#include <linux/module.h>
+#include <linux/cpu.h>
+#include <linux/highmem.h>
+#include <linux/list.h>
+#include <linux/lzo.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/math64.h>
+#include "tmem.h"
+
+#include "../zram/xvmalloc.h" /* if built in drivers/staging */
+
+#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP))
+#error "zcache is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP"
+#endif
+#ifdef CONFIG_CLEANCACHE
+#include <linux/cleancache.h>
+#endif
+#ifdef CONFIG_FRONTSWAP
+#include <linux/frontswap.h>
+#endif
+
+#if 0
+/* this is more aggressive but may cause other problems? */
+#define ZCACHE_GFP_MASK        (GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN)
+#else
+#define ZCACHE_GFP_MASK \
+       (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
+#endif
+
+#define MAX_POOLS_PER_CLIENT 16
+
+#define MAX_CLIENTS 16
+#define LOCAL_CLIENT ((uint16_t)-1)
+
+MODULE_LICENSE("GPL");
+
+struct zcache_client {
+       struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
+       struct xv_pool *xvpool;
+       bool allocated;
+       atomic_t refcount;
+};
+
+static struct zcache_client zcache_host;
+static struct zcache_client zcache_clients[MAX_CLIENTS];
+
+static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
+{
+       BUG_ON(cli == NULL);
+       if (cli == &zcache_host)
+               return LOCAL_CLIENT;
+       return cli - &zcache_clients[0];
+}
+
+static inline bool is_local_client(struct zcache_client *cli)
+{
+       return cli == &zcache_host;
+}
+
+/**********
+ * Compression buddies ("zbud") provides for packing two (or, possibly
+ * in the future, more) compressed ephemeral pages into a single "raw"
+ * (physical) page and tracking them with data structures so that
+ * the raw pages can be easily reclaimed.
+ *
+ * A zbud page ("zbpg") is an aligned page containing a list_head,
+ * a lock, and two "zbud headers".  The remainder of the physical
+ * page is divided up into aligned 64-byte "chunks" which contain
+ * the compressed data for zero, one, or two zbuds.  Each zbpg
+ * resides on: (1) an "unused list" if it has no zbuds; (2) a
+ * "buddied" list if it is fully populated  with two zbuds; or
+ * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
+ * the one unbuddied zbud uses.  The data inside a zbpg cannot be
+ * read or written unless the zbpg's lock is held.
+ */
+
+#define ZBH_SENTINEL  0x43214321
+#define ZBPG_SENTINEL  0xdeadbeef
+
+#define ZBUD_MAX_BUDS 2
+
+struct zbud_hdr {
+       uint16_t client_id;
+       uint16_t pool_id;
+       struct tmem_oid oid;
+       uint32_t index;
+       uint16_t size; /* compressed size in bytes, zero means unused */
+       DECL_SENTINEL
+};
+
+struct zbud_page {
+       struct list_head bud_list;
+       spinlock_t lock;
+       struct zbud_hdr buddy[ZBUD_MAX_BUDS];
+       DECL_SENTINEL
+       /* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
+};
+
+#define CHUNK_SHIFT    6
+#define CHUNK_SIZE     (1 << CHUNK_SHIFT)
+#define CHUNK_MASK     (~(CHUNK_SIZE-1))
+#define NCHUNKS                (((PAGE_SIZE - sizeof(struct zbud_page)) & \
+                               CHUNK_MASK) >> CHUNK_SHIFT)
+#define MAX_CHUNK      (NCHUNKS-1)
+
+static struct {
+       struct list_head list;
+       unsigned count;
+} zbud_unbuddied[NCHUNKS];
+/* list N contains pages with N chunks USED and NCHUNKS-N unused */
+/* element 0 is never used but optimizing that isn't worth it */
+static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
+
+struct list_head zbud_buddied_list;
+static unsigned long zcache_zbud_buddied_count;
+
+/* protects the buddied list and all unbuddied lists */
+static DEFINE_SPINLOCK(zbud_budlists_spinlock);
+
+static LIST_HEAD(zbpg_unused_list);
+static unsigned long zcache_zbpg_unused_list_count;
+
+/* protects the unused page list */
+static DEFINE_SPINLOCK(zbpg_unused_list_spinlock);
+
+static atomic_t zcache_zbud_curr_raw_pages;
+static atomic_t zcache_zbud_curr_zpages;
+static unsigned long zcache_zbud_curr_zbytes;
+static unsigned long zcache_zbud_cumul_zpages;
+static unsigned long zcache_zbud_cumul_zbytes;
+static unsigned long zcache_compress_poor;
+static unsigned long zcache_mean_compress_poor;
+
+/* forward references */
+static void *zcache_get_free_page(void);
+static void zcache_free_page(void *p);
+
+/*
+ * zbud helper functions
+ */
+
+static inline unsigned zbud_max_buddy_size(void)
+{
+       return MAX_CHUNK << CHUNK_SHIFT;
+}
+
+static inline unsigned zbud_size_to_chunks(unsigned size)
+{
+       BUG_ON(size == 0 || size > zbud_max_buddy_size());
+       return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
+}
+
+static inline int zbud_budnum(struct zbud_hdr *zh)
+{
+       unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
+       struct zbud_page *zbpg = NULL;
+       unsigned budnum = -1U;
+       int i;
+
+       for (i = 0; i < ZBUD_MAX_BUDS; i++)
+               if (offset == offsetof(typeof(*zbpg), buddy[i])) {
+                       budnum = i;
+                       break;
+               }
+       BUG_ON(budnum == -1U);
+       return budnum;
+}
+
+static char *zbud_data(struct zbud_hdr *zh, unsigned size)
+{
+       struct zbud_page *zbpg;
+       char *p;
+       unsigned budnum;
+
+       ASSERT_SENTINEL(zh, ZBH);
+       budnum = zbud_budnum(zh);
+       BUG_ON(size == 0 || size > zbud_max_buddy_size());
+       zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+       ASSERT_SPINLOCK(&zbpg->lock);
+       p = (char *)zbpg;
+       if (budnum == 0)
+               p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
+                                                       CHUNK_MASK);
+       else if (budnum == 1)
+               p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
+       return p;
+}
+
+/*
+ * zbud raw page management
+ */
+
+static struct zbud_page *zbud_alloc_raw_page(void)
+{
+       struct zbud_page *zbpg = NULL;
+       struct zbud_hdr *zh0, *zh1;
+       bool recycled = 0;
+
+       /* if any pages on the zbpg list, use one */
+       spin_lock(&zbpg_unused_list_spinlock);
+       if (!list_empty(&zbpg_unused_list)) {
+               zbpg = list_first_entry(&zbpg_unused_list,
+                               struct zbud_page, bud_list);
+               list_del_init(&zbpg->bud_list);
+               zcache_zbpg_unused_list_count--;
+               recycled = 1;
+       }
+       spin_unlock(&zbpg_unused_list_spinlock);
+       if (zbpg == NULL)
+               /* none on zbpg list, try to get a kernel page */
+               zbpg = zcache_get_free_page();
+       if (likely(zbpg != NULL)) {
+               INIT_LIST_HEAD(&zbpg->bud_list);
+               zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+               spin_lock_init(&zbpg->lock);
+               if (recycled) {
+                       ASSERT_INVERTED_SENTINEL(zbpg, ZBPG);
+                       SET_SENTINEL(zbpg, ZBPG);
+                       BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
+                       BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
+               } else {
+                       atomic_inc(&zcache_zbud_curr_raw_pages);
+                       INIT_LIST_HEAD(&zbpg->bud_list);
+                       SET_SENTINEL(zbpg, ZBPG);
+                       zh0->size = 0; zh1->size = 0;
+                       tmem_oid_set_invalid(&zh0->oid);
+                       tmem_oid_set_invalid(&zh1->oid);
+               }
+       }
+       return zbpg;
+}
+
+static void zbud_free_raw_page(struct zbud_page *zbpg)
+{
+       struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
+
+       ASSERT_SENTINEL(zbpg, ZBPG);
+       BUG_ON(!list_empty(&zbpg->bud_list));
+       ASSERT_SPINLOCK(&zbpg->lock);
+       BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
+       BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
+       INVERT_SENTINEL(zbpg, ZBPG);
+       spin_unlock(&zbpg->lock);
+       spin_lock(&zbpg_unused_list_spinlock);
+       list_add(&zbpg->bud_list, &zbpg_unused_list);
+       zcache_zbpg_unused_list_count++;
+       spin_unlock(&zbpg_unused_list_spinlock);
+}
+
+/*
+ * core zbud handling routines
+ */
+
+static unsigned zbud_free(struct zbud_hdr *zh)
+{
+       unsigned size;
+
+       ASSERT_SENTINEL(zh, ZBH);
+       BUG_ON(!tmem_oid_valid(&zh->oid));
+       size = zh->size;
+       BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+       zh->size = 0;
+       tmem_oid_set_invalid(&zh->oid);
+       INVERT_SENTINEL(zh, ZBH);
+       zcache_zbud_curr_zbytes -= size;
+       atomic_dec(&zcache_zbud_curr_zpages);
+       return size;
+}
+
+static void zbud_free_and_delist(struct zbud_hdr *zh)
+{
+       unsigned chunks;
+       struct zbud_hdr *zh_other;
+       unsigned budnum = zbud_budnum(zh), size;
+       struct zbud_page *zbpg =
+               container_of(zh, struct zbud_page, buddy[budnum]);
+
+       spin_lock(&zbpg->lock);
+       if (list_empty(&zbpg->bud_list)) {
+               /* ignore zombie page... see zbud_evict_pages() */
+               spin_unlock(&zbpg->lock);
+               return;
+       }
+       size = zbud_free(zh);
+       ASSERT_SPINLOCK(&zbpg->lock);
+       zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
+       if (zh_other->size == 0) { /* was unbuddied: unlist and free */
+               chunks = zbud_size_to_chunks(size) ;
+               spin_lock(&zbud_budlists_spinlock);
+               BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
+               list_del_init(&zbpg->bud_list);
+               zbud_unbuddied[chunks].count--;
+               spin_unlock(&zbud_budlists_spinlock);
+               zbud_free_raw_page(zbpg);
+       } else { /* was buddied: move remaining buddy to unbuddied list */
+               chunks = zbud_size_to_chunks(zh_other->size) ;
+               spin_lock(&zbud_budlists_spinlock);
+               list_del_init(&zbpg->bud_list);
+               zcache_zbud_buddied_count--;
+               list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
+               zbud_unbuddied[chunks].count++;
+               spin_unlock(&zbud_budlists_spinlock);
+               spin_unlock(&zbpg->lock);
+       }
+}
+
+static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
+                                       struct tmem_oid *oid,
+                                       uint32_t index, struct page *page,
+                                       void *cdata, unsigned size)
+{
+       struct zbud_hdr *zh0, *zh1, *zh = NULL;
+       struct zbud_page *zbpg = NULL, *ztmp;
+       unsigned nchunks;
+       char *to;
+       int i, found_good_buddy = 0;
+
+       nchunks = zbud_size_to_chunks(size) ;
+       for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
+               spin_lock(&zbud_budlists_spinlock);
+               if (!list_empty(&zbud_unbuddied[i].list)) {
+                       list_for_each_entry_safe(zbpg, ztmp,
+                                   &zbud_unbuddied[i].list, bud_list) {
+                               if (spin_trylock(&zbpg->lock)) {
+                                       found_good_buddy = i;
+                                       goto found_unbuddied;
+                               }
+                       }
+               }
+               spin_unlock(&zbud_budlists_spinlock);
+       }
+       /* didn't find a good buddy, try allocating a new page */
+       zbpg = zbud_alloc_raw_page();
+       if (unlikely(zbpg == NULL))
+               goto out;
+       /* ok, have a page, now compress the data before taking locks */
+       spin_lock(&zbpg->lock);
+       spin_lock(&zbud_budlists_spinlock);
+       list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
+       zbud_unbuddied[nchunks].count++;
+       zh = &zbpg->buddy[0];
+       goto init_zh;
+
+found_unbuddied:
+       ASSERT_SPINLOCK(&zbpg->lock);
+       zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
+       BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
+       if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
+               ASSERT_SENTINEL(zh0, ZBH);
+               zh = zh1;
+       } else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
+               ASSERT_SENTINEL(zh1, ZBH);
+               zh = zh0;
+       } else
+               BUG();
+       list_del_init(&zbpg->bud_list);
+       zbud_unbuddied[found_good_buddy].count--;
+       list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
+       zcache_zbud_buddied_count++;
+
+init_zh:
+       SET_SENTINEL(zh, ZBH);
+       zh->size = size;
+       zh->index = index;
+       zh->oid = *oid;
+       zh->pool_id = pool_id;
+       zh->client_id = client_id;
+       /* can wait to copy the data until the list locks are dropped */
+       spin_unlock(&zbud_budlists_spinlock);
+
+       to = zbud_data(zh, size);
+       memcpy(to, cdata, size);
+       spin_unlock(&zbpg->lock);
+       zbud_cumul_chunk_counts[nchunks]++;
+       atomic_inc(&zcache_zbud_curr_zpages);
+       zcache_zbud_cumul_zpages++;
+       zcache_zbud_curr_zbytes += size;
+       zcache_zbud_cumul_zbytes += size;
+out:
+       return zh;
+}
+
+static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
+{
+       struct zbud_page *zbpg;
+       unsigned budnum = zbud_budnum(zh);
+       size_t out_len = PAGE_SIZE;
+       char *to_va, *from_va;
+       unsigned size;
+       int ret = 0;
+
+       zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
+       spin_lock(&zbpg->lock);
+       if (list_empty(&zbpg->bud_list)) {
+               /* ignore zombie page... see zbud_evict_pages() */
+               ret = -EINVAL;
+               goto out;
+       }
+       ASSERT_SENTINEL(zh, ZBH);
+       BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
+       to_va = kmap_atomic(page, KM_USER0);
+       size = zh->size;
+       from_va = zbud_data(zh, size);
+       ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
+       BUG_ON(ret != LZO_E_OK);
+       BUG_ON(out_len != PAGE_SIZE);
+       kunmap_atomic(to_va, KM_USER0);
+out:
+       spin_unlock(&zbpg->lock);
+       return ret;
+}
+
+/*
+ * The following routines handle shrinking of ephemeral pages by evicting
+ * pages "least valuable" first.
+ */
+
+static unsigned long zcache_evicted_raw_pages;
+static unsigned long zcache_evicted_buddied_pages;
+static unsigned long zcache_evicted_unbuddied_pages;
+
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
+                                               uint16_t poolid);
+static void zcache_put_pool(struct tmem_pool *pool);
+
+/*
+ * Flush and free all zbuds in a zbpg, then free the pageframe
+ */
+static void zbud_evict_zbpg(struct zbud_page *zbpg)
+{
+       struct zbud_hdr *zh;
+       int i, j;
+       uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS];
+       uint32_t index[ZBUD_MAX_BUDS];
+       struct tmem_oid oid[ZBUD_MAX_BUDS];
+       struct tmem_pool *pool;
+
+       ASSERT_SPINLOCK(&zbpg->lock);
+       BUG_ON(!list_empty(&zbpg->bud_list));
+       for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) {
+               zh = &zbpg->buddy[i];
+               if (zh->size) {
+                       client_id[j] = zh->client_id;
+                       pool_id[j] = zh->pool_id;
+                       oid[j] = zh->oid;
+                       index[j] = zh->index;
+                       j++;
+                       zbud_free(zh);
+               }
+       }
+       spin_unlock(&zbpg->lock);
+       for (i = 0; i < j; i++) {
+               pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
+               if (pool != NULL) {
+                       tmem_flush_page(pool, &oid[i], index[i]);
+                       zcache_put_pool(pool);
+               }
+       }
+       ASSERT_SENTINEL(zbpg, ZBPG);
+       spin_lock(&zbpg->lock);
+       zbud_free_raw_page(zbpg);
+}
+
+/*
+ * Free nr pages.  This code is funky because we want to hold the locks
+ * protecting various lists for as short a time as possible, and in some
+ * circumstances the list may change asynchronously when the list lock is
+ * not held.  In some cases we also trylock not only to avoid waiting on a
+ * page in use by another cpu, but also to avoid potential deadlock due to
+ * lock inversion.
+ */
+static void zbud_evict_pages(int nr)
+{
+       struct zbud_page *zbpg;
+       int i;
+
+       /* first try freeing any pages on unused list */
+retry_unused_list:
+       spin_lock_bh(&zbpg_unused_list_spinlock);
+       if (!list_empty(&zbpg_unused_list)) {
+               /* can't walk list here, since it may change when unlocked */
+               zbpg = list_first_entry(&zbpg_unused_list,
+                               struct zbud_page, bud_list);
+               list_del_init(&zbpg->bud_list);
+               zcache_zbpg_unused_list_count--;
+               atomic_dec(&zcache_zbud_curr_raw_pages);
+               spin_unlock_bh(&zbpg_unused_list_spinlock);
+               zcache_free_page(zbpg);
+               zcache_evicted_raw_pages++;
+               if (--nr <= 0)
+                       goto out;
+               goto retry_unused_list;
+       }
+       spin_unlock_bh(&zbpg_unused_list_spinlock);
+
+       /* now try freeing unbuddied pages, starting with least space avail */
+       for (i = 0; i < MAX_CHUNK; i++) {
+retry_unbud_list_i:
+               spin_lock_bh(&zbud_budlists_spinlock);
+               if (list_empty(&zbud_unbuddied[i].list)) {
+                       spin_unlock_bh(&zbud_budlists_spinlock);
+                       continue;
+               }
+               list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
+                       if (unlikely(!spin_trylock(&zbpg->lock)))
+                               continue;
+                       list_del_init(&zbpg->bud_list);
+                       zbud_unbuddied[i].count--;
+                       spin_unlock(&zbud_budlists_spinlock);
+                       zcache_evicted_unbuddied_pages++;
+                       /* want budlists unlocked when doing zbpg eviction */
+                       zbud_evict_zbpg(zbpg);
+                       local_bh_enable();
+                       if (--nr <= 0)
+                               goto out;
+                       goto retry_unbud_list_i;
+               }
+               spin_unlock_bh(&zbud_budlists_spinlock);
+       }
+
+       /* as a last resort, free buddied pages */
+retry_bud_list:
+       spin_lock_bh(&zbud_budlists_spinlock);
+       if (list_empty(&zbud_buddied_list)) {
+               spin_unlock_bh(&zbud_budlists_spinlock);
+               goto out;
+       }
+       list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
+               if (unlikely(!spin_trylock(&zbpg->lock)))
+                       continue;
+               list_del_init(&zbpg->bud_list);
+               zcache_zbud_buddied_count--;
+               spin_unlock(&zbud_budlists_spinlock);
+               zcache_evicted_buddied_pages++;
+               /* want budlists unlocked when doing zbpg eviction */
+               zbud_evict_zbpg(zbpg);
+               local_bh_enable();
+               if (--nr <= 0)
+                       goto out;
+               goto retry_bud_list;
+       }
+       spin_unlock_bh(&zbud_budlists_spinlock);
+out:
+       return;
+}
+
+static void zbud_init(void)
+{
+       int i;
+
+       INIT_LIST_HEAD(&zbud_buddied_list);
+       zcache_zbud_buddied_count = 0;
+       for (i = 0; i < NCHUNKS; i++) {
+               INIT_LIST_HEAD(&zbud_unbuddied[i].list);
+               zbud_unbuddied[i].count = 0;
+       }
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * These sysfs routines show a nice distribution of how many zbpg's are
+ * currently (and have ever been placed) in each unbuddied list.  It's fun
+ * to watch but can probably go away before final merge.
+ */
+static int zbud_show_unbuddied_list_counts(char *buf)
+{
+       int i;
+       char *p = buf;
+
+       for (i = 0; i < NCHUNKS; i++)
+               p += sprintf(p, "%u ", zbud_unbuddied[i].count);
+       return p - buf;
+}
+
+static int zbud_show_cumul_chunk_counts(char *buf)
+{
+       unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
+       unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
+       unsigned long total_chunks_lte_42 = 0;
+       char *p = buf;
+
+       for (i = 0; i < NCHUNKS; i++) {
+               p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
+               chunks += zbud_cumul_chunk_counts[i];
+               total_chunks += zbud_cumul_chunk_counts[i];
+               sum_total_chunks += i * zbud_cumul_chunk_counts[i];
+               if (i == 21)
+                       total_chunks_lte_21 = total_chunks;
+               if (i == 32)
+                       total_chunks_lte_32 = total_chunks;
+               if (i == 42)
+                       total_chunks_lte_42 = total_chunks;
+       }
+       p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
+               total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
+               chunks == 0 ? 0 : sum_total_chunks / chunks);
+       return p - buf;
+}
+#endif
+
+/**********
+ * This "zv" PAM implementation combines the TLSF-based xvMalloc
+ * with lzo1x compression to maximize the amount of data that can
+ * be packed into a physical page.
+ *
+ * Zv represents a PAM page with the index and object (plus a "size" value
+ * necessary for decompression) immediately preceding the compressed data.
+ */
+
+#define ZVH_SENTINEL  0x43214321
+
+struct zv_hdr {
+       uint32_t pool_id;
+       struct tmem_oid oid;
+       uint32_t index;
+       DECL_SENTINEL
+};
+
+/* rudimentary policy limits */
+/* total number of persistent pages may not exceed this percentage */
+static unsigned int zv_page_count_policy_percent = 75;
+/*
+ * byte count defining poor compression; pages with greater zsize will be
+ * rejected
+ */
+static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7;
+/*
+ * byte count defining poor *mean* compression; pages with greater zsize
+ * will be rejected until sufficient better-compressed pages are accepted
+ * driving the man below this threshold
+ */
+static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5;
+
+static unsigned long zv_curr_dist_counts[NCHUNKS];
+static unsigned long zv_cumul_dist_counts[NCHUNKS];
+
+static struct zv_hdr *zv_create(struct xv_pool *xvpool, uint32_t pool_id,
+                               struct tmem_oid *oid, uint32_t index,
+                               void *cdata, unsigned clen)
+{
+       struct page *page;
+       struct zv_hdr *zv = NULL;
+       uint32_t offset;
+       int alloc_size = clen + sizeof(struct zv_hdr);
+       int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+       int ret;
+
+       BUG_ON(!irqs_disabled());
+       BUG_ON(chunks >= NCHUNKS);
+       ret = xv_malloc(xvpool, alloc_size,
+                       &page, &offset, ZCACHE_GFP_MASK);
+       if (unlikely(ret))
+               goto out;
+       zv_curr_dist_counts[chunks]++;
+       zv_cumul_dist_counts[chunks]++;
+       zv = kmap_atomic(page, KM_USER0) + offset;
+       zv->index = index;
+       zv->oid = *oid;
+       zv->pool_id = pool_id;
+       SET_SENTINEL(zv, ZVH);
+       memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen);
+       kunmap_atomic(zv, KM_USER0);
+out:
+       return zv;
+}
+
+static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
+{
+       unsigned long flags;
+       struct page *page;
+       uint32_t offset;
+       uint16_t size = xv_get_object_size(zv);
+       int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
+
+       ASSERT_SENTINEL(zv, ZVH);
+       BUG_ON(chunks >= NCHUNKS);
+       zv_curr_dist_counts[chunks]--;
+       size -= sizeof(*zv);
+       BUG_ON(size == 0);
+       INVERT_SENTINEL(zv, ZVH);
+       page = virt_to_page(zv);
+       offset = (unsigned long)zv & ~PAGE_MASK;
+       local_irq_save(flags);
+       xv_free(xvpool, page, offset);
+       local_irq_restore(flags);
+}
+
+static void zv_decompress(struct page *page, struct zv_hdr *zv)
+{
+       size_t clen = PAGE_SIZE;
+       char *to_va;
+       unsigned size;
+       int ret;
+
+       ASSERT_SENTINEL(zv, ZVH);
+       size = xv_get_object_size(zv) - sizeof(*zv);
+       BUG_ON(size == 0);
+       to_va = kmap_atomic(page, KM_USER0);
+       ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
+                                       size, to_va, &clen);
+       kunmap_atomic(to_va, KM_USER0);
+       BUG_ON(ret != LZO_E_OK);
+       BUG_ON(clen != PAGE_SIZE);
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * show a distribution of compression stats for zv pages.
+ */
+
+static int zv_curr_dist_counts_show(char *buf)
+{
+       unsigned long i, n, chunks = 0, sum_total_chunks = 0;
+       char *p = buf;
+
+       for (i = 0; i < NCHUNKS; i++) {
+               n = zv_curr_dist_counts[i];
+               p += sprintf(p, "%lu ", n);
+               chunks += n;
+               sum_total_chunks += i * n;
+       }
+       p += sprintf(p, "mean:%lu\n",
+               chunks == 0 ? 0 : sum_total_chunks / chunks);
+       return p - buf;
+}
+
+static int zv_cumul_dist_counts_show(char *buf)
+{
+       unsigned long i, n, chunks = 0, sum_total_chunks = 0;
+       char *p = buf;
+
+       for (i = 0; i < NCHUNKS; i++) {
+               n = zv_cumul_dist_counts[i];
+               p += sprintf(p, "%lu ", n);
+               chunks += n;
+               sum_total_chunks += i * n;
+       }
+       p += sprintf(p, "mean:%lu\n",
+               chunks == 0 ? 0 : sum_total_chunks / chunks);
+       return p - buf;
+}
+
+/*
+ * setting zv_max_zsize via sysfs causes all persistent (e.g. swap)
+ * pages that don't compress to less than this value (including metadata
+ * overhead) to be rejected.  We don't allow the value to get too close
+ * to PAGE_SIZE.
+ */
+static ssize_t zv_max_zsize_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   char *buf)
+{
+       return sprintf(buf, "%u\n", zv_max_zsize);
+}
+
+static ssize_t zv_max_zsize_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       unsigned long val;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
+               return -EINVAL;
+       zv_max_zsize = val;
+       return count;
+}
+
+/*
+ * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap)
+ * pages that don't compress to less than this value (including metadata
+ * overhead) to be rejected UNLESS the mean compression is also smaller
+ * than this value.  In other words, we are load-balancing-by-zsize the
+ * accepted pages.  Again, we don't allow the value to get too close
+ * to PAGE_SIZE.
+ */
+static ssize_t zv_max_mean_zsize_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   char *buf)
+{
+       return sprintf(buf, "%u\n", zv_max_mean_zsize);
+}
+
+static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       unsigned long val;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
+               return -EINVAL;
+       zv_max_mean_zsize = val;
+       return count;
+}
+
+/*
+ * setting zv_page_count_policy_percent via sysfs sets an upper bound of
+ * persistent (e.g. swap) pages that will be retained according to:
+ *     (zv_page_count_policy_percent * totalram_pages) / 100)
+ * when that limit is reached, further puts will be rejected (until
+ * some pages have been flushed).  Note that, due to compression,
+ * this number may exceed 100; it defaults to 75 and we set an
+ * arbitary limit of 150.  A poor choice will almost certainly result
+ * in OOM's, so this value should only be changed prudently.
+ */
+static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
+                                                struct kobj_attribute *attr,
+                                                char *buf)
+{
+       return sprintf(buf, "%u\n", zv_page_count_policy_percent);
+}
+
+static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj,
+                                                 struct kobj_attribute *attr,
+                                                 const char *buf, size_t count)
+{
+       unsigned long val;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err || (val == 0) || (val > 150))
+               return -EINVAL;
+       zv_page_count_policy_percent = val;
+       return count;
+}
+
+static struct kobj_attribute zcache_zv_max_zsize_attr = {
+               .attr = { .name = "zv_max_zsize", .mode = 0644 },
+               .show = zv_max_zsize_show,
+               .store = zv_max_zsize_store,
+};
+
+static struct kobj_attribute zcache_zv_max_mean_zsize_attr = {
+               .attr = { .name = "zv_max_mean_zsize", .mode = 0644 },
+               .show = zv_max_mean_zsize_show,
+               .store = zv_max_mean_zsize_store,
+};
+
+static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = {
+               .attr = { .name = "zv_page_count_policy_percent",
+                         .mode = 0644 },
+               .show = zv_page_count_policy_percent_show,
+               .store = zv_page_count_policy_percent_store,
+};
+#endif
+
+/*
+ * zcache core code starts here
+ */
+
+/* useful stats not collected by cleancache or frontswap */
+static unsigned long zcache_flush_total;
+static unsigned long zcache_flush_found;
+static unsigned long zcache_flobj_total;
+static unsigned long zcache_flobj_found;
+static unsigned long zcache_failed_eph_puts;
+static unsigned long zcache_failed_pers_puts;
+
+/*
+ * Tmem operations assume the poolid implies the invoking client.
+ * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
+ * RAMster has each client numbered by cluster node, and a KVM version
+ * of zcache would have one client per guest and each client might
+ * have a poolid==N.
+ */
+static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
+{
+       struct tmem_pool *pool = NULL;
+       struct zcache_client *cli = NULL;
+
+       if (cli_id == LOCAL_CLIENT)
+               cli = &zcache_host;
+       else {
+               if (cli_id >= MAX_CLIENTS)
+                       goto out;
+               cli = &zcache_clients[cli_id];
+               if (cli == NULL)
+                       goto out;
+               atomic_inc(&cli->refcount);
+       }
+       if (poolid < MAX_POOLS_PER_CLIENT) {
+               pool = cli->tmem_pools[poolid];
+               if (pool != NULL)
+                       atomic_inc(&pool->refcount);
+       }
+out:
+       return pool;
+}
+
+static void zcache_put_pool(struct tmem_pool *pool)
+{
+       struct zcache_client *cli = NULL;
+
+       if (pool == NULL)
+               BUG();
+       cli = pool->client;
+       atomic_dec(&pool->refcount);
+       atomic_dec(&cli->refcount);
+}
+
+int zcache_new_client(uint16_t cli_id)
+{
+       struct zcache_client *cli = NULL;
+       int ret = -1;
+
+       if (cli_id == LOCAL_CLIENT)
+               cli = &zcache_host;
+       else if ((unsigned int)cli_id < MAX_CLIENTS)
+               cli = &zcache_clients[cli_id];
+       if (cli == NULL)
+               goto out;
+       if (cli->allocated)
+               goto out;
+       cli->allocated = 1;
+#ifdef CONFIG_FRONTSWAP
+       cli->xvpool = xv_create_pool();
+       if (cli->xvpool == NULL)
+               goto out;
+#endif
+       ret = 0;
+out:
+       return ret;
+}
+
+/* counters for debugging */
+static unsigned long zcache_failed_get_free_pages;
+static unsigned long zcache_failed_alloc;
+static unsigned long zcache_put_to_flush;
+static unsigned long zcache_aborted_preload;
+static unsigned long zcache_aborted_shrink;
+
+/*
+ * Ensure that memory allocation requests in zcache don't result
+ * in direct reclaim requests via the shrinker, which would cause
+ * an infinite loop.  Maybe a GFP flag would be better?
+ */
+static DEFINE_SPINLOCK(zcache_direct_reclaim_lock);
+
+/*
+ * for now, used named slabs so can easily track usage; later can
+ * either just use kmalloc, or perhaps add a slab-like allocator
+ * to more carefully manage total memory utilization
+ */
+static struct kmem_cache *zcache_objnode_cache;
+static struct kmem_cache *zcache_obj_cache;
+static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_obj_count_max;
+static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_objnode_count_max;
+
+/*
+ * to avoid memory allocation recursion (e.g. due to direct reclaim), we
+ * preload all necessary data structures so the hostops callbacks never
+ * actually do a malloc
+ */
+struct zcache_preload {
+       void *page;
+       struct tmem_obj *obj;
+       int nr;
+       struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
+};
+static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
+
+static int zcache_do_preload(struct tmem_pool *pool)
+{
+       struct zcache_preload *kp;
+       struct tmem_objnode *objnode;
+       struct tmem_obj *obj;
+       void *page;
+       int ret = -ENOMEM;
+
+       if (unlikely(zcache_objnode_cache == NULL))
+               goto out;
+       if (unlikely(zcache_obj_cache == NULL))
+               goto out;
+       if (!spin_trylock(&zcache_direct_reclaim_lock)) {
+               zcache_aborted_preload++;
+               goto out;
+       }
+       preempt_disable();
+       kp = &__get_cpu_var(zcache_preloads);
+       while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
+               preempt_enable_no_resched();
+               objnode = kmem_cache_alloc(zcache_objnode_cache,
+                               ZCACHE_GFP_MASK);
+               if (unlikely(objnode == NULL)) {
+                       zcache_failed_alloc++;
+                       goto unlock_out;
+               }
+               preempt_disable();
+               kp = &__get_cpu_var(zcache_preloads);
+               if (kp->nr < ARRAY_SIZE(kp->objnodes))
+                       kp->objnodes[kp->nr++] = objnode;
+               else
+                       kmem_cache_free(zcache_objnode_cache, objnode);
+       }
+       preempt_enable_no_resched();
+       obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
+       if (unlikely(obj == NULL)) {
+               zcache_failed_alloc++;
+               goto unlock_out;
+       }
+       page = (void *)__get_free_page(ZCACHE_GFP_MASK);
+       if (unlikely(page == NULL)) {
+               zcache_failed_get_free_pages++;
+               kmem_cache_free(zcache_obj_cache, obj);
+               goto unlock_out;
+       }
+       preempt_disable();
+       kp = &__get_cpu_var(zcache_preloads);
+       if (kp->obj == NULL)
+               kp->obj = obj;
+       else
+               kmem_cache_free(zcache_obj_cache, obj);
+       if (kp->page == NULL)
+               kp->page = page;
+       else
+               free_page((unsigned long)page);
+       ret = 0;
+unlock_out:
+       spin_unlock(&zcache_direct_reclaim_lock);
+out:
+       return ret;
+}
+
+static void *zcache_get_free_page(void)
+{
+       struct zcache_preload *kp;
+       void *page;
+
+       kp = &__get_cpu_var(zcache_preloads);
+       page = kp->page;
+       BUG_ON(page == NULL);
+       kp->page = NULL;
+       return page;
+}
+
+static void zcache_free_page(void *p)
+{
+       free_page((unsigned long)p);
+}
+
+/*
+ * zcache implementation for tmem host ops
+ */
+
+static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
+{
+       struct tmem_objnode *objnode = NULL;
+       unsigned long count;
+       struct zcache_preload *kp;
+
+       kp = &__get_cpu_var(zcache_preloads);
+       if (kp->nr <= 0)
+               goto out;
+       objnode = kp->objnodes[kp->nr - 1];
+       BUG_ON(objnode == NULL);
+       kp->objnodes[kp->nr - 1] = NULL;
+       kp->nr--;
+       count = atomic_inc_return(&zcache_curr_objnode_count);
+       if (count > zcache_curr_objnode_count_max)
+               zcache_curr_objnode_count_max = count;
+out:
+       return objnode;
+}
+
+static void zcache_objnode_free(struct tmem_objnode *objnode,
+                                       struct tmem_pool *pool)
+{
+       atomic_dec(&zcache_curr_objnode_count);
+       BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
+       kmem_cache_free(zcache_objnode_cache, objnode);
+}
+
+static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
+{
+       struct tmem_obj *obj = NULL;
+       unsigned long count;
+       struct zcache_preload *kp;
+
+       kp = &__get_cpu_var(zcache_preloads);
+       obj = kp->obj;
+       BUG_ON(obj == NULL);
+       kp->obj = NULL;
+       count = atomic_inc_return(&zcache_curr_obj_count);
+       if (count > zcache_curr_obj_count_max)
+               zcache_curr_obj_count_max = count;
+       return obj;
+}
+
+static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
+{
+       atomic_dec(&zcache_curr_obj_count);
+       BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
+       kmem_cache_free(zcache_obj_cache, obj);
+}
+
+static struct tmem_hostops zcache_hostops = {
+       .obj_alloc = zcache_obj_alloc,
+       .obj_free = zcache_obj_free,
+       .objnode_alloc = zcache_objnode_alloc,
+       .objnode_free = zcache_objnode_free,
+};
+
+/*
+ * zcache implementations for PAM page descriptor ops
+ */
+
+static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_eph_pampd_count_max;
+static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0);
+static unsigned long zcache_curr_pers_pampd_count_max;
+
+/* forward reference */
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
+
+static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
+                               struct tmem_pool *pool, struct tmem_oid *oid,
+                                uint32_t index)
+{
+       void *pampd = NULL, *cdata;
+       size_t clen;
+       int ret;
+       unsigned long count;
+       struct page *page = virt_to_page(data);
+       struct zcache_client *cli = pool->client;
+       uint16_t client_id = get_client_id_from_client(cli);
+       unsigned long zv_mean_zsize;
+       unsigned long curr_pers_pampd_count;
+       u64 total_zsize;
+
+       if (eph) {
+               ret = zcache_compress(page, &cdata, &clen);
+               if (ret == 0)
+                       goto out;
+               if (clen == 0 || clen > zbud_max_buddy_size()) {
+                       zcache_compress_poor++;
+                       goto out;
+               }
+               pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
+                                               index, page, cdata, clen);
+               if (pampd != NULL) {
+                       count = atomic_inc_return(&zcache_curr_eph_pampd_count);
+                       if (count > zcache_curr_eph_pampd_count_max)
+                               zcache_curr_eph_pampd_count_max = count;
+               }
+       } else {
+               curr_pers_pampd_count =
+                       atomic_read(&zcache_curr_pers_pampd_count);
+               if (curr_pers_pampd_count >
+                   (zv_page_count_policy_percent * totalram_pages) / 100)
+                       goto out;
+               ret = zcache_compress(page, &cdata, &clen);
+               if (ret == 0)
+                       goto out;
+               /* reject if compression is too poor */
+               if (clen > zv_max_zsize) {
+                       zcache_compress_poor++;
+                       goto out;
+               }
+               /* reject if mean compression is too poor */
+               if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
+                       total_zsize = xv_get_total_size_bytes(cli->xvpool);
+                       zv_mean_zsize = div_u64(total_zsize,
+                                               curr_pers_pampd_count);
+                       if (zv_mean_zsize > zv_max_mean_zsize) {
+                               zcache_mean_compress_poor++;
+                               goto out;
+                       }
+               }
+               pampd = (void *)zv_create(cli->xvpool, pool->pool_id,
+                                               oid, index, cdata, clen);
+               if (pampd == NULL)
+                       goto out;
+               count = atomic_inc_return(&zcache_curr_pers_pampd_count);
+               if (count > zcache_curr_pers_pampd_count_max)
+                       zcache_curr_pers_pampd_count_max = count;
+       }
+out:
+       return pampd;
+}
+
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
+                                       void *pampd, struct tmem_pool *pool,
+                                       struct tmem_oid *oid, uint32_t index)
+{
+       int ret = 0;
+
+       BUG_ON(is_ephemeral(pool));
+       zv_decompress(virt_to_page(data), pampd);
+       return ret;
+}
+
+/*
+ * fill the pageframe corresponding to the struct page with the data
+ * from the passed pampd
+ */
+static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
+                                       void *pampd, struct tmem_pool *pool,
+                                       struct tmem_oid *oid, uint32_t index)
+{
+       int ret = 0;
+
+       BUG_ON(!is_ephemeral(pool));
+       zbud_decompress(virt_to_page(data), pampd);
+       zbud_free_and_delist((struct zbud_hdr *)pampd);
+       atomic_dec(&zcache_curr_eph_pampd_count);
+       return ret;
+}
+
+/*
+ * free the pampd and remove it from any zcache lists
+ * pampd must no longer be pointed to from any tmem data structures!
+ */
+static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
+                               struct tmem_oid *oid, uint32_t index)
+{
+       struct zcache_client *cli = pool->client;
+
+       if (is_ephemeral(pool)) {
+               zbud_free_and_delist((struct zbud_hdr *)pampd);
+               atomic_dec(&zcache_curr_eph_pampd_count);
+               BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
+       } else {
+               zv_free(cli->xvpool, (struct zv_hdr *)pampd);
+               atomic_dec(&zcache_curr_pers_pampd_count);
+               BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0);
+       }
+}
+
+static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj)
+{
+}
+
+static void zcache_pampd_new_obj(struct tmem_obj *obj)
+{
+}
+
+static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj)
+{
+       return -1;
+}
+
+static bool zcache_pampd_is_remote(void *pampd)
+{
+       return 0;
+}
+
+static struct tmem_pamops zcache_pamops = {
+       .create = zcache_pampd_create,
+       .get_data = zcache_pampd_get_data,
+       .get_data_and_free = zcache_pampd_get_data_and_free,
+       .free = zcache_pampd_free,
+       .free_obj = zcache_pampd_free_obj,
+       .new_obj = zcache_pampd_new_obj,
+       .replace_in_obj = zcache_pampd_replace_in_obj,
+       .is_remote = zcache_pampd_is_remote,
+};
+
+/*
+ * zcache compression/decompression and related per-cpu stuff
+ */
+
+#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
+#define LZO_DSTMEM_PAGE_ORDER 1
+static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
+static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
+
+static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
+{
+       int ret = 0;
+       unsigned char *dmem = __get_cpu_var(zcache_dstmem);
+       unsigned char *wmem = __get_cpu_var(zcache_workmem);
+       char *from_va;
+
+       BUG_ON(!irqs_disabled());
+       if (unlikely(dmem == NULL || wmem == NULL))
+               goto out;  /* no buffer, so can't compress */
+       from_va = kmap_atomic(from, KM_USER0);
+       mb();
+       ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
+       BUG_ON(ret != LZO_E_OK);
+       *out_va = dmem;
+       kunmap_atomic(from_va, KM_USER0);
+       ret = 1;
+out:
+       return ret;
+}
+
+
+static int zcache_cpu_notifier(struct notifier_block *nb,
+                               unsigned long action, void *pcpu)
+{
+       int cpu = (long)pcpu;
+       struct zcache_preload *kp;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+               per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
+                       GFP_KERNEL | __GFP_REPEAT,
+                       LZO_DSTMEM_PAGE_ORDER),
+               per_cpu(zcache_workmem, cpu) =
+                       kzalloc(LZO1X_MEM_COMPRESS,
+                               GFP_KERNEL | __GFP_REPEAT);
+               break;
+       case CPU_DEAD:
+       case CPU_UP_CANCELED:
+               free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
+                               LZO_DSTMEM_PAGE_ORDER);
+               per_cpu(zcache_dstmem, cpu) = NULL;
+               kfree(per_cpu(zcache_workmem, cpu));
+               per_cpu(zcache_workmem, cpu) = NULL;
+               kp = &per_cpu(zcache_preloads, cpu);
+               while (kp->nr) {
+                       kmem_cache_free(zcache_objnode_cache,
+                                       kp->objnodes[kp->nr - 1]);
+                       kp->objnodes[kp->nr - 1] = NULL;
+                       kp->nr--;
+               }
+               kmem_cache_free(zcache_obj_cache, kp->obj);
+               free_page((unsigned long)kp->page);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block zcache_cpu_notifier_block = {
+       .notifier_call = zcache_cpu_notifier
+};
+
+#ifdef CONFIG_SYSFS
+#define ZCACHE_SYSFS_RO(_name) \
+       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+       { \
+               return sprintf(buf, "%lu\n", zcache_##_name); \
+       } \
+       static struct kobj_attribute zcache_##_name##_attr = { \
+               .attr = { .name = __stringify(_name), .mode = 0444 }, \
+               .show = zcache_##_name##_show, \
+       }
+
+#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
+       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+       { \
+           return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
+       } \
+       static struct kobj_attribute zcache_##_name##_attr = { \
+               .attr = { .name = __stringify(_name), .mode = 0444 }, \
+               .show = zcache_##_name##_show, \
+       }
+
+#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
+       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+       { \
+           return _func(buf); \
+       } \
+       static struct kobj_attribute zcache_##_name##_attr = { \
+               .attr = { .name = __stringify(_name), .mode = 0444 }, \
+               .show = zcache_##_name##_show, \
+       }
+
+ZCACHE_SYSFS_RO(curr_obj_count_max);
+ZCACHE_SYSFS_RO(curr_objnode_count_max);
+ZCACHE_SYSFS_RO(flush_total);
+ZCACHE_SYSFS_RO(flush_found);
+ZCACHE_SYSFS_RO(flobj_total);
+ZCACHE_SYSFS_RO(flobj_found);
+ZCACHE_SYSFS_RO(failed_eph_puts);
+ZCACHE_SYSFS_RO(failed_pers_puts);
+ZCACHE_SYSFS_RO(zbud_curr_zbytes);
+ZCACHE_SYSFS_RO(zbud_cumul_zpages);
+ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
+ZCACHE_SYSFS_RO(zbud_buddied_count);
+ZCACHE_SYSFS_RO(zbpg_unused_list_count);
+ZCACHE_SYSFS_RO(evicted_raw_pages);
+ZCACHE_SYSFS_RO(evicted_unbuddied_pages);
+ZCACHE_SYSFS_RO(evicted_buddied_pages);
+ZCACHE_SYSFS_RO(failed_get_free_pages);
+ZCACHE_SYSFS_RO(failed_alloc);
+ZCACHE_SYSFS_RO(put_to_flush);
+ZCACHE_SYSFS_RO(aborted_preload);
+ZCACHE_SYSFS_RO(aborted_shrink);
+ZCACHE_SYSFS_RO(compress_poor);
+ZCACHE_SYSFS_RO(mean_compress_poor);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
+ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
+ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
+ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
+                       zbud_show_unbuddied_list_counts);
+ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
+                       zbud_show_cumul_chunk_counts);
+ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts,
+                       zv_curr_dist_counts_show);
+ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts,
+                       zv_cumul_dist_counts_show);
+
+static struct attribute *zcache_attrs[] = {
+       &zcache_curr_obj_count_attr.attr,
+       &zcache_curr_obj_count_max_attr.attr,
+       &zcache_curr_objnode_count_attr.attr,
+       &zcache_curr_objnode_count_max_attr.attr,
+       &zcache_flush_total_attr.attr,
+       &zcache_flobj_total_attr.attr,
+       &zcache_flush_found_attr.attr,
+       &zcache_flobj_found_attr.attr,
+       &zcache_failed_eph_puts_attr.attr,
+       &zcache_failed_pers_puts_attr.attr,
+       &zcache_compress_poor_attr.attr,
+       &zcache_mean_compress_poor_attr.attr,
+       &zcache_zbud_curr_raw_pages_attr.attr,
+       &zcache_zbud_curr_zpages_attr.attr,
+       &zcache_zbud_curr_zbytes_attr.attr,
+       &zcache_zbud_cumul_zpages_attr.attr,
+       &zcache_zbud_cumul_zbytes_attr.attr,
+       &zcache_zbud_buddied_count_attr.attr,
+       &zcache_zbpg_unused_list_count_attr.attr,
+       &zcache_evicted_raw_pages_attr.attr,
+       &zcache_evicted_unbuddied_pages_attr.attr,
+       &zcache_evicted_buddied_pages_attr.attr,
+       &zcache_failed_get_free_pages_attr.attr,
+       &zcache_failed_alloc_attr.attr,
+       &zcache_put_to_flush_attr.attr,
+       &zcache_aborted_preload_attr.attr,
+       &zcache_aborted_shrink_attr.attr,
+       &zcache_zbud_unbuddied_list_counts_attr.attr,
+       &zcache_zbud_cumul_chunk_counts_attr.attr,
+       &zcache_zv_curr_dist_counts_attr.attr,
+       &zcache_zv_cumul_dist_counts_attr.attr,
+       &zcache_zv_max_zsize_attr.attr,
+       &zcache_zv_max_mean_zsize_attr.attr,
+       &zcache_zv_page_count_policy_percent_attr.attr,
+       NULL,
+};
+
+static struct attribute_group zcache_attr_group = {
+       .attrs = zcache_attrs,
+       .name = "zcache",
+};
+
+#endif /* CONFIG_SYSFS */
+/*
+ * When zcache is disabled ("frozen"), pools can be created and destroyed,
+ * but all puts (and thus all other operations that require memory allocation)
+ * must fail.  If zcache is unfrozen, accepts puts, then frozen again,
+ * data consistency requires all puts while frozen to be converted into
+ * flushes.
+ */
+static bool zcache_freeze;
+
+/*
+ * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
+ */
+static int shrink_zcache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
+{
+       int ret = -1;
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
+
+       if (nr >= 0) {
+               if (!(gfp_mask & __GFP_FS))
+                       /* does this case really need to be skipped? */
+                       goto out;
+               if (spin_trylock(&zcache_direct_reclaim_lock)) {
+                       zbud_evict_pages(nr);
+                       spin_unlock(&zcache_direct_reclaim_lock);
+               } else
+                       zcache_aborted_shrink++;
+       }
+       ret = (int)atomic_read(&zcache_zbud_curr_raw_pages);
+out:
+       return ret;
+}
+
+static struct shrinker zcache_shrinker = {
+       .shrink = shrink_zcache_memory,
+       .seeks = DEFAULT_SEEKS,
+};
+
+/*
+ * zcache shims between cleancache/frontswap ops and tmem
+ */
+
+static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+                               uint32_t index, struct page *page)
+{
+       struct tmem_pool *pool;
+       int ret = -1;
+
+       BUG_ON(!irqs_disabled());
+       pool = zcache_get_pool_by_id(cli_id, pool_id);
+       if (unlikely(pool == NULL))
+               goto out;
+       if (!zcache_freeze && zcache_do_preload(pool) == 0) {
+               /* preload does preempt_disable on success */
+               ret = tmem_put(pool, oidp, index, page_address(page),
+                               PAGE_SIZE, 0, is_ephemeral(pool));
+               if (ret < 0) {
+                       if (is_ephemeral(pool))
+                               zcache_failed_eph_puts++;
+                       else
+                               zcache_failed_pers_puts++;
+               }
+               zcache_put_pool(pool);
+               preempt_enable_no_resched();
+       } else {
+               zcache_put_to_flush++;
+               if (atomic_read(&pool->obj_count) > 0)
+                       /* the put fails whether the flush succeeds or not */
+                       (void)tmem_flush_page(pool, oidp, index);
+               zcache_put_pool(pool);
+       }
+out:
+       return ret;
+}
+
+static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
+                               uint32_t index, struct page *page)
+{
+       struct tmem_pool *pool;
+       int ret = -1;
+       unsigned long flags;
+       size_t size = PAGE_SIZE;
+
+       local_irq_save(flags);
+       pool = zcache_get_pool_by_id(cli_id, pool_id);
+       if (likely(pool != NULL)) {
+               if (atomic_read(&pool->obj_count) > 0)
+                       ret = tmem_get(pool, oidp, index, page_address(page),
+                                       &size, 0, is_ephemeral(pool));
+               zcache_put_pool(pool);
+       }
+       local_irq_restore(flags);
+       return ret;
+}
+
+static int zcache_flush_page(int cli_id, int pool_id,
+                               struct tmem_oid *oidp, uint32_t index)
+{
+       struct tmem_pool *pool;
+       int ret = -1;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       zcache_flush_total++;
+       pool = zcache_get_pool_by_id(cli_id, pool_id);
+       if (likely(pool != NULL)) {
+               if (atomic_read(&pool->obj_count) > 0)
+                       ret = tmem_flush_page(pool, oidp, index);
+               zcache_put_pool(pool);
+       }
+       if (ret >= 0)
+               zcache_flush_found++;
+       local_irq_restore(flags);
+       return ret;
+}
+
+static int zcache_flush_object(int cli_id, int pool_id,
+                               struct tmem_oid *oidp)
+{
+       struct tmem_pool *pool;
+       int ret = -1;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       zcache_flobj_total++;
+       pool = zcache_get_pool_by_id(cli_id, pool_id);
+       if (likely(pool != NULL)) {
+               if (atomic_read(&pool->obj_count) > 0)
+                       ret = tmem_flush_object(pool, oidp);
+               zcache_put_pool(pool);
+       }
+       if (ret >= 0)
+               zcache_flobj_found++;
+       local_irq_restore(flags);
+       return ret;
+}
+
+static int zcache_destroy_pool(int cli_id, int pool_id)
+{
+       struct tmem_pool *pool = NULL;
+       struct zcache_client *cli = NULL;
+       int ret = -1;
+
+       if (pool_id < 0)
+               goto out;
+       if (cli_id == LOCAL_CLIENT)
+               cli = &zcache_host;
+       else if ((unsigned int)cli_id < MAX_CLIENTS)
+               cli = &zcache_clients[cli_id];
+       if (cli == NULL)
+               goto out;
+       atomic_inc(&cli->refcount);
+       pool = cli->tmem_pools[pool_id];
+       if (pool == NULL)
+               goto out;
+       cli->tmem_pools[pool_id] = NULL;
+       /* wait for pool activity on other cpus to quiesce */
+       while (atomic_read(&pool->refcount) != 0)
+               ;
+       atomic_dec(&cli->refcount);
+       local_bh_disable();
+       ret = tmem_destroy_pool(pool);
+       local_bh_enable();
+       kfree(pool);
+       pr_info("zcache: destroyed pool id=%d, cli_id=%d\n",
+                       pool_id, cli_id);
+out:
+       return ret;
+}
+
+static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
+{
+       int poolid = -1;
+       struct tmem_pool *pool;
+       struct zcache_client *cli = NULL;
+
+       if (cli_id == LOCAL_CLIENT)
+               cli = &zcache_host;
+       else if ((unsigned int)cli_id < MAX_CLIENTS)
+               cli = &zcache_clients[cli_id];
+       if (cli == NULL)
+               goto out;
+       atomic_inc(&cli->refcount);
+       pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
+       if (pool == NULL) {
+               pr_info("zcache: pool creation failed: out of memory\n");
+               goto out;
+       }
+
+       for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
+               if (cli->tmem_pools[poolid] == NULL)
+                       break;
+       if (poolid >= MAX_POOLS_PER_CLIENT) {
+               pr_info("zcache: pool creation failed: max exceeded\n");
+               kfree(pool);
+               poolid = -1;
+               goto out;
+       }
+       atomic_set(&pool->refcount, 0);
+       pool->client = cli;
+       pool->pool_id = poolid;
+       tmem_new_pool(pool, flags);
+       cli->tmem_pools[poolid] = pool;
+       pr_info("zcache: created %s tmem pool, id=%d, client=%d\n",
+               flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
+               poolid, cli_id);
+out:
+       if (cli != NULL)
+               atomic_dec(&cli->refcount);
+       return poolid;
+}
+
+/**********
+ * Two kernel functionalities currently can be layered on top of tmem.
+ * These are "cleancache" which is used as a second-chance cache for clean
+ * page cache pages; and "frontswap" which is used for swap pages
+ * to avoid writes to disk.  A generic "shim" is provided here for each
+ * to translate in-kernel semantics to zcache semantics.
+ */
+
+#ifdef CONFIG_CLEANCACHE
+static void zcache_cleancache_put_page(int pool_id,
+                                       struct cleancache_filekey key,
+                                       pgoff_t index, struct page *page)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+       if (likely(ind == index))
+               (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page);
+}
+
+static int zcache_cleancache_get_page(int pool_id,
+                                       struct cleancache_filekey key,
+                                       pgoff_t index, struct page *page)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+       int ret = -1;
+
+       if (likely(ind == index))
+               ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page);
+       return ret;
+}
+
+static void zcache_cleancache_flush_page(int pool_id,
+                                       struct cleancache_filekey key,
+                                       pgoff_t index)
+{
+       u32 ind = (u32) index;
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+       if (likely(ind == index))
+               (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
+}
+
+static void zcache_cleancache_flush_inode(int pool_id,
+                                       struct cleancache_filekey key)
+{
+       struct tmem_oid oid = *(struct tmem_oid *)&key;
+
+       (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
+}
+
+static void zcache_cleancache_flush_fs(int pool_id)
+{
+       if (pool_id >= 0)
+               (void)zcache_destroy_pool(LOCAL_CLIENT, pool_id);
+}
+
+static int zcache_cleancache_init_fs(size_t pagesize)
+{
+       BUG_ON(sizeof(struct cleancache_filekey) !=
+                               sizeof(struct tmem_oid));
+       BUG_ON(pagesize != PAGE_SIZE);
+       return zcache_new_pool(LOCAL_CLIENT, 0);
+}
+
+static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
+{
+       /* shared pools are unsupported and map to private */
+       BUG_ON(sizeof(struct cleancache_filekey) !=
+                               sizeof(struct tmem_oid));
+       BUG_ON(pagesize != PAGE_SIZE);
+       return zcache_new_pool(LOCAL_CLIENT, 0);
+}
+
+static struct cleancache_ops zcache_cleancache_ops = {
+       .put_page = zcache_cleancache_put_page,
+       .get_page = zcache_cleancache_get_page,
+       .flush_page = zcache_cleancache_flush_page,
+       .flush_inode = zcache_cleancache_flush_inode,
+       .flush_fs = zcache_cleancache_flush_fs,
+       .init_shared_fs = zcache_cleancache_init_shared_fs,
+       .init_fs = zcache_cleancache_init_fs
+};
+
+struct cleancache_ops zcache_cleancache_register_ops(void)
+{
+       struct cleancache_ops old_ops =
+               cleancache_register_ops(&zcache_cleancache_ops);
+
+       return old_ops;
+}
+#endif
+
+#ifdef CONFIG_FRONTSWAP
+/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
+static int zcache_frontswap_poolid = -1;
+
+/*
+ * Swizzling increases objects per swaptype, increasing tmem concurrency
+ * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
+ */
+#define SWIZ_BITS              4
+#define SWIZ_MASK              ((1 << SWIZ_BITS) - 1)
+#define _oswiz(_type, _ind)    ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
+#define iswiz(_ind)            (_ind >> SWIZ_BITS)
+
+static inline struct tmem_oid oswiz(unsigned type, u32 ind)
+{
+       struct tmem_oid oid = { .oid = { 0 } };
+       oid.oid[0] = _oswiz(type, ind);
+       return oid;
+}
+
+static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
+                                  struct page *page)
+{
+       u64 ind64 = (u64)offset;
+       u32 ind = (u32)offset;
+       struct tmem_oid oid = oswiz(type, ind);
+       int ret = -1;
+       unsigned long flags;
+
+       BUG_ON(!PageLocked(page));
+       if (likely(ind64 == ind)) {
+               local_irq_save(flags);
+               ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid,
+                                       &oid, iswiz(ind), page);
+               local_irq_restore(flags);
+       }
+       return ret;
+}
+
+/* returns 0 if the page was successfully gotten from frontswap, -1 if
+ * was not present (should never happen!) */
+static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,
+                                  struct page *page)
+{
+       u64 ind64 = (u64)offset;
+       u32 ind = (u32)offset;
+       struct tmem_oid oid = oswiz(type, ind);
+       int ret = -1;
+
+       BUG_ON(!PageLocked(page));
+       if (likely(ind64 == ind))
+               ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid,
+                                       &oid, iswiz(ind), page);
+       return ret;
+}
+
+/* flush a single page from frontswap */
+static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset)
+{
+       u64 ind64 = (u64)offset;
+       u32 ind = (u32)offset;
+       struct tmem_oid oid = oswiz(type, ind);
+
+       if (likely(ind64 == ind))
+               (void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid,
+                                       &oid, iswiz(ind));
+}
+
+/* flush all pages from the passed swaptype */
+static void zcache_frontswap_flush_area(unsigned type)
+{
+       struct tmem_oid oid;
+       int ind;
+
+       for (ind = SWIZ_MASK; ind >= 0; ind--) {
+               oid = oswiz(type, ind);
+               (void)zcache_flush_object(LOCAL_CLIENT,
+                                               zcache_frontswap_poolid, &oid);
+       }
+}
+
+static void zcache_frontswap_init(unsigned ignored)
+{
+       /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
+       if (zcache_frontswap_poolid < 0)
+               zcache_frontswap_poolid =
+                       zcache_new_pool(LOCAL_CLIENT, TMEM_POOL_PERSIST);
+}
+
+static struct frontswap_ops zcache_frontswap_ops = {
+       .put_page = zcache_frontswap_put_page,
+       .get_page = zcache_frontswap_get_page,
+       .flush_page = zcache_frontswap_flush_page,
+       .flush_area = zcache_frontswap_flush_area,
+       .init = zcache_frontswap_init
+};
+
+struct frontswap_ops zcache_frontswap_register_ops(void)
+{
+       struct frontswap_ops old_ops =
+               frontswap_register_ops(&zcache_frontswap_ops);
+
+       return old_ops;
+}
+#endif
+
+/*
+ * zcache initialization
+ * NOTE FOR NOW zcache MUST BE PROVIDED AS A KERNEL BOOT PARAMETER OR
+ * NOTHING HAPPENS!
+ */
+
+static int zcache_enabled;
+
+static int __init enable_zcache(char *s)
+{
+       zcache_enabled = 1;
+       return 1;
+}
+__setup("zcache", enable_zcache);
+
+/* allow independent dynamic disabling of cleancache and frontswap */
+
+static int use_cleancache = 1;
+
+static int __init no_cleancache(char *s)
+{
+       use_cleancache = 0;
+       return 1;
+}
+
+__setup("nocleancache", no_cleancache);
+
+static int use_frontswap = 1;
+
+static int __init no_frontswap(char *s)
+{
+       use_frontswap = 0;
+       return 1;
+}
+
+__setup("nofrontswap", no_frontswap);
+
+static int __init zcache_init(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_SYSFS
+       ret = sysfs_create_group(mm_kobj, &zcache_attr_group);
+       if (ret) {
+               pr_err("zcache: can't create sysfs\n");
+               goto out;
+       }
+#endif /* CONFIG_SYSFS */
+#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP)
+       if (zcache_enabled) {
+               unsigned int cpu;
+
+               tmem_register_hostops(&zcache_hostops);
+               tmem_register_pamops(&zcache_pamops);
+               ret = register_cpu_notifier(&zcache_cpu_notifier_block);
+               if (ret) {
+                       pr_err("zcache: can't register cpu notifier\n");
+                       goto out;
+               }
+               for_each_online_cpu(cpu) {
+                       void *pcpu = (void *)(long)cpu;
+                       zcache_cpu_notifier(&zcache_cpu_notifier_block,
+                               CPU_UP_PREPARE, pcpu);
+               }
+       }
+       zcache_objnode_cache = kmem_cache_create("zcache_objnode",
+                               sizeof(struct tmem_objnode), 0, 0, NULL);
+       zcache_obj_cache = kmem_cache_create("zcache_obj",
+                               sizeof(struct tmem_obj), 0, 0, NULL);
+       ret = zcache_new_client(LOCAL_CLIENT);
+       if (ret) {
+               pr_err("zcache: can't create client\n");
+               goto out;
+       }
+#endif
+#ifdef CONFIG_CLEANCACHE
+       if (zcache_enabled && use_cleancache) {
+               struct cleancache_ops old_ops;
+
+               zbud_init();
+               register_shrinker(&zcache_shrinker);
+               old_ops = zcache_cleancache_register_ops();
+               pr_info("zcache: cleancache enabled using kernel "
+                       "transcendent memory and compression buddies\n");
+               if (old_ops.init_fs != NULL)
+                       pr_warning("zcache: cleancache_ops overridden");
+       }
+#endif
+#ifdef CONFIG_FRONTSWAP
+       if (zcache_enabled && use_frontswap) {
+               struct frontswap_ops old_ops;
+
+               old_ops = zcache_frontswap_register_ops();
+               pr_info("zcache: frontswap enabled using kernel "
+                       "transcendent memory and xvmalloc\n");
+               if (old_ops.init != NULL)
+                       pr_warning("ktmem: frontswap_ops overridden");
+       }
+#endif
+out:
+       return ret;
+}
+
+module_init(zcache_init)
diff --git a/drivers/staging/zcache/zcache.c b/drivers/staging/zcache/zcache.c
deleted file mode 100644 (file)
index 65a81a0..0000000
+++ /dev/null
@@ -1,1996 +0,0 @@
-/*
- * zcache.c
- *
- * Copyright (c) 2010,2011, Dan Magenheimer, Oracle Corp.
- * Copyright (c) 2010,2011, Nitin Gupta
- *
- * Zcache provides an in-kernel "host implementation" for transcendent memory
- * and, thus indirectly, for cleancache and frontswap.  Zcache includes two
- * page-accessible memory [1] interfaces, both utilizing lzo1x compression:
- * 1) "compression buddies" ("zbud") is used for ephemeral pages
- * 2) xvmalloc is used for persistent pages.
- * Xvmalloc (based on the TLSF allocator) has very low fragmentation
- * so maximizes space efficiency, while zbud allows pairs (and potentially,
- * in the future, more than a pair of) compressed pages to be closely linked
- * so that reclaiming can be done via the kernel's physical-page-oriented
- * "shrinker" interface.
- *
- * [1] For a definition of page-accessible memory (aka PAM), see:
- *   http://marc.info/?l=linux-mm&m=127811271605009
- */
-
-#include <linux/cpu.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/lzo.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/atomic.h>
-#include "tmem.h"
-
-#include "../zram/xvmalloc.h" /* if built in drivers/staging */
-
-#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP))
-#error "zcache is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP"
-#endif
-#ifdef CONFIG_CLEANCACHE
-#include <linux/cleancache.h>
-#endif
-#ifdef CONFIG_FRONTSWAP
-#include <linux/frontswap.h>
-#endif
-
-#if 0
-/* this is more aggressive but may cause other problems? */
-#define ZCACHE_GFP_MASK        (GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN)
-#else
-#define ZCACHE_GFP_MASK \
-       (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-#endif
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-struct zcache_client {
-       struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
-       struct xv_pool *xvpool;
-       bool allocated;
-       atomic_t refcount;
-};
-
-static struct zcache_client zcache_host;
-static struct zcache_client zcache_clients[MAX_CLIENTS];
-
-static inline uint16_t get_client_id_from_client(struct zcache_client *cli)
-{
-       BUG_ON(cli == NULL);
-       if (cli == &zcache_host)
-               return LOCAL_CLIENT;
-       return cli - &zcache_clients[0];
-}
-
-static inline bool is_local_client(struct zcache_client *cli)
-{
-       return cli == &zcache_host;
-}
-
-/**********
- * Compression buddies ("zbud") provides for packing two (or, possibly
- * in the future, more) compressed ephemeral pages into a single "raw"
- * (physical) page and tracking them with data structures so that
- * the raw pages can be easily reclaimed.
- *
- * A zbud page ("zbpg") is an aligned page containing a list_head,
- * a lock, and two "zbud headers".  The remainder of the physical
- * page is divided up into aligned 64-byte "chunks" which contain
- * the compressed data for zero, one, or two zbuds.  Each zbpg
- * resides on: (1) an "unused list" if it has no zbuds; (2) a
- * "buddied" list if it is fully populated  with two zbuds; or
- * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks
- * the one unbuddied zbud uses.  The data inside a zbpg cannot be
- * read or written unless the zbpg's lock is held.
- */
-
-#define ZBH_SENTINEL  0x43214321
-#define ZBPG_SENTINEL  0xdeadbeef
-
-#define ZBUD_MAX_BUDS 2
-
-struct zbud_hdr {
-       uint16_t client_id;
-       uint16_t pool_id;
-       struct tmem_oid oid;
-       uint32_t index;
-       uint16_t size; /* compressed size in bytes, zero means unused */
-       DECL_SENTINEL
-};
-
-struct zbud_page {
-       struct list_head bud_list;
-       spinlock_t lock;
-       struct zbud_hdr buddy[ZBUD_MAX_BUDS];
-       DECL_SENTINEL
-       /* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */
-};
-
-#define CHUNK_SHIFT    6
-#define CHUNK_SIZE     (1 << CHUNK_SHIFT)
-#define CHUNK_MASK     (~(CHUNK_SIZE-1))
-#define NCHUNKS                (((PAGE_SIZE - sizeof(struct zbud_page)) & \
-                               CHUNK_MASK) >> CHUNK_SHIFT)
-#define MAX_CHUNK      (NCHUNKS-1)
-
-static struct {
-       struct list_head list;
-       unsigned count;
-} zbud_unbuddied[NCHUNKS];
-/* list N contains pages with N chunks USED and NCHUNKS-N unused */
-/* element 0 is never used but optimizing that isn't worth it */
-static unsigned long zbud_cumul_chunk_counts[NCHUNKS];
-
-struct list_head zbud_buddied_list;
-static unsigned long zcache_zbud_buddied_count;
-
-/* protects the buddied list and all unbuddied lists */
-static DEFINE_SPINLOCK(zbud_budlists_spinlock);
-
-static LIST_HEAD(zbpg_unused_list);
-static unsigned long zcache_zbpg_unused_list_count;
-
-/* protects the unused page list */
-static DEFINE_SPINLOCK(zbpg_unused_list_spinlock);
-
-static atomic_t zcache_zbud_curr_raw_pages;
-static atomic_t zcache_zbud_curr_zpages;
-static unsigned long zcache_zbud_curr_zbytes;
-static unsigned long zcache_zbud_cumul_zpages;
-static unsigned long zcache_zbud_cumul_zbytes;
-static unsigned long zcache_compress_poor;
-static unsigned long zcache_mean_compress_poor;
-
-/* forward references */
-static void *zcache_get_free_page(void);
-static void zcache_free_page(void *p);
-
-/*
- * zbud helper functions
- */
-
-static inline unsigned zbud_max_buddy_size(void)
-{
-       return MAX_CHUNK << CHUNK_SHIFT;
-}
-
-static inline unsigned zbud_size_to_chunks(unsigned size)
-{
-       BUG_ON(size == 0 || size > zbud_max_buddy_size());
-       return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
-}
-
-static inline int zbud_budnum(struct zbud_hdr *zh)
-{
-       unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1);
-       struct zbud_page *zbpg = NULL;
-       unsigned budnum = -1U;
-       int i;
-
-       for (i = 0; i < ZBUD_MAX_BUDS; i++)
-               if (offset == offsetof(typeof(*zbpg), buddy[i])) {
-                       budnum = i;
-                       break;
-               }
-       BUG_ON(budnum == -1U);
-       return budnum;
-}
-
-static char *zbud_data(struct zbud_hdr *zh, unsigned size)
-{
-       struct zbud_page *zbpg;
-       char *p;
-       unsigned budnum;
-
-       ASSERT_SENTINEL(zh, ZBH);
-       budnum = zbud_budnum(zh);
-       BUG_ON(size == 0 || size > zbud_max_buddy_size());
-       zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
-       ASSERT_SPINLOCK(&zbpg->lock);
-       p = (char *)zbpg;
-       if (budnum == 0)
-               p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) &
-                                                       CHUNK_MASK);
-       else if (budnum == 1)
-               p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
-       return p;
-}
-
-/*
- * zbud raw page management
- */
-
-static struct zbud_page *zbud_alloc_raw_page(void)
-{
-       struct zbud_page *zbpg = NULL;
-       struct zbud_hdr *zh0, *zh1;
-       bool recycled = 0;
-
-       /* if any pages on the zbpg list, use one */
-       spin_lock(&zbpg_unused_list_spinlock);
-       if (!list_empty(&zbpg_unused_list)) {
-               zbpg = list_first_entry(&zbpg_unused_list,
-                               struct zbud_page, bud_list);
-               list_del_init(&zbpg->bud_list);
-               zcache_zbpg_unused_list_count--;
-               recycled = 1;
-       }
-       spin_unlock(&zbpg_unused_list_spinlock);
-       if (zbpg == NULL)
-               /* none on zbpg list, try to get a kernel page */
-               zbpg = zcache_get_free_page();
-       if (likely(zbpg != NULL)) {
-               INIT_LIST_HEAD(&zbpg->bud_list);
-               zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
-               spin_lock_init(&zbpg->lock);
-               if (recycled) {
-                       ASSERT_INVERTED_SENTINEL(zbpg, ZBPG);
-                       SET_SENTINEL(zbpg, ZBPG);
-                       BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
-                       BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
-               } else {
-                       atomic_inc(&zcache_zbud_curr_raw_pages);
-                       INIT_LIST_HEAD(&zbpg->bud_list);
-                       SET_SENTINEL(zbpg, ZBPG);
-                       zh0->size = 0; zh1->size = 0;
-                       tmem_oid_set_invalid(&zh0->oid);
-                       tmem_oid_set_invalid(&zh1->oid);
-               }
-       }
-       return zbpg;
-}
-
-static void zbud_free_raw_page(struct zbud_page *zbpg)
-{
-       struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1];
-
-       ASSERT_SENTINEL(zbpg, ZBPG);
-       BUG_ON(!list_empty(&zbpg->bud_list));
-       ASSERT_SPINLOCK(&zbpg->lock);
-       BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid));
-       BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid));
-       INVERT_SENTINEL(zbpg, ZBPG);
-       spin_unlock(&zbpg->lock);
-       spin_lock(&zbpg_unused_list_spinlock);
-       list_add(&zbpg->bud_list, &zbpg_unused_list);
-       zcache_zbpg_unused_list_count++;
-       spin_unlock(&zbpg_unused_list_spinlock);
-}
-
-/*
- * core zbud handling routines
- */
-
-static unsigned zbud_free(struct zbud_hdr *zh)
-{
-       unsigned size;
-
-       ASSERT_SENTINEL(zh, ZBH);
-       BUG_ON(!tmem_oid_valid(&zh->oid));
-       size = zh->size;
-       BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
-       zh->size = 0;
-       tmem_oid_set_invalid(&zh->oid);
-       INVERT_SENTINEL(zh, ZBH);
-       zcache_zbud_curr_zbytes -= size;
-       atomic_dec(&zcache_zbud_curr_zpages);
-       return size;
-}
-
-static void zbud_free_and_delist(struct zbud_hdr *zh)
-{
-       unsigned chunks;
-       struct zbud_hdr *zh_other;
-       unsigned budnum = zbud_budnum(zh), size;
-       struct zbud_page *zbpg =
-               container_of(zh, struct zbud_page, buddy[budnum]);
-
-       spin_lock(&zbpg->lock);
-       if (list_empty(&zbpg->bud_list)) {
-               /* ignore zombie page... see zbud_evict_pages() */
-               spin_unlock(&zbpg->lock);
-               return;
-       }
-       size = zbud_free(zh);
-       ASSERT_SPINLOCK(&zbpg->lock);
-       zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
-       if (zh_other->size == 0) { /* was unbuddied: unlist and free */
-               chunks = zbud_size_to_chunks(size) ;
-               spin_lock(&zbud_budlists_spinlock);
-               BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
-               list_del_init(&zbpg->bud_list);
-               zbud_unbuddied[chunks].count--;
-               spin_unlock(&zbud_budlists_spinlock);
-               zbud_free_raw_page(zbpg);
-       } else { /* was buddied: move remaining buddy to unbuddied list */
-               chunks = zbud_size_to_chunks(zh_other->size) ;
-               spin_lock(&zbud_budlists_spinlock);
-               list_del_init(&zbpg->bud_list);
-               zcache_zbud_buddied_count--;
-               list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);
-               zbud_unbuddied[chunks].count++;
-               spin_unlock(&zbud_budlists_spinlock);
-               spin_unlock(&zbpg->lock);
-       }
-}
-
-static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id,
-                                       struct tmem_oid *oid,
-                                       uint32_t index, struct page *page,
-                                       void *cdata, unsigned size)
-{
-       struct zbud_hdr *zh0, *zh1, *zh = NULL;
-       struct zbud_page *zbpg = NULL, *ztmp;
-       unsigned nchunks;
-       char *to;
-       int i, found_good_buddy = 0;
-
-       nchunks = zbud_size_to_chunks(size) ;
-       for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
-               spin_lock(&zbud_budlists_spinlock);
-               if (!list_empty(&zbud_unbuddied[i].list)) {
-                       list_for_each_entry_safe(zbpg, ztmp,
-                                   &zbud_unbuddied[i].list, bud_list) {
-                               if (spin_trylock(&zbpg->lock)) {
-                                       found_good_buddy = i;
-                                       goto found_unbuddied;
-                               }
-                       }
-               }
-               spin_unlock(&zbud_budlists_spinlock);
-       }
-       /* didn't find a good buddy, try allocating a new page */
-       zbpg = zbud_alloc_raw_page();
-       if (unlikely(zbpg == NULL))
-               goto out;
-       /* ok, have a page, now compress the data before taking locks */
-       spin_lock(&zbpg->lock);
-       spin_lock(&zbud_budlists_spinlock);
-       list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list);
-       zbud_unbuddied[nchunks].count++;
-       zh = &zbpg->buddy[0];
-       goto init_zh;
-
-found_unbuddied:
-       ASSERT_SPINLOCK(&zbpg->lock);
-       zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1];
-       BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0)));
-       if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */
-               ASSERT_SENTINEL(zh0, ZBH);
-               zh = zh1;
-       } else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */
-               ASSERT_SENTINEL(zh1, ZBH);
-               zh = zh0;
-       } else
-               BUG();
-       list_del_init(&zbpg->bud_list);
-       zbud_unbuddied[found_good_buddy].count--;
-       list_add_tail(&zbpg->bud_list, &zbud_buddied_list);
-       zcache_zbud_buddied_count++;
-
-init_zh:
-       SET_SENTINEL(zh, ZBH);
-       zh->size = size;
-       zh->index = index;
-       zh->oid = *oid;
-       zh->pool_id = pool_id;
-       zh->client_id = client_id;
-       /* can wait to copy the data until the list locks are dropped */
-       spin_unlock(&zbud_budlists_spinlock);
-
-       to = zbud_data(zh, size);
-       memcpy(to, cdata, size);
-       spin_unlock(&zbpg->lock);
-       zbud_cumul_chunk_counts[nchunks]++;
-       atomic_inc(&zcache_zbud_curr_zpages);
-       zcache_zbud_cumul_zpages++;
-       zcache_zbud_curr_zbytes += size;
-       zcache_zbud_cumul_zbytes += size;
-out:
-       return zh;
-}
-
-static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
-{
-       struct zbud_page *zbpg;
-       unsigned budnum = zbud_budnum(zh);
-       size_t out_len = PAGE_SIZE;
-       char *to_va, *from_va;
-       unsigned size;
-       int ret = 0;
-
-       zbpg = container_of(zh, struct zbud_page, buddy[budnum]);
-       spin_lock(&zbpg->lock);
-       if (list_empty(&zbpg->bud_list)) {
-               /* ignore zombie page... see zbud_evict_pages() */
-               ret = -EINVAL;
-               goto out;
-       }
-       ASSERT_SENTINEL(zh, ZBH);
-       BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size());
-       to_va = kmap_atomic(page, KM_USER0);
-       size = zh->size;
-       from_va = zbud_data(zh, size);
-       ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
-       BUG_ON(ret != LZO_E_OK);
-       BUG_ON(out_len != PAGE_SIZE);
-       kunmap_atomic(to_va, KM_USER0);
-out:
-       spin_unlock(&zbpg->lock);
-       return ret;
-}
-
-/*
- * The following routines handle shrinking of ephemeral pages by evicting
- * pages "least valuable" first.
- */
-
-static unsigned long zcache_evicted_raw_pages;
-static unsigned long zcache_evicted_buddied_pages;
-static unsigned long zcache_evicted_unbuddied_pages;
-
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
-                                               uint16_t poolid);
-static void zcache_put_pool(struct tmem_pool *pool);
-
-/*
- * Flush and free all zbuds in a zbpg, then free the pageframe
- */
-static void zbud_evict_zbpg(struct zbud_page *zbpg)
-{
-       struct zbud_hdr *zh;
-       int i, j;
-       uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS];
-       uint32_t index[ZBUD_MAX_BUDS];
-       struct tmem_oid oid[ZBUD_MAX_BUDS];
-       struct tmem_pool *pool;
-
-       ASSERT_SPINLOCK(&zbpg->lock);
-       BUG_ON(!list_empty(&zbpg->bud_list));
-       for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) {
-               zh = &zbpg->buddy[i];
-               if (zh->size) {
-                       client_id[j] = zh->client_id;
-                       pool_id[j] = zh->pool_id;
-                       oid[j] = zh->oid;
-                       index[j] = zh->index;
-                       j++;
-                       zbud_free(zh);
-               }
-       }
-       spin_unlock(&zbpg->lock);
-       for (i = 0; i < j; i++) {
-               pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
-               if (pool != NULL) {
-                       tmem_flush_page(pool, &oid[i], index[i]);
-                       zcache_put_pool(pool);
-               }
-       }
-       ASSERT_SENTINEL(zbpg, ZBPG);
-       spin_lock(&zbpg->lock);
-       zbud_free_raw_page(zbpg);
-}
-
-/*
- * Free nr pages.  This code is funky because we want to hold the locks
- * protecting various lists for as short a time as possible, and in some
- * circumstances the list may change asynchronously when the list lock is
- * not held.  In some cases we also trylock not only to avoid waiting on a
- * page in use by another cpu, but also to avoid potential deadlock due to
- * lock inversion.
- */
-static void zbud_evict_pages(int nr)
-{
-       struct zbud_page *zbpg;
-       int i;
-
-       /* first try freeing any pages on unused list */
-retry_unused_list:
-       spin_lock_bh(&zbpg_unused_list_spinlock);
-       if (!list_empty(&zbpg_unused_list)) {
-               /* can't walk list here, since it may change when unlocked */
-               zbpg = list_first_entry(&zbpg_unused_list,
-                               struct zbud_page, bud_list);
-               list_del_init(&zbpg->bud_list);
-               zcache_zbpg_unused_list_count--;
-               atomic_dec(&zcache_zbud_curr_raw_pages);
-               spin_unlock_bh(&zbpg_unused_list_spinlock);
-               zcache_free_page(zbpg);
-               zcache_evicted_raw_pages++;
-               if (--nr <= 0)
-                       goto out;
-               goto retry_unused_list;
-       }
-       spin_unlock_bh(&zbpg_unused_list_spinlock);
-
-       /* now try freeing unbuddied pages, starting with least space avail */
-       for (i = 0; i < MAX_CHUNK; i++) {
-retry_unbud_list_i:
-               spin_lock_bh(&zbud_budlists_spinlock);
-               if (list_empty(&zbud_unbuddied[i].list)) {
-                       spin_unlock_bh(&zbud_budlists_spinlock);
-                       continue;
-               }
-               list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) {
-                       if (unlikely(!spin_trylock(&zbpg->lock)))
-                               continue;
-                       list_del_init(&zbpg->bud_list);
-                       zbud_unbuddied[i].count--;
-                       spin_unlock(&zbud_budlists_spinlock);
-                       zcache_evicted_unbuddied_pages++;
-                       /* want budlists unlocked when doing zbpg eviction */
-                       zbud_evict_zbpg(zbpg);
-                       local_bh_enable();
-                       if (--nr <= 0)
-                               goto out;
-                       goto retry_unbud_list_i;
-               }
-               spin_unlock_bh(&zbud_budlists_spinlock);
-       }
-
-       /* as a last resort, free buddied pages */
-retry_bud_list:
-       spin_lock_bh(&zbud_budlists_spinlock);
-       if (list_empty(&zbud_buddied_list)) {
-               spin_unlock_bh(&zbud_budlists_spinlock);
-               goto out;
-       }
-       list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) {
-               if (unlikely(!spin_trylock(&zbpg->lock)))
-                       continue;
-               list_del_init(&zbpg->bud_list);
-               zcache_zbud_buddied_count--;
-               spin_unlock(&zbud_budlists_spinlock);
-               zcache_evicted_buddied_pages++;
-               /* want budlists unlocked when doing zbpg eviction */
-               zbud_evict_zbpg(zbpg);
-               local_bh_enable();
-               if (--nr <= 0)
-                       goto out;
-               goto retry_bud_list;
-       }
-       spin_unlock_bh(&zbud_budlists_spinlock);
-out:
-       return;
-}
-
-static void zbud_init(void)
-{
-       int i;
-
-       INIT_LIST_HEAD(&zbud_buddied_list);
-       zcache_zbud_buddied_count = 0;
-       for (i = 0; i < NCHUNKS; i++) {
-               INIT_LIST_HEAD(&zbud_unbuddied[i].list);
-               zbud_unbuddied[i].count = 0;
-       }
-}
-
-#ifdef CONFIG_SYSFS
-/*
- * These sysfs routines show a nice distribution of how many zbpg's are
- * currently (and have ever been placed) in each unbuddied list.  It's fun
- * to watch but can probably go away before final merge.
- */
-static int zbud_show_unbuddied_list_counts(char *buf)
-{
-       int i;
-       char *p = buf;
-
-       for (i = 0; i < NCHUNKS; i++)
-               p += sprintf(p, "%u ", zbud_unbuddied[i].count);
-       return p - buf;
-}
-
-static int zbud_show_cumul_chunk_counts(char *buf)
-{
-       unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0;
-       unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0;
-       unsigned long total_chunks_lte_42 = 0;
-       char *p = buf;
-
-       for (i = 0; i < NCHUNKS; i++) {
-               p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]);
-               chunks += zbud_cumul_chunk_counts[i];
-               total_chunks += zbud_cumul_chunk_counts[i];
-               sum_total_chunks += i * zbud_cumul_chunk_counts[i];
-               if (i == 21)
-                       total_chunks_lte_21 = total_chunks;
-               if (i == 32)
-                       total_chunks_lte_32 = total_chunks;
-               if (i == 42)
-                       total_chunks_lte_42 = total_chunks;
-       }
-       p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n",
-               total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42,
-               chunks == 0 ? 0 : sum_total_chunks / chunks);
-       return p - buf;
-}
-#endif
-
-/**********
- * This "zv" PAM implementation combines the TLSF-based xvMalloc
- * with lzo1x compression to maximize the amount of data that can
- * be packed into a physical page.
- *
- * Zv represents a PAM page with the index and object (plus a "size" value
- * necessary for decompression) immediately preceding the compressed data.
- */
-
-#define ZVH_SENTINEL  0x43214321
-
-struct zv_hdr {
-       uint32_t pool_id;
-       struct tmem_oid oid;
-       uint32_t index;
-       DECL_SENTINEL
-};
-
-/* rudimentary policy limits */
-/* total number of persistent pages may not exceed this percentage */
-static unsigned int zv_page_count_policy_percent = 75;
-/*
- * byte count defining poor compression; pages with greater zsize will be
- * rejected
- */
-static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7;
-/*
- * byte count defining poor *mean* compression; pages with greater zsize
- * will be rejected until sufficient better-compressed pages are accepted
- * driving the man below this threshold
- */
-static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5;
-
-static unsigned long zv_curr_dist_counts[NCHUNKS];
-static unsigned long zv_cumul_dist_counts[NCHUNKS];
-
-static struct zv_hdr *zv_create(struct xv_pool *xvpool, uint32_t pool_id,
-                               struct tmem_oid *oid, uint32_t index,
-                               void *cdata, unsigned clen)
-{
-       struct page *page;
-       struct zv_hdr *zv = NULL;
-       uint32_t offset;
-       int alloc_size = clen + sizeof(struct zv_hdr);
-       int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-       int ret;
-
-       BUG_ON(!irqs_disabled());
-       BUG_ON(chunks >= NCHUNKS);
-       ret = xv_malloc(xvpool, alloc_size,
-                       &page, &offset, ZCACHE_GFP_MASK);
-       if (unlikely(ret))
-               goto out;
-       zv_curr_dist_counts[chunks]++;
-       zv_cumul_dist_counts[chunks]++;
-       zv = kmap_atomic(page, KM_USER0) + offset;
-       zv->index = index;
-       zv->oid = *oid;
-       zv->pool_id = pool_id;
-       SET_SENTINEL(zv, ZVH);
-       memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen);
-       kunmap_atomic(zv, KM_USER0);
-out:
-       return zv;
-}
-
-static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
-{
-       unsigned long flags;
-       struct page *page;
-       uint32_t offset;
-       uint16_t size = xv_get_object_size(zv);
-       int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT;
-
-       ASSERT_SENTINEL(zv, ZVH);
-       BUG_ON(chunks >= NCHUNKS);
-       zv_curr_dist_counts[chunks]--;
-       size -= sizeof(*zv);
-       BUG_ON(size == 0);
-       INVERT_SENTINEL(zv, ZVH);
-       page = virt_to_page(zv);
-       offset = (unsigned long)zv & ~PAGE_MASK;
-       local_irq_save(flags);
-       xv_free(xvpool, page, offset);
-       local_irq_restore(flags);
-}
-
-static void zv_decompress(struct page *page, struct zv_hdr *zv)
-{
-       size_t clen = PAGE_SIZE;
-       char *to_va;
-       unsigned size;
-       int ret;
-
-       ASSERT_SENTINEL(zv, ZVH);
-       size = xv_get_object_size(zv) - sizeof(*zv);
-       BUG_ON(size == 0);
-       to_va = kmap_atomic(page, KM_USER0);
-       ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
-                                       size, to_va, &clen);
-       kunmap_atomic(to_va, KM_USER0);
-       BUG_ON(ret != LZO_E_OK);
-       BUG_ON(clen != PAGE_SIZE);
-}
-
-#ifdef CONFIG_SYSFS
-/*
- * show a distribution of compression stats for zv pages.
- */
-
-static int zv_curr_dist_counts_show(char *buf)
-{
-       unsigned long i, n, chunks = 0, sum_total_chunks = 0;
-       char *p = buf;
-
-       for (i = 0; i < NCHUNKS; i++) {
-               n = zv_curr_dist_counts[i];
-               p += sprintf(p, "%lu ", n);
-               chunks += n;
-               sum_total_chunks += i * n;
-       }
-       p += sprintf(p, "mean:%lu\n",
-               chunks == 0 ? 0 : sum_total_chunks / chunks);
-       return p - buf;
-}
-
-static int zv_cumul_dist_counts_show(char *buf)
-{
-       unsigned long i, n, chunks = 0, sum_total_chunks = 0;
-       char *p = buf;
-
-       for (i = 0; i < NCHUNKS; i++) {
-               n = zv_cumul_dist_counts[i];
-               p += sprintf(p, "%lu ", n);
-               chunks += n;
-               sum_total_chunks += i * n;
-       }
-       p += sprintf(p, "mean:%lu\n",
-               chunks == 0 ? 0 : sum_total_chunks / chunks);
-       return p - buf;
-}
-
-/*
- * setting zv_max_zsize via sysfs causes all persistent (e.g. swap)
- * pages that don't compress to less than this value (including metadata
- * overhead) to be rejected.  We don't allow the value to get too close
- * to PAGE_SIZE.
- */
-static ssize_t zv_max_zsize_show(struct kobject *kobj,
-                                   struct kobj_attribute *attr,
-                                   char *buf)
-{
-       return sprintf(buf, "%u\n", zv_max_zsize);
-}
-
-static ssize_t zv_max_zsize_store(struct kobject *kobj,
-                                   struct kobj_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       err = strict_strtoul(buf, 10, &val);
-       if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
-               return -EINVAL;
-       zv_max_zsize = val;
-       return count;
-}
-
-/*
- * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap)
- * pages that don't compress to less than this value (including metadata
- * overhead) to be rejected UNLESS the mean compression is also smaller
- * than this value.  In other words, we are load-balancing-by-zsize the
- * accepted pages.  Again, we don't allow the value to get too close
- * to PAGE_SIZE.
- */
-static ssize_t zv_max_mean_zsize_show(struct kobject *kobj,
-                                   struct kobj_attribute *attr,
-                                   char *buf)
-{
-       return sprintf(buf, "%u\n", zv_max_mean_zsize);
-}
-
-static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
-                                   struct kobj_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       err = strict_strtoul(buf, 10, &val);
-       if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7))
-               return -EINVAL;
-       zv_max_mean_zsize = val;
-       return count;
-}
-
-/*
- * setting zv_page_count_policy_percent via sysfs sets an upper bound of
- * persistent (e.g. swap) pages that will be retained according to:
- *     (zv_page_count_policy_percent * totalram_pages) / 100)
- * when that limit is reached, further puts will be rejected (until
- * some pages have been flushed).  Note that, due to compression,
- * this number may exceed 100; it defaults to 75 and we set an
- * arbitary limit of 150.  A poor choice will almost certainly result
- * in OOM's, so this value should only be changed prudently.
- */
-static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
-                                                struct kobj_attribute *attr,
-                                                char *buf)
-{
-       return sprintf(buf, "%u\n", zv_page_count_policy_percent);
-}
-
-static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj,
-                                                 struct kobj_attribute *attr,
-                                                 const char *buf, size_t count)
-{
-       unsigned long val;
-       int err;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       err = strict_strtoul(buf, 10, &val);
-       if (err || (val == 0) || (val > 150))
-               return -EINVAL;
-       zv_page_count_policy_percent = val;
-       return count;
-}
-
-static struct kobj_attribute zcache_zv_max_zsize_attr = {
-               .attr = { .name = "zv_max_zsize", .mode = 0644 },
-               .show = zv_max_zsize_show,
-               .store = zv_max_zsize_store,
-};
-
-static struct kobj_attribute zcache_zv_max_mean_zsize_attr = {
-               .attr = { .name = "zv_max_mean_zsize", .mode = 0644 },
-               .show = zv_max_mean_zsize_show,
-               .store = zv_max_mean_zsize_store,
-};
-
-static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = {
-               .attr = { .name = "zv_page_count_policy_percent",
-                         .mode = 0644 },
-               .show = zv_page_count_policy_percent_show,
-               .store = zv_page_count_policy_percent_store,
-};
-#endif
-
-/*
- * zcache core code starts here
- */
-
-/* useful stats not collected by cleancache or frontswap */
-static unsigned long zcache_flush_total;
-static unsigned long zcache_flush_found;
-static unsigned long zcache_flobj_total;
-static unsigned long zcache_flobj_found;
-static unsigned long zcache_failed_eph_puts;
-static unsigned long zcache_failed_pers_puts;
-
-/*
- * Tmem operations assume the poolid implies the invoking client.
- * Zcache only has one client (the kernel itself): LOCAL_CLIENT.
- * RAMster has each client numbered by cluster node, and a KVM version
- * of zcache would have one client per guest and each client might
- * have a poolid==N.
- */
-static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid)
-{
-       struct tmem_pool *pool = NULL;
-       struct zcache_client *cli = NULL;
-
-       if (cli_id == LOCAL_CLIENT)
-               cli = &zcache_host;
-       else {
-               if (cli_id >= MAX_CLIENTS)
-                       goto out;
-               cli = &zcache_clients[cli_id];
-               if (cli == NULL)
-                       goto out;
-               atomic_inc(&cli->refcount);
-       }
-       if (poolid < MAX_POOLS_PER_CLIENT) {
-               pool = cli->tmem_pools[poolid];
-               if (pool != NULL)
-                       atomic_inc(&pool->refcount);
-       }
-out:
-       return pool;
-}
-
-static void zcache_put_pool(struct tmem_pool *pool)
-{
-       struct zcache_client *cli = NULL;
-
-       if (pool == NULL)
-               BUG();
-       cli = pool->client;
-       atomic_dec(&pool->refcount);
-       atomic_dec(&cli->refcount);
-}
-
-int zcache_new_client(uint16_t cli_id)
-{
-       struct zcache_client *cli = NULL;
-       int ret = -1;
-
-       if (cli_id == LOCAL_CLIENT)
-               cli = &zcache_host;
-       else if ((unsigned int)cli_id < MAX_CLIENTS)
-               cli = &zcache_clients[cli_id];
-       if (cli == NULL)
-               goto out;
-       if (cli->allocated)
-               goto out;
-       cli->allocated = 1;
-#ifdef CONFIG_FRONTSWAP
-       cli->xvpool = xv_create_pool();
-       if (cli->xvpool == NULL)
-               goto out;
-#endif
-       ret = 0;
-out:
-       return ret;
-}
-
-/* counters for debugging */
-static unsigned long zcache_failed_get_free_pages;
-static unsigned long zcache_failed_alloc;
-static unsigned long zcache_put_to_flush;
-static unsigned long zcache_aborted_preload;
-static unsigned long zcache_aborted_shrink;
-
-/*
- * Ensure that memory allocation requests in zcache don't result
- * in direct reclaim requests via the shrinker, which would cause
- * an infinite loop.  Maybe a GFP flag would be better?
- */
-static DEFINE_SPINLOCK(zcache_direct_reclaim_lock);
-
-/*
- * for now, used named slabs so can easily track usage; later can
- * either just use kmalloc, or perhaps add a slab-like allocator
- * to more carefully manage total memory utilization
- */
-static struct kmem_cache *zcache_objnode_cache;
-static struct kmem_cache *zcache_obj_cache;
-static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_obj_count_max;
-static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_objnode_count_max;
-
-/*
- * to avoid memory allocation recursion (e.g. due to direct reclaim), we
- * preload all necessary data structures so the hostops callbacks never
- * actually do a malloc
- */
-struct zcache_preload {
-       void *page;
-       struct tmem_obj *obj;
-       int nr;
-       struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
-};
-static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-
-static int zcache_do_preload(struct tmem_pool *pool)
-{
-       struct zcache_preload *kp;
-       struct tmem_objnode *objnode;
-       struct tmem_obj *obj;
-       void *page;
-       int ret = -ENOMEM;
-
-       if (unlikely(zcache_objnode_cache == NULL))
-               goto out;
-       if (unlikely(zcache_obj_cache == NULL))
-               goto out;
-       if (!spin_trylock(&zcache_direct_reclaim_lock)) {
-               zcache_aborted_preload++;
-               goto out;
-       }
-       preempt_disable();
-       kp = &__get_cpu_var(zcache_preloads);
-       while (kp->nr < ARRAY_SIZE(kp->objnodes)) {
-               preempt_enable_no_resched();
-               objnode = kmem_cache_alloc(zcache_objnode_cache,
-                               ZCACHE_GFP_MASK);
-               if (unlikely(objnode == NULL)) {
-                       zcache_failed_alloc++;
-                       goto unlock_out;
-               }
-               preempt_disable();
-               kp = &__get_cpu_var(zcache_preloads);
-               if (kp->nr < ARRAY_SIZE(kp->objnodes))
-                       kp->objnodes[kp->nr++] = objnode;
-               else
-                       kmem_cache_free(zcache_objnode_cache, objnode);
-       }
-       preempt_enable_no_resched();
-       obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
-       if (unlikely(obj == NULL)) {
-               zcache_failed_alloc++;
-               goto unlock_out;
-       }
-       page = (void *)__get_free_page(ZCACHE_GFP_MASK);
-       if (unlikely(page == NULL)) {
-               zcache_failed_get_free_pages++;
-               kmem_cache_free(zcache_obj_cache, obj);
-               goto unlock_out;
-       }
-       preempt_disable();
-       kp = &__get_cpu_var(zcache_preloads);
-       if (kp->obj == NULL)
-               kp->obj = obj;
-       else
-               kmem_cache_free(zcache_obj_cache, obj);
-       if (kp->page == NULL)
-               kp->page = page;
-       else
-               free_page((unsigned long)page);
-       ret = 0;
-unlock_out:
-       spin_unlock(&zcache_direct_reclaim_lock);
-out:
-       return ret;
-}
-
-static void *zcache_get_free_page(void)
-{
-       struct zcache_preload *kp;
-       void *page;
-
-       kp = &__get_cpu_var(zcache_preloads);
-       page = kp->page;
-       BUG_ON(page == NULL);
-       kp->page = NULL;
-       return page;
-}
-
-static void zcache_free_page(void *p)
-{
-       free_page((unsigned long)p);
-}
-
-/*
- * zcache implementation for tmem host ops
- */
-
-static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
-{
-       struct tmem_objnode *objnode = NULL;
-       unsigned long count;
-       struct zcache_preload *kp;
-
-       kp = &__get_cpu_var(zcache_preloads);
-       if (kp->nr <= 0)
-               goto out;
-       objnode = kp->objnodes[kp->nr - 1];
-       BUG_ON(objnode == NULL);
-       kp->objnodes[kp->nr - 1] = NULL;
-       kp->nr--;
-       count = atomic_inc_return(&zcache_curr_objnode_count);
-       if (count > zcache_curr_objnode_count_max)
-               zcache_curr_objnode_count_max = count;
-out:
-       return objnode;
-}
-
-static void zcache_objnode_free(struct tmem_objnode *objnode,
-                                       struct tmem_pool *pool)
-{
-       atomic_dec(&zcache_curr_objnode_count);
-       BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0);
-       kmem_cache_free(zcache_objnode_cache, objnode);
-}
-
-static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
-{
-       struct tmem_obj *obj = NULL;
-       unsigned long count;
-       struct zcache_preload *kp;
-
-       kp = &__get_cpu_var(zcache_preloads);
-       obj = kp->obj;
-       BUG_ON(obj == NULL);
-       kp->obj = NULL;
-       count = atomic_inc_return(&zcache_curr_obj_count);
-       if (count > zcache_curr_obj_count_max)
-               zcache_curr_obj_count_max = count;
-       return obj;
-}
-
-static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
-{
-       atomic_dec(&zcache_curr_obj_count);
-       BUG_ON(atomic_read(&zcache_curr_obj_count) < 0);
-       kmem_cache_free(zcache_obj_cache, obj);
-}
-
-static struct tmem_hostops zcache_hostops = {
-       .obj_alloc = zcache_obj_alloc,
-       .obj_free = zcache_obj_free,
-       .objnode_alloc = zcache_objnode_alloc,
-       .objnode_free = zcache_objnode_free,
-};
-
-/*
- * zcache implementations for PAM page descriptor ops
- */
-
-static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_eph_pampd_count_max;
-static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0);
-static unsigned long zcache_curr_pers_pampd_count_max;
-
-/* forward reference */
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len);
-
-static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph,
-                               struct tmem_pool *pool, struct tmem_oid *oid,
-                                uint32_t index)
-{
-       void *pampd = NULL, *cdata;
-       size_t clen;
-       int ret;
-       unsigned long count;
-       struct page *page = virt_to_page(data);
-       struct zcache_client *cli = pool->client;
-       uint16_t client_id = get_client_id_from_client(cli);
-       unsigned long zv_mean_zsize;
-       unsigned long curr_pers_pampd_count;
-
-       if (eph) {
-               ret = zcache_compress(page, &cdata, &clen);
-               if (ret == 0)
-                       goto out;
-               if (clen == 0 || clen > zbud_max_buddy_size()) {
-                       zcache_compress_poor++;
-                       goto out;
-               }
-               pampd = (void *)zbud_create(client_id, pool->pool_id, oid,
-                                               index, page, cdata, clen);
-               if (pampd != NULL) {
-                       count = atomic_inc_return(&zcache_curr_eph_pampd_count);
-                       if (count > zcache_curr_eph_pampd_count_max)
-                               zcache_curr_eph_pampd_count_max = count;
-               }
-       } else {
-               curr_pers_pampd_count =
-                       atomic_read(&zcache_curr_pers_pampd_count);
-               if (curr_pers_pampd_count >
-                   (zv_page_count_policy_percent * totalram_pages) / 100)
-                       goto out;
-               ret = zcache_compress(page, &cdata, &clen);
-               if (ret == 0)
-                       goto out;
-               /* reject if compression is too poor */
-               if (clen > zv_max_zsize) {
-                       zcache_compress_poor++;
-                       goto out;
-               }
-               /* reject if mean compression is too poor */
-               if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) {
-                       zv_mean_zsize = xv_get_total_size_bytes(cli->xvpool) /
-                                               curr_pers_pampd_count;
-                       if (zv_mean_zsize > zv_max_mean_zsize) {
-                               zcache_mean_compress_poor++;
-                               goto out;
-                       }
-               }
-               pampd = (void *)zv_create(cli->xvpool, pool->pool_id,
-                                               oid, index, cdata, clen);
-               if (pampd == NULL)
-                       goto out;
-               count = atomic_inc_return(&zcache_curr_pers_pampd_count);
-               if (count > zcache_curr_pers_pampd_count_max)
-                       zcache_curr_pers_pampd_count_max = count;
-       }
-out:
-       return pampd;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw,
-                                       void *pampd, struct tmem_pool *pool,
-                                       struct tmem_oid *oid, uint32_t index)
-{
-       int ret = 0;
-
-       BUG_ON(is_ephemeral(pool));
-       zv_decompress(virt_to_page(data), pampd);
-       return ret;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw,
-                                       void *pampd, struct tmem_pool *pool,
-                                       struct tmem_oid *oid, uint32_t index)
-{
-       int ret = 0;
-
-       BUG_ON(!is_ephemeral(pool));
-       zbud_decompress(virt_to_page(data), pampd);
-       zbud_free_and_delist((struct zbud_hdr *)pampd);
-       atomic_dec(&zcache_curr_eph_pampd_count);
-       return ret;
-}
-
-/*
- * free the pampd and remove it from any zcache lists
- * pampd must no longer be pointed to from any tmem data structures!
- */
-static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
-                               struct tmem_oid *oid, uint32_t index)
-{
-       struct zcache_client *cli = pool->client;
-
-       if (is_ephemeral(pool)) {
-               zbud_free_and_delist((struct zbud_hdr *)pampd);
-               atomic_dec(&zcache_curr_eph_pampd_count);
-               BUG_ON(atomic_read(&zcache_curr_eph_pampd_count) < 0);
-       } else {
-               zv_free(cli->xvpool, (struct zv_hdr *)pampd);
-               atomic_dec(&zcache_curr_pers_pampd_count);
-               BUG_ON(atomic_read(&zcache_curr_pers_pampd_count) < 0);
-       }
-}
-
-static void zcache_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj)
-{
-}
-
-static void zcache_pampd_new_obj(struct tmem_obj *obj)
-{
-}
-
-static int zcache_pampd_replace_in_obj(void *pampd, struct tmem_obj *obj)
-{
-       return -1;
-}
-
-static bool zcache_pampd_is_remote(void *pampd)
-{
-       return 0;
-}
-
-static struct tmem_pamops zcache_pamops = {
-       .create = zcache_pampd_create,
-       .get_data = zcache_pampd_get_data,
-       .get_data_and_free = zcache_pampd_get_data_and_free,
-       .free = zcache_pampd_free,
-       .free_obj = zcache_pampd_free_obj,
-       .new_obj = zcache_pampd_new_obj,
-       .replace_in_obj = zcache_pampd_replace_in_obj,
-       .is_remote = zcache_pampd_is_remote,
-};
-
-/*
- * zcache compression/decompression and related per-cpu stuff
- */
-
-#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
-#define LZO_DSTMEM_PAGE_ORDER 1
-static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
-static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
-
-static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
-{
-       int ret = 0;
-       unsigned char *dmem = __get_cpu_var(zcache_dstmem);
-       unsigned char *wmem = __get_cpu_var(zcache_workmem);
-       char *from_va;
-
-       BUG_ON(!irqs_disabled());
-       if (unlikely(dmem == NULL || wmem == NULL))
-               goto out;  /* no buffer, so can't compress */
-       from_va = kmap_atomic(from, KM_USER0);
-       mb();
-       ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
-       BUG_ON(ret != LZO_E_OK);
-       *out_va = dmem;
-       kunmap_atomic(from_va, KM_USER0);
-       ret = 1;
-out:
-       return ret;
-}
-
-
-static int zcache_cpu_notifier(struct notifier_block *nb,
-                               unsigned long action, void *pcpu)
-{
-       int cpu = (long)pcpu;
-       struct zcache_preload *kp;
-
-       switch (action) {
-       case CPU_UP_PREPARE:
-               per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
-                       GFP_KERNEL | __GFP_REPEAT,
-                       LZO_DSTMEM_PAGE_ORDER),
-               per_cpu(zcache_workmem, cpu) =
-                       kzalloc(LZO1X_MEM_COMPRESS,
-                               GFP_KERNEL | __GFP_REPEAT);
-               break;
-       case CPU_DEAD:
-       case CPU_UP_CANCELED:
-               free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
-                               LZO_DSTMEM_PAGE_ORDER);
-               per_cpu(zcache_dstmem, cpu) = NULL;
-               kfree(per_cpu(zcache_workmem, cpu));
-               per_cpu(zcache_workmem, cpu) = NULL;
-               kp = &per_cpu(zcache_preloads, cpu);
-               while (kp->nr) {
-                       kmem_cache_free(zcache_objnode_cache,
-                                       kp->objnodes[kp->nr - 1]);
-                       kp->objnodes[kp->nr - 1] = NULL;
-                       kp->nr--;
-               }
-               kmem_cache_free(zcache_obj_cache, kp->obj);
-               free_page((unsigned long)kp->page);
-               break;
-       default:
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block zcache_cpu_notifier_block = {
-       .notifier_call = zcache_cpu_notifier
-};
-
-#ifdef CONFIG_SYSFS
-#define ZCACHE_SYSFS_RO(_name) \
-       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-                               struct kobj_attribute *attr, char *buf) \
-       { \
-               return sprintf(buf, "%lu\n", zcache_##_name); \
-       } \
-       static struct kobj_attribute zcache_##_name##_attr = { \
-               .attr = { .name = __stringify(_name), .mode = 0444 }, \
-               .show = zcache_##_name##_show, \
-       }
-
-#define ZCACHE_SYSFS_RO_ATOMIC(_name) \
-       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-                               struct kobj_attribute *attr, char *buf) \
-       { \
-           return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \
-       } \
-       static struct kobj_attribute zcache_##_name##_attr = { \
-               .attr = { .name = __stringify(_name), .mode = 0444 }, \
-               .show = zcache_##_name##_show, \
-       }
-
-#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \
-       static ssize_t zcache_##_name##_show(struct kobject *kobj, \
-                               struct kobj_attribute *attr, char *buf) \
-       { \
-           return _func(buf); \
-       } \
-       static struct kobj_attribute zcache_##_name##_attr = { \
-               .attr = { .name = __stringify(_name), .mode = 0444 }, \
-               .show = zcache_##_name##_show, \
-       }
-
-ZCACHE_SYSFS_RO(curr_obj_count_max);
-ZCACHE_SYSFS_RO(curr_objnode_count_max);
-ZCACHE_SYSFS_RO(flush_total);
-ZCACHE_SYSFS_RO(flush_found);
-ZCACHE_SYSFS_RO(flobj_total);
-ZCACHE_SYSFS_RO(flobj_found);
-ZCACHE_SYSFS_RO(failed_eph_puts);
-ZCACHE_SYSFS_RO(failed_pers_puts);
-ZCACHE_SYSFS_RO(zbud_curr_zbytes);
-ZCACHE_SYSFS_RO(zbud_cumul_zpages);
-ZCACHE_SYSFS_RO(zbud_cumul_zbytes);
-ZCACHE_SYSFS_RO(zbud_buddied_count);
-ZCACHE_SYSFS_RO(zbpg_unused_list_count);
-ZCACHE_SYSFS_RO(evicted_raw_pages);
-ZCACHE_SYSFS_RO(evicted_unbuddied_pages);
-ZCACHE_SYSFS_RO(evicted_buddied_pages);
-ZCACHE_SYSFS_RO(failed_get_free_pages);
-ZCACHE_SYSFS_RO(failed_alloc);
-ZCACHE_SYSFS_RO(put_to_flush);
-ZCACHE_SYSFS_RO(aborted_preload);
-ZCACHE_SYSFS_RO(aborted_shrink);
-ZCACHE_SYSFS_RO(compress_poor);
-ZCACHE_SYSFS_RO(mean_compress_poor);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages);
-ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages);
-ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count);
-ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts,
-                       zbud_show_unbuddied_list_counts);
-ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts,
-                       zbud_show_cumul_chunk_counts);
-ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts,
-                       zv_curr_dist_counts_show);
-ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts,
-                       zv_cumul_dist_counts_show);
-
-static struct attribute *zcache_attrs[] = {
-       &zcache_curr_obj_count_attr.attr,
-       &zcache_curr_obj_count_max_attr.attr,
-       &zcache_curr_objnode_count_attr.attr,
-       &zcache_curr_objnode_count_max_attr.attr,
-       &zcache_flush_total_attr.attr,
-       &zcache_flobj_total_attr.attr,
-       &zcache_flush_found_attr.attr,
-       &zcache_flobj_found_attr.attr,
-       &zcache_failed_eph_puts_attr.attr,
-       &zcache_failed_pers_puts_attr.attr,
-       &zcache_compress_poor_attr.attr,
-       &zcache_mean_compress_poor_attr.attr,
-       &zcache_zbud_curr_raw_pages_attr.attr,
-       &zcache_zbud_curr_zpages_attr.attr,
-       &zcache_zbud_curr_zbytes_attr.attr,
-       &zcache_zbud_cumul_zpages_attr.attr,
-       &zcache_zbud_cumul_zbytes_attr.attr,
-       &zcache_zbud_buddied_count_attr.attr,
-       &zcache_zbpg_unused_list_count_attr.attr,
-       &zcache_evicted_raw_pages_attr.attr,
-       &zcache_evicted_unbuddied_pages_attr.attr,
-       &zcache_evicted_buddied_pages_attr.attr,
-       &zcache_failed_get_free_pages_attr.attr,
-       &zcache_failed_alloc_attr.attr,
-       &zcache_put_to_flush_attr.attr,
-       &zcache_aborted_preload_attr.attr,
-       &zcache_aborted_shrink_attr.attr,
-       &zcache_zbud_unbuddied_list_counts_attr.attr,
-       &zcache_zbud_cumul_chunk_counts_attr.attr,
-       &zcache_zv_curr_dist_counts_attr.attr,
-       &zcache_zv_cumul_dist_counts_attr.attr,
-       &zcache_zv_max_zsize_attr.attr,
-       &zcache_zv_max_mean_zsize_attr.attr,
-       &zcache_zv_page_count_policy_percent_attr.attr,
-       NULL,
-};
-
-static struct attribute_group zcache_attr_group = {
-       .attrs = zcache_attrs,
-       .name = "zcache",
-};
-
-#endif /* CONFIG_SYSFS */
-/*
- * When zcache is disabled ("frozen"), pools can be created and destroyed,
- * but all puts (and thus all other operations that require memory allocation)
- * must fail.  If zcache is unfrozen, accepts puts, then frozen again,
- * data consistency requires all puts while frozen to be converted into
- * flushes.
- */
-static bool zcache_freeze;
-
-/*
- * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
- */
-static int shrink_zcache_memory(struct shrinker *shrink,
-                               struct shrink_control *sc)
-{
-       int ret = -1;
-       int nr = sc->nr_to_scan;
-       gfp_t gfp_mask = sc->gfp_mask;
-
-       if (nr >= 0) {
-               if (!(gfp_mask & __GFP_FS))
-                       /* does this case really need to be skipped? */
-                       goto out;
-               if (spin_trylock(&zcache_direct_reclaim_lock)) {
-                       zbud_evict_pages(nr);
-                       spin_unlock(&zcache_direct_reclaim_lock);
-               } else
-                       zcache_aborted_shrink++;
-       }
-       ret = (int)atomic_read(&zcache_zbud_curr_raw_pages);
-out:
-       return ret;
-}
-
-static struct shrinker zcache_shrinker = {
-       .shrink = shrink_zcache_memory,
-       .seeks = DEFAULT_SEEKS,
-};
-
-/*
- * zcache shims between cleancache/frontswap ops and tmem
- */
-
-static int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
-                               uint32_t index, struct page *page)
-{
-       struct tmem_pool *pool;
-       int ret = -1;
-
-       BUG_ON(!irqs_disabled());
-       pool = zcache_get_pool_by_id(cli_id, pool_id);
-       if (unlikely(pool == NULL))
-               goto out;
-       if (!zcache_freeze && zcache_do_preload(pool) == 0) {
-               /* preload does preempt_disable on success */
-               ret = tmem_put(pool, oidp, index, page_address(page),
-                               PAGE_SIZE, 0, is_ephemeral(pool));
-               if (ret < 0) {
-                       if (is_ephemeral(pool))
-                               zcache_failed_eph_puts++;
-                       else
-                               zcache_failed_pers_puts++;
-               }
-               zcache_put_pool(pool);
-               preempt_enable_no_resched();
-       } else {
-               zcache_put_to_flush++;
-               if (atomic_read(&pool->obj_count) > 0)
-                       /* the put fails whether the flush succeeds or not */
-                       (void)tmem_flush_page(pool, oidp, index);
-               zcache_put_pool(pool);
-       }
-out:
-       return ret;
-}
-
-static int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp,
-                               uint32_t index, struct page *page)
-{
-       struct tmem_pool *pool;
-       int ret = -1;
-       unsigned long flags;
-       size_t size = PAGE_SIZE;
-
-       local_irq_save(flags);
-       pool = zcache_get_pool_by_id(cli_id, pool_id);
-       if (likely(pool != NULL)) {
-               if (atomic_read(&pool->obj_count) > 0)
-                       ret = tmem_get(pool, oidp, index, page_address(page),
-                                       &size, 0, is_ephemeral(pool));
-               zcache_put_pool(pool);
-       }
-       local_irq_restore(flags);
-       return ret;
-}
-
-static int zcache_flush_page(int cli_id, int pool_id,
-                               struct tmem_oid *oidp, uint32_t index)
-{
-       struct tmem_pool *pool;
-       int ret = -1;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       zcache_flush_total++;
-       pool = zcache_get_pool_by_id(cli_id, pool_id);
-       if (likely(pool != NULL)) {
-               if (atomic_read(&pool->obj_count) > 0)
-                       ret = tmem_flush_page(pool, oidp, index);
-               zcache_put_pool(pool);
-       }
-       if (ret >= 0)
-               zcache_flush_found++;
-       local_irq_restore(flags);
-       return ret;
-}
-
-static int zcache_flush_object(int cli_id, int pool_id,
-                               struct tmem_oid *oidp)
-{
-       struct tmem_pool *pool;
-       int ret = -1;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       zcache_flobj_total++;
-       pool = zcache_get_pool_by_id(cli_id, pool_id);
-       if (likely(pool != NULL)) {
-               if (atomic_read(&pool->obj_count) > 0)
-                       ret = tmem_flush_object(pool, oidp);
-               zcache_put_pool(pool);
-       }
-       if (ret >= 0)
-               zcache_flobj_found++;
-       local_irq_restore(flags);
-       return ret;
-}
-
-static int zcache_destroy_pool(int cli_id, int pool_id)
-{
-       struct tmem_pool *pool = NULL;
-       struct zcache_client *cli = NULL;
-       int ret = -1;
-
-       if (pool_id < 0)
-               goto out;
-       if (cli_id == LOCAL_CLIENT)
-               cli = &zcache_host;
-       else if ((unsigned int)cli_id < MAX_CLIENTS)
-               cli = &zcache_clients[cli_id];
-       if (cli == NULL)
-               goto out;
-       atomic_inc(&cli->refcount);
-       pool = cli->tmem_pools[pool_id];
-       if (pool == NULL)
-               goto out;
-       cli->tmem_pools[pool_id] = NULL;
-       /* wait for pool activity on other cpus to quiesce */
-       while (atomic_read(&pool->refcount) != 0)
-               ;
-       atomic_dec(&cli->refcount);
-       local_bh_disable();
-       ret = tmem_destroy_pool(pool);
-       local_bh_enable();
-       kfree(pool);
-       pr_info("zcache: destroyed pool id=%d, cli_id=%d\n",
-                       pool_id, cli_id);
-out:
-       return ret;
-}
-
-static int zcache_new_pool(uint16_t cli_id, uint32_t flags)
-{
-       int poolid = -1;
-       struct tmem_pool *pool;
-       struct zcache_client *cli = NULL;
-
-       if (cli_id == LOCAL_CLIENT)
-               cli = &zcache_host;
-       else if ((unsigned int)cli_id < MAX_CLIENTS)
-               cli = &zcache_clients[cli_id];
-       if (cli == NULL)
-               goto out;
-       atomic_inc(&cli->refcount);
-       pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL);
-       if (pool == NULL) {
-               pr_info("zcache: pool creation failed: out of memory\n");
-               goto out;
-       }
-
-       for (poolid = 0; poolid < MAX_POOLS_PER_CLIENT; poolid++)
-               if (cli->tmem_pools[poolid] == NULL)
-                       break;
-       if (poolid >= MAX_POOLS_PER_CLIENT) {
-               pr_info("zcache: pool creation failed: max exceeded\n");
-               kfree(pool);
-               poolid = -1;
-               goto out;
-       }
-       atomic_set(&pool->refcount, 0);
-       pool->client = cli;
-       pool->pool_id = poolid;
-       tmem_new_pool(pool, flags);
-       cli->tmem_pools[poolid] = pool;
-       pr_info("zcache: created %s tmem pool, id=%d, client=%d\n",
-               flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
-               poolid, cli_id);
-out:
-       if (cli != NULL)
-               atomic_dec(&cli->refcount);
-       return poolid;
-}
-
-/**********
- * Two kernel functionalities currently can be layered on top of tmem.
- * These are "cleancache" which is used as a second-chance cache for clean
- * page cache pages; and "frontswap" which is used for swap pages
- * to avoid writes to disk.  A generic "shim" is provided here for each
- * to translate in-kernel semantics to zcache semantics.
- */
-
-#ifdef CONFIG_CLEANCACHE
-static void zcache_cleancache_put_page(int pool_id,
-                                       struct cleancache_filekey key,
-                                       pgoff_t index, struct page *page)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       if (likely(ind == index))
-               (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, page);
-}
-
-static int zcache_cleancache_get_page(int pool_id,
-                                       struct cleancache_filekey key,
-                                       pgoff_t index, struct page *page)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-       int ret = -1;
-
-       if (likely(ind == index))
-               ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, page);
-       return ret;
-}
-
-static void zcache_cleancache_flush_page(int pool_id,
-                                       struct cleancache_filekey key,
-                                       pgoff_t index)
-{
-       u32 ind = (u32) index;
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       if (likely(ind == index))
-               (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind);
-}
-
-static void zcache_cleancache_flush_inode(int pool_id,
-                                       struct cleancache_filekey key)
-{
-       struct tmem_oid oid = *(struct tmem_oid *)&key;
-
-       (void)zcache_flush_object(LOCAL_CLIENT, pool_id, &oid);
-}
-
-static void zcache_cleancache_flush_fs(int pool_id)
-{
-       if (pool_id >= 0)
-               (void)zcache_destroy_pool(LOCAL_CLIENT, pool_id);
-}
-
-static int zcache_cleancache_init_fs(size_t pagesize)
-{
-       BUG_ON(sizeof(struct cleancache_filekey) !=
-                               sizeof(struct tmem_oid));
-       BUG_ON(pagesize != PAGE_SIZE);
-       return zcache_new_pool(LOCAL_CLIENT, 0);
-}
-
-static int zcache_cleancache_init_shared_fs(char *uuid, size_t pagesize)
-{
-       /* shared pools are unsupported and map to private */
-       BUG_ON(sizeof(struct cleancache_filekey) !=
-                               sizeof(struct tmem_oid));
-       BUG_ON(pagesize != PAGE_SIZE);
-       return zcache_new_pool(LOCAL_CLIENT, 0);
-}
-
-static struct cleancache_ops zcache_cleancache_ops = {
-       .put_page = zcache_cleancache_put_page,
-       .get_page = zcache_cleancache_get_page,
-       .flush_page = zcache_cleancache_flush_page,
-       .flush_inode = zcache_cleancache_flush_inode,
-       .flush_fs = zcache_cleancache_flush_fs,
-       .init_shared_fs = zcache_cleancache_init_shared_fs,
-       .init_fs = zcache_cleancache_init_fs
-};
-
-struct cleancache_ops zcache_cleancache_register_ops(void)
-{
-       struct cleancache_ops old_ops =
-               cleancache_register_ops(&zcache_cleancache_ops);
-
-       return old_ops;
-}
-#endif
-
-#ifdef CONFIG_FRONTSWAP
-/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int zcache_frontswap_poolid = -1;
-
-/*
- * Swizzling increases objects per swaptype, increasing tmem concurrency
- * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
- */
-#define SWIZ_BITS              4
-#define SWIZ_MASK              ((1 << SWIZ_BITS) - 1)
-#define _oswiz(_type, _ind)    ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
-#define iswiz(_ind)            (_ind >> SWIZ_BITS)
-
-static inline struct tmem_oid oswiz(unsigned type, u32 ind)
-{
-       struct tmem_oid oid = { .oid = { 0 } };
-       oid.oid[0] = _oswiz(type, ind);
-       return oid;
-}
-
-static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
-                                  struct page *page)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       struct tmem_oid oid = oswiz(type, ind);
-       int ret = -1;
-       unsigned long flags;
-
-       BUG_ON(!PageLocked(page));
-       if (likely(ind64 == ind)) {
-               local_irq_save(flags);
-               ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid,
-                                       &oid, iswiz(ind), page);
-               local_irq_restore(flags);
-       }
-       return ret;
-}
-
-/* returns 0 if the page was successfully gotten from frontswap, -1 if
- * was not present (should never happen!) */
-static int zcache_frontswap_get_page(unsigned type, pgoff_t offset,
-                                  struct page *page)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       struct tmem_oid oid = oswiz(type, ind);
-       int ret = -1;
-
-       BUG_ON(!PageLocked(page));
-       if (likely(ind64 == ind))
-               ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid,
-                                       &oid, iswiz(ind), page);
-       return ret;
-}
-
-/* flush a single page from frontswap */
-static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset)
-{
-       u64 ind64 = (u64)offset;
-       u32 ind = (u32)offset;
-       struct tmem_oid oid = oswiz(type, ind);
-
-       if (likely(ind64 == ind))
-               (void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid,
-                                       &oid, iswiz(ind));
-}
-
-/* flush all pages from the passed swaptype */
-static void zcache_frontswap_flush_area(unsigned type)
-{
-       struct tmem_oid oid;
-       int ind;
-
-       for (ind = SWIZ_MASK; ind >= 0; ind--) {
-               oid = oswiz(type, ind);
-               (void)zcache_flush_object(LOCAL_CLIENT,
-                                               zcache_frontswap_poolid, &oid);
-       }
-}
-
-static void zcache_frontswap_init(unsigned ignored)
-{
-       /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-       if (zcache_frontswap_poolid < 0)
-               zcache_frontswap_poolid =
-                       zcache_new_pool(LOCAL_CLIENT, TMEM_POOL_PERSIST);
-}
-
-static struct frontswap_ops zcache_frontswap_ops = {
-       .put_page = zcache_frontswap_put_page,
-       .get_page = zcache_frontswap_get_page,
-       .flush_page = zcache_frontswap_flush_page,
-       .flush_area = zcache_frontswap_flush_area,
-       .init = zcache_frontswap_init
-};
-
-struct frontswap_ops zcache_frontswap_register_ops(void)
-{
-       struct frontswap_ops old_ops =
-               frontswap_register_ops(&zcache_frontswap_ops);
-
-       return old_ops;
-}
-#endif
-
-/*
- * zcache initialization
- * NOTE FOR NOW zcache MUST BE PROVIDED AS A KERNEL BOOT PARAMETER OR
- * NOTHING HAPPENS!
- */
-
-static int zcache_enabled;
-
-static int __init enable_zcache(char *s)
-{
-       zcache_enabled = 1;
-       return 1;
-}
-__setup("zcache", enable_zcache);
-
-/* allow independent dynamic disabling of cleancache and frontswap */
-
-static int use_cleancache = 1;
-
-static int __init no_cleancache(char *s)
-{
-       use_cleancache = 0;
-       return 1;
-}
-
-__setup("nocleancache", no_cleancache);
-
-static int use_frontswap = 1;
-
-static int __init no_frontswap(char *s)
-{
-       use_frontswap = 0;
-       return 1;
-}
-
-__setup("nofrontswap", no_frontswap);
-
-static int __init zcache_init(void)
-{
-#ifdef CONFIG_SYSFS
-       int ret = 0;
-
-       ret = sysfs_create_group(mm_kobj, &zcache_attr_group);
-       if (ret) {
-               pr_err("zcache: can't create sysfs\n");
-               goto out;
-       }
-#endif /* CONFIG_SYSFS */
-#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP)
-       if (zcache_enabled) {
-               unsigned int cpu;
-
-               tmem_register_hostops(&zcache_hostops);
-               tmem_register_pamops(&zcache_pamops);
-               ret = register_cpu_notifier(&zcache_cpu_notifier_block);
-               if (ret) {
-                       pr_err("zcache: can't register cpu notifier\n");
-                       goto out;
-               }
-               for_each_online_cpu(cpu) {
-                       void *pcpu = (void *)(long)cpu;
-                       zcache_cpu_notifier(&zcache_cpu_notifier_block,
-                               CPU_UP_PREPARE, pcpu);
-               }
-       }
-       zcache_objnode_cache = kmem_cache_create("zcache_objnode",
-                               sizeof(struct tmem_objnode), 0, 0, NULL);
-       zcache_obj_cache = kmem_cache_create("zcache_obj",
-                               sizeof(struct tmem_obj), 0, 0, NULL);
-       ret = zcache_new_client(LOCAL_CLIENT);
-       if (ret) {
-               pr_err("zcache: can't create client\n");
-               goto out;
-       }
-#endif
-#ifdef CONFIG_CLEANCACHE
-       if (zcache_enabled && use_cleancache) {
-               struct cleancache_ops old_ops;
-
-               zbud_init();
-               register_shrinker(&zcache_shrinker);
-               old_ops = zcache_cleancache_register_ops();
-               pr_info("zcache: cleancache enabled using kernel "
-                       "transcendent memory and compression buddies\n");
-               if (old_ops.init_fs != NULL)
-                       pr_warning("zcache: cleancache_ops overridden");
-       }
-#endif
-#ifdef CONFIG_FRONTSWAP
-       if (zcache_enabled && use_frontswap) {
-               struct frontswap_ops old_ops;
-
-               old_ops = zcache_frontswap_register_ops();
-               pr_info("zcache: frontswap enabled using kernel "
-                       "transcendent memory and xvmalloc\n");
-               if (old_ops.init != NULL)
-                       pr_warning("ktmem: frontswap_ops overridden");
-       }
-#endif
-out:
-       return ret;
-}
-
-module_init(zcache_init)
index 385acb8..3f94ac3 100644 (file)
@@ -268,7 +268,7 @@ usbtmc_abort_bulk_in_status:
                                dev_err(dev, "usb_bulk_msg returned %d\n", rv);
                                goto exit;
                        }
-               } while ((actual = max_size) &&
+               } while ((actual == max_size) &&
                         (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
 
        if (actual == max_size) {
index c962608..26678ca 100644 (file)
@@ -123,10 +123,11 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
        }
 
        if (usb_endpoint_xfer_isoc(&ep->desc))
-               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
-                       (desc->bmAttributes + 1);
+               max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
+                       le16_to_cpu(ep->desc.wMaxPacketSize);
        else if (usb_endpoint_xfer_int(&ep->desc))
-               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
+               max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+                       (desc->bMaxBurst + 1);
        else
                max_tx = 999999;
        if (le16_to_cpu(desc->wBytesPerInterval) > max_tx) {
@@ -134,10 +135,10 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
                                "config %d interface %d altsetting %d ep %d: "
                                "setting to %d\n",
                                usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
-                               desc->wBytesPerInterval,
+                               le16_to_cpu(desc->wBytesPerInterval),
                                cfgno, inum, asnum, ep->desc.bEndpointAddress,
                                max_tx);
-               ep->ss_ep_comp.wBytesPerInterval = max_tx;
+               ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx);
        }
 }
 
index 44b6b40..5a084b9 100644 (file)
@@ -310,7 +310,7 @@ config USB_PXA_U2O
 # musb builds in ../musb along with host support
 config USB_GADGET_MUSB_HDRC
        tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
-       depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
+       depends on USB_MUSB_HDRC
        select USB_GADGET_DUALSPEED
        help
          This OTG-capable silicon IP is used in dual designs including
index 98cbc06..ddb118a 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
+#include <linux/prefetch.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
index 5ef8779..aef4741 100644 (file)
@@ -1079,10 +1079,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        cdev->desc.bMaxPacketSize0 =
                                cdev->gadget->ep0->maxpacket;
                        if (gadget_is_superspeed(gadget)) {
-                               if (gadget->speed >= USB_SPEED_SUPER)
+                               if (gadget->speed >= USB_SPEED_SUPER) {
                                        cdev->desc.bcdUSB = cpu_to_le16(0x0300);
-                               else
+                                       cdev->desc.bMaxPacketSize0 = 9;
+                               } else {
                                        cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+                               }
                        }
 
                        value = min(w_length, (u16) sizeof cdev->desc);
index 403a48b..83a266b 100644 (file)
@@ -367,6 +367,13 @@ static int hidg_setup(struct usb_function *f,
        case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8
                  | USB_REQ_GET_DESCRIPTOR):
                switch (value >> 8) {
+               case HID_DT_HID:
+                       VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
+                       length = min_t(unsigned short, length,
+                                                  hidg_desc.bLength);
+                       memcpy(req->buf, &hidg_desc, length);
+                       goto respond;
+                       break;
                case HID_DT_REPORT:
                        VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");
                        length = min_t(unsigned short, length,
index 24a9243..4ec888f 100644 (file)
@@ -609,107 +609,6 @@ void fusb300_rdcxf(struct fusb300 *fusb300,
        }
 }
 
-#if 0
-static void fusb300_dbg_fifo(struct fusb300_ep *ep,
-                               u8 entry, u16 length)
-{
-       u32 reg;
-       u32 i = 0;
-       u32 j = 0;
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM);
-       reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) |
-               FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG);
-       reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) |
-               FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG);
-       iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM);
-
-       for (i = 0; i < (length >> 2); i++) {
-               if (i * 4 == 1024)
-                       break;
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i * 4);
-               printk(KERN_DEBUG"  0x%-8x", reg);
-               j++;
-               if ((j % 4)  == 0)
-                       printk(KERN_DEBUG "\n");
-       }
-
-       if (length % 4) {
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i * 4);
-               printk(KERN_DEBUG "  0x%x\n", reg);
-       }
-
-       if ((j % 4)  != 0)
-               printk(KERN_DEBUG "\n");
-
-       fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM,
-               FUSB300_GTM_TST_FIFO_DEG);
-}
-
-static void fusb300_cmp_dbg_fifo(struct fusb300_ep *ep,
-                               u8 entry, u16 length, u8 *golden)
-{
-       u32 reg;
-       u32 i = 0;
-       u32 golden_value;
-       u8 *tmp;
-
-       tmp = golden;
-
-       printk(KERN_DEBUG "fusb300_cmp_dbg_fifo (entry %d) : start\n", entry);
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_GTM);
-       reg &= ~(FUSB300_GTM_TST_EP_ENTRY(0xF) |
-               FUSB300_GTM_TST_EP_NUM(0xF) | FUSB300_GTM_TST_FIFO_DEG);
-       reg |= (FUSB300_GTM_TST_EP_ENTRY(entry) |
-               FUSB300_GTM_TST_EP_NUM(ep->epnum) | FUSB300_GTM_TST_FIFO_DEG);
-       iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_GTM);
-
-       for (i = 0; i < (length >> 2); i++) {
-               if (i * 4 == 1024)
-                       break;
-               golden_value = *tmp | *(tmp + 1) << 8 |
-                               *(tmp + 2) << 16 | *(tmp + 3) << 24;
-
-               reg = ioread32(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i*4);
-
-               if (reg != golden_value) {
-                       printk(KERN_DEBUG "0x%x  :  ", (u32)(ep->fusb300->reg +
-                               FUSB300_OFFSET_BUFDBG_START + i*4));
-                       printk(KERN_DEBUG "    golden = 0x%x, reg = 0x%x\n",
-                               golden_value, reg);
-               }
-               tmp += 4;
-       }
-
-       switch (length % 4) {
-       case 1:
-               golden_value = *tmp;
-       case 2:
-               golden_value = *tmp | *(tmp + 1) << 8;
-       case 3:
-               golden_value = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
-       default:
-               break;
-
-       reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_BUFDBG_START + i*4);
-       if (reg != golden_value) {
-               printk(KERN_DEBUG "0x%x:", (u32)(ep->fusb300->reg +
-                       FUSB300_OFFSET_BUFDBG_START + i*4));
-               printk(KERN_DEBUG "  golden = 0x%x, reg = 0x%x\n",
-                       golden_value, reg);
-       }
-       }
-
-       printk(KERN_DEBUG "fusb300_cmp_dbg_fifo : end\n");
-       fusb300_disable_bit(ep->fusb300, FUSB300_OFFSET_GTM,
-               FUSB300_GTM_TST_FIFO_DEG);
-}
-#endif
-
 static void fusb300_rdfifo(struct fusb300_ep *ep,
                          struct fusb300_request *req,
                          u32 length)
index 7c7b0e1..ab98ea9 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
-#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/prefetch.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
index 85c1b0d..8d31848 100644 (file)
@@ -2060,6 +2060,7 @@ static int s3c2410_udc_resume(struct platform_device *pdev)
 static const struct platform_device_id s3c_udc_ids[] = {
        { "s3c2410-usbgadget", },
        { "s3c2440-usbgadget", },
+       { }
 };
 MODULE_DEVICE_TABLE(platform, s3c_udc_ids);
 
index bf2c8f6..e051b30 100644 (file)
@@ -1046,7 +1046,19 @@ static int ehci_hub_control (
                        if (!selector || selector > 5)
                                goto error;
                        ehci_quiesce(ehci);
+
+                       /* Put all enabled ports into suspend */
+                       while (ports--) {
+                               u32 __iomem *sreg =
+                                               &ehci->regs->port_status[ports];
+
+                               temp = ehci_readl(ehci, sreg) & ~PORT_RWC_BITS;
+                               if (temp & PORT_PE)
+                                       ehci_writel(ehci, temp | PORT_SUSPEND,
+                                                       sreg);
+                       }
                        ehci_halt(ehci);
+                       temp = ehci_readl(ehci, status_reg);
                        temp |= selector << 16;
                        ehci_writel(ehci, temp, status_reg);
                        break;
index 0c058be..555a73c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/usb/ulpi.h>
 #include <linux/slab.h>
 
+#include <mach/hardware.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/mach-types.h>
index 55a57c2..4524032 100644 (file)
@@ -98,6 +98,18 @@ static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port)
        }
 }
 
+static void disable_put_regulator(
+               struct ehci_hcd_omap_platform_data *pdata)
+{
+       int i;
+
+       for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+               if (pdata->regulator[i]) {
+                       regulator_disable(pdata->regulator[i]);
+                       regulator_put(pdata->regulator[i]);
+               }
+       }
+}
 
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
@@ -231,9 +243,11 @@ err_add_hcd:
        omap_usbhs_disable(dev);
 
 err_enable:
+       disable_put_regulator(pdata);
        usb_put_hcd(hcd);
 
 err_io:
+       iounmap(regs);
        return ret;
 }
 
@@ -253,6 +267,8 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
 
        usb_remove_hcd(hcd);
        omap_usbhs_disable(dev);
+       disable_put_regulator(dev->platform_data);
+       iounmap(hcd->regs);
        usb_put_hcd(hcd);
        return 0;
 }
index 55d3d58..840beda 100644 (file)
@@ -1583,6 +1583,9 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
        int retval = 0;
 
        spin_lock_irqsave(&priv->lock, spinflags);
+       retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (retval)
+               goto out;
 
        qh = urb->ep->hcpriv;
        if (!qh) {
index a9d3159..629a968 100644 (file)
@@ -535,7 +535,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
        iounmap(base);
 }
 
-static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = {
+static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = {
        {
                /*  Pegatron Lucid (ExoPC) */
                .matches = {
@@ -817,7 +817,7 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
 
        /* If the BIOS owns the HC, signal that the OS wants it, and wait */
        if (val & XHCI_HC_BIOS_OWNED) {
-               writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
+               writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
 
                /* Wait for 5 seconds with 10 microsecond polling interval */
                timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
index 763f484..1c4432d 100644 (file)
@@ -345,7 +345,8 @@ static void xhci_event_ring_work(unsigned long arg)
        spin_lock_irqsave(&xhci->lock, flags);
        temp = xhci_readl(xhci, &xhci->op_regs->status);
        xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
-       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+       if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_dbg(xhci, "HW died, polling stopped.\n");
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
@@ -939,8 +940,11 @@ static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
                return 0;
        }
 
+       xhci = hcd_to_xhci(hcd);
+       if (xhci->xhc_state & XHCI_STATE_HALTED)
+               return -ENODEV;
+
        if (check_virt_dev) {
-               xhci = hcd_to_xhci(hcd);
                if (!udev->slot_id || !xhci->devs
                        || !xhci->devs[udev->slot_id]) {
                        printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1242,7 +1246,8 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_urb_free_priv(xhci, urb_priv);
                return ret;
        }
-       if (xhci->xhc_state & XHCI_STATE_DYING) {
+       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
                                "non-responsive xHCI host.\n",
                                urb->ep->desc.bEndpointAddress, urb);
@@ -2665,7 +2670,10 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        int i, ret;
 
        ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
-       if (ret <= 0)
+       /* If the host is halted due to driver unload, we still need to free the
+        * device.
+        */
+       if (ret <= 0 && ret != -ENODEV)
                return;
 
        virt_dev = xhci->devs[udev->slot_id];
@@ -2679,7 +2687,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        spin_lock_irqsave(&xhci->lock, flags);
        /* Don't disable the slot if the host controller is dead. */
        state = xhci_readl(xhci, &xhci->op_regs->status);
-       if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING)) {
+       if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
+                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
                xhci_free_virt_device(xhci, udev->slot_id);
                spin_unlock_irqrestore(&xhci->lock, flags);
                return;
index 6192b45..fc34b8b 100644 (file)
@@ -3,9 +3,6 @@
 # for silicon based on Mentor Graphics INVENTRA designs
 #
 
-comment "Enable Host or Gadget support to see Inventra options"
-       depends on !USB && USB_GADGET=n
-
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
        depends on USB && USB_GADGET
index b67a062..8c41a2e 100644 (file)
@@ -1698,6 +1698,8 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
 
        is_on = !!is_on;
 
+       pm_runtime_get_sync(musb->controller);
+
        /* NOTE: this assumes we are sensing vbus; we'd rather
         * not pullup unless the B-session is active.
         */
@@ -1707,6 +1709,9 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
                musb_pullup(musb, is_on);
        }
        spin_unlock_irqrestore(&musb->lock, flags);
+
+       pm_runtime_put(musb->controller);
+
        return 0;
 }
 
index c784e6c..07c8a73 100644 (file)
@@ -89,7 +89,7 @@ static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat)
        u32             reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
 
        if (reg != 0) {
-               dev_dbg(musb->controller, "ep%i dmareq0 is busy for ep%i\n",
+               dev_dbg(chdat->musb->controller, "ep%i dmareq0 is busy for ep%i\n",
                        chdat->epnum, reg & 0xf);
                return -EAGAIN;
        }
index ba79dbf..cb2d451 100644 (file)
@@ -14,6 +14,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -76,7 +77,7 @@ struct usbhsg_recip_handle {
                struct usbhsg_gpriv, mod)
 
 #define __usbhsg_for_each_uep(start, pos, g, i)        \
-       for (i = start, pos = (g)->uep;         \
+       for (i = start, pos = (g)->uep + i;     \
             i < (g)->uep_size;                 \
             i++, pos = (g)->uep + i)
 
index 2e06b90..78a2cf9 100644 (file)
@@ -151,6 +151,7 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
  * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
  */
 static struct usb_device_id id_table_combined [] = {
+       { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
@@ -1171,7 +1172,7 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
        case FT2232H: /* FT2232H chip */
        case FT4232H: /* FT4232H chip */
        case FT232H:  /* FT232H chip */
-               if ((baud <= 12000000) & (baud >= 1200)) {
+               if ((baud <= 12000000) && (baud >= 1200)) {
                        div_value = ftdi_2232h_baud_to_divisor(baud);
                } else if (baud < 1200) {
                        div_value = ftdi_232bm_baud_to_divisor(baud);
@@ -1205,7 +1206,10 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
        urb_index_value = get_ftdi_divisor(tty, port);
        urb_value = (__u16)urb_index_value;
        urb_index = (__u16)(urb_index_value >> 16);
-       if (priv->interface) {  /* FT2232C */
+       if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) ||
+               (priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) {
+               /* Probably the BM type needs the MSB of the encoded fractional
+                * divider also moved like for the chips above. Any infos? */
                urb_index = (__u16)((urb_index << 8) | priv->interface);
        }
 
index 19156d1..bf5227a 100644 (file)
 /* USB-Nano-485*/
 #define FTDI_CTI_NANO_PID      0xF60B
 
-
+/*
+ * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de
+ */
+/* TagTracer MIFARE*/
+#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID   0xF7C0
index 60b25d8..8156561 100644 (file)
@@ -148,6 +148,10 @@ static void option_instat_callback(struct urb *urb);
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
 #define HUAWEI_PRODUCT_E14AC                   0x14AC
+#define HUAWEI_PRODUCT_K3770                   0x14C9
+#define HUAWEI_PRODUCT_K3771                   0x14CA
+#define HUAWEI_PRODUCT_K4510                   0x14CB
+#define HUAWEI_PRODUCT_K4511                   0x14CC
 #define HUAWEI_PRODUCT_ETS1220                 0x1803
 #define HUAWEI_PRODUCT_E353                    0x1506
 
@@ -547,6 +551,14 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
index 54a9dab..aeccc7f 100644 (file)
@@ -45,6 +45,7 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x05c6, 0x9203)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9222)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9008)},   /* Generic Gobi QDL device */
+       {USB_DEVICE(0x05c6, 0x9009)},   /* Generic Gobi Modem device */
        {USB_DEVICE(0x05c6, 0x9201)},   /* Generic Gobi QDL device */
        {USB_DEVICE(0x05c6, 0x9221)},   /* Generic Gobi QDL device */
        {USB_DEVICE(0x05c6, 0x9231)},   /* Generic Gobi QDL device */
@@ -78,6 +79,7 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x1199, 0x9008)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {USB_DEVICE(0x1199, 0x9009)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {USB_DEVICE(0x1199, 0x900a)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
+       {USB_DEVICE(0x1199, 0x9011)},   /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
        {USB_DEVICE(0x16d8, 0x8001)},   /* CMDTech Gobi 2000 QDL device (VU922) */
        {USB_DEVICE(0x16d8, 0x8002)},   /* CMDTech Gobi 2000 Modem device (VU922) */
        {USB_DEVICE(0x05c6, 0x9204)},   /* Gobi 2000 QDL device */
index ccff348..3041a97 100644 (file)
@@ -1988,6 +1988,16 @@ UNUSUAL_DEV(  0x4146, 0xba01, 0x0100, 0x0100,
                "Micro Mini 1GB",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
 
+/*
+ * Nick Bowler <nbowler@elliptictech.com>
+ * SCSI stack spams (otherwise harmless) error messages.
+ */
+UNUSUAL_DEV(  0xc251, 0x4003, 0x0100, 0x0100,
+               "Keil Software, Inc.",
+               "V2M MotherBoard",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NOT_LOCKABLE),
+
 /* Reported by Andrew Simmons <andrew.simmons@gmail.com> */
 UNUSUAL_DEV(  0xed06, 0x4500, 0x0001, 0x0001,
                "DataStor",
index 1b4afd8..6ea852e 100644 (file)
@@ -70,6 +70,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/module.h>
 #include <linux/workqueue.h>
 #include <xen/balloon.h>
 #include <xen/tmem.h>
index 475f9c5..326dc08 100644 (file)
 
 /* #define DEBUG */
 
-#ifdef DEBUG
-#define DPRINTK(fmt, args...)                          \
-do {                                                   \
-       printk(KERN_DEBUG "pid %d: %s: " fmt "\n",      \
-               current->pid, __func__, ##args);        \
-} while (0)
-#else
-#define DPRINTK(fmt, args...) do {} while (0)
-#endif
-
-#define AUTOFS_WARN(fmt, args...)                      \
-do {                                                   \
+#define DPRINTK(fmt, ...)                              \
+       pr_debug("pid %d: %s: " fmt "\n",               \
+               current->pid, __func__, ##__VA_ARGS__)
+
+#define AUTOFS_WARN(fmt, ...)                          \
        printk(KERN_WARNING "pid %d: %s: " fmt "\n",    \
-               current->pid, __func__, ##args);        \
-} while (0)
+               current->pid, __func__, ##__VA_ARGS__)
 
-#define AUTOFS_ERROR(fmt, args...)                     \
-do {                                                   \
+#define AUTOFS_ERROR(fmt, ...)                         \
        printk(KERN_ERR "pid %d: %s: " fmt "\n",        \
-               current->pid, __func__, ##args);        \
-} while (0)
+               current->pid, __func__, ##__VA_ARGS__)
 
 /* Unified info structure.  This is pointed to by both the dentry and
    inode structures.  Each file in the filesystem has an instance of this
index 2543598..e1fbdee 100644 (file)
@@ -104,7 +104,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        size_t pktsz;
 
        DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
-               wq->wait_queue_token, wq->name.len, wq->name.name, type);
+               (unsigned long) wq->wait_queue_token, wq->name.len, wq->name.name, type);
 
        memset(&pkt,0,sizeof pkt); /* For security reasons */
 
index 54b8c28..720d885 100644 (file)
@@ -474,17 +474,22 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
                befs_data_stream *data = &befs_ino->i_data.ds;
                befs_off_t len = data->size;
 
-               befs_debug(sb, "Follow long symlink");
-
-               link = kmalloc(len, GFP_NOFS);
-               if (!link) {
-                       link = ERR_PTR(-ENOMEM);
-               } else if (befs_read_lsymlink(sb, data, link, len) != len) {
-                       kfree(link);
-                       befs_error(sb, "Failed to read entire long symlink");
+               if (len == 0) {
+                       befs_error(sb, "Long symlink with illegal length");
                        link = ERR_PTR(-EIO);
                } else {
-                       link[len - 1] = '\0';
+                       befs_debug(sb, "Follow long symlink");
+
+                       link = kmalloc(len, GFP_NOFS);
+                       if (!link) {
+                               link = ERR_PTR(-ENOMEM);
+                       } else if (befs_read_lsymlink(sb, data, link, len) != len) {
+                               kfree(link);
+                               befs_error(sb, "Failed to read entire long symlink");
+                               link = ERR_PTR(-EIO);
+                       } else {
+                               link[len - 1] = '\0';
+                       }
                }
        } else {
                link = befs_ino->i_data.symlink;
index 2fe3cf1..6d40656 100644 (file)
@@ -176,7 +176,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
 
 #ifdef CONFIG_CIFS_STATS2
                        seq_printf(m, " In Send: %d In MaxReq Wait: %d",
-                               atomic_read(&server->inSend),
+                               atomic_read(&server->in_send),
                                atomic_read(&server->num_waiters));
 #endif
 
index 21de1d6..d0f59fa 100644 (file)
@@ -991,24 +991,6 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        return pntsd;
 }
 
-static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
-               struct cifs_ntsd *pnntsd, u32 acllen)
-{
-       int xid, rc;
-       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
-
-       if (IS_ERR(tlink))
-               return PTR_ERR(tlink);
-
-       xid = GetXid();
-       rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
-       FreeXid(xid);
-       cifs_put_tlink(tlink);
-
-       cFYI(DBG2, "SetCIFSACL rc = %d", rc);
-       return rc;
-}
-
 static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
                struct cifs_ntsd *pnntsd, u32 acllen)
 {
@@ -1047,18 +1029,10 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
                                struct inode *inode, const char *path)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct cifsFileInfo *open_file;
-       int rc;
 
        cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
 
-       open_file = find_readable_file(CIFS_I(inode), true);
-       if (!open_file)
-               return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
-
-       rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
-       cifsFileInfo_put(open_file);
-       return rc;
+       return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
index 38ce6d4..95dad9d 100644 (file)
@@ -291,7 +291,7 @@ struct TCP_Server_Info {
        struct fscache_cookie   *fscache; /* client index cache cookie */
 #endif
 #ifdef CONFIG_CIFS_STATS2
-       atomic_t inSend; /* requests trying to send */
+       atomic_t in_send; /* requests trying to send */
        atomic_t num_waiters;   /* blocked waiting to get in sendrecv */
 #endif
 };
@@ -672,12 +672,54 @@ struct mid_q_entry {
        bool multiEnd:1;        /* both received */
 };
 
-struct oplock_q_entry {
-       struct list_head qhead;
-       struct inode *pinode;
-       struct cifs_tcon *tcon;
-       __u16 netfid;
-};
+/*     Make code in transport.c a little cleaner by moving
+       update of optional stats into function below */
+#ifdef CONFIG_CIFS_STATS2
+
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->in_send);
+}
+
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->in_send);
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+       atomic_inc(&server->num_waiters);
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+       atomic_dec(&server->num_waiters);
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+       mid->when_sent = jiffies;
+}
+#else
+static inline void cifs_in_send_inc(struct TCP_Server_Info *server)
+{
+}
+static inline void cifs_in_send_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_inc(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_num_waiters_dec(struct TCP_Server_Info *server)
+{
+}
+
+static inline void cifs_save_when_sent(struct mid_q_entry *mid)
+{
+}
+#endif
 
 /* for pending dnotify requests */
 struct dir_notify_req {
index c1b9c4b..10ca6b2 100644 (file)
@@ -266,15 +266,11 @@ static int wait_for_free_request(struct TCP_Server_Info *server,
        while (1) {
                if (atomic_read(&server->inFlight) >= cifs_max_pending) {
                        spin_unlock(&GlobalMid_Lock);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_inc(&server->num_waiters);
-#endif
+                       cifs_num_waiters_inc(server);
                        wait_event(server->request_q,
                                   atomic_read(&server->inFlight)
                                     < cifs_max_pending);
-#ifdef CONFIG_CIFS_STATS2
-                       atomic_dec(&server->num_waiters);
-#endif
+                       cifs_num_waiters_dec(server);
                        spin_lock(&GlobalMid_Lock);
                } else {
                        if (server->tcpStatus == CifsExiting) {
@@ -381,15 +377,13 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid->callback = callback;
        mid->callback_data = cbdata;
        mid->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&server->inSend);
-#endif
+
+       cifs_in_send_inc(server);
        rc = smb_sendv(server, iov, nvec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&server->inSend);
-       mid->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(server);
+       cifs_save_when_sent(mid);
        mutex_unlock(&server->srv_mutex);
+
        if (rc)
                goto out_err;
 
@@ -575,14 +569,10 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_sendv(ses->server, iov, n_vec);
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
 
        mutex_unlock(&ses->server->srv_mutex);
 
@@ -703,14 +693,11 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0)
@@ -843,14 +830,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-#ifdef CONFIG_CIFS_STATS2
-       atomic_inc(&ses->server->inSend);
-#endif
+       cifs_in_send_inc(ses->server);
        rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
-#ifdef CONFIG_CIFS_STATS2
-       atomic_dec(&ses->server->inSend);
-       midQ->when_sent = jiffies;
-#endif
+       cifs_in_send_dec(ses->server);
+       cifs_save_when_sent(midQ);
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0) {
index 8be086e..51352de 100644 (file)
@@ -1003,6 +1003,7 @@ COMPATIBLE_IOCTL(PPPIOCCONNECT)
 COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
+COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
 /* PPPOX */
 COMPATIBLE_IOCTL(PPPOEIOCSFWD)
 COMPATIBLE_IOCTL(PPPOEIOCDFWD)
index 1cd6d9d..cc16562 100644 (file)
@@ -1,6 +1,6 @@
 config ECRYPT_FS
        tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && KEYS && CRYPTO
+       depends on EXPERIMENTAL && KEYS && CRYPTO && (ENCRYPTED_KEYS || ENCRYPTED_KEYS=n)
        select CRYPTO_ECB
        select CRYPTO_CBC
        select CRYPTO_MD5
index 08a2b52..ac1ad48 100644 (file)
@@ -1973,7 +1973,7 @@ pki_encrypt_session_key(struct key *auth_tok_key,
 {
        struct ecryptfs_msg_ctx *msg_ctx = NULL;
        char *payload = NULL;
-       size_t payload_len;
+       size_t payload_len = 0;
        struct ecryptfs_message *msg;
        int rc;
 
index 9f1bb74..b4a6bef 100644 (file)
@@ -175,6 +175,7 @@ enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,
        ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,
        ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,
        ecryptfs_opt_unlink_sigs, ecryptfs_opt_mount_auth_tok_only,
+       ecryptfs_opt_check_dev_ruid,
        ecryptfs_opt_err };
 
 static const match_table_t tokens = {
@@ -191,6 +192,7 @@ static const match_table_t tokens = {
        {ecryptfs_opt_fn_cipher_key_bytes, "ecryptfs_fn_key_bytes=%u"},
        {ecryptfs_opt_unlink_sigs, "ecryptfs_unlink_sigs"},
        {ecryptfs_opt_mount_auth_tok_only, "ecryptfs_mount_auth_tok_only"},
+       {ecryptfs_opt_check_dev_ruid, "ecryptfs_check_dev_ruid"},
        {ecryptfs_opt_err, NULL}
 };
 
@@ -236,6 +238,7 @@ static void ecryptfs_init_mount_crypt_stat(
  * ecryptfs_parse_options
  * @sb: The ecryptfs super block
  * @options: The options passed to the kernel
+ * @check_ruid: set to 1 if device uid should be checked against the ruid
  *
  * Parse mount options:
  * debug=N        - ecryptfs_verbosity level for debug output
@@ -251,7 +254,8 @@ static void ecryptfs_init_mount_crypt_stat(
  *
  * Returns zero on success; non-zero on error
  */
-static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
+static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
+                                 uid_t *check_ruid)
 {
        char *p;
        int rc = 0;
@@ -276,6 +280,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
        char *cipher_key_bytes_src;
        char *fn_cipher_key_bytes_src;
 
+       *check_ruid = 0;
+
        if (!options) {
                rc = -EINVAL;
                goto out;
@@ -380,6 +386,9 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options)
                        mount_crypt_stat->flags |=
                                ECRYPTFS_GLOBAL_MOUNT_AUTH_TOK_ONLY;
                        break;
+               case ecryptfs_opt_check_dev_ruid:
+                       *check_ruid = 1;
+                       break;
                case ecryptfs_opt_err:
                default:
                        printk(KERN_WARNING
@@ -475,6 +484,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
        const char *err = "Getting sb failed";
        struct inode *inode;
        struct path path;
+       uid_t check_ruid;
        int rc;
 
        sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
@@ -483,7 +493,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
                goto out;
        }
 
-       rc = ecryptfs_parse_options(sbi, raw_data);
+       rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);
        if (rc) {
                err = "Error parsing options";
                goto out;
@@ -521,6 +531,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
                        "known incompatibilities\n");
                goto out_free;
        }
+
+       if (check_ruid && path.dentry->d_inode->i_uid != current_uid()) {
+               rc = -EPERM;
+               printk(KERN_ERR "Mount of device (uid: %d) not owned by "
+                      "requested user (uid: %d)\n",
+                      path.dentry->d_inode->i_uid, current_uid());
+               goto out_free;
+       }
+
        ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
        s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
        s->s_blocksize = path.dentry->d_sb->s_blocksize;
index 85d4309..3745f7c 100644 (file)
 int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
                         loff_t offset, size_t size)
 {
-       struct ecryptfs_inode_info *inode_info;
+       struct file *lower_file;
        mm_segment_t fs_save;
        ssize_t rc;
 
-       inode_info = ecryptfs_inode_to_private(ecryptfs_inode);
-       BUG_ON(!inode_info->lower_file);
+       lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+       if (!lower_file)
+               return -EIO;
        fs_save = get_fs();
        set_fs(get_ds());
-       rc = vfs_write(inode_info->lower_file, data, size, &offset);
+       rc = vfs_write(lower_file, data, size, &offset);
        set_fs(fs_save);
        mark_inode_dirty_sync(ecryptfs_inode);
        return rc;
@@ -225,15 +226,16 @@ out:
 int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
                        struct inode *ecryptfs_inode)
 {
-       struct ecryptfs_inode_info *inode_info =
-               ecryptfs_inode_to_private(ecryptfs_inode);
+       struct file *lower_file;
        mm_segment_t fs_save;
        ssize_t rc;
 
-       BUG_ON(!inode_info->lower_file);
+       lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
+       if (!lower_file)
+               return -EIO;
        fs_save = get_fs();
        set_fs(get_ds());
-       rc = vfs_read(inode_info->lower_file, data, size, &offset);
+       rc = vfs_read(lower_file, data, size, &offset);
        set_fs(fs_save);
        return rc;
 }
index da80612..25dcbe5 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1459,6 +1459,23 @@ static int do_execve_common(const char *filename,
        struct files_struct *displaced;
        bool clear_in_exec;
        int retval;
+       const struct cred *cred = current_cred();
+
+       /*
+        * We move the actual failure in case of RLIMIT_NPROC excess from
+        * set*uid() to execve() because too many poorly written programs
+        * don't check setuid() return code.  Here we additionally recheck
+        * whether NPROC limit is still exceeded.
+        */
+       if ((current->flags & PF_NPROC_EXCEEDED) &&
+           atomic_read(&cred->user->processes) > rlimit(RLIMIT_NPROC)) {
+               retval = -EAGAIN;
+               goto out_ret;
+       }
+
+       /* We're below the limit (still or again), so we don't want to make
+        * further execve() calls fail. */
+       current->flags &= ~PF_NPROC_EXCEEDED;
 
        retval = unshare_files(&displaced);
        if (retval)
index 6e18a0b..5571708 100644 (file)
@@ -2209,9 +2209,11 @@ static int ext3_symlink (struct inode * dir,
                /*
                 * For non-fast symlinks, we just allocate inode and put it on
                 * orphan list in the first transaction => we need bitmap,
-                * group descriptor, sb, inode block, quota blocks.
+                * group descriptor, sb, inode block, quota blocks, and
+                * possibly selinux xattr blocks.
                 */
-               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         EXT3_XATTR_TRANS_BLOCKS;
        } else {
                /*
                 * Fast symlink. We have to add entry to directory
index 565a154..f8068c7 100644 (file)
@@ -2253,9 +2253,11 @@ static int ext4_symlink(struct inode *dir,
                /*
                 * For non-fast symlinks, we just allocate inode and put it on
                 * orphan list in the first transaction => we need bitmap,
-                * group descriptor, sb, inode block, quota blocks.
+                * group descriptor, sb, inode block, quota blocks, and
+                * possibly selinux xattr blocks.
                 */
-               credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+               credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
+                         EXT4_XATTR_TRANS_BLOCKS;
        } else {
                /*
                 * Fast symlink. We have to add entry to directory
index 4ad6473..5efbd5d 100644 (file)
@@ -1231,7 +1231,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
        struct super_block *sb = dir->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
        struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
-       struct msdos_dir_entry *de;
+       struct msdos_dir_entry *uninitialized_var(de);
        int err, free_slots, i, nr_bhs;
        loff_t pos, i_pos;
 
index 5942fec..1726d73 100644 (file)
@@ -1188,9 +1188,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 out:
        /* UTF-8 doesn't provide FAT semantics */
        if (!strcmp(opts->iocharset, "utf8")) {
-               fat_msg(sb, KERN_ERR, "utf8 is not a recommended IO charset"
+               fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
                       " for FAT filesystems, filesystem will be "
-                      "case sensitive!\n");
+                      "case sensitive!");
        }
 
        /* If user doesn't specify allow_utime, it's initialized from dmask. */
@@ -1367,6 +1367,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->free_clusters = -1;        /* Don't know yet */
        sbi->free_clus_valid = 0;
        sbi->prev_free = FAT_START_ENT;
+       sb->s_maxbytes = 0xffffffff;
 
        if (!sbi->fat_length && b->fat32_length) {
                struct fat_boot_fsinfo *fsinfo;
@@ -1377,8 +1378,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
                sbi->fat_length = le32_to_cpu(b->fat32_length);
                sbi->root_cluster = le32_to_cpu(b->root_cluster);
 
-               sb->s_maxbytes = 0xffffffff;
-
                /* MC - if info_sector is 0, don't multiply by 0 */
                sbi->fsinfo_sector = le16_to_cpu(b->info_sector);
                if (sbi->fsinfo_sector == 0)
index adcf92d..7971f37 100644 (file)
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
                /*
                 * Wait for outstanding transactions to be written to log:
                 */
-               jfs_flush_journal(log, 1);
+               jfs_flush_journal(log, 2);
 
        /*
         * close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
         *
         * remove file system from log active file system list.
         */
-       jfs_flush_journal(log, 1);
+       jfs_flush_journal(log, 2);
 
        /*
         * Make sure all metadata makes it to disk
index be02077..dbcd821 100644 (file)
@@ -79,12 +79,9 @@ config NFS_V4_1
        depends on NFS_FS && NFS_V4 && EXPERIMENTAL
        select SUNRPC_BACKCHANNEL
        select PNFS_FILE_LAYOUT
-       select PNFS_BLOCK
-       select MD
-       select BLK_DEV_DM
        help
          This option enables support for minor version 1 of the NFSv4 protocol
-         (RFC 5661 and RFC 5663) in the kernel's NFS client.
+         (RFC 5661) in the kernel's NFS client.
 
          If unsure, say N.
 
@@ -93,16 +90,13 @@ config PNFS_FILE_LAYOUT
 
 config PNFS_BLOCK
        tristate
+       depends on NFS_FS && NFS_V4_1 && BLK_DEV_DM
+       default m
 
 config PNFS_OBJLAYOUT
-       tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)"
+       tristate
        depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
-       help
-         Say M here if you want your pNFS client to support the Objects Layout Driver.
-         Requires the SCSI osd initiator library (SCSI_OSD_INITIATOR) and
-         upper level driver (SCSI_OSD_ULD).
-
-         If unsure, say N.
+       default m
 
 config ROOT_NFS
        bool "Root file system on NFS"
index d1fe745..c57836d 100644 (file)
@@ -596,7 +596,7 @@ _xfs_buf_read(
        bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
 
        status = xfs_buf_iorequest(bp);
-       if (status || XFS_BUF_ISERROR(bp) || (flags & XBF_ASYNC))
+       if (status || bp->b_error || (flags & XBF_ASYNC))
                return status;
        return xfs_buf_iowait(bp);
 }
@@ -679,7 +679,6 @@ xfs_buf_read_uncached(
        /* set up the buffer for a read IO */
        XFS_BUF_SET_ADDR(bp, daddr);
        XFS_BUF_READ(bp);
-       XFS_BUF_BUSY(bp);
 
        xfsbdstrat(mp, bp);
        error = xfs_buf_iowait(bp);
@@ -1069,7 +1068,7 @@ xfs_bioerror(
        /*
         * No need to wait until the buffer is unpinned, we aren't flushing it.
         */
-       XFS_BUF_ERROR(bp, EIO);
+       xfs_buf_ioerror(bp, EIO);
 
        /*
         * We're calling xfs_buf_ioend, so delete XBF_DONE flag.
@@ -1094,7 +1093,7 @@ STATIC int
 xfs_bioerror_relse(
        struct xfs_buf  *bp)
 {
-       int64_t         fl = XFS_BUF_BFLAGS(bp);
+       int64_t         fl = bp->b_flags;
        /*
         * No need to wait until the buffer is unpinned.
         * We aren't flushing it.
@@ -1115,7 +1114,7 @@ xfs_bioerror_relse(
                 * There's no reason to mark error for
                 * ASYNC buffers.
                 */
-               XFS_BUF_ERROR(bp, EIO);
+               xfs_buf_ioerror(bp, EIO);
                XFS_BUF_FINISH_IOWAIT(bp);
        } else {
                xfs_buf_relse(bp);
@@ -1324,7 +1323,7 @@ xfs_buf_offset(
        struct page             *page;
 
        if (bp->b_flags & XBF_MAPPED)
-               return XFS_BUF_PTR(bp) + offset;
+               return bp->b_addr + offset;
 
        offset += bp->b_offset;
        page = bp->b_pages[offset >> PAGE_SHIFT];
@@ -1484,7 +1483,7 @@ xfs_setsize_buftarg_flags(
        if (set_blocksize(btp->bt_bdev, sectorsize)) {
                xfs_warn(btp->bt_mount,
                        "Cannot set_blocksize to %u on device %s\n",
-                       sectorsize, XFS_BUFTARG_NAME(btp));
+                       sectorsize, xfs_buf_target_name(btp));
                return EINVAL;
        }
 
@@ -1681,7 +1680,7 @@ xfs_buf_delwri_split(
        list_for_each_entry_safe(bp, n, dwq, b_list) {
                ASSERT(bp->b_flags & XBF_DELWRI);
 
-               if (!XFS_BUF_ISPINNED(bp) && xfs_buf_trylock(bp)) {
+               if (!xfs_buf_ispinned(bp) && xfs_buf_trylock(bp)) {
                        if (!force &&
                            time_before(jiffies, bp->b_queuetime + age)) {
                                xfs_buf_unlock(bp);
index 6a83b46..620972b 100644 (file)
@@ -228,11 +228,15 @@ extern void xfs_buf_delwri_promote(xfs_buf_t *);
 extern int xfs_buf_init(void);
 extern void xfs_buf_terminate(void);
 
-#define xfs_buf_target_name(target)    \
-       ({ char __b[BDEVNAME_SIZE]; bdevname((target)->bt_bdev, __b); __b; })
+static inline const char *
+xfs_buf_target_name(struct xfs_buftarg *target)
+{
+       static char __b[BDEVNAME_SIZE];
+
+       return bdevname(target->bt_bdev, __b);
+}
 
 
-#define XFS_BUF_BFLAGS(bp)     ((bp)->b_flags)
 #define XFS_BUF_ZEROFLAGS(bp) \
        ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI| \
                            XBF_SYNCIO|XBF_FUA|XBF_FLUSH))
@@ -251,23 +255,14 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_UNDELAYWRITE(bp)       xfs_buf_delwri_dequeue(bp)
 #define XFS_BUF_ISDELAYWRITE(bp)       ((bp)->b_flags & XBF_DELWRI)
 
-#define XFS_BUF_ERROR(bp,no)   xfs_buf_ioerror(bp,no)
-#define XFS_BUF_GETERROR(bp)   xfs_buf_geterror(bp)
-#define XFS_BUF_ISERROR(bp)    (xfs_buf_geterror(bp) ? 1 : 0)
-
 #define XFS_BUF_DONE(bp)       ((bp)->b_flags |= XBF_DONE)
 #define XFS_BUF_UNDONE(bp)     ((bp)->b_flags &= ~XBF_DONE)
 #define XFS_BUF_ISDONE(bp)     ((bp)->b_flags & XBF_DONE)
 
-#define XFS_BUF_BUSY(bp)       do { } while (0)
-#define XFS_BUF_UNBUSY(bp)     do { } while (0)
-#define XFS_BUF_ISBUSY(bp)     (1)
-
 #define XFS_BUF_ASYNC(bp)      ((bp)->b_flags |= XBF_ASYNC)
 #define XFS_BUF_UNASYNC(bp)    ((bp)->b_flags &= ~XBF_ASYNC)
 #define XFS_BUF_ISASYNC(bp)    ((bp)->b_flags & XBF_ASYNC)
 
-#define XFS_BUF_HOLD(bp)       xfs_buf_hold(bp)
 #define XFS_BUF_READ(bp)       ((bp)->b_flags |= XBF_READ)
 #define XFS_BUF_UNREAD(bp)     ((bp)->b_flags &= ~XBF_READ)
 #define XFS_BUF_ISREAD(bp)     ((bp)->b_flags & XBF_READ)
@@ -276,10 +271,6 @@ void xfs_buf_stale(struct xfs_buf *bp);
 #define XFS_BUF_UNWRITE(bp)    ((bp)->b_flags &= ~XBF_WRITE)
 #define XFS_BUF_ISWRITE(bp)    ((bp)->b_flags & XBF_WRITE)
 
-#define XFS_BUF_SET_START(bp)                  do { } while (0)
-
-#define XFS_BUF_PTR(bp)                        (xfs_caddr_t)((bp)->b_addr)
-#define XFS_BUF_SET_PTR(bp, val, cnt)  xfs_buf_associate_memory(bp, val, cnt)
 #define XFS_BUF_ADDR(bp)               ((bp)->b_bn)
 #define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_bn = (xfs_daddr_t)(bno))
 #define XFS_BUF_OFFSET(bp)             ((bp)->b_file_offset)
@@ -299,14 +290,13 @@ xfs_buf_set_ref(
 #define XFS_BUF_SET_VTYPE_REF(bp, type, ref)   xfs_buf_set_ref(bp, ref)
 #define XFS_BUF_SET_VTYPE(bp, type)            do { } while (0)
 
-#define XFS_BUF_ISPINNED(bp)   atomic_read(&((bp)->b_pin_count))
+static inline int xfs_buf_ispinned(struct xfs_buf *bp)
+{
+       return atomic_read(&bp->b_pin_count);
+}
 
 #define XFS_BUF_FINISH_IOWAIT(bp)      complete(&bp->b_iowait);
 
-#define XFS_BUF_SET_TARGET(bp, target) ((bp)->b_target = (target))
-#define XFS_BUF_TARGET(bp)             ((bp)->b_target)
-#define XFS_BUFTARG_NAME(target)       xfs_buf_target_name(target)
-
 static inline void xfs_buf_relse(xfs_buf_t *bp)
 {
        xfs_buf_unlock(bp);
index e4c938a..4604f90 100644 (file)
@@ -332,7 +332,7 @@ xfs_sync_fsdata(
         * between there and here.
         */
        bp = xfs_getsb(mp, 0);
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                xfs_log_force(mp, 0);
 
        return xfs_bwrite(mp, bp);
index 837f311..db62959 100644 (file)
@@ -318,10 +318,9 @@ xfs_qm_init_dquot_blk(
        int             curid, i;
 
        ASSERT(tp);
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
-       d = (xfs_dqblk_t *)XFS_BUF_PTR(bp);
+       d = bp->b_addr;
 
        /*
         * ID of the first dquot in the block - id's are zero based.
@@ -403,7 +402,7 @@ xfs_qm_dqalloc(
                               dqp->q_blkno,
                               mp->m_quotainfo->qi_dqchunklen,
                               0);
-       if (!bp || (error = XFS_BUF_GETERROR(bp)))
+       if (!bp || (error = xfs_buf_geterror(bp)))
                goto error1;
        /*
         * Make a chunk of dquots out of this buffer and log
@@ -534,13 +533,12 @@ xfs_qm_dqtobp(
                        return XFS_ERROR(error);
        }
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
        /*
         * calculate the location of the dquot inside the buffer.
         */
-       ddq = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       ddq = bp->b_addr + dqp->q_bufoffset;
 
        /*
         * A simple sanity check in case we got a corrupted dquot...
@@ -553,7 +551,6 @@ xfs_qm_dqtobp(
                        xfs_trans_brelse(tp, bp);
                        return XFS_ERROR(EIO);
                }
-               XFS_BUF_BUSY(bp); /* We dirtied this */
        }
 
        *O_bpp = bp;
@@ -622,7 +619,6 @@ xfs_qm_dqread(
         * this particular dquot was repaired. We still aren't afraid to
         * brelse it because we have the changes incore.
         */
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
        xfs_trans_brelse(tp, bp);
 
@@ -1204,7 +1200,7 @@ xfs_qm_dqflush(
        /*
         * Calculate the location of the dquot inside the buffer.
         */
-       ddqp = (struct xfs_disk_dquot *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       ddqp = bp->b_addr + dqp->q_bufoffset;
 
        /*
         * A simple sanity check in case we got a corrupted dquot..
@@ -1240,7 +1236,7 @@ xfs_qm_dqflush(
         * If the buffer is pinned then push on the log so we won't
         * get stuck waiting in the write for too long.
         */
-       if (XFS_BUF_ISPINNED(bp)) {
+       if (xfs_buf_ispinned(bp)) {
                trace_xfs_dqflush_force(dqp);
                xfs_log_force(mp, 0);
        }
@@ -1447,7 +1443,7 @@ xfs_qm_dqflock_pushbuf_wait(
                goto out_lock;
 
        if (XFS_BUF_ISDELAYWRITE(bp)) {
-               if (XFS_BUF_ISPINNED(bp))
+               if (xfs_buf_ispinned(bp))
                        xfs_log_force(mp, 0);
                xfs_buf_delwri_promote(bp);
                wake_up_process(bp->b_target->bt_task);
index 46e54ad..9a0aa76 100644 (file)
@@ -1240,7 +1240,7 @@ xfs_qm_reset_dqcounts(
        do_div(j, sizeof(xfs_dqblk_t));
        ASSERT(mp->m_quotainfo->qi_dqperchunk == j);
 #endif
-       ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp);
+       ddq = bp->b_addr;
        for (j = 0; j < mp->m_quotainfo->qi_dqperchunk; j++) {
                /*
                 * Do a sanity check, and if needed, repair the dqblk. Don't
index 6530769..4805f00 100644 (file)
@@ -103,7 +103,7 @@ typedef struct xfs_agf {
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGF_DADDR(mp)      ((xfs_daddr_t)(1 << (mp)->m_sectbb_log))
 #define        XFS_AGF_BLOCK(mp)       XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp))
-#define        XFS_BUF_TO_AGF(bp)      ((xfs_agf_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGF(bp)      ((xfs_agf_t *)((bp)->b_addr))
 
 extern int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
                        xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
@@ -156,7 +156,7 @@ typedef struct xfs_agi {
 /* disk block (xfs_daddr_t) in the AG */
 #define XFS_AGI_DADDR(mp)      ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
 #define        XFS_AGI_BLOCK(mp)       XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp))
-#define        XFS_BUF_TO_AGI(bp)      ((xfs_agi_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGI(bp)      ((xfs_agi_t *)((bp)->b_addr))
 
 extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
                                xfs_agnumber_t agno, struct xfs_buf **bpp);
@@ -168,7 +168,7 @@ extern int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp,
 #define XFS_AGFL_DADDR(mp)     ((xfs_daddr_t)(3 << (mp)->m_sectbb_log))
 #define        XFS_AGFL_BLOCK(mp)      XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp))
 #define XFS_AGFL_SIZE(mp)      ((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
-#define        XFS_BUF_TO_AGFL(bp)     ((xfs_agfl_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_AGFL(bp)     ((xfs_agfl_t *)((bp)->b_addr))
 
 typedef struct xfs_agfl {
        __be32          agfl_bno[1];    /* actually XFS_AGFL_SIZE(mp) */
index 1e00b3e..bdd9cb5 100644 (file)
@@ -451,8 +451,7 @@ xfs_alloc_read_agfl(
                        XFS_FSS_TO_BB(mp, 1), 0, &bp);
        if (error)
                return error;
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF);
        *bpp = bp;
        return 0;
@@ -2116,7 +2115,7 @@ xfs_read_agf(
        if (!*bpp)
                return 0;
 
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
        agf = XFS_BUF_TO_AGF(*bpp);
 
        /*
@@ -2168,7 +2167,7 @@ xfs_alloc_read_agf(
                return error;
        if (!*bpp)
                return 0;
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!(*bpp)->b_error);
 
        agf = XFS_BUF_TO_AGF(*bpp);
        pag = xfs_perag_get(mp, agno);
index cbae424..160bcdc 100644 (file)
@@ -2121,8 +2121,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
 
                bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt,
                                 XBF_LOCK | XBF_DONT_BLOCK);
-               ASSERT(bp);
-               ASSERT(!XFS_BUF_GETERROR(bp));
+               ASSERT(!xfs_buf_geterror(bp));
 
                tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
                                                        XFS_BUF_SIZE(bp);
index ab3e5c6..452a291 100644 (file)
@@ -3383,8 +3383,7 @@ xfs_bmap_local_to_extents(
                ASSERT(args.len == 1);
                *firstblock = args.fsbno;
                bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
-               memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
-                       ifp->if_bytes);
+               memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
                xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
                xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
                xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
index cabf4b5..2b9fd38 100644 (file)
@@ -275,8 +275,7 @@ xfs_btree_dup_cursor(
                                return error;
                        }
                        new->bc_bufs[i] = bp;
-                       ASSERT(bp);
-                       ASSERT(!XFS_BUF_GETERROR(bp));
+                       ASSERT(!xfs_buf_geterror(bp));
                } else
                        new->bc_bufs[i] = NULL;
        }
@@ -467,8 +466,7 @@ xfs_btree_get_bufl(
        ASSERT(fsbno != NULLFSBLOCK);
        d = XFS_FSB_TO_DADDR(mp, fsbno);
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        return bp;
 }
 
@@ -491,8 +489,7 @@ xfs_btree_get_bufs(
        ASSERT(agbno != NULLAGBLOCK);
        d = XFS_AGB_TO_DADDR(mp, agno, agbno);
        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
-       ASSERT(bp);
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        return bp;
 }
 
@@ -632,7 +629,7 @@ xfs_btree_read_bufl(
                        mp->m_bsize, lock, &bp))) {
                return error;
        }
-       ASSERT(!bp || !XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        if (bp)
                XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval);
        *bpp = bp;
@@ -973,8 +970,7 @@ xfs_btree_get_buf_block(
        *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d,
                                 mp->m_bsize, flags);
 
-       ASSERT(*bpp);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
 
        *block = XFS_BUF_TO_BLOCK(*bpp);
        return 0;
@@ -1006,8 +1002,7 @@ xfs_btree_read_buf_block(
        if (error)
                return error;
 
-       ASSERT(*bpp != NULL);
-       ASSERT(!XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
 
        xfs_btree_set_refs(cur, *bpp);
        *block = XFS_BUF_TO_BLOCK(*bpp);
index 8d05a6a..5b240de 100644 (file)
@@ -262,7 +262,7 @@ typedef struct xfs_btree_cur
 /*
  * Convert from buffer to btree block header.
  */
-#define        XFS_BUF_TO_BLOCK(bp)    ((struct xfs_btree_block *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_BLOCK(bp)    ((struct xfs_btree_block *)((bp)->b_addr))
 
 
 /*
index 8849291..cac2ecf 100644 (file)
@@ -124,9 +124,9 @@ xfs_buf_item_log_check(
 
        bp = bip->bli_buf;
        ASSERT(XFS_BUF_COUNT(bp) > 0);
-       ASSERT(XFS_BUF_PTR(bp) != NULL);
+       ASSERT(bp->b_addr != NULL);
        orig = bip->bli_orig;
-       buffer = XFS_BUF_PTR(bp);
+       buffer = bp->b_addr;
        for (x = 0; x < XFS_BUF_COUNT(bp); x++) {
                if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) {
                        xfs_emerg(bp->b_mount,
@@ -371,7 +371,6 @@ xfs_buf_item_pin(
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
 
-       ASSERT(XFS_BUF_ISBUSY(bip->bli_buf));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
               (bip->bli_flags & XFS_BLI_STALE));
@@ -479,13 +478,13 @@ xfs_buf_item_trylock(
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
        struct xfs_buf          *bp = bip->bli_buf;
 
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                return XFS_ITEM_PINNED;
        if (!xfs_buf_trylock(bp))
                return XFS_ITEM_LOCKED;
 
        /* take a reference to the buffer.  */
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
 
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
        trace_xfs_buf_item_trylock(bip);
@@ -726,7 +725,7 @@ xfs_buf_item_init(
         * to have logged.
         */
        bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP);
-       memcpy(bip->bli_orig, XFS_BUF_PTR(bp), XFS_BUF_COUNT(bp));
+       memcpy(bip->bli_orig, bp->b_addr, XFS_BUF_COUNT(bp));
        bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);
 #endif
 
@@ -895,7 +894,6 @@ xfs_buf_attach_iodone(
 {
        xfs_log_item_t  *head_lip;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
 
        lip->li_cb = cb;
@@ -960,7 +958,7 @@ xfs_buf_iodone_callbacks(
        static ulong            lasttime;
        static xfs_buftarg_t    *lasttarg;
 
-       if (likely(!XFS_BUF_GETERROR(bp)))
+       if (likely(!xfs_buf_geterror(bp)))
                goto do_callbacks;
 
        /*
@@ -973,14 +971,14 @@ xfs_buf_iodone_callbacks(
                goto do_callbacks;
        }
 
-       if (XFS_BUF_TARGET(bp) != lasttarg ||
+       if (bp->b_target != lasttarg ||
            time_after(jiffies, (lasttime + 5*HZ))) {
                lasttime = jiffies;
                xfs_alert(mp, "Device %s: metadata write error block 0x%llx",
-                       XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+                       xfs_buf_target_name(bp->b_target),
                      (__uint64_t)XFS_BUF_ADDR(bp));
        }
-       lasttarg = XFS_BUF_TARGET(bp);
+       lasttarg = bp->b_target;
 
        /*
         * If the write was asynchronous then no one will be looking for the
@@ -991,12 +989,11 @@ xfs_buf_iodone_callbacks(
         * around.
         */
        if (XFS_BUF_ISASYNC(bp)) {
-               XFS_BUF_ERROR(bp, 0); /* errno of 0 unsets the flag */
+               xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */
 
                if (!XFS_BUF_ISSTALE(bp)) {
                        XFS_BUF_DELAYWRITE(bp);
                        XFS_BUF_DONE(bp);
-                       XFS_BUF_SET_START(bp);
                }
                ASSERT(bp->b_iodone != NULL);
                trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
@@ -1013,7 +1010,6 @@ xfs_buf_iodone_callbacks(
        XFS_BUF_UNDELAYWRITE(bp);
 
        trace_xfs_buf_error_relse(bp, _RET_IP_);
-       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
 
 do_callbacks:
        xfs_buf_do_callbacks(bp);
index 5bfcb87..ee9d542 100644 (file)
@@ -2050,7 +2050,7 @@ xfs_da_do_buf(
                case 0:
                        bp = xfs_trans_get_buf(trans, mp->m_ddev_targp,
                                mappedbno, nmapped, 0);
-                       error = bp ? XFS_BUF_GETERROR(bp) : XFS_ERROR(EIO);
+                       error = bp ? bp->b_error : XFS_ERROR(EIO);
                        break;
                case 1:
                case 2:
@@ -2268,7 +2268,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
                dabuf->nbuf = 1;
                bp = bps[0];
                dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
-               dabuf->data = XFS_BUF_PTR(bp);
+               dabuf->data = bp->b_addr;
                dabuf->bps[0] = bp;
        } else {
                dabuf->nbuf = nbuf;
@@ -2279,7 +2279,7 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
                dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
                for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
                        bp = bps[i];
-                       memcpy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
+                       memcpy((char *)dabuf->data + off, bp->b_addr,
                                XFS_BUF_COUNT(bp));
                }
        }
@@ -2302,8 +2302,8 @@ xfs_da_buf_clean(xfs_dabuf_t *dabuf)
                for (i = off = 0; i < dabuf->nbuf;
                                i++, off += XFS_BUF_COUNT(bp)) {
                        bp = dabuf->bps[i];
-                       memcpy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
-                               XFS_BUF_COUNT(bp));
+                       memcpy(bp->b_addr, dabuf->data + off,
+                                               XFS_BUF_COUNT(bp));
                }
        }
 }
@@ -2340,7 +2340,7 @@ xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
 
        ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]);
        if (dabuf->nbuf == 1) {
-               ASSERT(dabuf->data == (void *)XFS_BUF_PTR(dabuf->bps[0]));
+               ASSERT(dabuf->data == dabuf->bps[0]->b_addr);
                xfs_trans_log_buf(tp, dabuf->bps[0], first, last);
                return;
        }
index dffba9b..a372163 100644 (file)
@@ -148,7 +148,7 @@ typedef enum xfs_dinode_fmt {
                be32_to_cpu((dip)->di_nextents) : \
                be16_to_cpu((dip)->di_anextents))
 
-#define        XFS_BUF_TO_DINODE(bp)   ((xfs_dinode_t *)XFS_BUF_PTR(bp))
+#define        XFS_BUF_TO_DINODE(bp)   ((xfs_dinode_t *)((bp)->b_addr))
 
 /*
  * For block and character special files the 32bit dev_t is stored at the
index dd5628b..9f24ec2 100644 (file)
@@ -202,8 +202,7 @@ xfs_ialloc_inode_init(
                fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                         mp->m_bsize * blks_per_cluster,
                                         XBF_LOCK);
-               ASSERT(fbuf);
-               ASSERT(!XFS_BUF_GETERROR(fbuf));
+               ASSERT(!xfs_buf_geterror(fbuf));
 
                /*
                 * Initialize all inodes in this buffer and then log them.
@@ -1486,7 +1485,7 @@ xfs_read_agi(
        if (error)
                return error;
 
-       ASSERT(*bpp && !XFS_BUF_GETERROR(*bpp));
+       ASSERT(!xfs_buf_geterror(*bpp));
        agi = XFS_BUF_TO_AGI(*bpp);
 
        /*
index 2fcca4b..0239a7c 100644 (file)
@@ -2473,7 +2473,7 @@ cluster_corrupt_out:
                if (bp->b_iodone) {
                        XFS_BUF_UNDONE(bp);
                        XFS_BUF_STALE(bp);
-                       XFS_BUF_ERROR(bp,EIO);
+                       xfs_buf_ioerror(bp, EIO);
                        xfs_buf_ioend(bp, 0);
                } else {
                        XFS_BUF_STALE(bp);
@@ -2585,7 +2585,7 @@ xfs_iflush(
         * If the buffer is pinned then push on the log now so we won't
         * get stuck waiting in the write for too long.
         */
-       if (XFS_BUF_ISPINNED(bp))
+       if (xfs_buf_ispinned(bp))
                xfs_log_force(mp, 0);
 
        /*
index 06ff843..3a8d4f6 100644 (file)
@@ -878,7 +878,7 @@ xlog_iodone(xfs_buf_t *bp)
        /*
         * Race to shutdown the filesystem if we see an error.
         */
-       if (XFS_TEST_ERROR((XFS_BUF_GETERROR(bp)), l->l_mp,
+       if (XFS_TEST_ERROR((xfs_buf_geterror(bp)), l->l_mp,
                        XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
                xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
                XFS_BUF_STALE(bp);
@@ -1051,7 +1051,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
        if (!bp)
                goto out_free_log;
        bp->b_iodone = xlog_iodone;
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(xfs_buf_islocked(bp));
        log->l_xbuf = bp;
 
@@ -1108,7 +1107,6 @@ xlog_alloc_log(xfs_mount_t        *mp,
                iclog->ic_callback_tail = &(iclog->ic_callback);
                iclog->ic_datap = (char *)iclog->ic_data + log->l_iclog_hsize;
 
-               ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp));
                ASSERT(xfs_buf_islocked(iclog->ic_bp));
                init_waitqueue_head(&iclog->ic_force_wait);
                init_waitqueue_head(&iclog->ic_write_wait);
@@ -1248,7 +1246,7 @@ xlog_bdstrat(
        struct xlog_in_core     *iclog = bp->b_fspriv;
 
        if (iclog->ic_state & XLOG_STATE_IOERROR) {
-               XFS_BUF_ERROR(bp, EIO);
+               xfs_buf_ioerror(bp, EIO);
                XFS_BUF_STALE(bp);
                xfs_buf_ioend(bp, 0);
                /*
@@ -1355,7 +1353,6 @@ xlog_sync(xlog_t          *log,
        XFS_BUF_SET_COUNT(bp, count);
        bp->b_fspriv = iclog;
        XFS_BUF_ZEROFLAGS(bp);
-       XFS_BUF_BUSY(bp);
        XFS_BUF_ASYNC(bp);
        bp->b_flags |= XBF_SYNCIO;
 
@@ -1398,16 +1395,15 @@ xlog_sync(xlog_t                *log,
        if (split) {
                bp = iclog->ic_log->l_xbuf;
                XFS_BUF_SET_ADDR(bp, 0);             /* logical 0 */
-               XFS_BUF_SET_PTR(bp, (xfs_caddr_t)((__psint_t)&(iclog->ic_header)+
-                                           (__psint_t)count), split);
+               xfs_buf_associate_memory(bp,
+                               (char *)&iclog->ic_header + count, split);
                bp->b_fspriv = iclog;
                XFS_BUF_ZEROFLAGS(bp);
-               XFS_BUF_BUSY(bp);
                XFS_BUF_ASYNC(bp);
                bp->b_flags |= XBF_SYNCIO;
                if (log->l_mp->m_flags & XFS_MOUNT_BARRIER)
                        bp->b_flags |= XBF_FUA;
-               dptr = XFS_BUF_PTR(bp);
+               dptr = bp->b_addr;
                /*
                 * Bump the cycle numbers at the start of each block
                 * since this part of the buffer is at the start of
index 052a2c0..a199dbc 100644 (file)
@@ -147,7 +147,7 @@ xlog_align(
        xfs_daddr_t     offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
 
        ASSERT(BBTOB(offset + nbblks) <= XFS_BUF_SIZE(bp));
-       return XFS_BUF_PTR(bp) + BBTOB(offset);
+       return bp->b_addr + BBTOB(offset);
 }
 
 
@@ -178,9 +178,7 @@ xlog_bread_noalign(
 
        XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
        XFS_BUF_READ(bp);
-       XFS_BUF_BUSY(bp);
        XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
-       XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
 
        xfsbdstrat(log->l_mp, bp);
        error = xfs_buf_iowait(bp);
@@ -220,18 +218,18 @@ xlog_bread_offset(
        xfs_buf_t       *bp,
        xfs_caddr_t     offset)
 {
-       xfs_caddr_t     orig_offset = XFS_BUF_PTR(bp);
+       xfs_caddr_t     orig_offset = bp->b_addr;
        int             orig_len = bp->b_buffer_length;
        int             error, error2;
 
-       error = XFS_BUF_SET_PTR(bp, offset, BBTOB(nbblks));
+       error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks));
        if (error)
                return error;
 
        error = xlog_bread_noalign(log, blk_no, nbblks, bp);
 
        /* must reset buffer pointer even on error */
-       error2 = XFS_BUF_SET_PTR(bp, orig_offset, orig_len);
+       error2 = xfs_buf_associate_memory(bp, orig_offset, orig_len);
        if (error)
                return error;
        return error2;
@@ -266,11 +264,9 @@ xlog_bwrite(
 
        XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
        XFS_BUF_ZEROFLAGS(bp);
-       XFS_BUF_BUSY(bp);
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
        xfs_buf_lock(bp);
        XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
-       XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
 
        if ((error = xfs_bwrite(log->l_mp, bp)))
                xfs_ioerror_alert("xlog_bwrite", log->l_mp,
@@ -360,7 +356,7 @@ STATIC void
 xlog_recover_iodone(
        struct xfs_buf  *bp)
 {
-       if (XFS_BUF_GETERROR(bp)) {
+       if (bp->b_error) {
                /*
                 * We're not going to bother about retrying
                 * this during recovery. One strike!
@@ -1262,7 +1258,7 @@ xlog_write_log_records(
                 */
                ealign = round_down(end_block, sectbb);
                if (j == 0 && (start_block + endcount > ealign)) {
-                       offset = XFS_BUF_PTR(bp) + BBTOB(ealign - start_block);
+                       offset = bp->b_addr + BBTOB(ealign - start_block);
                        error = xlog_bread_offset(log, ealign, sectbb,
                                                        bp, offset);
                        if (error)
@@ -2135,15 +2131,16 @@ xlog_recover_buffer_pass2(
 
        bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
                          buf_flags);
-       if (XFS_BUF_ISERROR(bp)) {
+       if (!bp)
+               return XFS_ERROR(ENOMEM);
+       error = bp->b_error;
+       if (error) {
                xfs_ioerror_alert("xlog_recover_do..(read#1)", mp,
                                  bp, buf_f->blf_blkno);
-               error = XFS_BUF_GETERROR(bp);
                xfs_buf_relse(bp);
                return error;
        }
 
-       error = 0;
        if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
                error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
        } else if (buf_f->blf_flags &
@@ -2227,14 +2224,17 @@ xlog_recover_inode_pass2(
 
        bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
                          XBF_LOCK);
-       if (XFS_BUF_ISERROR(bp)) {
+       if (!bp) {
+               error = ENOMEM;
+               goto error;
+       }
+       error = bp->b_error;
+       if (error) {
                xfs_ioerror_alert("xlog_recover_do..(read#2)", mp,
                                  bp, in_f->ilf_blkno);
-               error = XFS_BUF_GETERROR(bp);
                xfs_buf_relse(bp);
                goto error;
        }
-       error = 0;
        ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
        dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset);
 
@@ -3437,7 +3437,7 @@ xlog_do_recovery_pass(
                        /*
                         * Check for header wrapping around physical end-of-log
                         */
-                       offset = XFS_BUF_PTR(hbp);
+                       offset = hbp->b_addr;
                        split_hblks = 0;
                        wrapped_hblks = 0;
                        if (blk_no + hblks <= log->l_logBBsize) {
@@ -3497,7 +3497,7 @@ xlog_do_recovery_pass(
                        } else {
                                /* This log record is split across the
                                 * physical end of log */
-                               offset = XFS_BUF_PTR(dbp);
+                               offset = dbp->b_addr;
                                split_bblks = 0;
                                if (blk_no != log->l_logBBsize) {
                                        /* some data is before the physical
index 092e16a..0081657 100644 (file)
@@ -1615,7 +1615,7 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
                XFS_BUF_UNDELAYWRITE(sbp);
                XFS_BUF_WRITE(sbp);
                XFS_BUF_UNASYNC(sbp);
-               ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);
+               ASSERT(sbp->b_target == mp->m_ddev_targp);
                xfsbdstrat(mp, sbp);
                error = xfs_buf_iowait(sbp);
                if (error)
@@ -1938,7 +1938,7 @@ xfs_getsb(
                xfs_buf_lock(bp);
        }
 
-       XFS_BUF_HOLD(bp);
+       xfs_buf_hold(bp);
        ASSERT(XFS_BUF_ISDONE(bp));
        return bp;
 }
index 8f76fdf..35561a5 100644 (file)
@@ -168,7 +168,7 @@ error_cancel:
                                xfs_trans_cancel(tp, cancelflags);
                                goto error;
                        }
-                       memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
+                       memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
                        xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
                        /*
                         * Commit the transaction.
@@ -883,7 +883,7 @@ xfs_rtbuf_get(
        if (error) {
                return error;
        }
-       ASSERT(bp && !XFS_BUF_GETERROR(bp));
+       ASSERT(!xfs_buf_geterror(bp));
        *bpp = bp;
        return 0;
 }
@@ -943,7 +943,7 @@ xfs_rtcheck_range(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Compute the starting word's address, and starting bit.
         */
@@ -994,7 +994,7 @@ xfs_rtcheck_range(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1040,7 +1040,7 @@ xfs_rtcheck_range(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1158,7 +1158,7 @@ xfs_rtfind_back(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Get the first word's index & point to it.
         */
@@ -1210,7 +1210,7 @@ xfs_rtfind_back(
                        if (error) {
                                return error;
                        }
-                       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       bufp = bp->b_addr;
                        word = XFS_BLOCKWMASK(mp);
                        b = &bufp[word];
                } else {
@@ -1256,7 +1256,7 @@ xfs_rtfind_back(
                        if (error) {
                                return error;
                        }
-                       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       bufp = bp->b_addr;
                        word = XFS_BLOCKWMASK(mp);
                        b = &bufp[word];
                } else {
@@ -1333,7 +1333,7 @@ xfs_rtfind_forw(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Get the first word's index & point to it.
         */
@@ -1384,7 +1384,7 @@ xfs_rtfind_forw(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1429,7 +1429,7 @@ xfs_rtfind_forw(
                        if (error) {
                                return error;
                        }
-                       b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1649,7 +1649,7 @@ xfs_rtmodify_range(
        if (error) {
                return error;
        }
-       bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+       bufp = bp->b_addr;
        /*
         * Compute the starting word's address, and starting bit.
         */
@@ -1694,7 +1694,7 @@ xfs_rtmodify_range(
                        if (error) {
                                return error;
                        }
-                       first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       first = b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1734,7 +1734,7 @@ xfs_rtmodify_range(
                        if (error) {
                                return error;
                        }
-                       first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp);
+                       first = b = bufp = bp->b_addr;
                        word = 0;
                } else {
                        /*
@@ -1832,8 +1832,8 @@ xfs_rtmodify_summary(
         */
        sp = XFS_SUMPTR(mp, bp, so);
        *sp += delta;
-       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)XFS_BUF_PTR(bp)),
-               (uint)((char *)sp - (char *)XFS_BUF_PTR(bp) + sizeof(*sp) - 1));
+       xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)bp->b_addr),
+               (uint)((char *)sp - (char *)bp->b_addr + sizeof(*sp) - 1));
        return 0;
 }
 
index 09e1f4f..f7f3a35 100644 (file)
@@ -47,7 +47,7 @@ struct xfs_trans;
 #define        XFS_SUMOFFSTOBLOCK(mp,s)        \
        (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
 #define        XFS_SUMPTR(mp,bp,so)    \
-       ((xfs_suminfo_t *)((char *)XFS_BUF_PTR(bp) + \
+       ((xfs_suminfo_t *)((bp)->b_addr + \
                (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
 
 #define        XFS_BITTOBLOCK(mp,bi)   ((bi) >> (mp)->m_blkbit_log)
index d6d6fdf..c96a8a0 100644 (file)
@@ -104,9 +104,9 @@ xfs_ioerror_alert(
        xfs_alert(mp,
                 "I/O error occurred: meta-data dev %s block 0x%llx"
                 "       (\"%s\") error %d buf count %zd",
-               XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+               xfs_buf_target_name(bp->b_target),
                (__uint64_t)blkno, func,
-               XFS_BUF_GETERROR(bp), XFS_BUF_COUNT(bp));
+               bp->b_error, XFS_BUF_COUNT(bp));
 }
 
 /*
@@ -137,8 +137,8 @@ xfs_read_buf(
        bp = xfs_buf_read(target, blkno, len, flags);
        if (!bp)
                return XFS_ERROR(EIO);
-       error = XFS_BUF_GETERROR(bp);
-       if (bp && !error && !XFS_FORCED_SHUTDOWN(mp)) {
+       error = bp->b_error;
+       if (!error && !XFS_FORCED_SHUTDOWN(mp)) {
                *bpp = bp;
        } else {
                *bpp = NULL;
index 1eb2ba5..cb6ae71 100644 (file)
@@ -509,7 +509,7 @@ static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
 
 #define XFS_SB_DADDR           ((xfs_daddr_t)0) /* daddr in filesystem/ag */
 #define        XFS_SB_BLOCK(mp)        XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
-#define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)XFS_BUF_PTR(bp))
+#define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)((bp)->b_addr))
 
 #define        XFS_HDR_BLOCK(mp,d)     ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d))
 #define        XFS_DADDR_TO_FSB(mp,d)  XFS_AGB_TO_FSB(mp, \
index 43233e9..c15aa29 100644 (file)
@@ -299,7 +299,7 @@ xfs_trans_ail_cursor_last(
  * Splice the log item list into the AIL at the given LSN. We splice to the
  * tail of the given LSN to maintain insert order for push traversals. The
  * cursor is optional, allowing repeated updates to the same LSN to avoid
- * repeated traversals.
+ * repeated traversals.  This should not be called with an empty list.
  */
 static void
 xfs_ail_splice(
@@ -308,50 +308,39 @@ xfs_ail_splice(
        struct list_head        *list,
        xfs_lsn_t               lsn)
 {
-       struct xfs_log_item     *lip = cur ? cur->item : NULL;
-       struct xfs_log_item     *next_lip;
+       struct xfs_log_item     *lip;
+
+       ASSERT(!list_empty(list));
 
        /*
-        * Get a new cursor if we don't have a placeholder or the existing one
-        * has been invalidated.
+        * Use the cursor to determine the insertion point if one is
+        * provided.  If not, or if the one we got is not valid,
+        * find the place in the AIL where the items belong.
         */
-       if (!lip || (__psint_t)lip & 1) {
+       lip = cur ? cur->item : NULL;
+       if (!lip || (__psint_t) lip & 1)
                lip = __xfs_trans_ail_cursor_last(ailp, lsn);
 
-               if (!lip) {
-                       /* The list is empty, so just splice and return.  */
-                       if (cur)
-                               cur->item = NULL;
-                       list_splice(list, &ailp->xa_ail);
-                       return;
-               }
-       }
+       /*
+        * If a cursor is provided, we know we're processing the AIL
+        * in lsn order, and future items to be spliced in will
+        * follow the last one being inserted now.  Update the
+        * cursor to point to that last item, now while we have a
+        * reliable pointer to it.
+        */
+       if (cur)
+               cur->item = list_entry(list->prev, struct xfs_log_item, li_ail);
 
        /*
-        * Our cursor points to the item we want to insert _after_, so we have
-        * to update the cursor to point to the end of the list we are splicing
-        * in so that it points to the correct location for the next splice.
-        * i.e. before the splice
-        *
-        *  lsn -> lsn -> lsn + x -> lsn + x ...
-        *          ^
-        *          | cursor points here
-        *
-        * After the splice we have:
-        *
-        *  lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ...
-        *          ^                            ^
-        *          | cursor points here         | needs to move here
-        *
-        * So we set the cursor to the last item in the list to be spliced
-        * before we execute the splice, resulting in the cursor pointing to
-        * the correct item after the splice occurs.
+        * Finally perform the splice.  Unless the AIL was empty,
+        * lip points to the item in the AIL _after_ which the new
+        * items should go.  If lip is null the AIL was empty, so
+        * the new items go at the head of the AIL.
         */
-       if (cur) {
-               next_lip = list_entry(list->prev, struct xfs_log_item, li_ail);
-               cur->item = next_lip;
-       }
-       list_splice(list, &lip->li_ail);
+       if (lip)
+               list_splice(list, &lip->li_ail);
+       else
+               list_splice(list, &ailp->xa_ail);
 }
 
 /*
@@ -682,6 +671,7 @@ xfs_trans_ail_update_bulk(
        int                     i;
        LIST_HEAD(tmp);
 
+       ASSERT(nr_items > 0);           /* Not required, but true. */
        mlip = xfs_ail_min(ailp);
 
        for (i = 0; i < nr_items; i++) {
@@ -701,7 +691,8 @@ xfs_trans_ail_update_bulk(
                list_add(&lip->li_ail, &tmp);
        }
 
-       xfs_ail_splice(ailp, cur, &tmp, lsn);
+       if (!list_empty(&tmp))
+               xfs_ail_splice(ailp, cur, &tmp, lsn);
 
        if (!mlip_changed) {
                spin_unlock(&ailp->xa_lock);
index 15584fc..137e2b9 100644 (file)
@@ -54,7 +54,7 @@ xfs_trans_buf_item_match(
        list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                blip = (struct xfs_buf_log_item *)lidp->lid_item;
                if (blip->bli_item.li_type == XFS_LI_BUF &&
-                   XFS_BUF_TARGET(blip->bli_buf) == target &&
+                   blip->bli_buf->b_target == target &&
                    XFS_BUF_ADDR(blip->bli_buf) == blkno &&
                    XFS_BUF_COUNT(blip->bli_buf) == len)
                        return blip->bli_buf;
@@ -80,7 +80,6 @@ _xfs_trans_bjoin(
 {
        struct xfs_buf_log_item *bip;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == NULL);
 
        /*
@@ -194,7 +193,7 @@ xfs_trans_get_buf(xfs_trans_t       *tp,
                return NULL;
        }
 
-       ASSERT(!XFS_BUF_GETERROR(bp));
+       ASSERT(!bp->b_error);
 
        _xfs_trans_bjoin(tp, bp, 1);
        trace_xfs_trans_get_buf(bp->b_fspriv);
@@ -293,10 +292,10 @@ xfs_trans_read_buf(
                        return (flags & XBF_TRYLOCK) ?
                                        EAGAIN : XFS_ERROR(ENOMEM);
 
-               if (XFS_BUF_GETERROR(bp) != 0) {
+               if (bp->b_error) {
+                       error = bp->b_error;
                        xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                          bp, blkno);
-                       error = XFS_BUF_GETERROR(bp);
                        xfs_buf_relse(bp);
                        return error;
                }
@@ -330,7 +329,7 @@ xfs_trans_read_buf(
                ASSERT(xfs_buf_islocked(bp));
                ASSERT(bp->b_transp == tp);
                ASSERT(bp->b_fspriv != NULL);
-               ASSERT((XFS_BUF_ISERROR(bp)) == 0);
+               ASSERT(!bp->b_error);
                if (!(XFS_BUF_ISDONE(bp))) {
                        trace_xfs_trans_read_buf_io(bp, _RET_IP_);
                        ASSERT(!XFS_BUF_ISASYNC(bp));
@@ -386,10 +385,9 @@ xfs_trans_read_buf(
                return (flags & XBF_TRYLOCK) ?
                                        0 : XFS_ERROR(ENOMEM);
        }
-       if (XFS_BUF_GETERROR(bp) != 0) {
-           XFS_BUF_SUPER_STALE(bp);
-               error = XFS_BUF_GETERROR(bp);
-
+       if (bp->b_error) {
+               error = bp->b_error;
+               XFS_BUF_SUPER_STALE(bp);
                xfs_ioerror_alert("xfs_trans_read_buf", mp,
                                  bp, blkno);
                if (tp->t_flags & XFS_TRANS_DIRTY)
@@ -430,7 +428,7 @@ shutdown_abort:
        if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
                xfs_notice(mp, "about to pop assert, bp == 0x%p", bp);
 #endif
-       ASSERT((XFS_BUF_BFLAGS(bp) & (XBF_STALE|XBF_DELWRI)) !=
+       ASSERT((bp->b_flags & (XBF_STALE|XBF_DELWRI)) !=
                                     (XBF_STALE|XBF_DELWRI));
 
        trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
@@ -581,7 +579,6 @@ xfs_trans_bhold(xfs_trans_t *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
@@ -602,7 +599,6 @@ xfs_trans_bhold_release(xfs_trans_t *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
@@ -631,7 +627,6 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp)));
@@ -702,7 +697,6 @@ xfs_trans_binval(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -774,7 +768,6 @@ xfs_trans_inode_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -798,7 +791,6 @@ xfs_trans_stale_inode_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -823,7 +815,6 @@ xfs_trans_inode_alloc_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -851,7 +842,6 @@ xfs_trans_dquot_buf(
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
 
-       ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(type == XFS_BLF_UDQUOT_BUF ||
index 9322e13..51fc429 100644 (file)
@@ -83,7 +83,9 @@ xfs_readlink_bmap(
 
                bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
                                  XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
-               error = XFS_BUF_GETERROR(bp);
+               if (!bp)
+                       return XFS_ERROR(ENOMEM);
+               error = bp->b_error;
                if (error) {
                        xfs_ioerror_alert("xfs_readlink",
                                  ip->i_mount, bp, XFS_BUF_ADDR(bp));
@@ -94,7 +96,7 @@ xfs_readlink_bmap(
                        byte_cnt = pathlen;
                pathlen -= byte_cnt;
 
-               memcpy(link, XFS_BUF_PTR(bp), byte_cnt);
+               memcpy(link, bp->b_addr, byte_cnt);
                xfs_buf_relse(bp);
        }
 
@@ -1648,13 +1650,13 @@ xfs_symlink(
                        byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
                        bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
                                               BTOBB(byte_cnt), 0);
-                       ASSERT(bp && !XFS_BUF_GETERROR(bp));
+                       ASSERT(!xfs_buf_geterror(bp));
                        if (pathlen < byte_cnt) {
                                byte_cnt = pathlen;
                        }
                        pathlen -= byte_cnt;
 
-                       memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt);
+                       memcpy(bp->b_addr, cur_chunk, byte_cnt);
                        cur_chunk += byte_cnt;
 
                        xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
@@ -1999,7 +2001,7 @@ xfs_zero_remaining_bytes(
                                          mp, bp, XFS_BUF_ADDR(bp));
                        break;
                }
-               memset(XFS_BUF_PTR(bp) +
+               memset(bp->b_addr +
                        (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
                      0, lastoffset - offset + 1);
                XFS_BUF_UNDONE(bp);
index fb2d63f..aea9e45 100644 (file)
@@ -39,7 +39,7 @@
 })
 
 #define __page_to_pfn(pg)                                              \
-({     struct page *__pg = (pg);                                       \
+({     const struct page *__pg = (pg);                                 \
        struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));     \
        (unsigned long)(__pg - __pgdat->node_mem_map) +                 \
         __pgdat->node_start_pfn;                                       \
@@ -57,7 +57,7 @@
  * section[i].section_mem_map == mem_map's address - start_pfn;
  */
 #define __page_to_pfn(pg)                                      \
-({     struct page *__pg = (pg);                               \
+({     const struct page *__pg = (pg);                         \
        int __sec = page_to_section(__pg);                      \
        (unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec))); \
 })
index 98f46ef..4030896 100644 (file)
@@ -269,7 +269,7 @@ static inline void put_cred(const struct cred *_cred)
  * since nobody else can modify it.
  */
 #define current_cred() \
-       (*(__force struct cred **)&current->cred)
+       rcu_dereference_protected(current->cred, 1)
 
 /**
  * __task_cred - Access a task's objective credentials
@@ -307,7 +307,7 @@ static inline void put_cred(const struct cred *_cred)
 #define get_current_user()                             \
 ({                                                     \
        struct user_struct *__u;                        \
-       struct cred *__cred;                            \
+       const struct cred *__cred;                      \
        __cred = current_cred();                        \
        __u = get_uid(__cred->user);                    \
        __u;                                            \
@@ -322,7 +322,7 @@ static inline void put_cred(const struct cred *_cred)
 #define get_current_groups()                           \
 ({                                                     \
        struct group_info *__groups;                    \
-       struct cred *__cred;                            \
+       const struct cred *__cred;                      \
        __cred = current_cred();                        \
        __groups = get_group_info(__cred->group_info);  \
        __groups;                                       \
index 06d25c1..b80506b 100644 (file)
@@ -63,7 +63,7 @@ static inline u32 hash_32(u32 val, unsigned int bits)
        return hash >> (32 - bits);
 }
 
-static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
+static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
 }
index 87a06f3..5951730 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/topology.h>
 #include <linux/wait.h>
+#include <linux/module.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -547,7 +548,15 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
        return d->msi_desc;
 }
 
-int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
+int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+               struct module *owner);
+
+static inline int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt,
+               int node)
+{
+       return __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE);
+}
+
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
 
index 2d921b3..150134a 100644 (file)
@@ -66,6 +66,7 @@ struct irq_desc {
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *dir;
 #endif
+       struct module           *owner;
        const char              *name;
 } ____cacheline_internodealigned_in_smp;
 
index f2690cf..7438071 100644 (file)
@@ -685,7 +685,7 @@ static inline void set_page_section(struct page *page, unsigned long section)
        page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
 }
 
-static inline unsigned long page_to_section(struct page *page)
+static inline unsigned long page_to_section(const struct page *page)
 {
        return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
 }
@@ -720,7 +720,7 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
 
 static __always_inline void *lowmem_page_address(const struct page *page)
 {
-       return __va(PFN_PHYS(page_to_pfn((struct page *)page)));
+       return __va(PFN_PHYS(page_to_pfn(page)));
 }
 
 #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
@@ -737,7 +737,7 @@ static __always_inline void *lowmem_page_address(const struct page *page)
 #endif
 
 #if defined(HASHED_PAGE_VIRTUAL)
-void *page_address(struct page *page);
+void *page_address(const struct page *page);
 void set_page_address(struct page *page, void *virtual);
 void page_address_init(void);
 #endif
@@ -962,6 +962,8 @@ int invalidate_inode_page(struct page *page);
 #ifdef CONFIG_MMU
 extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, unsigned int flags);
+extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
+                           unsigned long address, unsigned int fault_flags);
 #else
 static inline int handle_mm_fault(struct mm_struct *mm,
                        struct vm_area_struct *vma, unsigned long address,
@@ -971,6 +973,14 @@ static inline int handle_mm_fault(struct mm_struct *mm,
        BUG();
        return VM_FAULT_SIGBUS;
 }
+static inline int fixup_user_fault(struct task_struct *tsk,
+               struct mm_struct *mm, unsigned long address,
+               unsigned int fault_flags)
+{
+       /* should never happen if there's no MMU */
+       BUG();
+       return -EFAULT;
+}
 #endif
 
 extern int make_pages_present(unsigned long addr, unsigned long end);
@@ -988,8 +998,6 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 int get_user_pages_fast(unsigned long start, int nr_pages, int write,
                        struct page **pages);
 struct page *get_dump_page(unsigned long addr);
-extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
-                           unsigned long address, unsigned int fault_flags);
 
 extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
 extern void do_invalidatepage(struct page *page, unsigned long offset);
index 0f83858..1d09562 100644 (file)
@@ -56,8 +56,6 @@ struct mmc_ios {
 #define MMC_TIMING_UHS_SDR104  4
 #define MMC_TIMING_UHS_DDR50   5
 
-       unsigned char   ddr;                    /* dual data rate used */
-
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
index 2e17c5d..180540a 100644 (file)
@@ -29,7 +29,7 @@
 #define MAX_LINKS 32           
 
 struct sockaddr_nl {
-       sa_family_t     nl_family;      /* AF_NETLINK   */
+       __kernel_sa_family_t    nl_family;      /* AF_NETLINK   */
        unsigned short  nl_pad;         /* zero         */
        __u32           nl_pid;         /* port ID      */
                __u32           nl_groups;      /* multicast groups mask */
index 0085bb0..9180dc5 100644 (file)
@@ -256,6 +256,13 @@ static inline int of_property_read_string(struct device_node *np,
        return -ENOSYS;
 }
 
+static inline const void *of_get_property(const struct device_node *node,
+                               const char *name,
+                               int *lenp)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_OF */
 
 static inline int of_property_read_u32(const struct device_node *np,
index 21097cb..f9ec173 100644 (file)
@@ -72,8 +72,6 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
-extern void pm_genpd_poweroff_unused(void);
-extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
 #else
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
                                      struct device *dev)
@@ -101,8 +99,14 @@ static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
        return -ENOSYS;
 }
-static inline void pm_genpd_poweroff_unused(void) {}
+#endif
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
+extern void genpd_queue_power_off_work(struct generic_pm_domain *genpd);
+extern void pm_genpd_poweroff_unused(void);
+#else
 static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
+static inline void pm_genpd_poweroff_unused(void) {}
 #endif
 
 #endif /* _LINUX_PM_DOMAIN_H */
index b27ebea..93f4d03 100644 (file)
@@ -97,6 +97,9 @@ struct rtc_pll_info {
 #define RTC_AF 0x20    /* Alarm interrupt */
 #define RTC_UF 0x10    /* Update interrupt for 1Hz RTC */
 
+
+#define RTC_MAX_FREQ   8192
+
 #ifdef __KERNEL__
 
 #include <linux/types.h>
index 20b03bf..4ac2c05 100644 (file)
@@ -1767,6 +1767,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_DUMPCORE    0x00000200      /* dumped core */
 #define PF_SIGNALED    0x00000400      /* killed by a signal */
 #define PF_MEMALLOC    0x00000800      /* Allocating memory */
+#define PF_NPROC_EXCEEDED 0x00001000   /* set_user noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH   0x00002000      /* if unset the fpu must be initialized before use */
 #define PF_FREEZING    0x00004000      /* freeze in progress. do not account to load */
 #define PF_NOFREEZE    0x00008000      /* this thread should not be frozen */
index e17f822..d0e77f6 100644 (file)
@@ -8,8 +8,10 @@
 #define _K_SS_ALIGNSIZE        (__alignof__ (struct sockaddr *))
                                /* Implementation specific desired alignment */
 
+typedef unsigned short __kernel_sa_family_t;
+
 struct __kernel_sockaddr_storage {
-       unsigned short  ss_family;              /* address family */
+       __kernel_sa_family_t    ss_family;              /* address family */
        /* Following field(s) are implementation specific */
        char            __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
                                /* space to achieve desired size, */
@@ -35,7 +37,7 @@ struct seq_file;
 extern void socket_seq_show(struct seq_file *seq);
 #endif
 
-typedef unsigned short sa_family_t;
+typedef __kernel_sa_family_t   sa_family_t;
 
 /*
  *     1003.1g requires sa_family_t and that sa_data is char.
index caaff5f..b897d6e 100644 (file)
@@ -238,7 +238,7 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
 {
        __u8 flags = 0;
 
-       if (inet_sk(sk)->transparent)
+       if (inet_sk(sk)->transparent || inet_sk(sk)->hdrincl)
                flags |= FLOWI_FLAG_ANYSRC;
        if (sk->sk_protocol == IPPROTO_TCP)
                flags |= FLOWI_FLAG_PRECOW_METRICS;
index 99e0308..ffd9bc7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Platform data for Texas Instruments TLV320AIC3x codec
  *
- * Author: Jarkko Nikula <jhnikula@gmail.com>
+ * Author: Jarkko Nikula <jarkko.nikula@bitmer.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
diff --git a/include/sound/wm8915.h b/include/sound/wm8915.h
deleted file mode 100644 (file)
index 5817d76..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * linux/sound/wm8915.h -- Platform data for WM8915
- *
- * Copyright 2011 Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __LINUX_SND_WM8903_H
-#define __LINUX_SND_WM8903_H
-
-enum wm8915_inmode {
-       WM8915_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
-       WM8915_INVERTING = 1,         /* IN1xN */
-       WM8915_NON_INVERTING = 2,     /* IN1xP */
-       WM8915_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
-};
-
-/**
- * ReTune Mobile configurations are specified with a label, sample
- * rate and set of values to write (the enable bits will be ignored).
- *
- * Configurations are expected to be generated using the ReTune Mobile
- * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
- */
-struct wm8915_retune_mobile_config {
-       const char *name;
-       int rate;
-       u16 regs[20];
-};
-
-#define WM8915_SET_DEFAULT 0x10000
-
-struct wm8915_pdata {
-       int irq_flags;  /** Set IRQ trigger flags; default active low */
-
-       int ldo_ena;  /** GPIO for LDO1; -1 for none */
-
-       int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
-
-       enum wm8915_inmode inl_mode;
-       enum wm8915_inmode inr_mode;
-
-       u32 spkmute_seq;  /** Value for register 0x802 */
-
-       int gpio_base;
-       u32 gpio_default[5];
-
-       int num_retune_mobile_cfgs;
-       struct wm8915_retune_mobile_config *retune_mobile_cfgs;
-};
-
-#endif
diff --git a/include/sound/wm8996.h b/include/sound/wm8996.h
new file mode 100644 (file)
index 0000000..ea4d88f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * linux/sound/wm8996.h -- Platform data for WM8996
+ *
+ * Copyright 2011 Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_WM8996_H
+#define __LINUX_SND_WM8996_H
+
+enum wm8996_inmode {
+       WM8996_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
+       WM8996_INVERTING = 1,         /* IN1xN */
+       WM8996_NON_INVERTING = 2,     /* IN1xP */
+       WM8996_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
+};
+
+/**
+ * ReTune Mobile configurations are specified with a label, sample
+ * rate and set of values to write (the enable bits will be ignored).
+ *
+ * Configurations are expected to be generated using the ReTune Mobile
+ * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8996_retune_mobile_config {
+       const char *name;
+       int rate;
+       u16 regs[20];
+};
+
+#define WM8996_SET_DEFAULT 0x10000
+
+struct wm8996_pdata {
+       int irq_flags;  /** Set IRQ trigger flags; default active low */
+
+       int ldo_ena;  /** GPIO for LDO1; -1 for none */
+
+       int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
+
+       enum wm8996_inmode inl_mode;
+       enum wm8996_inmode inr_mode;
+
+       u32 spkmute_seq;  /** Value for register 0x802 */
+
+       int gpio_base;
+       u32 gpio_default[5];
+
+       int num_retune_mobile_cfgs;
+       struct wm8996_retune_mobile_config *retune_mobile_cfgs;
+};
+
+#endif
index d06467f..eca595e 100644 (file)
@@ -10,7 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
            notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
-           async.o range.o jump_label.o
+           async.o range.o
 obj-y += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
@@ -107,6 +107,7 @@ obj-$(CONFIG_PERF_EVENTS) += events/
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
 obj-$(CONFIG_PADATA) += padata.o
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
index 174fa84..8ef31f5 100644 (file)
@@ -508,10 +508,8 @@ int commit_creds(struct cred *new)
                key_fsgid_changed(task);
 
        /* do it
-        * - What if a process setreuid()'s and this brings the
-        *   new uid over his NPROC rlimit?  We can check this now
-        *   cheaply with the new uid cache, so if it matters
-        *   we should be checking for it.  -DaveM
+        * RLIMIT_NPROC limits on user->processes have already been checked
+        * in set_user().
         */
        alter_cred_subscribers(new, 2);
        if (new->user != old->user)
index e7ceaca..8e6b6f4 100644 (file)
@@ -1111,6 +1111,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                    p->real_cred->user != INIT_USER)
                        goto bad_fork_free;
        }
+       current->flags &= ~PF_NPROC_EXCEEDED;
 
        retval = copy_creds(p, clone_flags);
        if (retval < 0)
index 3a2cab4..e38544d 100644 (file)
@@ -246,7 +246,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
                gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
 
        for (i = gc->irq_base; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                if (flags & IRQ_GC_INIT_NESTED_LOCK)
@@ -301,7 +301,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
        raw_spin_unlock(&gc_lock);
 
        for (; msk; msk >>= 1, i++) {
-               if (!msk & 0x01)
+               if (!(msk & 0x01))
                        continue;
 
                /* Remove handler first. That will mask the irq line */
index 4c60a50..039b889 100644 (file)
@@ -70,7 +70,8 @@ static inline void desc_smp_init(struct irq_desc *desc, int node) { }
 static inline int desc_node(struct irq_desc *desc) { return 0; }
 #endif
 
-static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
+static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
+               struct module *owner)
 {
        int cpu;
 
@@ -86,6 +87,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
        desc->name = NULL;
+       desc->owner = owner;
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
        desc_smp_init(desc, node);
@@ -128,7 +130,7 @@ static void free_masks(struct irq_desc *desc)
 static inline void free_masks(struct irq_desc *desc) { }
 #endif
 
-static struct irq_desc *alloc_desc(int irq, int node)
+static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
 {
        struct irq_desc *desc;
        gfp_t gfp = GFP_KERNEL;
@@ -147,7 +149,7 @@ static struct irq_desc *alloc_desc(int irq, int node)
        raw_spin_lock_init(&desc->lock);
        lockdep_set_class(&desc->lock, &irq_desc_lock_class);
 
-       desc_set_defaults(irq, desc, node);
+       desc_set_defaults(irq, desc, node, owner);
 
        return desc;
 
@@ -173,13 +175,14 @@ static void free_desc(unsigned int irq)
        kfree(desc);
 }
 
-static int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                      struct module *owner)
 {
        struct irq_desc *desc;
        int i;
 
        for (i = 0; i < cnt; i++) {
-               desc = alloc_desc(start + i, node);
+               desc = alloc_desc(start + i, node, owner);
                if (!desc)
                        goto err;
                mutex_lock(&sparse_irq_lock);
@@ -227,7 +230,7 @@ int __init early_irq_init(void)
                nr_irqs = initcnt;
 
        for (i = 0; i < initcnt; i++) {
-               desc = alloc_desc(i, node);
+               desc = alloc_desc(i, node, NULL);
                set_bit(i, allocated_irqs);
                irq_insert_desc(i, desc);
        }
@@ -261,7 +264,7 @@ int __init early_irq_init(void)
                alloc_masks(&desc[i], GFP_KERNEL, node);
                raw_spin_lock_init(&desc[i].lock);
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               desc_set_defaults(i, &desc[i], node);
+               desc_set_defaults(i, &desc[i], node, NULL);
        }
        return arch_early_irq_init();
 }
@@ -276,8 +279,16 @@ static void free_desc(unsigned int irq)
        dynamic_irq_cleanup(irq);
 }
 
-static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
+static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
+                             struct module *owner)
 {
+       u32 i;
+
+       for (i = 0; i < cnt; i++) {
+               struct irq_desc *desc = irq_to_desc(start + i);
+
+               desc->owner = owner;
+       }
        return start;
 }
 
@@ -333,11 +344,13 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
  * @from:      Start the search from this irq number
  * @cnt:       Number of consecutive irqs to allocate.
  * @node:      Preferred node on which the irq descriptor should be allocated
+ * @owner:     Owning module (can be NULL)
  *
  * Returns the first irq number or error code
  */
 int __ref
-irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
+__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
+                 struct module *owner)
 {
        int start, ret;
 
@@ -366,13 +379,13 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
 
        bitmap_set(allocated_irqs, start, cnt);
        mutex_unlock(&sparse_irq_lock);
-       return alloc_descs(start, cnt, node);
+       return alloc_descs(start, cnt, node, owner);
 
 err:
        mutex_unlock(&sparse_irq_lock);
        return ret;
 }
-EXPORT_SYMBOL_GPL(irq_alloc_descs);
+EXPORT_SYMBOL_GPL(__irq_alloc_descs);
 
 /**
  * irq_reserve_irqs - mark irqs allocated
@@ -440,7 +453,7 @@ void dynamic_irq_cleanup(unsigned int irq)
        unsigned long flags;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc_set_defaults(irq, desc, desc_node(desc));
+       desc_set_defaults(irq, desc, desc_node(desc), NULL);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
index 0a7840a..2e94258 100644 (file)
@@ -883,6 +883,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
        if (desc->irq_data.chip == &no_irq_chip)
                return -ENOSYS;
+       if (!try_module_get(desc->owner))
+               return -ENODEV;
        /*
         * Some drivers like serial.c use request_irq() heavily,
         * so we have to be careful not to interfere with a
@@ -906,8 +908,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         */
        nested = irq_settings_is_nested_thread(desc);
        if (nested) {
-               if (!new->thread_fn)
-                       return -EINVAL;
+               if (!new->thread_fn) {
+                       ret = -EINVAL;
+                       goto out_mput;
+               }
                /*
                 * Replace the primary handler which was provided from
                 * the driver for non nested interrupt handling by the
@@ -929,8 +933,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 
                t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
                                   new->name);
-               if (IS_ERR(t))
-                       return PTR_ERR(t);
+               if (IS_ERR(t)) {
+                       ret = PTR_ERR(t);
+                       goto out_mput;
+               }
                /*
                 * We keep the reference to the task struct even if
                 * the thread dies to avoid that the interrupt code
@@ -1095,6 +1101,8 @@ out_thread:
                        kthread_stop(t);
                put_task_struct(t);
        }
+out_mput:
+       module_put(desc->owner);
        return ret;
 }
 
@@ -1203,6 +1211,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
                put_task_struct(action->thread);
        }
 
+       module_put(desc->owner);
        return action;
 }
 
@@ -1322,6 +1331,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
                if (!thread_fn)
                        return -EINVAL;
                handler = irq_default_primary_handler;
+               irqflags |= IRQF_ONESHOT;
        }
 
        action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
index 8c24294..91d67ce 100644 (file)
@@ -3111,7 +3111,13 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
                if (!class)
                        class = look_up_lock_class(lock, 0);
 
-               if (DEBUG_LOCKS_WARN_ON(!class))
+               /*
+                * If look_up_lock_class() failed to find a class, we're trying
+                * to test if we hold a lock that has never yet been acquired.
+                * Clearly if the lock hasn't been acquired _ever_, we're not
+                * holding it either, so report failure.
+                */
+               if (!class)
                        return 0;
 
                if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock))
index b1914cb..3744c59 100644 (file)
@@ -231,3 +231,7 @@ config PM_CLK
 config PM_GENERIC_DOMAINS
        bool
        depends on PM
+
+config PM_GENERIC_DOMAINS_RUNTIME
+       def_bool y
+       depends on PM_RUNTIME && PM_GENERIC_DOMAINS
index 37dff34..836a2ae 100644 (file)
@@ -318,8 +318,10 @@ static int check_syslog_permissions(int type, bool from_file)
                        return 0;
                /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
                if (capable(CAP_SYS_ADMIN)) {
-                       WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
-                                "but no CAP_SYSLOG (deprecated).\n");
+                       printk_once(KERN_WARNING "%s (%d): "
+                                "Attempt to access syslog with CAP_SYS_ADMIN "
+                                "but no CAP_SYSLOG (deprecated).\n",
+                                current->comm, task_pid_nr(current));
                        return 0;
                }
                return -EPERM;
index a101ba3..dd948a1 100644 (file)
@@ -621,11 +621,18 @@ static int set_user(struct cred *new)
        if (!new_user)
                return -EAGAIN;
 
+       /*
+        * We don't fail in case of NPROC limit excess here because too many
+        * poorly written programs don't check set*uid() return code, assuming
+        * it never fails if called by root.  We may still enforce NPROC limit
+        * for programs doing set*uid()+execve() by harmlessly deferring the
+        * failure to the execve() stage.
+        */
        if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
-                       new_user != INIT_USER) {
-               free_uid(new_user);
-               return -EAGAIN;
-       }
+                       new_user != INIT_USER)
+               current->flags |= PF_NPROC_EXCEEDED;
+       else
+               current->flags &= ~PF_NPROC_EXCEEDED;
 
        free_uid(new->user);
        new->user = new_user;
index 2ad39e5..cd31345 100644 (file)
@@ -82,7 +82,7 @@ config EVENT_POWER_TRACING_DEPRECATED
          power:power_frequency
          This is for userspace compatibility
          and will vanish after 5 kernel iterations,
-         namely 2.6.41.
+         namely 3.1.
 
 config CONTEXT_SWITCH_TRACER
        bool
index 693394d..5ef672c 100644 (file)
@@ -326,7 +326,7 @@ static struct page_address_slot {
        spinlock_t lock;                        /* Protect this bucket's list */
 } ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];
 
-static struct page_address_slot *page_slot(struct page *page)
+static struct page_address_slot *page_slot(const struct page *page)
 {
        return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)];
 }
@@ -337,7 +337,7 @@ static struct page_address_slot *page_slot(struct page *page)
  *
  * Returns the page's virtual address.
  */
-void *page_address(struct page *page)
+void *page_address(const struct page *page)
 {
        unsigned long flags;
        void *ret;
index f4ec4e7..930de94 100644 (file)
@@ -2091,6 +2091,7 @@ struct memcg_stock_pcp {
 #define FLUSHING_CACHED_CHARGE (0)
 };
 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
+static DEFINE_MUTEX(percpu_charge_mutex);
 
 /*
  * Try to consume stocked charge on this cpu. If success, one page is consumed
@@ -2197,8 +2198,7 @@ static void drain_all_stock(struct mem_cgroup *root_mem, bool sync)
 
        for_each_online_cpu(cpu) {
                struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
-               if (mem_cgroup_same_or_subtree(root_mem, stock->cached) &&
-                               test_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
+               if (test_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
                        flush_work(&stock->work);
        }
 out:
@@ -2213,14 +2213,22 @@ out:
  */
 static void drain_all_stock_async(struct mem_cgroup *root_mem)
 {
+       /*
+        * If someone calls draining, avoid adding more kworker runs.
+        */
+       if (!mutex_trylock(&percpu_charge_mutex))
+               return;
        drain_all_stock(root_mem, false);
+       mutex_unlock(&percpu_charge_mutex);
 }
 
 /* This is a synchronous drain interface. */
 static void drain_all_stock_sync(struct mem_cgroup *root_mem)
 {
        /* called when force_empty is called */
+       mutex_lock(&percpu_charge_mutex);
        drain_all_stock(root_mem, true);
+       mutex_unlock(&percpu_charge_mutex);
 }
 
 /*
index eb5a8f9..9f662d7 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -701,7 +701,7 @@ static u8 *check_bytes(u8 *start, u8 value, unsigned int bytes)
                return check_bytes8(start, value, bytes);
 
        value64 = value | value << 8 | value << 16 | value << 24;
-       value64 = value64 | value64 << 32;
+       value64 = (value64 & 0xffffffff) | value64 << 32;
        prefix = 8 - ((unsigned long)start) % 8;
 
        if (prefix) {
@@ -1854,7 +1854,7 @@ redo:
 
        new.frozen = 0;
 
-       if (!new.inuse && n->nr_partial < s->min_partial)
+       if (!new.inuse && n->nr_partial > s->min_partial)
                m = M_FREE;
        else if (new.freelist) {
                m = M_PARTIAL;
@@ -2387,11 +2387,13 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 slab_empty:
        if (prior) {
                /*
-                * Slab still on the partial list.
+                * Slab on the partial list.
                 */
                remove_partial(n, page);
                stat(s, FREE_REMOVE_PARTIAL);
-       }
+       } else
+               /* Slab must be on the full list */
+               remove_full(s, page);
 
        spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
index 464621d..7ef0903 100644 (file)
@@ -725,9 +725,10 @@ static void free_unmap_vmap_area_addr(unsigned long addr)
 #define VMAP_BBMAP_BITS_MIN    (VMAP_MAX_ALLOC*2)
 #define VMAP_MIN(x, y)         ((x) < (y) ? (x) : (y)) /* can't use min() */
 #define VMAP_MAX(x, y)         ((x) > (y) ? (x) : (y)) /* can't use max() */
-#define VMAP_BBMAP_BITS                VMAP_MIN(VMAP_BBMAP_BITS_MAX,           \
-                                       VMAP_MAX(VMAP_BBMAP_BITS_MIN,   \
-                                               VMALLOC_PAGES / NR_CPUS / 16))
+#define VMAP_BBMAP_BITS                \
+               VMAP_MIN(VMAP_BBMAP_BITS_MAX,   \
+               VMAP_MAX(VMAP_BBMAP_BITS_MIN,   \
+                       VMALLOC_PAGES / roundup_pow_of_two(NR_CPUS) / 16))
 
 #define VMAP_BLOCK_SIZE                (VMAP_BBMAP_BITS * PAGE_SIZE)
 
index 3176e2e..2cdf007 100644 (file)
@@ -417,6 +417,7 @@ put_back:
 int br_del_if(struct net_bridge *br, struct net_device *dev)
 {
        struct net_bridge_port *p;
+       bool changed_addr;
 
        p = br_port_get_rtnl(dev);
        if (!p || p->br != br)
@@ -425,9 +426,12 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
        del_nbp(p);
 
        spin_lock_bh(&br->lock);
-       br_stp_recalculate_bridge_id(br);
+       changed_addr = br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
 
+       if (changed_addr)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
+
        netdev_update_features(br->dev);
 
        return 0;
index 6545ee9..a76b621 100644 (file)
@@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        struct net_device *dev = ptr;
        struct net_bridge_port *p;
        struct net_bridge *br;
+       bool changed_addr;
        int err;
 
        /* register of bridge completed, add sysfs entries */
@@ -57,8 +58,12 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        case NETDEV_CHANGEADDR:
                spin_lock_bh(&br->lock);
                br_fdb_changeaddr(p, dev->dev_addr);
-               br_stp_recalculate_bridge_id(br);
+               changed_addr = br_stp_recalculate_bridge_id(br);
                spin_unlock_bh(&br->lock);
+
+               if (changed_addr)
+                       call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
+
                break;
 
        case NETDEV_CHANGE:
index 2b5ca1a..5864cc4 100644 (file)
@@ -1198,7 +1198,8 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table)
 
        if (table->check && table->check(newinfo, table->valid_hooks)) {
                BUGPRINT("The table doesn't like its own initial data, lol\n");
-               return ERR_PTR(-EINVAL);
+               ret = -EINVAL;
+               goto free_chainstack;
        }
 
        table->private = newinfo;
index 4c1ef02..811b53f 100644 (file)
@@ -192,7 +192,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                                        goto error;
 
                                cred->uid = cred->euid = p->creds.uid;
-                               cred->gid = cred->egid = p->creds.uid;
+                               cred->gid = cred->egid = p->creds.gid;
                                put_cred(p->cred);
                                p->cred = cred;
                        }
index 77d3ede..8c65633 100644 (file)
@@ -122,6 +122,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
        WARN_ON(!skb_dst(newskb));
+       skb_dst_force(newskb);
        netif_rx_ni(newskb);
        return 0;
 }
index ab0c9ef..8905e92 100644 (file)
@@ -1067,7 +1067,7 @@ EXPORT_SYMBOL(compat_ip_setsockopt);
  */
 
 static int do_ip_getsockopt(struct sock *sk, int level, int optname,
-                           char __user *optval, int __user *optlen)
+                           char __user *optval, int __user *optlen, unsigned flags)
 {
        struct inet_sock *inet = inet_sk(sk);
        int val;
@@ -1240,7 +1240,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
 
                msg.msg_control = optval;
                msg.msg_controllen = len;
-               msg.msg_flags = 0;
+               msg.msg_flags = flags;
 
                if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
                        struct in_pktinfo info;
@@ -1294,7 +1294,7 @@ int ip_getsockopt(struct sock *sk, int level,
 {
        int err;
 
-       err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
@@ -1327,7 +1327,8 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
                return compat_mc_getsockopt(sk, level, optname, optval, optlen,
                        ip_getsockopt);
 
-       err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+       err = do_ip_getsockopt(sk, level, optname, optval, optlen,
+               MSG_CMSG_COMPAT);
 
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
index 2e97e3e..929b27b 100644 (file)
@@ -18,17 +18,15 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
        struct rtable *rt;
        struct flowi4 fl4 = {};
        __be32 saddr = iph->saddr;
-       __u8 flags = 0;
+       __u8 flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
        unsigned int hh_len;
 
-       if (!skb->sk && addr_type != RTN_LOCAL) {
-               if (addr_type == RTN_UNSPEC)
-                       addr_type = inet_addr_type(net, saddr);
-               if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
-                       flags |= FLOWI_FLAG_ANYSRC;
-               else
-                       saddr = 0;
-       }
+       if (addr_type == RTN_UNSPEC)
+               addr_type = inet_addr_type(net, saddr);
+       if (addr_type == RTN_LOCAL || addr_type == RTN_UNICAST)
+               flags |= FLOWI_FLAG_ANYSRC;
+       else
+               saddr = 0;
 
        /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
         * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook.
@@ -38,7 +36,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
        fl4.flowi4_tos = RT_TOS(iph->tos);
        fl4.flowi4_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
        fl4.flowi4_mark = skb->mark;
-       fl4.flowi4_flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : flags;
+       fl4.flowi4_flags = flags;
        rt = ip_route_output_key(net, &fl4);
        if (IS_ERR(rt))
                return -1;
index 1457acb..61714bd 100644 (file)
@@ -563,7 +563,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
                           RT_SCOPE_UNIVERSE,
                           inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
-                          FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0);
+                          inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
+                          daddr, saddr, 0, 0);
 
        if (!inet->hdrincl) {
                err = raw_probe_proto_opt(&fl4, msg);
index e3dec1c..075212e 100644 (file)
@@ -722,7 +722,7 @@ static inline bool compare_hash_inputs(const struct rtable *rt1,
 {
        return ((((__force u32)rt1->rt_key_dst ^ (__force u32)rt2->rt_key_dst) |
                ((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
-               (rt1->rt_iif ^ rt2->rt_iif)) == 0);
+               (rt1->rt_route_iif ^ rt2->rt_route_iif)) == 0);
 }
 
 static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
@@ -731,8 +731,8 @@ static inline int compare_keys(struct rtable *rt1, struct rtable *rt2)
                ((__force u32)rt1->rt_key_src ^ (__force u32)rt2->rt_key_src) |
                (rt1->rt_mark ^ rt2->rt_mark) |
                (rt1->rt_key_tos ^ rt2->rt_key_tos) |
-               (rt1->rt_oif ^ rt2->rt_oif) |
-               (rt1->rt_iif ^ rt2->rt_iif)) == 0;
+               (rt1->rt_route_iif ^ rt2->rt_route_iif) |
+               (rt1->rt_oif ^ rt2->rt_oif)) == 0;
 }
 
 static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
@@ -2320,8 +2320,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
             rth = rcu_dereference(rth->dst.rt_next)) {
                if ((((__force u32)rth->rt_key_dst ^ (__force u32)daddr) |
                     ((__force u32)rth->rt_key_src ^ (__force u32)saddr) |
-                    (rth->rt_iif ^ iif) |
-                    rth->rt_oif |
+                    (rth->rt_route_iif ^ iif) |
                     (rth->rt_key_tos ^ tos)) == 0 &&
                    rth->rt_mark == skb->mark &&
                    net_eq(dev_net(rth->dst.dev), net) &&
index 92bb943..3bc5c8f 100644 (file)
@@ -276,7 +276,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        int mss;
        struct rtable *rt;
        __u8 rcv_wscale;
-       bool ecn_ok;
+       bool ecn_ok = false;
 
        if (!sysctl_tcp_syncookies || !th->ack || th->rst)
                goto out;
index 89d5bf8..ac83896 100644 (file)
@@ -165,7 +165,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        int mss;
        struct dst_entry *dst;
        __u8 rcv_wscale;
-       bool ecn_ok;
+       bool ecn_ok = false;
 
        if (!sysctl_tcp_syncookies || !th->ack || th->rst)
                goto out;
index 5b466cd..84d0fd4 100644 (file)
@@ -312,6 +312,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
                }
                break;
        case NF_STOLEN:
+               break;
        default:
                kfree_skb(skb);
        }
index 58107d0..9c24de1 100644 (file)
@@ -341,11 +341,11 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
 
        entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL)
-               return -ENOMEM;
+               goto out_entry;
        if (domain != NULL) {
                entry->domain = kstrdup(domain, GFP_ATOMIC);
                if (entry->domain == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_domain;
        }
 
        if (addr == NULL && mask == NULL) {
@@ -354,13 +354,13 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        } else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_addrmap;
                INIT_LIST_HEAD(&addrmap->list4);
                INIT_LIST_HEAD(&addrmap->list6);
 
                addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
                if (addrinfo == NULL)
-                       goto cfg_cipsov4_map_add_failure;
+                       goto out_addrinfo;
                addrinfo->type_def.cipsov4 = doi_def;
                addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
                addrinfo->list.addr = addr->s_addr & mask->s_addr;
@@ -374,7 +374,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                entry->type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
-               goto cfg_cipsov4_map_add_failure;
+               goto out_addrmap;
        }
 
        ret_val = netlbl_domhsh_add(entry, audit_info);
@@ -384,11 +384,15 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        return 0;
 
 cfg_cipsov4_map_add_failure:
-       cipso_v4_doi_putdef(doi_def);
+       kfree(addrinfo);
+out_addrinfo:
+       kfree(addrmap);
+out_addrmap:
        kfree(entry->domain);
+out_domain:
        kfree(entry);
-       kfree(addrmap);
-       kfree(addrinfo);
+out_entry:
+       cipso_v4_doi_putdef(doi_def);
        return ret_val;
 }
 
index 2a318f2..b5d56a2 100644 (file)
@@ -112,7 +112,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc *sch)
 
        for (prio = 0; prio < q->bands; prio++) {
                struct Qdisc *qdisc = q->queues[prio];
-               struct sk_buff *skb = qdisc->dequeue(qdisc);
+               struct sk_buff *skb = qdisc_dequeue_peeked(qdisc);
                if (skb) {
                        qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
index c8439cf..2e43aec 100644 (file)
@@ -710,8 +710,10 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                      head->r.index++)
                        if (ns->profile_ptr[head->r.index])
                                break;
-               if (head->r.index == TOMOYO_MAX_PROFILES)
+               if (head->r.index == TOMOYO_MAX_PROFILES) {
+                       head->r.eof = true;
                        return;
+               }
                head->r.step++;
                break;
        case 2:
@@ -723,6 +725,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                        tomoyo_io_printf(head, "%u-COMMENT=", index);
                        tomoyo_set_string(head, comment ? comment->name : "");
                        tomoyo_set_lf(head);
+                       tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
                        for (i = 0; i < TOMOYO_MAX_PREF; i++)
                                tomoyo_io_printf(head, "%s=%u ",
index 7c1cbf0..67ebf1c 100644 (file)
@@ -328,6 +328,8 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                mutex_unlock(&register_mutex);
        } else {
                timer = timeri->timer;
+               if (snd_BUG_ON(!timer))
+                       goto out;
                /* wait, until the active callback is finished */
                spin_lock_irq(&timer->lock);
                while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -353,6 +355,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                }
                mutex_unlock(&register_mutex);
        }
+ out:
        if (timeri->private_free)
                timeri->private_free(timeri);
        kfree(timeri->owner);
@@ -531,6 +534,8 @@ int snd_timer_stop(struct snd_timer_instance *timeri)
        if (err < 0)
                return err;
        timer = timeri->timer;
+       if (!timer)
+               return -EINVAL;
        spin_lock_irqsave(&timer->lock, flags);
        timeri->cticks = timeri->ticks;
        timeri->pticks = 0;
index 8f7d175..6f13ab4 100644 (file)
@@ -63,13 +63,13 @@ static int pcm_set_speed(int arg)
 
        if (pcm_channels & 2)
        {
-               foo = ((CLOCK_TICK_RATE / 2) + (arg / 2)) / arg;
-               arg = ((CLOCK_TICK_RATE / 2) + (foo / 2)) / foo;
+               foo = ((PIT_TICK_RATE / 2) + (arg / 2)) / arg;
+               arg = ((PIT_TICK_RATE / 2) + (foo / 2)) / foo;
        }
        else
        {
-               foo = (CLOCK_TICK_RATE + (arg / 2)) / arg;
-               arg = (CLOCK_TICK_RATE + (foo / 2)) / foo;
+               foo = (PIT_TICK_RATE + (arg / 2)) / arg;
+               arg = (PIT_TICK_RATE + (foo / 2)) / foo;
        }
 
        pcm_speed = arg;
index 9b800ce..2fc0624 100644 (file)
@@ -673,7 +673,8 @@ static void configure_nonsound_components(void)
 
        if (pss_cdrom_port == -1) {     /* If cdrom port enablation wasn't requested */
                printk(KERN_INFO "PSS: CDROM port not enabled.\n");
-       } else if (check_region(pss_cdrom_port, 2)) {
+       } else if (!request_region(pss_cdrom_port, 2, "PSS CDROM")) {
+               pss_cdrom_port = -1;
                printk(KERN_ERR "PSS: CDROM I/O port conflict.\n");
        } else {
                set_io_base(devc, CONF_CDROM, pss_cdrom_port);
@@ -1232,7 +1233,8 @@ static void __exit cleanup_pss(void)
                if(pssmpu)
                        unload_pss_mpu(&cfg_mpu);
                unload_pss(&cfg);
-       }
+       } else if (pss_cdrom_port != -1)
+               release_region(pss_cdrom_port, 2);
 
        if(!pss_keep_settings)  /* Keep hardware settings if asked */
        {
index 50abf5b..8816804 100644 (file)
@@ -1,5 +1,10 @@
 # ALSA PCI drivers
 
+config SND_TEA575X
+       tristate
+       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2
+       default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2
+
 menuconfig SND_PCI
        bool "PCI sound devices"
        depends on PCI
@@ -563,11 +568,6 @@ config SND_FM801_TEA575X_BOOL
          FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and
          SF64-PCR) into the snd-fm801 driver.
 
-config SND_TEA575X
-       tristate
-       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2
-       default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2
-
 source "sound/pci/hda/Kconfig"
 
 config SND_HDSP
index 65b7ca1..bd47521 100644 (file)
@@ -631,13 +631,12 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
        if (!p_cache)
                return NULL;
 
-       p_cache->p_info =
-               kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL);
+       p_cache->p_info = kzalloc(sizeof(*p_cache->p_info) * control_count,
+                                 GFP_KERNEL);
        if (!p_cache->p_info) {
                kfree(p_cache);
                return NULL;
        }
-       memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count);
        p_cache->cache_size_in_bytes = size_in_bytes;
        p_cache->control_count = control_count;
        p_cache->p_cache = p_dsp_control_buffer;
index e4d76a2..579fc0d 100644 (file)
@@ -2625,16 +2625,19 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        int err;
 
        snd_azf3328_dbgcallenter();
-       if (dev >= SNDRV_CARDS)
-               return -ENODEV;
+       if (dev >= SNDRV_CARDS) {
+               err = -ENODEV;
+               goto out;
+       }
        if (!enable[dev]) {
                dev++;
-               return -ENOENT;
+               err = -ENOENT;
+               goto out;
        }
 
        err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
        if (err < 0)
-               return err;
+               goto out;
 
        strcpy(card->driver, "AZF3328");
        strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
index 14fdcf2..5ac0e21 100644 (file)
@@ -531,17 +531,10 @@ static const struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
-                     ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
        SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
        SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
index e125c60..9a1aa09 100644 (file)
@@ -4484,6 +4484,22 @@ static void alc269_fixup_pcm_44k(struct hda_codec *codec,
        spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
 }
 
+static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
+                                    const struct alc_fixup *fix, int action)
+{
+       int coef;
+
+       if (action != ALC_FIXUP_ACT_INIT)
+               return;
+       /* The digital-mic unit sends PDM (differential signal) instead of
+        * the standard PCM, thus you can't record a valid mono stream as is.
+        * Below is a workaround specific to ALC269 to control the dmic
+        * signal source as mono.
+        */
+       coef = alc_read_coef_idx(codec, 0x07);
+       alc_write_coef_idx(codec, 0x07, coef | 0x80);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -4494,6 +4510,7 @@ enum {
        ALC275_FIXUP_SONY_HWEQ,
        ALC271_FIXUP_DMIC,
        ALC269_FIXUP_PCM_44K,
+       ALC269_FIXUP_STEREO_DMIC,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -4556,10 +4573,19 @@ static const struct alc_fixup alc269_fixups[] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc269_fixup_pcm_44k,
        },
+       [ALC269_FIXUP_STEREO_DMIC] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_stereo_dmic,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
index aa376b5..5145b66 100644 (file)
@@ -673,6 +673,7 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
 static int stac_vrefout_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
 {
@@ -696,6 +697,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
 
        return 1;
 }
+#endif
 
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
index 84d8798..4ebfbd8 100644 (file)
@@ -2084,7 +2084,7 @@ static int via_auto_create_speaker_ctls(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
        struct nid_path *path;
        bool check_dac;
-       hda_nid_t pin, dac;
+       hda_nid_t pin, dac = 0;
        int err;
 
        pin = spec->autocfg.speaker_pins[0];
index 6edc67c..493e394 100644 (file)
@@ -1339,6 +1339,10 @@ static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period)
                break;
        case MADIface:
                freq_const = 131072000000000ULL;
+               break;
+       default:
+               snd_BUG();
+               return 0;
        }
 
        return div_u64(freq_const, period);
@@ -1356,16 +1360,19 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
 
        switch (hdspm->io_type) {
        case MADIface:
-         n = 131072000000000ULL;  /* 125 MHz */
-         break;
+               n = 131072000000000ULL;  /* 125 MHz */
+               break;
        case MADI:
        case AES32:
-         n = 110069313433624ULL;  /* 105 MHz */
-         break;
+               n = 110069313433624ULL;  /* 105 MHz */
+               break;
        case RayDAT:
        case AIO:
-         n = 104857600000000ULL;  /* 100 MHz */
-         break;
+               n = 104857600000000ULL;  /* 100 MHz */
+               break;
+       default:
+               snd_BUG();
+               return;
        }
 
        n = div_u64(n, rate);
index 379b2e3..665d924 100644 (file)
@@ -78,7 +78,6 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8900 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
-       select SND_SOC_WM8915 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
@@ -95,6 +94,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8993 if I2C
        select SND_SOC_WM8994 if MFD_WM8994
        select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8996 if I2C
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9090 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -329,9 +329,6 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
        tristate
 
-config SND_SOC_WM8915
-       tristate
-
 config SND_SOC_WM8940
         tristate
 
@@ -380,6 +377,9 @@ config SND_SOC_WM8994
 config SND_SOC_WM8995
        tristate
 
+config SND_SOC_WM8996
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
index da9990f..5119a7e 100644 (file)
@@ -63,7 +63,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
-snd-soc-wm8915-objs := wm8915.o
+snd-soc-wm8996-objs := wm8996.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
@@ -160,7 +160,7 @@ obj-$(CONFIG_SND_SOC_WM8804)        += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
-obj-$(CONFIG_SND_SOC_WM8915)   += snd-soc-wm8915.o
+obj-$(CONFIG_SND_SOC_WM8996)   += snd-soc-wm8996.o
 obj-$(CONFIG_SND_SOC_WM8940)   += snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)   += snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
index 76258f2..7e4066e 100644 (file)
 #define SGTL5000_DAP_REG_OFFSET        0x0100
 #define SGTL5000_MAX_REG_OFFSET        0x013A
 
-/* default value of sgtl5000 registers except DAP */
-static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] =  {
-       0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */
-       0x0000, /* 0x0002, CHIP_DIG_POWER. */
-       0x0008, /* 0x0004, CHIP_CKL_CTRL */
-       0x0010, /* 0x0006, CHIP_I2S_CTRL */
-       0x0000, /* 0x0008, reserved */
-       0x0008, /* 0x000A, CHIP_SSS_CTRL */
-       0x0000, /* 0x000C, reserved */
-       0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */
-       0x3c3c, /* 0x0010, CHIP_DAC_VOL */
-       0x0000, /* 0x0012, reserved */
-       0x015f, /* 0x0014, CHIP_PAD_STRENGTH */
-       0x0000, /* 0x0016, reserved */
-       0x0000, /* 0x0018, reserved */
-       0x0000, /* 0x001A, reserved */
-       0x0000, /* 0x001E, reserved */
-       0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */
-       0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */
-       0x0111, /* 0x0024, CHIP_ANN_CTRL */
-       0x0000, /* 0x0026, CHIP_LINREG_CTRL */
-       0x0000, /* 0x0028, CHIP_REF_CTRL */
-       0x0000, /* 0x002A, CHIP_MIC_CTRL */
-       0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */
-       0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */
-       0x7060, /* 0x0030, CHIP_ANA_POWER */
-       0x5000, /* 0x0032, CHIP_PLL_CTRL */
-       0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */
-       0x0000, /* 0x0036, CHIP_ANA_STATUS */
-       0x0000, /* 0x0038, reserved */
-       0x0000, /* 0x003A, CHIP_ANA_TEST2 */
-       0x0000, /* 0x003C, CHIP_SHORT_CTRL */
-       0x0000, /* reserved */
-};
-
-/* default value of dap registers */
-static const u16 sgtl5000_dap_regs[] = {
-       0x0000, /* 0x0100, DAP_CONTROL */
-       0x0000, /* 0x0102, DAP_PEQ */
-       0x0040, /* 0x0104, DAP_BASS_ENHANCE */
-       0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */
-       0x0000, /* 0x0108, DAP_AUDIO_EQ */
-       0x0040, /* 0x010A, DAP_SGTL_SURROUND */
-       0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */
-       0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */
-       0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */
-       0x0000, /* 0x0112, reserved */
-       0x0000, /* 0x0114, reserved */
-       0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */
-       0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */
-       0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */
-       0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */
-       0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */
-       0x8000, /* 0x0120, DAP_MAIN_CHAN */
-       0x0000, /* 0x0122, DAP_MIX_CHAN */
-       0x0510, /* 0x0124, DAP_AVC_CTRL */
-       0x1473, /* 0x0126, DAP_AVC_THRESHOLD */
-       0x0028, /* 0x0128, DAP_AVC_ATTACK */
-       0x0050, /* 0x012A, DAP_AVC_DECAY */
-       0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */
-       0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */
-       0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */
-       0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */
-       0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */
-       0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */
-       0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */
-       0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */
+/* default value of sgtl5000 registers */
+static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] =  {
+       [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
+       [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
+       [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
+       [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
+       [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
+       [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
+       [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
+       [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
+       [SGTL5000_CHIP_ANA_POWER] = 0x7060,
+       [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
+       [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
+       [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
+       [SGTL5000_DAP_SURROUND] = 0x0040,
+       [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
+       [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
+       [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
+       [SGTL5000_DAP_AVC_CTRL] = 0x0510,
+       [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
+       [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
+       [SGTL5000_DAP_AVC_DECAY] = 0x0050,
 };
 
 /* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -1023,12 +981,10 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
 {
        u16 *cache = codec->reg_cache;
-       int i;
-       int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1;
+       u16 reg;
 
        /* restore regular registers */
-       for (i = 0; i < regular_regs; i++) {
-               int reg = i << 1;
+       for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
 
                /* this regs depends on the others */
                if (reg == SGTL5000_CHIP_ANA_POWER ||
@@ -1038,35 +994,31 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
                        reg == SGTL5000_CHIP_CLK_CTRL)
                        continue;
 
-               snd_soc_write(codec, reg, cache[i]);
+               snd_soc_write(codec, reg, cache[reg]);
        }
 
        /* restore dap registers */
-       for (i = SGTL5000_DAP_REG_OFFSET >> 1;
-                       i < SGTL5000_MAX_REG_OFFSET >> 1; i++) {
-               int reg = i << 1;
-
-               snd_soc_write(codec, reg, cache[i]);
-       }
+       for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
+               snd_soc_write(codec, reg, cache[reg]);
 
        /*
         * restore power and other regs according
         * to set_power() and set_clock()
         */
        snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
-                       cache[SGTL5000_CHIP_LINREG_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_LINREG_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
-                       cache[SGTL5000_CHIP_ANA_POWER >> 1]);
+                       cache[SGTL5000_CHIP_ANA_POWER]);
 
        snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
-                       cache[SGTL5000_CHIP_CLK_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_CLK_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
-                       cache[SGTL5000_CHIP_REF_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_REF_CTRL]);
 
        snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
-                       cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]);
+                       cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
        return 0;
 }
 
@@ -1454,16 +1406,6 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
        if (!sgtl5000)
                return -ENOMEM;
 
-       /*
-        * copy DAP default values to default value array.
-        * sgtl5000 register space has a big hole, merge it
-        * at init phase makes life easy.
-        * FIXME: should we drop 'const' of sgtl5000_regs?
-        */
-       memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)),
-                       sgtl5000_dap_regs,
-                       SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET);
-
        i2c_set_clientdata(client, sgtl5000);
 
        ret = snd_soc_register_codec(&client->dev,
index 38f38fd..d0003cc 100644 (file)
@@ -778,11 +778,19 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct spi_device_id wm8750_spi_ids[] = {
+       { "wm8750", 0 },
+       { "wm8987", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
+
 static struct spi_driver wm8750_spi_driver = {
        .driver = {
                .name   = "wm8750-codec",
                .owner  = THIS_MODULE,
        },
+       .id_table       = wm8750_spi_ids,
        .probe          = wm8750_spi_probe,
        .remove         = __devexit_p(wm8750_spi_remove),
 };
index 43e3d76..4ad8ebd 100644 (file)
@@ -2046,8 +2046,13 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 /* power down chip */
 static int wm8903_remove(struct snd_soc_codec *codec)
 {
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+
        wm8903_free_gpio(codec);
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       if (wm8903->irq)
+               free_irq(wm8903->irq, codec);
+
        return 0;
 }
 
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c
deleted file mode 100644 (file)
index 423baa9..0000000
+++ /dev/null
@@ -1,2995 +0,0 @@
-/*
- * wm8915.c - WM8915 audio codec interface
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/gcd.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/regulator/consumer.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <trace/events/asoc.h>
-
-#include <sound/wm8915.h>
-#include "wm8915.h"
-
-#define WM8915_AIFS 2
-
-#define HPOUT1L 1
-#define HPOUT1R 2
-#define HPOUT2L 4
-#define HPOUT2R 8
-
-#define WM8915_NUM_SUPPLIES 4
-static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
-       "DBVDD",
-       "AVDD1",
-       "AVDD2",
-       "CPVDD",
-};
-
-struct wm8915_priv {
-       struct snd_soc_codec *codec;
-
-       int ldo1ena;
-
-       int sysclk;
-       int sysclk_src;
-
-       int fll_src;
-       int fll_fref;
-       int fll_fout;
-
-       struct completion fll_lock;
-
-       u16 dcs_pending;
-       struct completion dcs_done;
-
-       u16 hpout_ena;
-       u16 hpout_pending;
-
-       struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES];
-       struct notifier_block disable_nb[WM8915_NUM_SUPPLIES];
-
-       struct wm8915_pdata pdata;
-
-       int rx_rate[WM8915_AIFS];
-       int bclk_rate[WM8915_AIFS];
-
-       /* Platform dependant ReTune mobile configuration */
-       int num_retune_mobile_texts;
-       const char **retune_mobile_texts;
-       int retune_mobile_cfg[2];
-       struct soc_enum retune_mobile_enum;
-
-       struct snd_soc_jack *jack;
-       bool detecting;
-       bool jack_mic;
-       wm8915_polarity_fn polarity_cb;
-
-#ifdef CONFIG_GPIOLIB
-       struct gpio_chip gpio_chip;
-#endif
-};
-
-/* We can't use the same notifier block for more than one supply and
- * there's no way I can see to get from a callback to the caller
- * except container_of().
- */
-#define WM8915_REGULATOR_EVENT(n) \
-static int wm8915_regulator_event_##n(struct notifier_block *nb, \
-                                   unsigned long event, void *data)    \
-{ \
-       struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \
-                                                 disable_nb[n]); \
-       if (event & REGULATOR_EVENT_DISABLE) { \
-               wm8915->codec->cache_sync = 1; \
-       } \
-       return 0; \
-}
-
-WM8915_REGULATOR_EVENT(0)
-WM8915_REGULATOR_EVENT(1)
-WM8915_REGULATOR_EVENT(2)
-WM8915_REGULATOR_EVENT(3)
-
-static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
-       [WM8915_SOFTWARE_RESET] = 0x8915,
-       [WM8915_POWER_MANAGEMENT_7] = 0x10,
-       [WM8915_DAC1_HPOUT1_VOLUME] = 0x88,
-       [WM8915_DAC2_HPOUT2_VOLUME] = 0x88,
-       [WM8915_DAC1_LEFT_VOLUME] = 0x2c0,
-       [WM8915_DAC1_RIGHT_VOLUME] = 0x2c0,
-       [WM8915_DAC2_LEFT_VOLUME] = 0x2c0,
-       [WM8915_DAC2_RIGHT_VOLUME] = 0x2c0,
-       [WM8915_OUTPUT1_LEFT_VOLUME] = 0x80,
-       [WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80,
-       [WM8915_OUTPUT2_LEFT_VOLUME] = 0x80,
-       [WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80,
-       [WM8915_MICBIAS_1] = 0x39,
-       [WM8915_MICBIAS_2] = 0x39,
-       [WM8915_LDO_1] = 0x3,
-       [WM8915_LDO_2] = 0x13,
-       [WM8915_ACCESSORY_DETECT_MODE_1] = 0x4,
-       [WM8915_HEADPHONE_DETECT_1] = 0x20,
-       [WM8915_MIC_DETECT_1] = 0x7600,
-       [WM8915_MIC_DETECT_2] = 0xbf,
-       [WM8915_CHARGE_PUMP_1] = 0x1f25,
-       [WM8915_CHARGE_PUMP_2] = 0xab19,
-       [WM8915_DC_SERVO_5] = 0x2a2a,
-       [WM8915_CONTROL_INTERFACE_1] = 0x8004,
-       [WM8915_CLOCKING_1] = 0x10,
-       [WM8915_AIF_RATE] = 0x83,
-       [WM8915_FLL_CONTROL_4] = 0x5dc0,
-       [WM8915_FLL_CONTROL_5] = 0xc84,
-       [WM8915_FLL_EFS_2] = 0x2,
-       [WM8915_AIF1_TX_LRCLK_1] = 0x80,
-       [WM8915_AIF1_TX_LRCLK_2] = 0x8,
-       [WM8915_AIF1_RX_LRCLK_1] = 0x80,
-       [WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8915_AIF1TX_TEST] = 0x7,
-       [WM8915_AIF2_TX_LRCLK_1] = 0x80,
-       [WM8915_AIF2_TX_LRCLK_2] = 0x8,
-       [WM8915_AIF2_RX_LRCLK_1] = 0x80,
-       [WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
-       [WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818,
-       [WM8915_AIF2TX_TEST] = 0x1,
-       [WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP1_TX_FILTERS] = 0x2000,
-       [WM8915_DSP1_RX_FILTERS_1] = 0x200,
-       [WM8915_DSP1_RX_FILTERS_2] = 0x10,
-       [WM8915_DSP1_DRC_1] = 0x98,
-       [WM8915_DSP1_DRC_2] = 0x845,
-       [WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318,
-       [WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300,
-       [WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400,
-       [WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564,
-       [WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559,
-       [WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0,
-       [WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0,
-       [WM8915_DSP2_TX_FILTERS] = 0x2000,
-       [WM8915_DSP2_RX_FILTERS_1] = 0x200,
-       [WM8915_DSP2_RX_FILTERS_2] = 0x10,
-       [WM8915_DSP2_DRC_1] = 0x98,
-       [WM8915_DSP2_DRC_2] = 0x845,
-       [WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318,
-       [WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300,
-       [WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca,
-       [WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400,
-       [WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
-       [WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
-       [WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145,
-       [WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75,
-       [WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
-       [WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
-       [WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373,
-       [WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54,
-       [WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558,
-       [WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e,
-       [WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829,
-       [WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
-       [WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
-       [WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564,
-       [WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559,
-       [WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
-       [WM8915_OVERSAMPLING] = 0xd,
-       [WM8915_SIDETONE] = 0x1040,
-       [WM8915_GPIO_1] = 0xa101,
-       [WM8915_GPIO_2] = 0xa101,
-       [WM8915_GPIO_3] = 0xa101,
-       [WM8915_GPIO_4] = 0xa101,
-       [WM8915_GPIO_5] = 0xa101,
-       [WM8915_PULL_CONTROL_2] = 0x140,
-       [WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f,
-       [WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
-       [WM8915_RIGHT_PDM_SPEAKER] = 0x1,
-       [WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
-       [WM8915_PDM_SPEAKER_VOLUME] = 0x66,
-       [WM8915_WRITE_SEQUENCER_0] = 0x1,
-       [WM8915_WRITE_SEQUENCER_1] = 0x1,
-       [WM8915_WRITE_SEQUENCER_3] = 0x6,
-       [WM8915_WRITE_SEQUENCER_4] = 0x40,
-       [WM8915_WRITE_SEQUENCER_5] = 0x1,
-       [WM8915_WRITE_SEQUENCER_6] = 0xf,
-       [WM8915_WRITE_SEQUENCER_7] = 0x6,
-       [WM8915_WRITE_SEQUENCER_8] = 0x1,
-       [WM8915_WRITE_SEQUENCER_9] = 0x3,
-       [WM8915_WRITE_SEQUENCER_10] = 0x104,
-       [WM8915_WRITE_SEQUENCER_12] = 0x60,
-       [WM8915_WRITE_SEQUENCER_13] = 0x11,
-       [WM8915_WRITE_SEQUENCER_14] = 0x401,
-       [WM8915_WRITE_SEQUENCER_16] = 0x50,
-       [WM8915_WRITE_SEQUENCER_17] = 0x3,
-       [WM8915_WRITE_SEQUENCER_18] = 0x100,
-       [WM8915_WRITE_SEQUENCER_20] = 0x51,
-       [WM8915_WRITE_SEQUENCER_21] = 0x3,
-       [WM8915_WRITE_SEQUENCER_22] = 0x104,
-       [WM8915_WRITE_SEQUENCER_23] = 0xa,
-       [WM8915_WRITE_SEQUENCER_24] = 0x60,
-       [WM8915_WRITE_SEQUENCER_25] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_26] = 0x502,
-       [WM8915_WRITE_SEQUENCER_27] = 0x100,
-       [WM8915_WRITE_SEQUENCER_28] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_32] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_36] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_40] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_44] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_48] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_52] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_56] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_60] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_64] = 0x1,
-       [WM8915_WRITE_SEQUENCER_65] = 0x1,
-       [WM8915_WRITE_SEQUENCER_67] = 0x6,
-       [WM8915_WRITE_SEQUENCER_68] = 0x40,
-       [WM8915_WRITE_SEQUENCER_69] = 0x1,
-       [WM8915_WRITE_SEQUENCER_70] = 0xf,
-       [WM8915_WRITE_SEQUENCER_71] = 0x6,
-       [WM8915_WRITE_SEQUENCER_72] = 0x1,
-       [WM8915_WRITE_SEQUENCER_73] = 0x3,
-       [WM8915_WRITE_SEQUENCER_74] = 0x104,
-       [WM8915_WRITE_SEQUENCER_76] = 0x60,
-       [WM8915_WRITE_SEQUENCER_77] = 0x11,
-       [WM8915_WRITE_SEQUENCER_78] = 0x401,
-       [WM8915_WRITE_SEQUENCER_80] = 0x50,
-       [WM8915_WRITE_SEQUENCER_81] = 0x3,
-       [WM8915_WRITE_SEQUENCER_82] = 0x100,
-       [WM8915_WRITE_SEQUENCER_84] = 0x60,
-       [WM8915_WRITE_SEQUENCER_85] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_86] = 0x502,
-       [WM8915_WRITE_SEQUENCER_87] = 0x100,
-       [WM8915_WRITE_SEQUENCER_88] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_92] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_96] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_100] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_104] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_108] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_112] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_116] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_120] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_124] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_128] = 0x1,
-       [WM8915_WRITE_SEQUENCER_129] = 0x1,
-       [WM8915_WRITE_SEQUENCER_131] = 0x6,
-       [WM8915_WRITE_SEQUENCER_132] = 0x40,
-       [WM8915_WRITE_SEQUENCER_133] = 0x1,
-       [WM8915_WRITE_SEQUENCER_134] = 0xf,
-       [WM8915_WRITE_SEQUENCER_135] = 0x6,
-       [WM8915_WRITE_SEQUENCER_136] = 0x1,
-       [WM8915_WRITE_SEQUENCER_137] = 0x3,
-       [WM8915_WRITE_SEQUENCER_138] = 0x106,
-       [WM8915_WRITE_SEQUENCER_140] = 0x61,
-       [WM8915_WRITE_SEQUENCER_141] = 0x11,
-       [WM8915_WRITE_SEQUENCER_142] = 0x401,
-       [WM8915_WRITE_SEQUENCER_144] = 0x50,
-       [WM8915_WRITE_SEQUENCER_145] = 0x3,
-       [WM8915_WRITE_SEQUENCER_146] = 0x102,
-       [WM8915_WRITE_SEQUENCER_148] = 0x51,
-       [WM8915_WRITE_SEQUENCER_149] = 0x3,
-       [WM8915_WRITE_SEQUENCER_150] = 0x106,
-       [WM8915_WRITE_SEQUENCER_151] = 0xa,
-       [WM8915_WRITE_SEQUENCER_152] = 0x61,
-       [WM8915_WRITE_SEQUENCER_153] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_154] = 0x502,
-       [WM8915_WRITE_SEQUENCER_155] = 0x100,
-       [WM8915_WRITE_SEQUENCER_156] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_160] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_164] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_168] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_172] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_176] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_180] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_184] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_188] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_192] = 0x1,
-       [WM8915_WRITE_SEQUENCER_193] = 0x1,
-       [WM8915_WRITE_SEQUENCER_195] = 0x6,
-       [WM8915_WRITE_SEQUENCER_196] = 0x40,
-       [WM8915_WRITE_SEQUENCER_197] = 0x1,
-       [WM8915_WRITE_SEQUENCER_198] = 0xf,
-       [WM8915_WRITE_SEQUENCER_199] = 0x6,
-       [WM8915_WRITE_SEQUENCER_200] = 0x1,
-       [WM8915_WRITE_SEQUENCER_201] = 0x3,
-       [WM8915_WRITE_SEQUENCER_202] = 0x106,
-       [WM8915_WRITE_SEQUENCER_204] = 0x61,
-       [WM8915_WRITE_SEQUENCER_205] = 0x11,
-       [WM8915_WRITE_SEQUENCER_206] = 0x401,
-       [WM8915_WRITE_SEQUENCER_208] = 0x50,
-       [WM8915_WRITE_SEQUENCER_209] = 0x3,
-       [WM8915_WRITE_SEQUENCER_210] = 0x102,
-       [WM8915_WRITE_SEQUENCER_212] = 0x61,
-       [WM8915_WRITE_SEQUENCER_213] = 0x3b,
-       [WM8915_WRITE_SEQUENCER_214] = 0x502,
-       [WM8915_WRITE_SEQUENCER_215] = 0x100,
-       [WM8915_WRITE_SEQUENCER_216] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_220] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_224] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_228] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_232] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_236] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_240] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_244] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_248] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_252] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_256] = 0x60,
-       [WM8915_WRITE_SEQUENCER_258] = 0x601,
-       [WM8915_WRITE_SEQUENCER_260] = 0x50,
-       [WM8915_WRITE_SEQUENCER_262] = 0x100,
-       [WM8915_WRITE_SEQUENCER_264] = 0x1,
-       [WM8915_WRITE_SEQUENCER_266] = 0x104,
-       [WM8915_WRITE_SEQUENCER_267] = 0x100,
-       [WM8915_WRITE_SEQUENCER_268] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_272] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_276] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_280] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_284] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_288] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_292] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_296] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_300] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_304] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_308] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_312] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_316] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_320] = 0x61,
-       [WM8915_WRITE_SEQUENCER_322] = 0x601,
-       [WM8915_WRITE_SEQUENCER_324] = 0x50,
-       [WM8915_WRITE_SEQUENCER_326] = 0x102,
-       [WM8915_WRITE_SEQUENCER_328] = 0x1,
-       [WM8915_WRITE_SEQUENCER_330] = 0x106,
-       [WM8915_WRITE_SEQUENCER_331] = 0x100,
-       [WM8915_WRITE_SEQUENCER_332] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_336] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_340] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_344] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_348] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_352] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_356] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_360] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_364] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_368] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_372] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_376] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_380] = 0x2fff,
-       [WM8915_WRITE_SEQUENCER_384] = 0x60,
-       [WM8915_WRITE_SEQUENCER_386] = 0x601,
-       [WM8915_WRITE_SEQUENCER_388] = 0x61,
-       [WM8915_WRITE_SEQUENCER_390] = 0x601,
-       [WM8915_WRITE_SEQUENCER_392] = 0x50,
-       [WM8915_WRITE_SEQUENCER_394] = 0x300,
-       [WM8915_WRITE_SEQUENCER_396] = 0x1,
-       [WM8915_WRITE_SEQUENCER_398] = 0x304,
-       [WM8915_WRITE_SEQUENCER_400] = 0x40,
-       [WM8915_WRITE_SEQUENCER_402] = 0xf,
-       [WM8915_WRITE_SEQUENCER_404] = 0x1,
-       [WM8915_WRITE_SEQUENCER_407] = 0x100,
-};
-
-static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
-static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
-static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
-static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
-static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
-static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
-static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
-
-static const char *sidetone_hpf_text[] = {
-       "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
-};
-
-static const struct soc_enum sidetone_hpf =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text);
-
-static const char *hpf_mode_text[] = {
-       "HiFi", "Custom", "Voice"
-};
-
-static const struct soc_enum dsp1tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
-
-static const struct soc_enum dsp2tx_hpf_mode =
-       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
-
-static const char *hpf_cutoff_text[] = {
-       "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
-};
-
-static const struct soc_enum dsp1tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
-
-static const struct soc_enum dsp2tx_hpf_cutoff =
-       SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
-
-static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-       int base, best, best_val, save, i, cfg, iface;
-
-       if (!wm8915->num_retune_mobile_texts)
-               return;
-
-       switch (block) {
-       case 0:
-               base = WM8915_DSP1_RX_EQ_GAINS_1;
-               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
-                   WM8915_DSP1RX_SRC)
-                       iface = 1;
-               else
-                       iface = 0;
-               break;
-       case 1:
-               base = WM8915_DSP1_RX_EQ_GAINS_2;
-               if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
-                   WM8915_DSP2RX_SRC)
-                       iface = 1;
-               else
-                       iface = 0;
-               break;
-       default:
-               return;
-       }
-
-       /* Find the version of the currently selected configuration
-        * with the nearest sample rate. */
-       cfg = wm8915->retune_mobile_cfg[block];
-       best = 0;
-       best_val = INT_MAX;
-       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
-               if (strcmp(pdata->retune_mobile_cfgs[i].name,
-                          wm8915->retune_mobile_texts[cfg]) == 0 &&
-                   abs(pdata->retune_mobile_cfgs[i].rate
-                       - wm8915->rx_rate[iface]) < best_val) {
-                       best = i;
-                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
-                                      - wm8915->rx_rate[iface]);
-               }
-       }
-
-       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
-               block,
-               pdata->retune_mobile_cfgs[best].name,
-               pdata->retune_mobile_cfgs[best].rate,
-               wm8915->rx_rate[iface]);
-
-       /* The EQ will be disabled while reconfiguring it, remember the
-        * current configuration. 
-        */
-       save = snd_soc_read(codec, base);
-       save &= WM8915_DSP1RX_EQ_ENA;
-
-       for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
-               snd_soc_update_bits(codec, base + i, 0xffff,
-                                   pdata->retune_mobile_cfgs[best].regs[i]);
-
-       snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save);
-}
-
-/* Icky as hell but saves code duplication */
-static int wm8915_get_retune_mobile_block(const char *name)
-{
-       if (strcmp(name, "DSP1 EQ Mode") == 0)
-               return 0;
-       if (strcmp(name, "DSP2 EQ Mode") == 0)
-               return 1;
-       return -EINVAL;
-}
-
-static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
-       int value = ucontrol->value.integer.value[0];
-
-       if (block < 0)
-               return block;
-
-       if (value >= pdata->num_retune_mobile_cfgs)
-               return -EINVAL;
-
-       wm8915->retune_mobile_cfg[block] = value;
-
-       wm8915_set_retune_mobile(codec, block);
-
-       return 0;
-}
-
-static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
-
-       ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block];
-
-       return 0;
-}
-
-static const struct snd_kcontrol_new wm8915_snd_controls[] = {
-SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME,
-                WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
-SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME,
-            WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
-
-SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES,
-              0, 5, 24, 0, sidetone_tlv),
-SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES,
-              0, 5, 24, 0, sidetone_tlv),
-SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0),
-SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
-SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0),
-
-SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME,
-                WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME,
-                WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
-
-SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS,
-          13, 1, 0),
-SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0),
-SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
-SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
-
-SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS,
-          13, 1, 0),
-SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0),
-SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
-SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
-
-SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME,
-                WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME,
-                WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME,
-                WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME,
-            WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1),
-
-SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME,
-                WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
-SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME,
-            WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1),
-
-SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0),
-SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0),
-SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0),
-SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0),
-
-SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0),
-SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0),
-
-SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4,
-              8, 0, out_digital_tlv),
-SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4,
-              8, 0, out_digital_tlv),
-
-SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME,
-                WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
-SOC_DOUBLE_R("Output 1 ZC Switch",  WM8915_OUTPUT1_LEFT_VOLUME,
-            WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
-
-SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME,
-                WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
-SOC_DOUBLE_R("Output 2 ZC Switch",  WM8915_OUTPUT2_LEFT_VOLUME,
-            WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
-
-SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
-              spk_tlv),
-SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER,
-            WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1),
-SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER,
-            WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0),
-
-SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
-SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new wm8915_eq_controls[] = {
-SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
-              eq_tlv),
-
-SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
-              eq_tlv),
-SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
-              eq_tlv),
-};
-
-static int cp_event(struct snd_soc_dapm_widget *w,
-                   struct snd_kcontrol *kcontrol, int event)
-{
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               msleep(5);
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int rmv_short_event(struct snd_soc_dapm_widget *w,
-                          struct snd_kcontrol *kcontrol, int event)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
-
-       /* Record which outputs we enabled */
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMD:
-               wm8915->hpout_pending &= ~w->shift;
-               break;
-       case SND_SOC_DAPM_PRE_PMU:
-               wm8915->hpout_pending |= w->shift;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
-{
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
-       unsigned long timeout = 200;
-
-       snd_soc_write(codec, WM8915_DC_SERVO_2, mask);
-
-       /* Use the interrupt if possible */
-       do {
-               if (i2c->irq) {
-                       timeout = wait_for_completion_timeout(&wm8915->dcs_done,
-                                                             msecs_to_jiffies(200));
-                       if (timeout == 0)
-                               dev_err(codec->dev, "DC servo timed out\n");
-
-               } else {
-                       msleep(1);
-                       if (--i) {
-                               timeout = 0;
-                               break;
-                       }
-               }
-
-               ret = snd_soc_read(codec, WM8915_DC_SERVO_2);
-               dev_dbg(codec->dev, "DC servo state: %x\n", ret);
-       } while (ret & mask);
-
-       if (timeout == 0)
-               dev_err(codec->dev, "DC servo timed out for %x\n", mask);
-       else
-               dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
-}
-
-static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm,
-                               enum snd_soc_dapm_type event, int subseq)
-{
-       struct snd_soc_codec *codec = container_of(dapm,
-                                                  struct snd_soc_codec, dapm);
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       u16 val, mask;
-
-       /* Complete any pending DC servo starts */
-       if (wm8915->dcs_pending) {
-               dev_dbg(codec->dev, "Starting DC servo for %x\n",
-                       wm8915->dcs_pending);
-
-               /* Trigger a startup sequence */
-               wait_for_dc_servo(codec, wm8915->dcs_pending
-                                        << WM8915_DCS_TRIG_STARTUP_0_SHIFT);
-
-               wm8915->dcs_pending = 0;
-       }
-
-       if (wm8915->hpout_pending != wm8915->hpout_ena) {
-               dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
-                       wm8915->hpout_ena, wm8915->hpout_pending);
-
-               val = 0;
-               mask = 0;
-               if (wm8915->hpout_pending & HPOUT1L) {
-                       val |= WM8915_HPOUT1L_RMV_SHORT;
-                       mask |= WM8915_HPOUT1L_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT1L_RMV_SHORT |
-                               WM8915_HPOUT1L_OUTP |
-                               WM8915_HPOUT1L_DLY;
-               }
-
-               if (wm8915->hpout_pending & HPOUT1R) {
-                       val |= WM8915_HPOUT1R_RMV_SHORT;
-                       mask |= WM8915_HPOUT1R_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT1R_RMV_SHORT |
-                               WM8915_HPOUT1R_OUTP |
-                               WM8915_HPOUT1R_DLY;
-               }
-
-               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val);
-
-               val = 0;
-               mask = 0;
-               if (wm8915->hpout_pending & HPOUT2L) {
-                       val |= WM8915_HPOUT2L_RMV_SHORT;
-                       mask |= WM8915_HPOUT2L_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT2L_RMV_SHORT |
-                               WM8915_HPOUT2L_OUTP |
-                               WM8915_HPOUT2L_DLY;
-               }
-
-               if (wm8915->hpout_pending & HPOUT2R) {
-                       val |= WM8915_HPOUT2R_RMV_SHORT;
-                       mask |= WM8915_HPOUT2R_RMV_SHORT;
-               } else {
-                       mask |= WM8915_HPOUT2R_RMV_SHORT |
-                               WM8915_HPOUT2R_OUTP |
-                               WM8915_HPOUT2R_DLY;
-               }
-
-               snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val);
-
-               wm8915->hpout_ena = wm8915->hpout_pending;
-       }
-}
-
-static int dcs_start(struct snd_soc_dapm_widget *w,
-                    struct snd_kcontrol *kcontrol, int event)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               wm8915->dcs_pending |= 1 << w->shift;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const char *sidetone_text[] = {
-       "IN1", "IN2",
-};
-
-static const struct soc_enum left_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text);
-
-static const struct snd_kcontrol_new left_sidetone =
-       SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
-
-static const struct soc_enum right_sidetone_enum =
-       SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text);
-
-static const struct snd_kcontrol_new right_sidetone =
-       SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
-
-static const char *spk_text[] = {
-       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
-};
-
-static const struct soc_enum spkl_enum =
-       SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text);
-
-static const struct snd_kcontrol_new spkl_mux =
-       SOC_DAPM_ENUM("SPKL", spkl_enum);
-
-static const struct soc_enum spkr_enum =
-       SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
-
-static const struct snd_kcontrol_new spkr_mux =
-       SOC_DAPM_ENUM("SPKR", spkr_enum);
-
-static const char *dsp1rx_text[] = {
-       "AIF1", "AIF2"
-};
-
-static const struct soc_enum dsp1rx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
-
-static const struct snd_kcontrol_new dsp1rx =
-       SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
-
-static const char *dsp2rx_text[] = {
-        "AIF2", "AIF1"
-};
-
-static const struct soc_enum dsp2rx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
-
-static const struct snd_kcontrol_new dsp2rx =
-       SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
-
-static const char *aif2tx_text[] = {
-       "DSP2", "DSP1", "AIF1"
-};
-
-static const struct soc_enum aif2tx_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
-
-static const struct snd_kcontrol_new aif2tx =
-       SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
-
-static const char *inmux_text[] = {
-       "ADC", "DMIC1", "DMIC2"
-};
-
-static const struct soc_enum in1_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text);
-
-static const struct snd_kcontrol_new in1_mux =
-       SOC_DAPM_ENUM("IN1 Mux", in1_enum);
-
-static const struct soc_enum in2_enum =
-       SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text);
-
-static const struct snd_kcontrol_new in2_mux =
-       SOC_DAPM_ENUM("IN2 Mux", in2_enum);
-
-static const struct snd_kcontrol_new dac2r_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac2l_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac1r_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dac1l_mix[] = {
-SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
-               5, 1, 0),
-SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
-               4, 1, 0),
-SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
-SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp1txl[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp1txr[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp2txl[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-static const struct snd_kcontrol_new dsp2txr[] = {
-SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
-               1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
-               0, 1, 0),
-};
-
-
-static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = {
-SND_SOC_DAPM_INPUT("IN1LN"),
-SND_SOC_DAPM_INPUT("IN1LP"),
-SND_SOC_DAPM_INPUT("IN1RN"),
-SND_SOC_DAPM_INPUT("IN1RP"),
-
-SND_SOC_DAPM_INPUT("IN2LN"),
-SND_SOC_DAPM_INPUT("IN2LP"),
-SND_SOC_DAPM_INPUT("IN2RN"),
-SND_SOC_DAPM_INPUT("IN2RP"),
-
-SND_SOC_DAPM_INPUT("DMIC1DAT"),
-SND_SOC_DAPM_INPUT("DMIC2DAT"),
-
-SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event,
-                     SND_SOC_DAPM_POST_PMU),
-
-SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
-SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0),
-SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
-
-SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
-
-SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-
-SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
-
-SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
-
-SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0),
-SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0),
-SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0),
-SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0),
-
-SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0),
-SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0),
-
-SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
-SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
-
-SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0),
-SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0),
-SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0),
-SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0),
-
-SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0,
-                  dsp2txl, ARRAY_SIZE(dsp2txl)),
-SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0,
-                  dsp2txr, ARRAY_SIZE(dsp2txr)),
-SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0,
-                  dsp1txl, ARRAY_SIZE(dsp1txl)),
-SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0,
-                  dsp1txr, ARRAY_SIZE(dsp1txr)),
-
-SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
-                  dac2l_mix, ARRAY_SIZE(dac2l_mix)),
-SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
-                  dac2r_mix, ARRAY_SIZE(dac2r_mix)),
-SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
-                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
-SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
-                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
-
-SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0),
-SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0),
-SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0),
-SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
-                   WM8915_POWER_MANAGEMENT_4, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
-                   WM8915_POWER_MANAGEMENT_4, 8, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
-                   WM8915_POWER_MANAGEMENT_6, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
-                   WM8915_POWER_MANAGEMENT_6, 8, 0),
-
-SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
-                   WM8915_POWER_MANAGEMENT_4, 5, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
-                   WM8915_POWER_MANAGEMENT_4, 4, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
-                   WM8915_POWER_MANAGEMENT_4, 3, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
-                   WM8915_POWER_MANAGEMENT_4, 2, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
-                   WM8915_POWER_MANAGEMENT_4, 1, 0),
-SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
-                   WM8915_POWER_MANAGEMENT_4, 0, 0),
-
-SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
-                    WM8915_POWER_MANAGEMENT_6, 5, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
-                    WM8915_POWER_MANAGEMENT_6, 4, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
-                    WM8915_POWER_MANAGEMENT_6, 3, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
-                    WM8915_POWER_MANAGEMENT_6, 2, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
-                    WM8915_POWER_MANAGEMENT_6, 1, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
-                    WM8915_POWER_MANAGEMENT_6, 0, 0),
-
-/* We route as stereo pairs so define some dummy widgets to squash
- * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
-SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
-SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
-SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
-
-SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
-SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
-SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
-
-SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start,
-                  SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
-                  rmv_short_event,
-                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_OUTPUT("HPOUT1L"),
-SND_SOC_DAPM_OUTPUT("HPOUT1R"),
-SND_SOC_DAPM_OUTPUT("HPOUT2L"),
-SND_SOC_DAPM_OUTPUT("HPOUT2R"),
-SND_SOC_DAPM_OUTPUT("SPKDAT"),
-};
-
-static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
-       { "AIFCLK", NULL, "SYSCLK" },
-       { "SYSDSPCLK", NULL, "SYSCLK" },
-       { "Charge Pump", NULL, "SYSCLK" },
-
-       { "MICB1", NULL, "LDO2" },
-       { "MICB2", NULL, "LDO2" },
-
-       { "IN1L PGA", NULL, "IN2LN" },
-       { "IN1L PGA", NULL, "IN2LP" },
-       { "IN1L PGA", NULL, "IN1LN" },
-       { "IN1L PGA", NULL, "IN1LP" },
-
-       { "IN1R PGA", NULL, "IN2RN" },
-       { "IN1R PGA", NULL, "IN2RP" },
-       { "IN1R PGA", NULL, "IN1RN" },
-       { "IN1R PGA", NULL, "IN1RP" },
-
-       { "ADCL", NULL, "IN1L PGA" },
-
-       { "ADCR", NULL, "IN1R PGA" },
-
-       { "DMIC1L", NULL, "DMIC1DAT" },
-       { "DMIC1R", NULL, "DMIC1DAT" },
-       { "DMIC2L", NULL, "DMIC2DAT" },
-       { "DMIC2R", NULL, "DMIC2DAT" },
-
-       { "DMIC2L", NULL, "DMIC2" },
-       { "DMIC2R", NULL, "DMIC2" },
-       { "DMIC1L", NULL, "DMIC1" },
-       { "DMIC1R", NULL, "DMIC1" },
-
-       { "IN1L Mux", "ADC", "ADCL" },
-       { "IN1L Mux", "DMIC1", "DMIC1L" },
-       { "IN1L Mux", "DMIC2", "DMIC2L" },
-
-       { "IN1R Mux", "ADC", "ADCR" },
-       { "IN1R Mux", "DMIC1", "DMIC1R" },
-       { "IN1R Mux", "DMIC2", "DMIC2R" },
-
-       { "IN2L Mux", "ADC", "ADCL" },
-       { "IN2L Mux", "DMIC1", "DMIC1L" },
-       { "IN2L Mux", "DMIC2", "DMIC2L" },
-
-       { "IN2R Mux", "ADC", "ADCR" },
-       { "IN2R Mux", "DMIC1", "DMIC1R" },
-       { "IN2R Mux", "DMIC2", "DMIC2R" },
-
-       { "Left Sidetone", "IN1", "IN1L Mux" },
-       { "Left Sidetone", "IN2", "IN2L Mux" },
-
-       { "Right Sidetone", "IN1", "IN1R Mux" },
-       { "Right Sidetone", "IN2", "IN2R Mux" },
-
-       { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
-       { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
-
-       { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
-       { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
-
-       { "AIF1TX0", NULL, "DSP1TXL" },
-       { "AIF1TX1", NULL, "DSP1TXR" },
-       { "AIF1TX2", NULL, "DSP2TXL" },
-       { "AIF1TX3", NULL, "DSP2TXR" },
-       { "AIF1TX4", NULL, "AIF2RX0" },
-       { "AIF1TX5", NULL, "AIF2RX1" },
-
-       { "AIF1RX0", NULL, "AIFCLK" },
-       { "AIF1RX1", NULL, "AIFCLK" },
-       { "AIF1RX2", NULL, "AIFCLK" },
-       { "AIF1RX3", NULL, "AIFCLK" },
-       { "AIF1RX4", NULL, "AIFCLK" },
-       { "AIF1RX5", NULL, "AIFCLK" },
-
-       { "AIF2RX0", NULL, "AIFCLK" },
-       { "AIF2RX1", NULL, "AIFCLK" },
-
-       { "DSP1RXL", NULL, "SYSDSPCLK" },
-       { "DSP1RXR", NULL, "SYSDSPCLK" },
-       { "DSP2RXL", NULL, "SYSDSPCLK" },
-       { "DSP2RXR", NULL, "SYSDSPCLK" },
-       { "DSP1TXL", NULL, "SYSDSPCLK" },
-       { "DSP1TXR", NULL, "SYSDSPCLK" },
-       { "DSP2TXL", NULL, "SYSDSPCLK" },
-       { "DSP2TXR", NULL, "SYSDSPCLK" },
-
-       { "AIF1RXA", NULL, "AIF1RX0" },
-       { "AIF1RXA", NULL, "AIF1RX1" },
-       { "AIF1RXB", NULL, "AIF1RX2" },
-       { "AIF1RXB", NULL, "AIF1RX3" },
-       { "AIF1RXC", NULL, "AIF1RX4" },
-       { "AIF1RXC", NULL, "AIF1RX5" },
-
-       { "AIF2RX", NULL, "AIF2RX0" },
-       { "AIF2RX", NULL, "AIF2RX1" },
-
-       { "AIF2TX", "DSP2", "DSP2TX" },
-       { "AIF2TX", "DSP1", "DSP1RX" },
-       { "AIF2TX", "AIF1", "AIF1RXC" },
-
-       { "DSP1RXL", NULL, "DSP1RX" },
-       { "DSP1RXR", NULL, "DSP1RX" },
-       { "DSP2RXL", NULL, "DSP2RX" },
-       { "DSP2RXR", NULL, "DSP2RX" },
-
-       { "DSP2TX", NULL, "DSP2TXL" },
-       { "DSP2TX", NULL, "DSP2TXR" },
-
-       { "DSP1RX", "AIF1", "AIF1RXA" },
-       { "DSP1RX", "AIF2", "AIF2RX" },
-
-       { "DSP2RX", "AIF1", "AIF1RXB" },
-       { "DSP2RX", "AIF2", "AIF2RX" },
-
-       { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
-       { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
-       { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
-       { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
-       { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
-       { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
-       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
-       { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
-       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
-       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
-
-       { "DAC1L", NULL, "DAC1L Mixer" },
-       { "DAC1R", NULL, "DAC1R Mixer" },
-       { "DAC2L", NULL, "DAC2L Mixer" },
-       { "DAC2R", NULL, "DAC2R Mixer" },
-
-       { "HPOUT2L PGA", NULL, "Charge Pump" },
-       { "HPOUT2L PGA", NULL, "DAC2L" },
-       { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
-       { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
-       { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
-       { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
-
-       { "HPOUT2R PGA", NULL, "Charge Pump" },
-       { "HPOUT2R PGA", NULL, "DAC2R" },
-       { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
-       { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
-       { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
-       { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
-
-       { "HPOUT1L PGA", NULL, "Charge Pump" },
-       { "HPOUT1L PGA", NULL, "DAC1L" },
-       { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
-       { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
-       { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
-       { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
-
-       { "HPOUT1R PGA", NULL, "Charge Pump" },
-       { "HPOUT1R PGA", NULL, "DAC1R" },
-       { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
-       { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
-       { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
-       { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
-
-       { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
-       { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
-       { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
-       { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
-
-       { "SPKL", "DAC1L", "DAC1L" },
-       { "SPKL", "DAC1R", "DAC1R" },
-       { "SPKL", "DAC2L", "DAC2L" },
-       { "SPKL", "DAC2R", "DAC2R" },
-
-       { "SPKR", "DAC1L", "DAC1L" },
-       { "SPKR", "DAC1R", "DAC1R" },
-       { "SPKR", "DAC2L", "DAC2L" },
-       { "SPKR", "DAC2R", "DAC2R" },
-
-       { "SPKL PGA", NULL, "SPKL" },
-       { "SPKR PGA", NULL, "SPKR" },
-
-       { "SPKDAT", NULL, "SPKL PGA" },
-       { "SPKDAT", NULL, "SPKR PGA" },
-};
-
-static int wm8915_readable_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       /* Due to the sparseness of the register map the compiler
-        * output from an explicit switch statement ends up being much
-        * more efficient than a table.
-        */
-       switch (reg) {
-       case WM8915_SOFTWARE_RESET:
-       case WM8915_POWER_MANAGEMENT_1:
-       case WM8915_POWER_MANAGEMENT_2:
-       case WM8915_POWER_MANAGEMENT_3:
-       case WM8915_POWER_MANAGEMENT_4:
-       case WM8915_POWER_MANAGEMENT_5:
-       case WM8915_POWER_MANAGEMENT_6:
-       case WM8915_POWER_MANAGEMENT_7:
-       case WM8915_POWER_MANAGEMENT_8:
-       case WM8915_LEFT_LINE_INPUT_VOLUME:
-       case WM8915_RIGHT_LINE_INPUT_VOLUME:
-       case WM8915_LINE_INPUT_CONTROL:
-       case WM8915_DAC1_HPOUT1_VOLUME:
-       case WM8915_DAC2_HPOUT2_VOLUME:
-       case WM8915_DAC1_LEFT_VOLUME:
-       case WM8915_DAC1_RIGHT_VOLUME:
-       case WM8915_DAC2_LEFT_VOLUME:
-       case WM8915_DAC2_RIGHT_VOLUME:
-       case WM8915_OUTPUT1_LEFT_VOLUME:
-       case WM8915_OUTPUT1_RIGHT_VOLUME:
-       case WM8915_OUTPUT2_LEFT_VOLUME:
-       case WM8915_OUTPUT2_RIGHT_VOLUME:
-       case WM8915_MICBIAS_1:
-       case WM8915_MICBIAS_2:
-       case WM8915_LDO_1:
-       case WM8915_LDO_2:
-       case WM8915_ACCESSORY_DETECT_MODE_1:
-       case WM8915_ACCESSORY_DETECT_MODE_2:
-       case WM8915_HEADPHONE_DETECT_1:
-       case WM8915_HEADPHONE_DETECT_2:
-       case WM8915_MIC_DETECT_1:
-       case WM8915_MIC_DETECT_2:
-       case WM8915_MIC_DETECT_3:
-       case WM8915_CHARGE_PUMP_1:
-       case WM8915_CHARGE_PUMP_2:
-       case WM8915_DC_SERVO_1:
-       case WM8915_DC_SERVO_2:
-       case WM8915_DC_SERVO_3:
-       case WM8915_DC_SERVO_5:
-       case WM8915_DC_SERVO_6:
-       case WM8915_DC_SERVO_7:
-       case WM8915_DC_SERVO_READBACK_0:
-       case WM8915_ANALOGUE_HP_1:
-       case WM8915_ANALOGUE_HP_2:
-       case WM8915_CHIP_REVISION:
-       case WM8915_CONTROL_INTERFACE_1:
-       case WM8915_WRITE_SEQUENCER_CTRL_1:
-       case WM8915_WRITE_SEQUENCER_CTRL_2:
-       case WM8915_AIF_CLOCKING_1:
-       case WM8915_AIF_CLOCKING_2:
-       case WM8915_CLOCKING_1:
-       case WM8915_CLOCKING_2:
-       case WM8915_AIF_RATE:
-       case WM8915_FLL_CONTROL_1:
-       case WM8915_FLL_CONTROL_2:
-       case WM8915_FLL_CONTROL_3:
-       case WM8915_FLL_CONTROL_4:
-       case WM8915_FLL_CONTROL_5:
-       case WM8915_FLL_CONTROL_6:
-       case WM8915_FLL_EFS_1:
-       case WM8915_FLL_EFS_2:
-       case WM8915_AIF1_CONTROL:
-       case WM8915_AIF1_BCLK:
-       case WM8915_AIF1_TX_LRCLK_1:
-       case WM8915_AIF1_TX_LRCLK_2:
-       case WM8915_AIF1_RX_LRCLK_1:
-       case WM8915_AIF1_RX_LRCLK_2:
-       case WM8915_AIF1TX_DATA_CONFIGURATION_1:
-       case WM8915_AIF1TX_DATA_CONFIGURATION_2:
-       case WM8915_AIF1RX_DATA_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION:
-       case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION:
-       case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION:
-       case WM8915_AIF1RX_MONO_CONFIGURATION:
-       case WM8915_AIF1TX_TEST:
-       case WM8915_AIF2_CONTROL:
-       case WM8915_AIF2_BCLK:
-       case WM8915_AIF2_TX_LRCLK_1:
-       case WM8915_AIF2_TX_LRCLK_2:
-       case WM8915_AIF2_RX_LRCLK_1:
-       case WM8915_AIF2_RX_LRCLK_2:
-       case WM8915_AIF2TX_DATA_CONFIGURATION_1:
-       case WM8915_AIF2TX_DATA_CONFIGURATION_2:
-       case WM8915_AIF2RX_DATA_CONFIGURATION:
-       case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION:
-       case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION:
-       case WM8915_AIF2RX_MONO_CONFIGURATION:
-       case WM8915_AIF2TX_TEST:
-       case WM8915_DSP1_TX_LEFT_VOLUME:
-       case WM8915_DSP1_TX_RIGHT_VOLUME:
-       case WM8915_DSP1_RX_LEFT_VOLUME:
-       case WM8915_DSP1_RX_RIGHT_VOLUME:
-       case WM8915_DSP1_TX_FILTERS:
-       case WM8915_DSP1_RX_FILTERS_1:
-       case WM8915_DSP1_RX_FILTERS_2:
-       case WM8915_DSP1_DRC_1:
-       case WM8915_DSP1_DRC_2:
-       case WM8915_DSP1_DRC_3:
-       case WM8915_DSP1_DRC_4:
-       case WM8915_DSP1_DRC_5:
-       case WM8915_DSP1_RX_EQ_GAINS_1:
-       case WM8915_DSP1_RX_EQ_GAINS_2:
-       case WM8915_DSP1_RX_EQ_BAND_1_A:
-       case WM8915_DSP1_RX_EQ_BAND_1_B:
-       case WM8915_DSP1_RX_EQ_BAND_1_PG:
-       case WM8915_DSP1_RX_EQ_BAND_2_A:
-       case WM8915_DSP1_RX_EQ_BAND_2_B:
-       case WM8915_DSP1_RX_EQ_BAND_2_C:
-       case WM8915_DSP1_RX_EQ_BAND_2_PG:
-       case WM8915_DSP1_RX_EQ_BAND_3_A:
-       case WM8915_DSP1_RX_EQ_BAND_3_B:
-       case WM8915_DSP1_RX_EQ_BAND_3_C:
-       case WM8915_DSP1_RX_EQ_BAND_3_PG:
-       case WM8915_DSP1_RX_EQ_BAND_4_A:
-       case WM8915_DSP1_RX_EQ_BAND_4_B:
-       case WM8915_DSP1_RX_EQ_BAND_4_C:
-       case WM8915_DSP1_RX_EQ_BAND_4_PG:
-       case WM8915_DSP1_RX_EQ_BAND_5_A:
-       case WM8915_DSP1_RX_EQ_BAND_5_B:
-       case WM8915_DSP1_RX_EQ_BAND_5_PG:
-       case WM8915_DSP2_TX_LEFT_VOLUME:
-       case WM8915_DSP2_TX_RIGHT_VOLUME:
-       case WM8915_DSP2_RX_LEFT_VOLUME:
-       case WM8915_DSP2_RX_RIGHT_VOLUME:
-       case WM8915_DSP2_TX_FILTERS:
-       case WM8915_DSP2_RX_FILTERS_1:
-       case WM8915_DSP2_RX_FILTERS_2:
-       case WM8915_DSP2_DRC_1:
-       case WM8915_DSP2_DRC_2:
-       case WM8915_DSP2_DRC_3:
-       case WM8915_DSP2_DRC_4:
-       case WM8915_DSP2_DRC_5:
-       case WM8915_DSP2_RX_EQ_GAINS_1:
-       case WM8915_DSP2_RX_EQ_GAINS_2:
-       case WM8915_DSP2_RX_EQ_BAND_1_A:
-       case WM8915_DSP2_RX_EQ_BAND_1_B:
-       case WM8915_DSP2_RX_EQ_BAND_1_PG:
-       case WM8915_DSP2_RX_EQ_BAND_2_A:
-       case WM8915_DSP2_RX_EQ_BAND_2_B:
-       case WM8915_DSP2_RX_EQ_BAND_2_C:
-       case WM8915_DSP2_RX_EQ_BAND_2_PG:
-       case WM8915_DSP2_RX_EQ_BAND_3_A:
-       case WM8915_DSP2_RX_EQ_BAND_3_B:
-       case WM8915_DSP2_RX_EQ_BAND_3_C:
-       case WM8915_DSP2_RX_EQ_BAND_3_PG:
-       case WM8915_DSP2_RX_EQ_BAND_4_A:
-       case WM8915_DSP2_RX_EQ_BAND_4_B:
-       case WM8915_DSP2_RX_EQ_BAND_4_C:
-       case WM8915_DSP2_RX_EQ_BAND_4_PG:
-       case WM8915_DSP2_RX_EQ_BAND_5_A:
-       case WM8915_DSP2_RX_EQ_BAND_5_B:
-       case WM8915_DSP2_RX_EQ_BAND_5_PG:
-       case WM8915_DAC1_MIXER_VOLUMES:
-       case WM8915_DAC1_LEFT_MIXER_ROUTING:
-       case WM8915_DAC1_RIGHT_MIXER_ROUTING:
-       case WM8915_DAC2_MIXER_VOLUMES:
-       case WM8915_DAC2_LEFT_MIXER_ROUTING:
-       case WM8915_DAC2_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP1_TX_LEFT_MIXER_ROUTING:
-       case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP2_TX_LEFT_MIXER_ROUTING:
-       case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING:
-       case WM8915_DSP_TX_MIXER_SELECT:
-       case WM8915_DAC_SOFTMUTE:
-       case WM8915_OVERSAMPLING:
-       case WM8915_SIDETONE:
-       case WM8915_GPIO_1:
-       case WM8915_GPIO_2:
-       case WM8915_GPIO_3:
-       case WM8915_GPIO_4:
-       case WM8915_GPIO_5:
-       case WM8915_PULL_CONTROL_1:
-       case WM8915_PULL_CONTROL_2:
-       case WM8915_INTERRUPT_STATUS_1:
-       case WM8915_INTERRUPT_STATUS_2:
-       case WM8915_INTERRUPT_RAW_STATUS_2:
-       case WM8915_INTERRUPT_STATUS_1_MASK:
-       case WM8915_INTERRUPT_STATUS_2_MASK:
-       case WM8915_INTERRUPT_CONTROL:
-       case WM8915_LEFT_PDM_SPEAKER:
-       case WM8915_RIGHT_PDM_SPEAKER:
-       case WM8915_PDM_SPEAKER_MUTE_SEQUENCE:
-       case WM8915_PDM_SPEAKER_VOLUME:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static int wm8915_volatile_register(struct snd_soc_codec *codec,
-                                   unsigned int reg)
-{
-       switch (reg) {
-       case WM8915_SOFTWARE_RESET:
-       case WM8915_CHIP_REVISION:
-       case WM8915_LDO_1:
-       case WM8915_LDO_2:
-       case WM8915_INTERRUPT_STATUS_1:
-       case WM8915_INTERRUPT_STATUS_2:
-       case WM8915_INTERRUPT_RAW_STATUS_2:
-       case WM8915_DC_SERVO_READBACK_0:
-       case WM8915_DC_SERVO_2:
-       case WM8915_DC_SERVO_6:
-       case WM8915_DC_SERVO_7:
-       case WM8915_FLL_CONTROL_6:
-       case WM8915_MIC_DETECT_3:
-       case WM8915_HEADPHONE_DETECT_1:
-       case WM8915_HEADPHONE_DETECT_2:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static int wm8915_reset(struct snd_soc_codec *codec)
-{
-       return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
-}
-
-static const int bclk_divs[] = {
-       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
-};
-
-static void wm8915_update_bclk(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int aif, best, cur_val, bclk_rate, bclk_reg, i;
-
-       /* Don't bother if we're in a low frequency idle mode that
-        * can't support audio.
-        */
-       if (wm8915->sysclk < 64000)
-               return;
-
-       for (aif = 0; aif < WM8915_AIFS; aif++) {
-               switch (aif) {
-               case 0:
-                       bclk_reg = WM8915_AIF1_BCLK;
-                       break;
-               case 1:
-                       bclk_reg = WM8915_AIF2_BCLK;
-                       break;
-               }
-
-               bclk_rate = wm8915->bclk_rate[aif];
-
-               /* Pick a divisor for BCLK as close as we can get to ideal */
-               best = 0;
-               for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-                       cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
-                       if (cur_val < 0) /* BCLK table is sorted */
-                               break;
-                       best = i;
-               }
-               bclk_rate = wm8915->sysclk / bclk_divs[best];
-               dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
-                       bclk_divs[best], bclk_rate);
-
-               snd_soc_update_bits(codec, bclk_reg,
-                                   WM8915_AIF1_BCLK_DIV_MASK, best);
-       }
-}
-
-static int wm8915_set_bias_level(struct snd_soc_codec *codec,
-                                enum snd_soc_bias_level level)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       switch (level) {
-       case SND_SOC_BIAS_ON:
-               break;
-
-       case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
-                       snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
-                                           WM8915_BG_ENA, WM8915_BG_ENA);
-                       msleep(2);
-               }
-               break;
-
-       case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
-                                                   wm8915->supplies);
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to enable supplies: %d\n",
-                                       ret);
-                               return ret;
-                       }
-
-                       if (wm8915->pdata.ldo_ena >= 0) {
-                               gpio_set_value_cansleep(wm8915->pdata.ldo_ena,
-                                                       1);
-                               msleep(5);
-                       }
-
-                       codec->cache_only = false;
-                       snd_soc_cache_sync(codec);
-               }
-
-               snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
-                                   WM8915_BG_ENA, 0);
-               break;
-
-       case SND_SOC_BIAS_OFF:
-               codec->cache_only = true;
-               if (wm8915->pdata.ldo_ena >= 0)
-                       gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-               regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies),
-                                      wm8915->supplies);
-               break;
-       }
-
-       codec->dapm.bias_level = level;
-
-       return 0;
-}
-
-static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       int aifctrl = 0;
-       int bclk = 0;
-       int lrclk_tx = 0;
-       int lrclk_rx = 0;
-       int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
-
-       switch (dai->id) {
-       case 0:
-               aifctrl_reg = WM8915_AIF1_CONTROL;
-               bclk_reg = WM8915_AIF1_BCLK;
-               lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2;
-               lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2;
-               break;
-       case 1:
-               aifctrl_reg = WM8915_AIF2_CONTROL;
-               bclk_reg = WM8915_AIF2_BCLK;
-               lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2;
-               lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               break;
-       case SND_SOC_DAIFMT_IB_NF:
-               bclk |= WM8915_AIF1_BCLK_INV;
-               break;
-       case SND_SOC_DAIFMT_NB_IF:
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
-               break;
-       case SND_SOC_DAIFMT_IB_IF:
-               bclk |= WM8915_AIF1_BCLK_INV;
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
-               break;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               break;
-       case SND_SOC_DAIFMT_CBS_CFM:
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFS:
-               bclk |= WM8915_AIF1_BCLK_MSTR;
-               break;
-       case SND_SOC_DAIFMT_CBM_CFM:
-               bclk |= WM8915_AIF1_BCLK_MSTR;
-               lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
-               lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               aifctrl |= 1;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               aifctrl |= 2;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               aifctrl |= 3;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl);
-       snd_soc_update_bits(codec, bclk_reg,
-                           WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR,
-                           bclk);
-       snd_soc_update_bits(codec, lrclk_tx_reg,
-                           WM8915_AIF1TX_LRCLK_INV |
-                           WM8915_AIF1TX_LRCLK_MSTR,
-                           lrclk_tx);
-       snd_soc_update_bits(codec, lrclk_rx_reg,
-                           WM8915_AIF1RX_LRCLK_INV |
-                           WM8915_AIF1RX_LRCLK_MSTR,
-                           lrclk_rx);
-
-       return 0;
-}
-
-static const int dsp_divs[] = {
-       48000, 32000, 16000, 8000
-};
-
-static int wm8915_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int bits, i, bclk_rate;
-       int aifdata = 0;
-       int lrclk = 0;
-       int dsp = 0;
-       int aifdata_reg, lrclk_reg, dsp_shift;
-
-       switch (dai->id) {
-       case 0:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) {
-                       aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION;
-                       lrclk_reg = WM8915_AIF1_RX_LRCLK_1;
-               } else {
-                       aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
-                       lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
-               }
-               dsp_shift = 0;
-               break;
-       case 1:
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) {
-                       aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION;
-                       lrclk_reg = WM8915_AIF2_RX_LRCLK_1;
-               } else {
-                       aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
-                       lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
-               }
-               dsp_shift = WM8915_DSP2_DIV_SHIFT;
-               break;
-       default:
-               BUG();
-               return -EINVAL;
-       }
-
-       bclk_rate = snd_soc_params_to_bclk(params);
-       if (bclk_rate < 0) {
-               dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
-               return bclk_rate;
-       }
-
-       wm8915->bclk_rate[dai->id] = bclk_rate;
-       wm8915->rx_rate[dai->id] = params_rate(params);
-
-       /* Needs looking at for TDM */
-       bits = snd_pcm_format_width(params_format(params));
-       if (bits < 0)
-               return bits;
-       aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits;
-
-       for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
-               if (dsp_divs[i] == params_rate(params))
-                       break;
-       }
-       if (i == ARRAY_SIZE(dsp_divs)) {
-               dev_err(codec->dev, "Unsupported sample rate %dHz\n",
-                       params_rate(params));
-               return -EINVAL;
-       }
-       dsp |= i << dsp_shift;
-
-       wm8915_update_bclk(codec);
-
-       lrclk = bclk_rate / params_rate(params);
-       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
-               lrclk, bclk_rate / lrclk);
-
-       snd_soc_update_bits(codec, aifdata_reg,
-                           WM8915_AIF1TX_WL_MASK |
-                           WM8915_AIF1TX_SLOT_LEN_MASK,
-                           aifdata);
-       snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
-                           lrclk);
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
-                           WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
-
-       return 0;
-}
-
-static int wm8915_set_sysclk(struct snd_soc_dai *dai,
-               int clk_id, unsigned int freq, int dir)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int lfclk = 0;
-       int ratediv = 0;
-       int src;
-       int old;
-
-       if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src)
-               return 0;
-
-       /* Disable SYSCLK while we reconfigure */
-       old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA;
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_ENA, 0);
-
-       switch (clk_id) {
-       case WM8915_SYSCLK_MCLK1:
-               wm8915->sysclk = freq;
-               src = 0;
-               break;
-       case WM8915_SYSCLK_MCLK2:
-               wm8915->sysclk = freq;
-               src = 1;
-               break;
-       case WM8915_SYSCLK_FLL:
-               wm8915->sysclk = freq;
-               src = 2;
-               break;
-       default:
-               dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
-               return -EINVAL;
-       }
-
-       switch (wm8915->sysclk) {
-       case 6144000:
-               snd_soc_update_bits(codec, WM8915_AIF_RATE,
-                                   WM8915_SYSCLK_RATE, 0);
-               break;
-       case 24576000:
-               ratediv = WM8915_SYSCLK_DIV;
-       case 12288000:
-               snd_soc_update_bits(codec, WM8915_AIF_RATE,
-                                   WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE);
-               break;
-       case 32000:
-       case 32768:
-               lfclk = WM8915_LFCLK_ENA;
-               break;
-       default:
-               dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
-                        wm8915->sysclk);
-               return -EINVAL;
-       }
-
-       wm8915_update_bclk(codec);
-
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
-                           src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
-       snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk);
-       snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
-                           WM8915_SYSCLK_ENA, old);
-
-       wm8915->sysclk_src = clk_id;
-
-       return 0;
-}
-
-struct _fll_div {
-       u16 fll_fratio;
-       u16 fll_outdiv;
-       u16 fll_refclk_div;
-       u16 fll_loop_gain;
-       u16 fll_ref_freq;
-       u16 n;
-       u16 theta;
-       u16 lambda;
-};
-
-static struct {
-       unsigned int min;
-       unsigned int max;
-       u16 fll_fratio;
-       int ratio;
-} fll_fratios[] = {
-       {       0,    64000, 4, 16 },
-       {   64000,   128000, 3,  8 },
-       {  128000,   256000, 2,  4 },
-       {  256000,  1000000, 1,  2 },
-       { 1000000, 13500000, 0,  1 },
-};
-
-static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
-                      unsigned int Fout)
-{
-       unsigned int target;
-       unsigned int div;
-       unsigned int fratio, gcd_fll;
-       int i;
-
-       /* Fref must be <=13.5MHz */
-       div = 1;
-       fll_div->fll_refclk_div = 0;
-       while ((Fref / div) > 13500000) {
-               div *= 2;
-               fll_div->fll_refclk_div++;
-
-               if (div > 8) {
-                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
-                              Fref);
-                       return -EINVAL;
-               }
-       }
-
-       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
-
-       /* Apply the division for our remaining calculations */
-       Fref /= div;
-
-       if (Fref >= 3000000)
-               fll_div->fll_loop_gain = 5;
-       else
-               fll_div->fll_loop_gain = 0;
-
-       if (Fref >= 48000)
-               fll_div->fll_ref_freq = 0;
-       else
-               fll_div->fll_ref_freq = 1;
-
-       /* Fvco should be 90-100MHz; don't check the upper bound */
-       div = 2;
-       while (Fout * div < 90000000) {
-               div++;
-               if (div > 64) {
-                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
-                              Fout);
-                       return -EINVAL;
-               }
-       }
-       target = Fout * div;
-       fll_div->fll_outdiv = div - 1;
-
-       pr_debug("FLL Fvco=%dHz\n", target);
-
-       /* Find an appropraite FLL_FRATIO and factor it out of the target */
-       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
-               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
-                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
-                       fratio = fll_fratios[i].ratio;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(fll_fratios)) {
-               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
-               return -EINVAL;
-       }
-
-       fll_div->n = target / (fratio * Fref);
-
-       if (target % Fref == 0) {
-               fll_div->theta = 0;
-               fll_div->lambda = 0;
-       } else {
-               gcd_fll = gcd(target, fratio * Fref);
-
-               fll_div->theta = (target - (fll_div->n * fratio * Fref))
-                       / gcd_fll;
-               fll_div->lambda = (fratio * Fref) / gcd_fll;
-       }
-
-       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
-                fll_div->n, fll_div->theta, fll_div->lambda);
-       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
-                fll_div->fll_fratio, fll_div->fll_outdiv,
-                fll_div->fll_refclk_div);
-
-       return 0;
-}
-
-static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
-                         unsigned int Fref, unsigned int Fout)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct _fll_div fll_div;
-       unsigned long timeout;
-       int ret, reg;
-
-       /* Any change? */
-       if (source == wm8915->fll_src && Fref == wm8915->fll_fref &&
-           Fout == wm8915->fll_fout)
-               return 0;
-
-       if (Fout == 0) {
-               dev_dbg(codec->dev, "FLL disabled\n");
-
-               wm8915->fll_fref = 0;
-               wm8915->fll_fout = 0;
-
-               snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
-                                   WM8915_FLL_ENA, 0);
-
-               return 0;
-       }
-
-       ret = fll_factors(&fll_div, Fref, Fout);
-       if (ret != 0)
-               return ret;
-
-       switch (source) {
-       case WM8915_FLL_MCLK1:
-               reg = 0;
-               break;
-       case WM8915_FLL_MCLK2:
-               reg = 1;
-               break;
-       case WM8915_FLL_DACLRCLK1:
-               reg = 2;
-               break;
-       case WM8915_FLL_BCLK1:
-               reg = 3;
-               break;
-       default:
-               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
-               return -EINVAL;
-       }
-
-       reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT;
-       reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT;
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5,
-                           WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ |
-                           WM8915_FLL_REFCLK_SRC_MASK, reg);
-
-       reg = 0;
-       if (fll_div.theta || fll_div.lambda)
-               reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT);
-       else
-               reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT;
-       snd_soc_write(codec, WM8915_FLL_EFS_2, reg);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2,
-                           WM8915_FLL_OUTDIV_MASK |
-                           WM8915_FLL_FRATIO_MASK,
-                           (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) |
-                           (fll_div.fll_fratio));
-
-       snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4,
-                           WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK,
-                           (fll_div.n << WM8915_FLL_N_SHIFT) |
-                           fll_div.fll_loop_gain);
-
-       snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda);
-
-       snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
-                           WM8915_FLL_ENA, WM8915_FLL_ENA);
-
-       /* The FLL supports live reconfiguration - kick that in case we were
-        * already enabled.
-        */
-       snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK);
-
-       /* Wait for the FLL to lock, using the interrupt if possible */
-       if (Fref > 1000000)
-               timeout = usecs_to_jiffies(300);
-       else
-               timeout = msecs_to_jiffies(2);
-
-       /* Allow substantially longer if we've actually got the IRQ */
-       if (i2c->irq)
-               timeout *= 1000;
-
-       ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout);
-
-       if (ret == 0 && i2c->irq) {
-               dev_err(codec->dev, "Timed out waiting for FLL\n");
-               ret = -ETIMEDOUT;
-       } else {
-               ret = 0;
-       }
-
-       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
-
-       wm8915->fll_fref = Fref;
-       wm8915->fll_fout = Fout;
-       wm8915->fll_src = source;
-
-       return ret;
-}
-
-#ifdef CONFIG_GPIOLIB
-static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip)
-{
-       return container_of(chip, struct wm8915_priv, gpio_chip);
-}
-
-static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-
-       snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                           WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT);
-}
-
-static int wm8915_gpio_direction_out(struct gpio_chip *chip,
-                                    unsigned offset, int value)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-       int val;
-
-       val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT);
-
-       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR |
-                                  WM8915_GP1_LVL, val);
-}
-
-static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-       int ret;
-
-       ret = snd_soc_read(codec, WM8915_GPIO_1 + offset);
-       if (ret < 0)
-               return ret;
-
-       return (ret & WM8915_GP1_LVL) != 0;
-}
-
-static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
-       struct snd_soc_codec *codec = wm8915->codec;
-
-       return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
-                                  WM8915_GP1_FN_MASK | WM8915_GP1_DIR,
-                                  (1 << WM8915_GP1_FN_SHIFT) |
-                                  (1 << WM8915_GP1_DIR_SHIFT));
-}
-
-static struct gpio_chip wm8915_template_chip = {
-       .label                  = "wm8915",
-       .owner                  = THIS_MODULE,
-       .direction_output       = wm8915_gpio_direction_out,
-       .set                    = wm8915_gpio_set,
-       .direction_input        = wm8915_gpio_direction_in,
-       .get                    = wm8915_gpio_get,
-       .can_sleep              = 1,
-};
-
-static void wm8915_init_gpio(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       wm8915->gpio_chip = wm8915_template_chip;
-       wm8915->gpio_chip.ngpio = 5;
-       wm8915->gpio_chip.dev = codec->dev;
-
-       if (wm8915->pdata.gpio_base)
-               wm8915->gpio_chip.base = wm8915->pdata.gpio_base;
-       else
-               wm8915->gpio_chip.base = -1;
-
-       ret = gpiochip_add(&wm8915->gpio_chip);
-       if (ret != 0)
-               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
-}
-
-static void wm8915_free_gpio(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int ret;
-
-       ret = gpiochip_remove(&wm8915->gpio_chip);
-       if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
-}
-#else
-static void wm8915_init_gpio(struct snd_soc_codec *codec)
-{
-}
-
-static void wm8915_free_gpio(struct snd_soc_codec *codec)
-{
-}
-#endif
-
-/**
- * wm8915_detect - Enable default WM8915 jack detection
- *
- * The WM8915 has advanced accessory detection support for headsets.
- * This function provides a default implementation which integrates
- * the majority of this functionality with minimal user configuration.
- *
- * This will detect headset, headphone and short circuit button and
- * will also detect inverted microphone ground connections and update
- * the polarity of the connections.
- */
-int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-                 wm8915_polarity_fn polarity_cb)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-
-       wm8915->jack = jack;
-       wm8915->detecting = true;
-       wm8915->polarity_cb = polarity_cb;
-
-       if (wm8915->polarity_cb)
-               wm8915->polarity_cb(codec, 0);
-
-       /* Clear discarge to avoid noise during detection */
-       snd_soc_update_bits(codec, WM8915_MICBIAS_1,
-                           WM8915_MICB1_DISCH, 0);
-       snd_soc_update_bits(codec, WM8915_MICBIAS_2,
-                           WM8915_MICB2_DISCH, 0);
-
-       /* LDO2 powers the microphones, SYSCLK clocks detection */
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
-       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
-
-       /* We start off just enabling microphone detection - even a
-        * plain headphone will trigger detection.
-        */
-       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                           WM8915_MICD_ENA, WM8915_MICD_ENA);
-
-       /* Slowest detection rate, gives debounce for initial detection */
-       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                           WM8915_MICD_RATE_MASK,
-                           WM8915_MICD_RATE_MASK);
-
-       /* Enable interrupts and we're off */
-       snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK,
-                           WM8915_IM_MICD_EINT, 0);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wm8915_detect);
-
-static void wm8915_micd(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int val, reg;
-
-       val = snd_soc_read(codec, WM8915_MIC_DETECT_3);
-
-       dev_dbg(codec->dev, "Microphone event: %x\n", val);
-
-       if (!(val & WM8915_MICD_VALID)) {
-               dev_warn(codec->dev, "Microphone detection state invalid\n");
-               return;
-       }
-
-       /* No accessory, reset everything and report removal */
-       if (!(val & WM8915_MICD_STS)) {
-               dev_dbg(codec->dev, "Jack removal detected\n");
-               wm8915->jack_mic = false;
-               wm8915->detecting = true;
-               snd_soc_jack_report(wm8915->jack, 0,
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   WM8915_MICD_RATE_MASK);
-               return;
-       }
-
-       /* If the measurement is very high we've got a microphone but
-        * do a little debounce to account for mechanical issues.
-        */
-       if (val & 0x400) {
-               dev_dbg(codec->dev, "Microphone detected\n");
-               snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET,
-                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
-               wm8915->jack_mic = true;
-               wm8915->detecting = false;
-
-               /* Increase poll rate to give better responsiveness
-                * for buttons */
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   5 << WM8915_MICD_RATE_SHIFT);
-       }
-
-       /* If we detected a lower impedence during initial startup
-        * then we probably have the wrong polarity, flip it.  Don't
-        * do this for the lowest impedences to speed up detection of
-        * plain headphones.
-        */
-       if (wm8915->detecting && (val & 0x3f0)) {
-               reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2);
-               reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
-                       WM8915_MICD_BIAS_SRC;
-               snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
-                                   WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
-                                   WM8915_MICD_BIAS_SRC, reg);
-
-               if (wm8915->polarity_cb)
-                       wm8915->polarity_cb(codec,
-                                           (reg & WM8915_MICD_SRC) != 0);
-
-               dev_dbg(codec->dev, "Set microphone polarity to %d\n",
-                       (reg & WM8915_MICD_SRC) != 0);
-
-               return;
-       }
-
-       /* Don't distinguish between buttons, just report any low
-        * impedence as BTN_0.
-        */
-       if (val & 0x3fc) {
-               if (wm8915->jack_mic) {
-                       dev_dbg(codec->dev, "Mic button detected\n");
-                       snd_soc_jack_report(wm8915->jack,
-                                           SND_JACK_HEADSET | SND_JACK_BTN_0,
-                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
-               } else {
-                       dev_dbg(codec->dev, "Headphone detected\n");
-                       snd_soc_jack_report(wm8915->jack,
-                                           SND_JACK_HEADPHONE,
-                                           SND_JACK_HEADSET |
-                                           SND_JACK_BTN_0);
-
-                       /* Increase the detection rate a bit for
-                        * responsiveness.
-                        */
-                       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                           WM8915_MICD_RATE_MASK,
-                                           7 << WM8915_MICD_RATE_SHIFT);
-
-                       wm8915->detecting = false;
-               }
-       }
-}
-
-static irqreturn_t wm8915_irq(int irq, void *data)
-{
-       struct snd_soc_codec *codec = data;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       int irq_val;
-
-       irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2);
-       if (irq_val < 0) {
-               dev_err(codec->dev, "Failed to read IRQ status: %d\n",
-                       irq_val);
-               return IRQ_NONE;
-       }
-       irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK);
-
-       if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) {
-               dev_dbg(codec->dev, "DC servo IRQ\n");
-               complete(&wm8915->dcs_done);
-       }
-
-       if (irq_val & WM8915_FIFOS_ERR_EINT)
-               dev_err(codec->dev, "Digital core FIFO error\n");
-
-       if (irq_val & WM8915_FLL_LOCK_EINT) {
-               dev_dbg(codec->dev, "FLL locked\n");
-               complete(&wm8915->fll_lock);
-       }
-
-       if (irq_val & WM8915_MICD_EINT)
-               wm8915_micd(codec);
-
-       if (irq_val) {
-               snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val);
-
-               return IRQ_HANDLED;
-       } else {
-               return IRQ_NONE;
-       }
-}
-
-static irqreturn_t wm8915_edge_irq(int irq, void *data)
-{
-       irqreturn_t ret = IRQ_NONE;
-       irqreturn_t val;
-
-       do {
-               val = wm8915_irq(irq, data);
-               if (val != IRQ_NONE)
-                       ret = val;
-       } while (val != IRQ_NONE);
-
-       return ret;
-}
-
-static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct wm8915_pdata *pdata = &wm8915->pdata;
-
-       struct snd_kcontrol_new controls[] = {
-               SOC_ENUM_EXT("DSP1 EQ Mode",
-                            wm8915->retune_mobile_enum,
-                            wm8915_get_retune_mobile_enum,
-                            wm8915_put_retune_mobile_enum),
-               SOC_ENUM_EXT("DSP2 EQ Mode",
-                            wm8915->retune_mobile_enum,
-                            wm8915_get_retune_mobile_enum,
-                            wm8915_put_retune_mobile_enum),
-       };
-       int ret, i, j;
-       const char **t;
-
-       /* We need an array of texts for the enum API but the number
-        * of texts is likely to be less than the number of
-        * configurations due to the sample rate dependency of the
-        * configurations. */
-       wm8915->num_retune_mobile_texts = 0;
-       wm8915->retune_mobile_texts = NULL;
-       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
-               for (j = 0; j < wm8915->num_retune_mobile_texts; j++) {
-                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
-                                  wm8915->retune_mobile_texts[j]) == 0)
-                               break;
-               }
-
-               if (j != wm8915->num_retune_mobile_texts)
-                       continue;
-
-               /* Expand the array... */
-               t = krealloc(wm8915->retune_mobile_texts,
-                            sizeof(char *) * 
-                            (wm8915->num_retune_mobile_texts + 1),
-                            GFP_KERNEL);
-               if (t == NULL)
-                       continue;
-
-               /* ...store the new entry... */
-               t[wm8915->num_retune_mobile_texts] = 
-                       pdata->retune_mobile_cfgs[i].name;
-
-               /* ...and remember the new version. */
-               wm8915->num_retune_mobile_texts++;
-               wm8915->retune_mobile_texts = t;
-       }
-
-       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
-               wm8915->num_retune_mobile_texts);
-
-       wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts;
-       wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts;
-
-       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
-       if (ret != 0)
-               dev_err(codec->dev,
-                       "Failed to add ReTune Mobile controls: %d\n", ret);
-}
-
-static int wm8915_probe(struct snd_soc_codec *codec)
-{
-       int ret;
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int i, irq_flags;
-
-       wm8915->codec = codec;
-
-       init_completion(&wm8915->dcs_done);
-       init_completion(&wm8915->fll_lock);
-
-       dapm->idle_bias_off = true;
-       dapm->bias_level = SND_SOC_BIAS_OFF;
-
-       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(wm8915->supplies); i++)
-               wm8915->supplies[i].supply = wm8915_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies),
-                                wm8915->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
-
-       wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0;
-       wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
-       wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
-       wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
-
-       /* This should really be moved into the regulator core */
-       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
-               ret = regulator_register_notifier(wm8915->supplies[i].consumer,
-                                                 &wm8915->disable_nb[i]);
-               if (ret != 0) {
-                       dev_err(codec->dev,
-                               "Failed to register regulator notifier: %d\n",
-                               ret);
-               }
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
-                                   wm8915->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       if (wm8915->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1);
-               msleep(5);
-       }
-
-       ret = snd_soc_read(codec, WM8915_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 WM8915, ID %x\n", ret);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8915_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 & WM8915_CHIP_REV_MASK) + 'A');
-
-       if (wm8915->pdata.ldo_ena >= 0) {
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-       } else {
-               ret = wm8915_reset(codec);
-               if (ret < 0) {
-                       dev_err(codec->dev, "Failed to issue reset\n");
-                       goto err_enable;
-               }
-       }
-
-       codec->cache_only = true;
-
-       /* Apply platform data settings */
-       snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL,
-                           WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK,
-                           wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT |
-                           wm8915->pdata.inr_mode);
-
-       for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) {
-               if (!wm8915->pdata.gpio_default[i])
-                       continue;
-
-               snd_soc_write(codec, WM8915_GPIO_1 + i,
-                             wm8915->pdata.gpio_default[i] & 0xffff);
-       }
-
-       if (wm8915->pdata.spkmute_seq)
-               snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE,
-                                   WM8915_SPK_MUTE_ENDIAN |
-                                   WM8915_SPK_MUTE_SEQ1_MASK,
-                                   wm8915->pdata.spkmute_seq);
-
-       snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
-                           WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC |
-                           WM8915_MICD_SRC, wm8915->pdata.micdet_def);
-
-       /* Latch volume update bits */
-       snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME,
-                           WM8915_IN1_VU, WM8915_IN1_VU);
-       snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME,
-                           WM8915_IN1_VU, WM8915_IN1_VU);
-
-       snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-       snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-
-       snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME,
-                           WM8915_DAC1_VU, WM8915_DAC1_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-       snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME,
-                           WM8915_DAC2_VU, WM8915_DAC2_VU);
-
-       snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME,
-                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME,
-                           WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME,
-                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME,
-                           WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
-
-       snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME,
-                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME,
-                           WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME,
-                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
-       snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME,
-                           WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
-
-       /* No support currently for the underclocked TDM modes and
-        * pick a default TDM layout with each channel pair working with
-        * slots 0 and 1. */
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN2_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN2_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN3_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN4_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION,
-                           WM8915_AIF1RX_CHAN5_SLOTS_MASK |
-                           WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF2RX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF2RX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF2RX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF2RX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN2_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN3_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN4_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION,
-                           WM8915_AIF1TX_CHAN5_SLOTS_MASK |
-                           WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
-
-       snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION,
-                           WM8915_AIF2TX_CHAN0_SLOTS_MASK |
-                           WM8915_AIF2TX_CHAN0_START_SLOT_MASK,
-                           1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
-       snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
-                           WM8915_AIF2TX_CHAN1_SLOTS_MASK |
-                           WM8915_AIF2TX_CHAN1_START_SLOT_MASK,
-                           1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
-
-       if (wm8915->pdata.num_retune_mobile_cfgs)
-               wm8915_retune_mobile_pdata(codec);
-       else
-               snd_soc_add_controls(codec, wm8915_eq_controls,
-                                    ARRAY_SIZE(wm8915_eq_controls));
-
-       /* If the TX LRCLK pins are not in LRCLK mode configure the
-        * AIFs to source their clocks from the RX LRCLKs.
-        */
-       if ((snd_soc_read(codec, WM8915_GPIO_1)))
-               snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2,
-                                   WM8915_AIF1TX_LRCLK_MODE,
-                                   WM8915_AIF1TX_LRCLK_MODE);
-
-       if ((snd_soc_read(codec, WM8915_GPIO_2)))
-               snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2,
-                                   WM8915_AIF2TX_LRCLK_MODE,
-                                   WM8915_AIF2TX_LRCLK_MODE);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-
-       wm8915_init_gpio(codec);
-
-       if (i2c->irq) {
-               if (wm8915->pdata.irq_flags)
-                       irq_flags = wm8915->pdata.irq_flags;
-               else
-                       irq_flags = IRQF_TRIGGER_LOW;
-
-               irq_flags |= IRQF_ONESHOT;
-
-               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
-                       ret = request_threaded_irq(i2c->irq, NULL,
-                                                  wm8915_edge_irq,
-                                                  irq_flags, "wm8915", codec);
-               else
-                       ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
-                                                  irq_flags, "wm8915", codec);
-
-               if (ret == 0) {
-                       /* Unmask the interrupt */
-                       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
-                                           WM8915_IM_IRQ, 0);
-
-                       /* Enable error reporting and DC servo status */
-                       snd_soc_update_bits(codec,
-                                           WM8915_INTERRUPT_STATUS_2_MASK,
-                                           WM8915_IM_DCS_DONE_23_EINT |
-                                           WM8915_IM_DCS_DONE_01_EINT |
-                                           WM8915_IM_FLL_LOCK_EINT |
-                                           WM8915_IM_FIFOS_ERR_EINT,
-                                           0);
-               } else {
-                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
-                               ret);
-               }
-       }
-
-       return 0;
-
-err_enable:
-       if (wm8915->pdata.ldo_ena >= 0)
-               gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
-
-       regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-err:
-       return ret;
-}
-
-static int wm8915_remove(struct snd_soc_codec *codec)
-{
-       struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = to_i2c_client(codec->dev);
-       int i;
-
-       snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
-                           WM8915_IM_IRQ, WM8915_IM_IRQ);
-
-       if (i2c->irq)
-               free_irq(i2c->irq, codec);
-
-       wm8915_free_gpio(codec);
-
-       for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
-               regulator_unregister_notifier(wm8915->supplies[i].consumer,
-                                             &wm8915->disable_nb[i]);
-       regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
-
-       return 0;
-}
-
-static struct snd_soc_codec_driver soc_codec_dev_wm8915 = {
-       .probe =        wm8915_probe,
-       .remove =       wm8915_remove,
-       .set_bias_level = wm8915_set_bias_level,
-       .seq_notifier = wm8915_seq_notifier,
-       .reg_cache_size = WM8915_MAX_REGISTER + 1,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8915_reg,
-       .volatile_register = wm8915_volatile_register,
-       .readable_register = wm8915_readable_register,
-       .compress_type = SND_SOC_RBTREE_COMPRESSION,
-       .controls = wm8915_snd_controls,
-       .num_controls = ARRAY_SIZE(wm8915_snd_controls),
-       .dapm_widgets = wm8915_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets),
-       .dapm_routes = wm8915_dapm_routes,
-       .num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes),
-       .set_pll = wm8915_set_fll,
-};
-
-#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-                     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
-#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | 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 wm8915_dai_ops = {
-       .set_fmt = wm8915_set_fmt,
-       .hw_params = wm8915_hw_params,
-       .set_sysclk = wm8915_set_sysclk,
-};
-
-static struct snd_soc_dai_driver wm8915_dai[] = {
-       {
-               .name = "wm8915-aif1",
-               .playback = {
-                       .stream_name = "AIF1 Playback",
-                       .channels_min = 1,
-                       .channels_max = 6,
-                       .rates = WM8915_RATES,
-                       .formats = WM8915_FORMATS,
-               },
-               .capture = {
-                        .stream_name = "AIF1 Capture",
-                        .channels_min = 1,
-                        .channels_max = 6,
-                        .rates = WM8915_RATES,
-                        .formats = WM8915_FORMATS,
-                },
-               .ops = &wm8915_dai_ops,
-       },
-       {
-               .name = "wm8915-aif2",
-               .playback = {
-                       .stream_name = "AIF2 Playback",
-                       .channels_min = 1,
-                       .channels_max = 2,
-                       .rates = WM8915_RATES,
-                       .formats = WM8915_FORMATS,
-               },
-               .capture = {
-                        .stream_name = "AIF2 Capture",
-                        .channels_min = 1,
-                        .channels_max = 2,
-                        .rates = WM8915_RATES,
-                        .formats = WM8915_FORMATS,
-                },
-               .ops = &wm8915_dai_ops,
-       },
-};
-
-static __devinit int wm8915_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
-{
-       struct wm8915_priv *wm8915;
-       int ret;
-
-       wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL);
-       if (wm8915 == NULL)
-               return -ENOMEM;
-
-       i2c_set_clientdata(i2c, wm8915);
-
-       if (dev_get_platdata(&i2c->dev))
-               memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev),
-                      sizeof(wm8915->pdata));
-
-       if (wm8915->pdata.ldo_ena > 0) {
-               ret = gpio_request_one(wm8915->pdata.ldo_ena,
-                                      GPIOF_OUT_INIT_LOW, "WM8915 ENA");
-               if (ret < 0) {
-                       dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
-                               wm8915->pdata.ldo_ena, ret);
-                       goto err;
-               }
-       }
-
-       ret = snd_soc_register_codec(&i2c->dev,
-                                    &soc_codec_dev_wm8915, wm8915_dai,
-                                    ARRAY_SIZE(wm8915_dai));
-       if (ret < 0)
-               goto err_gpio;
-
-       return ret;
-
-err_gpio:
-       if (wm8915->pdata.ldo_ena > 0)
-               gpio_free(wm8915->pdata.ldo_ena);
-err:
-       kfree(wm8915);
-
-       return ret;
-}
-
-static __devexit int wm8915_i2c_remove(struct i2c_client *client)
-{
-       struct wm8915_priv *wm8915 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_codec(&client->dev);
-       if (wm8915->pdata.ldo_ena > 0)
-               gpio_free(wm8915->pdata.ldo_ena);
-       kfree(i2c_get_clientdata(client));
-       return 0;
-}
-
-static const struct i2c_device_id wm8915_i2c_id[] = {
-       { "wm8915", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id);
-
-static struct i2c_driver wm8915_i2c_driver = {
-       .driver = {
-               .name = "wm8915",
-               .owner = THIS_MODULE,
-       },
-       .probe =    wm8915_i2c_probe,
-       .remove =   __devexit_p(wm8915_i2c_remove),
-       .id_table = wm8915_i2c_id,
-};
-
-static int __init wm8915_modinit(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&wm8915_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n",
-                      ret);
-       }
-
-       return ret;
-}
-module_init(wm8915_modinit);
-
-static void __exit wm8915_exit(void)
-{
-       i2c_del_driver(&wm8915_i2c_driver);
-}
-module_exit(wm8915_exit);
-
-MODULE_DESCRIPTION("ASoC WM8915 driver");
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8915.h b/sound/soc/codecs/wm8915.h
deleted file mode 100644 (file)
index 200ffd7..0000000
+++ /dev/null
@@ -1,3717 +0,0 @@
-/*
- * wm8915.h - WM8915 audio codec interface
- *
- * 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 _WM8915_H
-#define _WM8915_H
-
-#define WM8915_SYSCLK_MCLK1 1
-#define WM8915_SYSCLK_MCLK2 2
-#define WM8915_SYSCLK_FLL   3
-
-#define WM8915_FLL_MCLK1      1
-#define WM8915_FLL_MCLK2      2
-#define WM8915_FLL_DACLRCLK1  3
-#define WM8915_FLL_BCLK1      4
-
-typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity);
-
-int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
-                 wm8915_polarity_fn polarity_cb);
-
-/*
- * Register values.
- */
-#define WM8915_SOFTWARE_RESET                   0x00
-#define WM8915_POWER_MANAGEMENT_1               0x01
-#define WM8915_POWER_MANAGEMENT_2               0x02
-#define WM8915_POWER_MANAGEMENT_3               0x03
-#define WM8915_POWER_MANAGEMENT_4               0x04
-#define WM8915_POWER_MANAGEMENT_5               0x05
-#define WM8915_POWER_MANAGEMENT_6               0x06
-#define WM8915_POWER_MANAGEMENT_7               0x07
-#define WM8915_POWER_MANAGEMENT_8               0x08
-#define WM8915_LEFT_LINE_INPUT_VOLUME           0x10
-#define WM8915_RIGHT_LINE_INPUT_VOLUME          0x11
-#define WM8915_LINE_INPUT_CONTROL               0x12
-#define WM8915_DAC1_HPOUT1_VOLUME               0x15
-#define WM8915_DAC2_HPOUT2_VOLUME               0x16
-#define WM8915_DAC1_LEFT_VOLUME                 0x18
-#define WM8915_DAC1_RIGHT_VOLUME                0x19
-#define WM8915_DAC2_LEFT_VOLUME                 0x1A
-#define WM8915_DAC2_RIGHT_VOLUME                0x1B
-#define WM8915_OUTPUT1_LEFT_VOLUME              0x1C
-#define WM8915_OUTPUT1_RIGHT_VOLUME             0x1D
-#define WM8915_OUTPUT2_LEFT_VOLUME              0x1E
-#define WM8915_OUTPUT2_RIGHT_VOLUME             0x1F
-#define WM8915_MICBIAS_1                        0x20
-#define WM8915_MICBIAS_2                        0x21
-#define WM8915_LDO_1                            0x28
-#define WM8915_LDO_2                            0x29
-#define WM8915_ACCESSORY_DETECT_MODE_1          0x30
-#define WM8915_ACCESSORY_DETECT_MODE_2          0x31
-#define WM8915_HEADPHONE_DETECT_1               0x34
-#define WM8915_HEADPHONE_DETECT_2               0x35
-#define WM8915_MIC_DETECT_1                     0x38
-#define WM8915_MIC_DETECT_2                     0x39
-#define WM8915_MIC_DETECT_3                     0x3A
-#define WM8915_CHARGE_PUMP_1                    0x40
-#define WM8915_CHARGE_PUMP_2                    0x41
-#define WM8915_DC_SERVO_1                       0x50
-#define WM8915_DC_SERVO_2                       0x51
-#define WM8915_DC_SERVO_3                       0x52
-#define WM8915_DC_SERVO_5                       0x54
-#define WM8915_DC_SERVO_6                       0x55
-#define WM8915_DC_SERVO_7                       0x56
-#define WM8915_DC_SERVO_READBACK_0              0x57
-#define WM8915_ANALOGUE_HP_1                    0x60
-#define WM8915_ANALOGUE_HP_2                    0x61
-#define WM8915_CHIP_REVISION                    0x100
-#define WM8915_CONTROL_INTERFACE_1              0x101
-#define WM8915_WRITE_SEQUENCER_CTRL_1           0x110
-#define WM8915_WRITE_SEQUENCER_CTRL_2           0x111
-#define WM8915_AIF_CLOCKING_1                   0x200
-#define WM8915_AIF_CLOCKING_2                   0x201
-#define WM8915_CLOCKING_1                       0x208
-#define WM8915_CLOCKING_2                       0x209
-#define WM8915_AIF_RATE                         0x210
-#define WM8915_FLL_CONTROL_1                    0x220
-#define WM8915_FLL_CONTROL_2                    0x221
-#define WM8915_FLL_CONTROL_3                    0x222
-#define WM8915_FLL_CONTROL_4                    0x223
-#define WM8915_FLL_CONTROL_5                    0x224
-#define WM8915_FLL_CONTROL_6                    0x225
-#define WM8915_FLL_EFS_1                        0x226
-#define WM8915_FLL_EFS_2                        0x227
-#define WM8915_AIF1_CONTROL                     0x300
-#define WM8915_AIF1_BCLK                        0x301
-#define WM8915_AIF1_TX_LRCLK_1                  0x302
-#define WM8915_AIF1_TX_LRCLK_2                  0x303
-#define WM8915_AIF1_RX_LRCLK_1                  0x304
-#define WM8915_AIF1_RX_LRCLK_2                  0x305
-#define WM8915_AIF1TX_DATA_CONFIGURATION_1      0x306
-#define WM8915_AIF1TX_DATA_CONFIGURATION_2      0x307
-#define WM8915_AIF1RX_DATA_CONFIGURATION        0x308
-#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
-#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
-#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
-#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
-#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
-#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
-#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
-#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
-#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
-#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
-#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
-#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
-#define WM8915_AIF1RX_MONO_CONFIGURATION        0x315
-#define WM8915_AIF1TX_TEST                      0x31A
-#define WM8915_AIF2_CONTROL                     0x320
-#define WM8915_AIF2_BCLK                        0x321
-#define WM8915_AIF2_TX_LRCLK_1                  0x322
-#define WM8915_AIF2_TX_LRCLK_2                  0x323
-#define WM8915_AIF2_RX_LRCLK_1                  0x324
-#define WM8915_AIF2_RX_LRCLK_2                  0x325
-#define WM8915_AIF2TX_DATA_CONFIGURATION_1      0x326
-#define WM8915_AIF2TX_DATA_CONFIGURATION_2      0x327
-#define WM8915_AIF2RX_DATA_CONFIGURATION        0x328
-#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
-#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
-#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
-#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
-#define WM8915_AIF2RX_MONO_CONFIGURATION        0x32D
-#define WM8915_AIF2TX_TEST                      0x32F
-#define WM8915_DSP1_TX_LEFT_VOLUME              0x400
-#define WM8915_DSP1_TX_RIGHT_VOLUME             0x401
-#define WM8915_DSP1_RX_LEFT_VOLUME              0x402
-#define WM8915_DSP1_RX_RIGHT_VOLUME             0x403
-#define WM8915_DSP1_TX_FILTERS                  0x410
-#define WM8915_DSP1_RX_FILTERS_1                0x420
-#define WM8915_DSP1_RX_FILTERS_2                0x421
-#define WM8915_DSP1_DRC_1                       0x440
-#define WM8915_DSP1_DRC_2                       0x441
-#define WM8915_DSP1_DRC_3                       0x442
-#define WM8915_DSP1_DRC_4                       0x443
-#define WM8915_DSP1_DRC_5                       0x444
-#define WM8915_DSP1_RX_EQ_GAINS_1               0x480
-#define WM8915_DSP1_RX_EQ_GAINS_2               0x481
-#define WM8915_DSP1_RX_EQ_BAND_1_A              0x482
-#define WM8915_DSP1_RX_EQ_BAND_1_B              0x483
-#define WM8915_DSP1_RX_EQ_BAND_1_PG             0x484
-#define WM8915_DSP1_RX_EQ_BAND_2_A              0x485
-#define WM8915_DSP1_RX_EQ_BAND_2_B              0x486
-#define WM8915_DSP1_RX_EQ_BAND_2_C              0x487
-#define WM8915_DSP1_RX_EQ_BAND_2_PG             0x488
-#define WM8915_DSP1_RX_EQ_BAND_3_A              0x489
-#define WM8915_DSP1_RX_EQ_BAND_3_B              0x48A
-#define WM8915_DSP1_RX_EQ_BAND_3_C              0x48B
-#define WM8915_DSP1_RX_EQ_BAND_3_PG             0x48C
-#define WM8915_DSP1_RX_EQ_BAND_4_A              0x48D
-#define WM8915_DSP1_RX_EQ_BAND_4_B              0x48E
-#define WM8915_DSP1_RX_EQ_BAND_4_C              0x48F
-#define WM8915_DSP1_RX_EQ_BAND_4_PG             0x490
-#define WM8915_DSP1_RX_EQ_BAND_5_A              0x491
-#define WM8915_DSP1_RX_EQ_BAND_5_B              0x492
-#define WM8915_DSP1_RX_EQ_BAND_5_PG             0x493
-#define WM8915_DSP2_TX_LEFT_VOLUME              0x500
-#define WM8915_DSP2_TX_RIGHT_VOLUME             0x501
-#define WM8915_DSP2_RX_LEFT_VOLUME              0x502
-#define WM8915_DSP2_RX_RIGHT_VOLUME             0x503
-#define WM8915_DSP2_TX_FILTERS                  0x510
-#define WM8915_DSP2_RX_FILTERS_1                0x520
-#define WM8915_DSP2_RX_FILTERS_2                0x521
-#define WM8915_DSP2_DRC_1                       0x540
-#define WM8915_DSP2_DRC_2                       0x541
-#define WM8915_DSP2_DRC_3                       0x542
-#define WM8915_DSP2_DRC_4                       0x543
-#define WM8915_DSP2_DRC_5                       0x544
-#define WM8915_DSP2_RX_EQ_GAINS_1               0x580
-#define WM8915_DSP2_RX_EQ_GAINS_2               0x581
-#define WM8915_DSP2_RX_EQ_BAND_1_A              0x582
-#define WM8915_DSP2_RX_EQ_BAND_1_B              0x583
-#define WM8915_DSP2_RX_EQ_BAND_1_PG             0x584
-#define WM8915_DSP2_RX_EQ_BAND_2_A              0x585
-#define WM8915_DSP2_RX_EQ_BAND_2_B              0x586
-#define WM8915_DSP2_RX_EQ_BAND_2_C              0x587
-#define WM8915_DSP2_RX_EQ_BAND_2_PG             0x588
-#define WM8915_DSP2_RX_EQ_BAND_3_A              0x589
-#define WM8915_DSP2_RX_EQ_BAND_3_B              0x58A
-#define WM8915_DSP2_RX_EQ_BAND_3_C              0x58B
-#define WM8915_DSP2_RX_EQ_BAND_3_PG             0x58C
-#define WM8915_DSP2_RX_EQ_BAND_4_A              0x58D
-#define WM8915_DSP2_RX_EQ_BAND_4_B              0x58E
-#define WM8915_DSP2_RX_EQ_BAND_4_C              0x58F
-#define WM8915_DSP2_RX_EQ_BAND_4_PG             0x590
-#define WM8915_DSP2_RX_EQ_BAND_5_A              0x591
-#define WM8915_DSP2_RX_EQ_BAND_5_B              0x592
-#define WM8915_DSP2_RX_EQ_BAND_5_PG             0x593
-#define WM8915_DAC1_MIXER_VOLUMES               0x600
-#define WM8915_DAC1_LEFT_MIXER_ROUTING          0x601
-#define WM8915_DAC1_RIGHT_MIXER_ROUTING         0x602
-#define WM8915_DAC2_MIXER_VOLUMES               0x603
-#define WM8915_DAC2_LEFT_MIXER_ROUTING          0x604
-#define WM8915_DAC2_RIGHT_MIXER_ROUTING         0x605
-#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING       0x606
-#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
-#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING       0x608
-#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
-#define WM8915_DSP_TX_MIXER_SELECT              0x60A
-#define WM8915_DAC_SOFTMUTE                     0x610
-#define WM8915_OVERSAMPLING                     0x620
-#define WM8915_SIDETONE                         0x621
-#define WM8915_GPIO_1                           0x700
-#define WM8915_GPIO_2                           0x701
-#define WM8915_GPIO_3                           0x702
-#define WM8915_GPIO_4                           0x703
-#define WM8915_GPIO_5                           0x704
-#define WM8915_PULL_CONTROL_1                   0x720
-#define WM8915_PULL_CONTROL_2                   0x721
-#define WM8915_INTERRUPT_STATUS_1               0x730
-#define WM8915_INTERRUPT_STATUS_2               0x731
-#define WM8915_INTERRUPT_RAW_STATUS_2           0x732
-#define WM8915_INTERRUPT_STATUS_1_MASK          0x738
-#define WM8915_INTERRUPT_STATUS_2_MASK          0x739
-#define WM8915_INTERRUPT_CONTROL                0x740
-#define WM8915_LEFT_PDM_SPEAKER                 0x800
-#define WM8915_RIGHT_PDM_SPEAKER                0x801
-#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE        0x802
-#define WM8915_PDM_SPEAKER_VOLUME               0x803
-#define WM8915_WRITE_SEQUENCER_0                0x3000
-#define WM8915_WRITE_SEQUENCER_1                0x3001
-#define WM8915_WRITE_SEQUENCER_2                0x3002
-#define WM8915_WRITE_SEQUENCER_3                0x3003
-#define WM8915_WRITE_SEQUENCER_4                0x3004
-#define WM8915_WRITE_SEQUENCER_5                0x3005
-#define WM8915_WRITE_SEQUENCER_6                0x3006
-#define WM8915_WRITE_SEQUENCER_7                0x3007
-#define WM8915_WRITE_SEQUENCER_8                0x3008
-#define WM8915_WRITE_SEQUENCER_9                0x3009
-#define WM8915_WRITE_SEQUENCER_10               0x300A
-#define WM8915_WRITE_SEQUENCER_11               0x300B
-#define WM8915_WRITE_SEQUENCER_12               0x300C
-#define WM8915_WRITE_SEQUENCER_13               0x300D
-#define WM8915_WRITE_SEQUENCER_14               0x300E
-#define WM8915_WRITE_SEQUENCER_15               0x300F
-#define WM8915_WRITE_SEQUENCER_16               0x3010
-#define WM8915_WRITE_SEQUENCER_17               0x3011
-#define WM8915_WRITE_SEQUENCER_18               0x3012
-#define WM8915_WRITE_SEQUENCER_19               0x3013
-#define WM8915_WRITE_SEQUENCER_20               0x3014
-#define WM8915_WRITE_SEQUENCER_21               0x3015
-#define WM8915_WRITE_SEQUENCER_22               0x3016
-#define WM8915_WRITE_SEQUENCER_23               0x3017
-#define WM8915_WRITE_SEQUENCER_24               0x3018
-#define WM8915_WRITE_SEQUENCER_25               0x3019
-#define WM8915_WRITE_SEQUENCER_26               0x301A
-#define WM8915_WRITE_SEQUENCER_27               0x301B
-#define WM8915_WRITE_SEQUENCER_28               0x301C
-#define WM8915_WRITE_SEQUENCER_29               0x301D
-#define WM8915_WRITE_SEQUENCER_30               0x301E
-#define WM8915_WRITE_SEQUENCER_31               0x301F
-#define WM8915_WRITE_SEQUENCER_32               0x3020
-#define WM8915_WRITE_SEQUENCER_33               0x3021
-#define WM8915_WRITE_SEQUENCER_34               0x3022
-#define WM8915_WRITE_SEQUENCER_35               0x3023
-#define WM8915_WRITE_SEQUENCER_36               0x3024
-#define WM8915_WRITE_SEQUENCER_37               0x3025
-#define WM8915_WRITE_SEQUENCER_38               0x3026
-#define WM8915_WRITE_SEQUENCER_39               0x3027
-#define WM8915_WRITE_SEQUENCER_40               0x3028
-#define WM8915_WRITE_SEQUENCER_41               0x3029
-#define WM8915_WRITE_SEQUENCER_42               0x302A
-#define WM8915_WRITE_SEQUENCER_43               0x302B
-#define WM8915_WRITE_SEQUENCER_44               0x302C
-#define WM8915_WRITE_SEQUENCER_45               0x302D
-#define WM8915_WRITE_SEQUENCER_46               0x302E
-#define WM8915_WRITE_SEQUENCER_47               0x302F
-#define WM8915_WRITE_SEQUENCER_48               0x3030
-#define WM8915_WRITE_SEQUENCER_49               0x3031
-#define WM8915_WRITE_SEQUENCER_50               0x3032
-#define WM8915_WRITE_SEQUENCER_51               0x3033
-#define WM8915_WRITE_SEQUENCER_52               0x3034
-#define WM8915_WRITE_SEQUENCER_53               0x3035
-#define WM8915_WRITE_SEQUENCER_54               0x3036
-#define WM8915_WRITE_SEQUENCER_55               0x3037
-#define WM8915_WRITE_SEQUENCER_56               0x3038
-#define WM8915_WRITE_SEQUENCER_57               0x3039
-#define WM8915_WRITE_SEQUENCER_58               0x303A
-#define WM8915_WRITE_SEQUENCER_59               0x303B
-#define WM8915_WRITE_SEQUENCER_60               0x303C
-#define WM8915_WRITE_SEQUENCER_61               0x303D
-#define WM8915_WRITE_SEQUENCER_62               0x303E
-#define WM8915_WRITE_SEQUENCER_63               0x303F
-#define WM8915_WRITE_SEQUENCER_64               0x3040
-#define WM8915_WRITE_SEQUENCER_65               0x3041
-#define WM8915_WRITE_SEQUENCER_66               0x3042
-#define WM8915_WRITE_SEQUENCER_67               0x3043
-#define WM8915_WRITE_SEQUENCER_68               0x3044
-#define WM8915_WRITE_SEQUENCER_69               0x3045
-#define WM8915_WRITE_SEQUENCER_70               0x3046
-#define WM8915_WRITE_SEQUENCER_71               0x3047
-#define WM8915_WRITE_SEQUENCER_72               0x3048
-#define WM8915_WRITE_SEQUENCER_73               0x3049
-#define WM8915_WRITE_SEQUENCER_74               0x304A
-#define WM8915_WRITE_SEQUENCER_75               0x304B
-#define WM8915_WRITE_SEQUENCER_76               0x304C
-#define WM8915_WRITE_SEQUENCER_77               0x304D
-#define WM8915_WRITE_SEQUENCER_78               0x304E
-#define WM8915_WRITE_SEQUENCER_79               0x304F
-#define WM8915_WRITE_SEQUENCER_80               0x3050
-#define WM8915_WRITE_SEQUENCER_81               0x3051
-#define WM8915_WRITE_SEQUENCER_82               0x3052
-#define WM8915_WRITE_SEQUENCER_83               0x3053
-#define WM8915_WRITE_SEQUENCER_84               0x3054
-#define WM8915_WRITE_SEQUENCER_85               0x3055
-#define WM8915_WRITE_SEQUENCER_86               0x3056
-#define WM8915_WRITE_SEQUENCER_87               0x3057
-#define WM8915_WRITE_SEQUENCER_88               0x3058
-#define WM8915_WRITE_SEQUENCER_89               0x3059
-#define WM8915_WRITE_SEQUENCER_90               0x305A
-#define WM8915_WRITE_SEQUENCER_91               0x305B
-#define WM8915_WRITE_SEQUENCER_92               0x305C
-#define WM8915_WRITE_SEQUENCER_93               0x305D
-#define WM8915_WRITE_SEQUENCER_94               0x305E
-#define WM8915_WRITE_SEQUENCER_95               0x305F
-#define WM8915_WRITE_SEQUENCER_96               0x3060
-#define WM8915_WRITE_SEQUENCER_97               0x3061
-#define WM8915_WRITE_SEQUENCER_98               0x3062
-#define WM8915_WRITE_SEQUENCER_99               0x3063
-#define WM8915_WRITE_SEQUENCER_100              0x3064
-#define WM8915_WRITE_SEQUENCER_101              0x3065
-#define WM8915_WRITE_SEQUENCER_102              0x3066
-#define WM8915_WRITE_SEQUENCER_103              0x3067
-#define WM8915_WRITE_SEQUENCER_104              0x3068
-#define WM8915_WRITE_SEQUENCER_105              0x3069
-#define WM8915_WRITE_SEQUENCER_106              0x306A
-#define WM8915_WRITE_SEQUENCER_107              0x306B
-#define WM8915_WRITE_SEQUENCER_108              0x306C
-#define WM8915_WRITE_SEQUENCER_109              0x306D
-#define WM8915_WRITE_SEQUENCER_110              0x306E
-#define WM8915_WRITE_SEQUENCER_111              0x306F
-#define WM8915_WRITE_SEQUENCER_112              0x3070
-#define WM8915_WRITE_SEQUENCER_113              0x3071
-#define WM8915_WRITE_SEQUENCER_114              0x3072
-#define WM8915_WRITE_SEQUENCER_115              0x3073
-#define WM8915_WRITE_SEQUENCER_116              0x3074
-#define WM8915_WRITE_SEQUENCER_117              0x3075
-#define WM8915_WRITE_SEQUENCER_118              0x3076
-#define WM8915_WRITE_SEQUENCER_119              0x3077
-#define WM8915_WRITE_SEQUENCER_120              0x3078
-#define WM8915_WRITE_SEQUENCER_121              0x3079
-#define WM8915_WRITE_SEQUENCER_122              0x307A
-#define WM8915_WRITE_SEQUENCER_123              0x307B
-#define WM8915_WRITE_SEQUENCER_124              0x307C
-#define WM8915_WRITE_SEQUENCER_125              0x307D
-#define WM8915_WRITE_SEQUENCER_126              0x307E
-#define WM8915_WRITE_SEQUENCER_127              0x307F
-#define WM8915_WRITE_SEQUENCER_128              0x3080
-#define WM8915_WRITE_SEQUENCER_129              0x3081
-#define WM8915_WRITE_SEQUENCER_130              0x3082
-#define WM8915_WRITE_SEQUENCER_131              0x3083
-#define WM8915_WRITE_SEQUENCER_132              0x3084
-#define WM8915_WRITE_SEQUENCER_133              0x3085
-#define WM8915_WRITE_SEQUENCER_134              0x3086
-#define WM8915_WRITE_SEQUENCER_135              0x3087
-#define WM8915_WRITE_SEQUENCER_136              0x3088
-#define WM8915_WRITE_SEQUENCER_137              0x3089
-#define WM8915_WRITE_SEQUENCER_138              0x308A
-#define WM8915_WRITE_SEQUENCER_139              0x308B
-#define WM8915_WRITE_SEQUENCER_140              0x308C
-#define WM8915_WRITE_SEQUENCER_141              0x308D
-#define WM8915_WRITE_SEQUENCER_142              0x308E
-#define WM8915_WRITE_SEQUENCER_143              0x308F
-#define WM8915_WRITE_SEQUENCER_144              0x3090
-#define WM8915_WRITE_SEQUENCER_145              0x3091
-#define WM8915_WRITE_SEQUENCER_146              0x3092
-#define WM8915_WRITE_SEQUENCER_147              0x3093
-#define WM8915_WRITE_SEQUENCER_148              0x3094
-#define WM8915_WRITE_SEQUENCER_149              0x3095
-#define WM8915_WRITE_SEQUENCER_150              0x3096
-#define WM8915_WRITE_SEQUENCER_151              0x3097
-#define WM8915_WRITE_SEQUENCER_152              0x3098
-#define WM8915_WRITE_SEQUENCER_153              0x3099
-#define WM8915_WRITE_SEQUENCER_154              0x309A
-#define WM8915_WRITE_SEQUENCER_155              0x309B
-#define WM8915_WRITE_SEQUENCER_156              0x309C
-#define WM8915_WRITE_SEQUENCER_157              0x309D
-#define WM8915_WRITE_SEQUENCER_158              0x309E
-#define WM8915_WRITE_SEQUENCER_159              0x309F
-#define WM8915_WRITE_SEQUENCER_160              0x30A0
-#define WM8915_WRITE_SEQUENCER_161              0x30A1
-#define WM8915_WRITE_SEQUENCER_162              0x30A2
-#define WM8915_WRITE_SEQUENCER_163              0x30A3
-#define WM8915_WRITE_SEQUENCER_164              0x30A4
-#define WM8915_WRITE_SEQUENCER_165              0x30A5
-#define WM8915_WRITE_SEQUENCER_166              0x30A6
-#define WM8915_WRITE_SEQUENCER_167              0x30A7
-#define WM8915_WRITE_SEQUENCER_168              0x30A8
-#define WM8915_WRITE_SEQUENCER_169              0x30A9
-#define WM8915_WRITE_SEQUENCER_170              0x30AA
-#define WM8915_WRITE_SEQUENCER_171              0x30AB
-#define WM8915_WRITE_SEQUENCER_172              0x30AC
-#define WM8915_WRITE_SEQUENCER_173              0x30AD
-#define WM8915_WRITE_SEQUENCER_174              0x30AE
-#define WM8915_WRITE_SEQUENCER_175              0x30AF
-#define WM8915_WRITE_SEQUENCER_176              0x30B0
-#define WM8915_WRITE_SEQUENCER_177              0x30B1
-#define WM8915_WRITE_SEQUENCER_178              0x30B2
-#define WM8915_WRITE_SEQUENCER_179              0x30B3
-#define WM8915_WRITE_SEQUENCER_180              0x30B4
-#define WM8915_WRITE_SEQUENCER_181              0x30B5
-#define WM8915_WRITE_SEQUENCER_182              0x30B6
-#define WM8915_WRITE_SEQUENCER_183              0x30B7
-#define WM8915_WRITE_SEQUENCER_184              0x30B8
-#define WM8915_WRITE_SEQUENCER_185              0x30B9
-#define WM8915_WRITE_SEQUENCER_186              0x30BA
-#define WM8915_WRITE_SEQUENCER_187              0x30BB
-#define WM8915_WRITE_SEQUENCER_188              0x30BC
-#define WM8915_WRITE_SEQUENCER_189              0x30BD
-#define WM8915_WRITE_SEQUENCER_190              0x30BE
-#define WM8915_WRITE_SEQUENCER_191              0x30BF
-#define WM8915_WRITE_SEQUENCER_192              0x30C0
-#define WM8915_WRITE_SEQUENCER_193              0x30C1
-#define WM8915_WRITE_SEQUENCER_194              0x30C2
-#define WM8915_WRITE_SEQUENCER_195              0x30C3
-#define WM8915_WRITE_SEQUENCER_196              0x30C4
-#define WM8915_WRITE_SEQUENCER_197              0x30C5
-#define WM8915_WRITE_SEQUENCER_198              0x30C6
-#define WM8915_WRITE_SEQUENCER_199              0x30C7
-#define WM8915_WRITE_SEQUENCER_200              0x30C8
-#define WM8915_WRITE_SEQUENCER_201              0x30C9
-#define WM8915_WRITE_SEQUENCER_202              0x30CA
-#define WM8915_WRITE_SEQUENCER_203              0x30CB
-#define WM8915_WRITE_SEQUENCER_204              0x30CC
-#define WM8915_WRITE_SEQUENCER_205              0x30CD
-#define WM8915_WRITE_SEQUENCER_206              0x30CE
-#define WM8915_WRITE_SEQUENCER_207              0x30CF
-#define WM8915_WRITE_SEQUENCER_208              0x30D0
-#define WM8915_WRITE_SEQUENCER_209              0x30D1
-#define WM8915_WRITE_SEQUENCER_210              0x30D2
-#define WM8915_WRITE_SEQUENCER_211              0x30D3
-#define WM8915_WRITE_SEQUENCER_212              0x30D4
-#define WM8915_WRITE_SEQUENCER_213              0x30D5
-#define WM8915_WRITE_SEQUENCER_214              0x30D6
-#define WM8915_WRITE_SEQUENCER_215              0x30D7
-#define WM8915_WRITE_SEQUENCER_216              0x30D8
-#define WM8915_WRITE_SEQUENCER_217              0x30D9
-#define WM8915_WRITE_SEQUENCER_218              0x30DA
-#define WM8915_WRITE_SEQUENCER_219              0x30DB
-#define WM8915_WRITE_SEQUENCER_220              0x30DC
-#define WM8915_WRITE_SEQUENCER_221              0x30DD
-#define WM8915_WRITE_SEQUENCER_222              0x30DE
-#define WM8915_WRITE_SEQUENCER_223              0x30DF
-#define WM8915_WRITE_SEQUENCER_224              0x30E0
-#define WM8915_WRITE_SEQUENCER_225              0x30E1
-#define WM8915_WRITE_SEQUENCER_226              0x30E2
-#define WM8915_WRITE_SEQUENCER_227              0x30E3
-#define WM8915_WRITE_SEQUENCER_228              0x30E4
-#define WM8915_WRITE_SEQUENCER_229              0x30E5
-#define WM8915_WRITE_SEQUENCER_230              0x30E6
-#define WM8915_WRITE_SEQUENCER_231              0x30E7
-#define WM8915_WRITE_SEQUENCER_232              0x30E8
-#define WM8915_WRITE_SEQUENCER_233              0x30E9
-#define WM8915_WRITE_SEQUENCER_234              0x30EA
-#define WM8915_WRITE_SEQUENCER_235              0x30EB
-#define WM8915_WRITE_SEQUENCER_236              0x30EC
-#define WM8915_WRITE_SEQUENCER_237              0x30ED
-#define WM8915_WRITE_SEQUENCER_238              0x30EE
-#define WM8915_WRITE_SEQUENCER_239              0x30EF
-#define WM8915_WRITE_SEQUENCER_240              0x30F0
-#define WM8915_WRITE_SEQUENCER_241              0x30F1
-#define WM8915_WRITE_SEQUENCER_242              0x30F2
-#define WM8915_WRITE_SEQUENCER_243              0x30F3
-#define WM8915_WRITE_SEQUENCER_244              0x30F4
-#define WM8915_WRITE_SEQUENCER_245              0x30F5
-#define WM8915_WRITE_SEQUENCER_246              0x30F6
-#define WM8915_WRITE_SEQUENCER_247              0x30F7
-#define WM8915_WRITE_SEQUENCER_248              0x30F8
-#define WM8915_WRITE_SEQUENCER_249              0x30F9
-#define WM8915_WRITE_SEQUENCER_250              0x30FA
-#define WM8915_WRITE_SEQUENCER_251              0x30FB
-#define WM8915_WRITE_SEQUENCER_252              0x30FC
-#define WM8915_WRITE_SEQUENCER_253              0x30FD
-#define WM8915_WRITE_SEQUENCER_254              0x30FE
-#define WM8915_WRITE_SEQUENCER_255              0x30FF
-#define WM8915_WRITE_SEQUENCER_256              0x3100
-#define WM8915_WRITE_SEQUENCER_257              0x3101
-#define WM8915_WRITE_SEQUENCER_258              0x3102
-#define WM8915_WRITE_SEQUENCER_259              0x3103
-#define WM8915_WRITE_SEQUENCER_260              0x3104
-#define WM8915_WRITE_SEQUENCER_261              0x3105
-#define WM8915_WRITE_SEQUENCER_262              0x3106
-#define WM8915_WRITE_SEQUENCER_263              0x3107
-#define WM8915_WRITE_SEQUENCER_264              0x3108
-#define WM8915_WRITE_SEQUENCER_265              0x3109
-#define WM8915_WRITE_SEQUENCER_266              0x310A
-#define WM8915_WRITE_SEQUENCER_267              0x310B
-#define WM8915_WRITE_SEQUENCER_268              0x310C
-#define WM8915_WRITE_SEQUENCER_269              0x310D
-#define WM8915_WRITE_SEQUENCER_270              0x310E
-#define WM8915_WRITE_SEQUENCER_271              0x310F
-#define WM8915_WRITE_SEQUENCER_272              0x3110
-#define WM8915_WRITE_SEQUENCER_273              0x3111
-#define WM8915_WRITE_SEQUENCER_274              0x3112
-#define WM8915_WRITE_SEQUENCER_275              0x3113
-#define WM8915_WRITE_SEQUENCER_276              0x3114
-#define WM8915_WRITE_SEQUENCER_277              0x3115
-#define WM8915_WRITE_SEQUENCER_278              0x3116
-#define WM8915_WRITE_SEQUENCER_279              0x3117
-#define WM8915_WRITE_SEQUENCER_280              0x3118
-#define WM8915_WRITE_SEQUENCER_281              0x3119
-#define WM8915_WRITE_SEQUENCER_282              0x311A
-#define WM8915_WRITE_SEQUENCER_283              0x311B
-#define WM8915_WRITE_SEQUENCER_284              0x311C
-#define WM8915_WRITE_SEQUENCER_285              0x311D
-#define WM8915_WRITE_SEQUENCER_286              0x311E
-#define WM8915_WRITE_SEQUENCER_287              0x311F
-#define WM8915_WRITE_SEQUENCER_288              0x3120
-#define WM8915_WRITE_SEQUENCER_289              0x3121
-#define WM8915_WRITE_SEQUENCER_290              0x3122
-#define WM8915_WRITE_SEQUENCER_291              0x3123
-#define WM8915_WRITE_SEQUENCER_292              0x3124
-#define WM8915_WRITE_SEQUENCER_293              0x3125
-#define WM8915_WRITE_SEQUENCER_294              0x3126
-#define WM8915_WRITE_SEQUENCER_295              0x3127
-#define WM8915_WRITE_SEQUENCER_296              0x3128
-#define WM8915_WRITE_SEQUENCER_297              0x3129
-#define WM8915_WRITE_SEQUENCER_298              0x312A
-#define WM8915_WRITE_SEQUENCER_299              0x312B
-#define WM8915_WRITE_SEQUENCER_300              0x312C
-#define WM8915_WRITE_SEQUENCER_301              0x312D
-#define WM8915_WRITE_SEQUENCER_302              0x312E
-#define WM8915_WRITE_SEQUENCER_303              0x312F
-#define WM8915_WRITE_SEQUENCER_304              0x3130
-#define WM8915_WRITE_SEQUENCER_305              0x3131
-#define WM8915_WRITE_SEQUENCER_306              0x3132
-#define WM8915_WRITE_SEQUENCER_307              0x3133
-#define WM8915_WRITE_SEQUENCER_308              0x3134
-#define WM8915_WRITE_SEQUENCER_309              0x3135
-#define WM8915_WRITE_SEQUENCER_310              0x3136
-#define WM8915_WRITE_SEQUENCER_311              0x3137
-#define WM8915_WRITE_SEQUENCER_312              0x3138
-#define WM8915_WRITE_SEQUENCER_313              0x3139
-#define WM8915_WRITE_SEQUENCER_314              0x313A
-#define WM8915_WRITE_SEQUENCER_315              0x313B
-#define WM8915_WRITE_SEQUENCER_316              0x313C
-#define WM8915_WRITE_SEQUENCER_317              0x313D
-#define WM8915_WRITE_SEQUENCER_318              0x313E
-#define WM8915_WRITE_SEQUENCER_319              0x313F
-#define WM8915_WRITE_SEQUENCER_320              0x3140
-#define WM8915_WRITE_SEQUENCER_321              0x3141
-#define WM8915_WRITE_SEQUENCER_322              0x3142
-#define WM8915_WRITE_SEQUENCER_323              0x3143
-#define WM8915_WRITE_SEQUENCER_324              0x3144
-#define WM8915_WRITE_SEQUENCER_325              0x3145
-#define WM8915_WRITE_SEQUENCER_326              0x3146
-#define WM8915_WRITE_SEQUENCER_327              0x3147
-#define WM8915_WRITE_SEQUENCER_328              0x3148
-#define WM8915_WRITE_SEQUENCER_329              0x3149
-#define WM8915_WRITE_SEQUENCER_330              0x314A
-#define WM8915_WRITE_SEQUENCER_331              0x314B
-#define WM8915_WRITE_SEQUENCER_332              0x314C
-#define WM8915_WRITE_SEQUENCER_333              0x314D
-#define WM8915_WRITE_SEQUENCER_334              0x314E
-#define WM8915_WRITE_SEQUENCER_335              0x314F
-#define WM8915_WRITE_SEQUENCER_336              0x3150
-#define WM8915_WRITE_SEQUENCER_337              0x3151
-#define WM8915_WRITE_SEQUENCER_338              0x3152
-#define WM8915_WRITE_SEQUENCER_339              0x3153
-#define WM8915_WRITE_SEQUENCER_340              0x3154
-#define WM8915_WRITE_SEQUENCER_341              0x3155
-#define WM8915_WRITE_SEQUENCER_342              0x3156
-#define WM8915_WRITE_SEQUENCER_343              0x3157
-#define WM8915_WRITE_SEQUENCER_344              0x3158
-#define WM8915_WRITE_SEQUENCER_345              0x3159
-#define WM8915_WRITE_SEQUENCER_346              0x315A
-#define WM8915_WRITE_SEQUENCER_347              0x315B
-#define WM8915_WRITE_SEQUENCER_348              0x315C
-#define WM8915_WRITE_SEQUENCER_349              0x315D
-#define WM8915_WRITE_SEQUENCER_350              0x315E
-#define WM8915_WRITE_SEQUENCER_351              0x315F
-#define WM8915_WRITE_SEQUENCER_352              0x3160
-#define WM8915_WRITE_SEQUENCER_353              0x3161
-#define WM8915_WRITE_SEQUENCER_354              0x3162
-#define WM8915_WRITE_SEQUENCER_355              0x3163
-#define WM8915_WRITE_SEQUENCER_356              0x3164
-#define WM8915_WRITE_SEQUENCER_357              0x3165
-#define WM8915_WRITE_SEQUENCER_358              0x3166
-#define WM8915_WRITE_SEQUENCER_359              0x3167
-#define WM8915_WRITE_SEQUENCER_360              0x3168
-#define WM8915_WRITE_SEQUENCER_361              0x3169
-#define WM8915_WRITE_SEQUENCER_362              0x316A
-#define WM8915_WRITE_SEQUENCER_363              0x316B
-#define WM8915_WRITE_SEQUENCER_364              0x316C
-#define WM8915_WRITE_SEQUENCER_365              0x316D
-#define WM8915_WRITE_SEQUENCER_366              0x316E
-#define WM8915_WRITE_SEQUENCER_367              0x316F
-#define WM8915_WRITE_SEQUENCER_368              0x3170
-#define WM8915_WRITE_SEQUENCER_369              0x3171
-#define WM8915_WRITE_SEQUENCER_370              0x3172
-#define WM8915_WRITE_SEQUENCER_371              0x3173
-#define WM8915_WRITE_SEQUENCER_372              0x3174
-#define WM8915_WRITE_SEQUENCER_373              0x3175
-#define WM8915_WRITE_SEQUENCER_374              0x3176
-#define WM8915_WRITE_SEQUENCER_375              0x3177
-#define WM8915_WRITE_SEQUENCER_376              0x3178
-#define WM8915_WRITE_SEQUENCER_377              0x3179
-#define WM8915_WRITE_SEQUENCER_378              0x317A
-#define WM8915_WRITE_SEQUENCER_379              0x317B
-#define WM8915_WRITE_SEQUENCER_380              0x317C
-#define WM8915_WRITE_SEQUENCER_381              0x317D
-#define WM8915_WRITE_SEQUENCER_382              0x317E
-#define WM8915_WRITE_SEQUENCER_383              0x317F
-#define WM8915_WRITE_SEQUENCER_384              0x3180
-#define WM8915_WRITE_SEQUENCER_385              0x3181
-#define WM8915_WRITE_SEQUENCER_386              0x3182
-#define WM8915_WRITE_SEQUENCER_387              0x3183
-#define WM8915_WRITE_SEQUENCER_388              0x3184
-#define WM8915_WRITE_SEQUENCER_389              0x3185
-#define WM8915_WRITE_SEQUENCER_390              0x3186
-#define WM8915_WRITE_SEQUENCER_391              0x3187
-#define WM8915_WRITE_SEQUENCER_392              0x3188
-#define WM8915_WRITE_SEQUENCER_393              0x3189
-#define WM8915_WRITE_SEQUENCER_394              0x318A
-#define WM8915_WRITE_SEQUENCER_395              0x318B
-#define WM8915_WRITE_SEQUENCER_396              0x318C
-#define WM8915_WRITE_SEQUENCER_397              0x318D
-#define WM8915_WRITE_SEQUENCER_398              0x318E
-#define WM8915_WRITE_SEQUENCER_399              0x318F
-#define WM8915_WRITE_SEQUENCER_400              0x3190
-#define WM8915_WRITE_SEQUENCER_401              0x3191
-#define WM8915_WRITE_SEQUENCER_402              0x3192
-#define WM8915_WRITE_SEQUENCER_403              0x3193
-#define WM8915_WRITE_SEQUENCER_404              0x3194
-#define WM8915_WRITE_SEQUENCER_405              0x3195
-#define WM8915_WRITE_SEQUENCER_406              0x3196
-#define WM8915_WRITE_SEQUENCER_407              0x3197
-#define WM8915_WRITE_SEQUENCER_408              0x3198
-#define WM8915_WRITE_SEQUENCER_409              0x3199
-#define WM8915_WRITE_SEQUENCER_410              0x319A
-#define WM8915_WRITE_SEQUENCER_411              0x319B
-#define WM8915_WRITE_SEQUENCER_412              0x319C
-#define WM8915_WRITE_SEQUENCER_413              0x319D
-#define WM8915_WRITE_SEQUENCER_414              0x319E
-#define WM8915_WRITE_SEQUENCER_415              0x319F
-#define WM8915_WRITE_SEQUENCER_416              0x31A0
-#define WM8915_WRITE_SEQUENCER_417              0x31A1
-#define WM8915_WRITE_SEQUENCER_418              0x31A2
-#define WM8915_WRITE_SEQUENCER_419              0x31A3
-#define WM8915_WRITE_SEQUENCER_420              0x31A4
-#define WM8915_WRITE_SEQUENCER_421              0x31A5
-#define WM8915_WRITE_SEQUENCER_422              0x31A6
-#define WM8915_WRITE_SEQUENCER_423              0x31A7
-#define WM8915_WRITE_SEQUENCER_424              0x31A8
-#define WM8915_WRITE_SEQUENCER_425              0x31A9
-#define WM8915_WRITE_SEQUENCER_426              0x31AA
-#define WM8915_WRITE_SEQUENCER_427              0x31AB
-#define WM8915_WRITE_SEQUENCER_428              0x31AC
-#define WM8915_WRITE_SEQUENCER_429              0x31AD
-#define WM8915_WRITE_SEQUENCER_430              0x31AE
-#define WM8915_WRITE_SEQUENCER_431              0x31AF
-#define WM8915_WRITE_SEQUENCER_432              0x31B0
-#define WM8915_WRITE_SEQUENCER_433              0x31B1
-#define WM8915_WRITE_SEQUENCER_434              0x31B2
-#define WM8915_WRITE_SEQUENCER_435              0x31B3
-#define WM8915_WRITE_SEQUENCER_436              0x31B4
-#define WM8915_WRITE_SEQUENCER_437              0x31B5
-#define WM8915_WRITE_SEQUENCER_438              0x31B6
-#define WM8915_WRITE_SEQUENCER_439              0x31B7
-#define WM8915_WRITE_SEQUENCER_440              0x31B8
-#define WM8915_WRITE_SEQUENCER_441              0x31B9
-#define WM8915_WRITE_SEQUENCER_442              0x31BA
-#define WM8915_WRITE_SEQUENCER_443              0x31BB
-#define WM8915_WRITE_SEQUENCER_444              0x31BC
-#define WM8915_WRITE_SEQUENCER_445              0x31BD
-#define WM8915_WRITE_SEQUENCER_446              0x31BE
-#define WM8915_WRITE_SEQUENCER_447              0x31BF
-#define WM8915_WRITE_SEQUENCER_448              0x31C0
-#define WM8915_WRITE_SEQUENCER_449              0x31C1
-#define WM8915_WRITE_SEQUENCER_450              0x31C2
-#define WM8915_WRITE_SEQUENCER_451              0x31C3
-#define WM8915_WRITE_SEQUENCER_452              0x31C4
-#define WM8915_WRITE_SEQUENCER_453              0x31C5
-#define WM8915_WRITE_SEQUENCER_454              0x31C6
-#define WM8915_WRITE_SEQUENCER_455              0x31C7
-#define WM8915_WRITE_SEQUENCER_456              0x31C8
-#define WM8915_WRITE_SEQUENCER_457              0x31C9
-#define WM8915_WRITE_SEQUENCER_458              0x31CA
-#define WM8915_WRITE_SEQUENCER_459              0x31CB
-#define WM8915_WRITE_SEQUENCER_460              0x31CC
-#define WM8915_WRITE_SEQUENCER_461              0x31CD
-#define WM8915_WRITE_SEQUENCER_462              0x31CE
-#define WM8915_WRITE_SEQUENCER_463              0x31CF
-#define WM8915_WRITE_SEQUENCER_464              0x31D0
-#define WM8915_WRITE_SEQUENCER_465              0x31D1
-#define WM8915_WRITE_SEQUENCER_466              0x31D2
-#define WM8915_WRITE_SEQUENCER_467              0x31D3
-#define WM8915_WRITE_SEQUENCER_468              0x31D4
-#define WM8915_WRITE_SEQUENCER_469              0x31D5
-#define WM8915_WRITE_SEQUENCER_470              0x31D6
-#define WM8915_WRITE_SEQUENCER_471              0x31D7
-#define WM8915_WRITE_SEQUENCER_472              0x31D8
-#define WM8915_WRITE_SEQUENCER_473              0x31D9
-#define WM8915_WRITE_SEQUENCER_474              0x31DA
-#define WM8915_WRITE_SEQUENCER_475              0x31DB
-#define WM8915_WRITE_SEQUENCER_476              0x31DC
-#define WM8915_WRITE_SEQUENCER_477              0x31DD
-#define WM8915_WRITE_SEQUENCER_478              0x31DE
-#define WM8915_WRITE_SEQUENCER_479              0x31DF
-#define WM8915_WRITE_SEQUENCER_480              0x31E0
-#define WM8915_WRITE_SEQUENCER_481              0x31E1
-#define WM8915_WRITE_SEQUENCER_482              0x31E2
-#define WM8915_WRITE_SEQUENCER_483              0x31E3
-#define WM8915_WRITE_SEQUENCER_484              0x31E4
-#define WM8915_WRITE_SEQUENCER_485              0x31E5
-#define WM8915_WRITE_SEQUENCER_486              0x31E6
-#define WM8915_WRITE_SEQUENCER_487              0x31E7
-#define WM8915_WRITE_SEQUENCER_488              0x31E8
-#define WM8915_WRITE_SEQUENCER_489              0x31E9
-#define WM8915_WRITE_SEQUENCER_490              0x31EA
-#define WM8915_WRITE_SEQUENCER_491              0x31EB
-#define WM8915_WRITE_SEQUENCER_492              0x31EC
-#define WM8915_WRITE_SEQUENCER_493              0x31ED
-#define WM8915_WRITE_SEQUENCER_494              0x31EE
-#define WM8915_WRITE_SEQUENCER_495              0x31EF
-#define WM8915_WRITE_SEQUENCER_496              0x31F0
-#define WM8915_WRITE_SEQUENCER_497              0x31F1
-#define WM8915_WRITE_SEQUENCER_498              0x31F2
-#define WM8915_WRITE_SEQUENCER_499              0x31F3
-#define WM8915_WRITE_SEQUENCER_500              0x31F4
-#define WM8915_WRITE_SEQUENCER_501              0x31F5
-#define WM8915_WRITE_SEQUENCER_502              0x31F6
-#define WM8915_WRITE_SEQUENCER_503              0x31F7
-#define WM8915_WRITE_SEQUENCER_504              0x31F8
-#define WM8915_WRITE_SEQUENCER_505              0x31F9
-#define WM8915_WRITE_SEQUENCER_506              0x31FA
-#define WM8915_WRITE_SEQUENCER_507              0x31FB
-#define WM8915_WRITE_SEQUENCER_508              0x31FC
-#define WM8915_WRITE_SEQUENCER_509              0x31FD
-#define WM8915_WRITE_SEQUENCER_510              0x31FE
-#define WM8915_WRITE_SEQUENCER_511              0x31FF
-
-#define WM8915_REGISTER_COUNT                   706
-#define WM8915_MAX_REGISTER                     0x31FF
-
-/*
- * Field Definitions.
- */
-
-/*
- * R0 (0x00) - Software Reset
- */
-#define WM8915_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
-#define WM8915_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
-#define WM8915_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
-
-/*
- * R1 (0x01) - Power Management (1)
- */
-#define WM8915_MICB2_ENA                        0x0200  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
-#define WM8915_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
-#define WM8915_MICB1_ENA                        0x0100  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
-#define WM8915_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
-#define WM8915_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
-#define WM8915_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
-#define WM8915_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
-#define WM8915_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
-#define WM8915_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
-#define WM8915_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
-#define WM8915_BG_ENA                           0x0001  /* BG_ENA */
-#define WM8915_BG_ENA_MASK                      0x0001  /* BG_ENA */
-#define WM8915_BG_ENA_SHIFT                          0  /* BG_ENA */
-#define WM8915_BG_ENA_WIDTH                          1  /* BG_ENA */
-
-/*
- * R2 (0x02) - Power Management (2)
- */
-#define WM8915_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
-#define WM8915_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
-#define WM8915_INL_ENA                          0x0020  /* INL_ENA */
-#define WM8915_INL_ENA_MASK                     0x0020  /* INL_ENA */
-#define WM8915_INL_ENA_SHIFT                         5  /* INL_ENA */
-#define WM8915_INL_ENA_WIDTH                         1  /* INL_ENA */
-#define WM8915_INR_ENA                          0x0010  /* INR_ENA */
-#define WM8915_INR_ENA_MASK                     0x0010  /* INR_ENA */
-#define WM8915_INR_ENA_SHIFT                         4  /* INR_ENA */
-#define WM8915_INR_ENA_WIDTH                         1  /* INR_ENA */
-#define WM8915_LDO2_ENA                         0x0002  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
-#define WM8915_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
-
-/*
- * R3 (0x03) - Power Management (3)
- */
-#define WM8915_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
-#define WM8915_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
-#define WM8915_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
-#define WM8915_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
-#define WM8915_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
-#define WM8915_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
-#define WM8915_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
-#define WM8915_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
-#define WM8915_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
-#define WM8915_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
-#define WM8915_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
-#define WM8915_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
-#define WM8915_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
-#define WM8915_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
-#define WM8915_ADCL_ENA                         0x0002  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
-#define WM8915_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
-#define WM8915_ADCR_ENA                         0x0001  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
-#define WM8915_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
-
-/*
- * R4 (0x04) - Power Management (4)
- */
-#define WM8915_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
-#define WM8915_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
-
-/*
- * R5 (0x05) - Power Management (5)
- */
-#define WM8915_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
-#define WM8915_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
-#define WM8915_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
-#define WM8915_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
-#define WM8915_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
-#define WM8915_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
-#define WM8915_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
-#define WM8915_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
-#define WM8915_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
-#define WM8915_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
-#define WM8915_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
-#define WM8915_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
-#define WM8915_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
-#define WM8915_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
-
-/*
- * R6 (0x06) - Power Management (6)
- */
-#define WM8915_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
-#define WM8915_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
-
-/*
- * R7 (0x07) - Power Management (7)
- */
-#define WM8915_DMIC2_FN                         0x0200  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
-#define WM8915_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
-#define WM8915_DMIC1_FN                         0x0100  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
-#define WM8915_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
-#define WM8915_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
-#define WM8915_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
-#define WM8915_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
-#define WM8915_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
-#define WM8915_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
-#define WM8915_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
-
-/*
- * R8 (0x08) - Power Management (8)
- */
-#define WM8915_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
-#define WM8915_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
-#define WM8915_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
-#define WM8915_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
-#define WM8915_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
-#define WM8915_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
-#define WM8915_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
-
-/*
- * R16 (0x10) - Left Line Input Volume
- */
-#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
-#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
-#define WM8915_IN1L_ZC                          0x0020  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
-#define WM8915_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
-#define WM8915_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
-#define WM8915_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
-#define WM8915_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
-
-/*
- * R17 (0x11) - Right Line Input Volume
- */
-#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
-#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
-#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
-#define WM8915_IN1R_ZC                          0x0020  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
-#define WM8915_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
-#define WM8915_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
-#define WM8915_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
-#define WM8915_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
-
-/*
- * R18 (0x12) - Line Input Control
- */
-#define WM8915_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
-#define WM8915_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
-#define WM8915_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
-#define WM8915_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
-#define WM8915_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
-#define WM8915_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
-
-/*
- * R21 (0x15) - DAC1 HPOUT1 Volume
- */
-#define WM8915_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
-#define WM8915_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
-#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
-#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
-
-/*
- * R22 (0x16) - DAC2 HPOUT2 Volume
- */
-#define WM8915_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
-#define WM8915_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
-#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
-#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
-
-/*
- * R24 (0x18) - DAC1 Left Volume
- */
-#define WM8915_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
-#define WM8915_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
-#define WM8915_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
-#define WM8915_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
-
-/*
- * R25 (0x19) - DAC1 Right Volume
- */
-#define WM8915_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
-#define WM8915_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
-#define WM8915_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
-#define WM8915_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
-
-/*
- * R26 (0x1A) - DAC2 Left Volume
- */
-#define WM8915_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
-#define WM8915_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
-#define WM8915_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
-#define WM8915_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
-
-/*
- * R27 (0x1B) - DAC2 Right Volume
- */
-#define WM8915_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
-#define WM8915_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
-#define WM8915_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
-#define WM8915_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
-
-/*
- * R28 (0x1C) - Output1 Left Volume
- */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
-#define WM8915_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
-#define WM8915_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
-#define WM8915_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
-
-/*
- * R29 (0x1D) - Output1 Right Volume
- */
-#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
-#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
-#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
-#define WM8915_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
-#define WM8915_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
-#define WM8915_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
-#define WM8915_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
-
-/*
- * R30 (0x1E) - Output2 Left Volume
- */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
-#define WM8915_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
-#define WM8915_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
-#define WM8915_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
-
-/*
- * R31 (0x1F) - Output2 Right Volume
- */
-#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
-#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
-#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
-#define WM8915_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
-#define WM8915_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
-#define WM8915_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
-#define WM8915_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
-
-/*
- * R32 (0x20) - MICBIAS (1)
- */
-#define WM8915_MICB1_RATE                       0x0020  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
-#define WM8915_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
-#define WM8915_MICB1_MODE                       0x0010  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
-#define WM8915_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
-#define WM8915_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
-#define WM8915_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
-#define WM8915_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
-
-/*
- * R33 (0x21) - MICBIAS (2)
- */
-#define WM8915_MICB2_RATE                       0x0020  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
-#define WM8915_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
-#define WM8915_MICB2_MODE                       0x0010  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
-#define WM8915_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
-#define WM8915_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
-#define WM8915_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
-#define WM8915_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
-
-/*
- * R40 (0x28) - LDO 1
- */
-#define WM8915_LDO1_MODE                        0x0020  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
-#define WM8915_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
-#define WM8915_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
-#define WM8915_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
-#define WM8915_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
-
-/*
- * R41 (0x29) - LDO 2
- */
-#define WM8915_LDO2_MODE                        0x0020  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
-#define WM8915_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
-#define WM8915_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
-#define WM8915_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
-#define WM8915_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
-
-/*
- * R48 (0x30) - Accessory Detect Mode 1
- */
-#define WM8915_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
-#define WM8915_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
-#define WM8915_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
-
-/*
- * R49 (0x31) - Accessory Detect Mode 2
- */
-#define WM8915_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
-#define WM8915_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
-#define WM8915_MICD_SRC                         0x0002  /* MICD_SRC */
-#define WM8915_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
-#define WM8915_MICD_SRC_SHIFT                        1  /* MICD_SRC */
-#define WM8915_MICD_SRC_WIDTH                        1  /* MICD_SRC */
-#define WM8915_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
-#define WM8915_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
-
-/*
- * R52 (0x34) - Headphone Detect 1
- */
-#define WM8915_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
-#define WM8915_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
-#define WM8915_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
-#define WM8915_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
-#define WM8915_HP_POLL                          0x0001  /* HP_POLL */
-#define WM8915_HP_POLL_MASK                     0x0001  /* HP_POLL */
-#define WM8915_HP_POLL_SHIFT                         0  /* HP_POLL */
-#define WM8915_HP_POLL_WIDTH                         1  /* HP_POLL */
-
-/*
- * R53 (0x35) - Headphone Detect 2
- */
-#define WM8915_HP_DONE                          0x0080  /* HP_DONE */
-#define WM8915_HP_DONE_MASK                     0x0080  /* HP_DONE */
-#define WM8915_HP_DONE_SHIFT                         7  /* HP_DONE */
-#define WM8915_HP_DONE_WIDTH                         1  /* HP_DONE */
-#define WM8915_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
-#define WM8915_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
-#define WM8915_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
-
-/*
- * R56 (0x38) - Mic Detect 1
- */
-#define WM8915_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
-#define WM8915_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
-#define WM8915_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
-#define WM8915_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
-#define WM8915_MICD_ENA                         0x0001  /* MICD_ENA */
-#define WM8915_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
-#define WM8915_MICD_ENA_SHIFT                        0  /* MICD_ENA */
-#define WM8915_MICD_ENA_WIDTH                        1  /* MICD_ENA */
-
-/*
- * R57 (0x39) - Mic Detect 2
- */
-#define WM8915_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
-#define WM8915_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
-#define WM8915_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
-
-/*
- * R58 (0x3A) - Mic Detect 3
- */
-#define WM8915_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
-#define WM8915_MICD_VALID                       0x0002  /* MICD_VALID */
-#define WM8915_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
-#define WM8915_MICD_VALID_SHIFT                      1  /* MICD_VALID */
-#define WM8915_MICD_VALID_WIDTH                      1  /* MICD_VALID */
-#define WM8915_MICD_STS                         0x0001  /* MICD_STS */
-#define WM8915_MICD_STS_MASK                    0x0001  /* MICD_STS */
-#define WM8915_MICD_STS_SHIFT                        0  /* MICD_STS */
-#define WM8915_MICD_STS_WIDTH                        1  /* MICD_STS */
-
-/*
- * R64 (0x40) - Charge Pump (1)
- */
-#define WM8915_CP_ENA                           0x8000  /* CP_ENA */
-#define WM8915_CP_ENA_MASK                      0x8000  /* CP_ENA */
-#define WM8915_CP_ENA_SHIFT                         15  /* CP_ENA */
-#define WM8915_CP_ENA_WIDTH                          1  /* CP_ENA */
-
-/*
- * R65 (0x41) - Charge Pump (2)
- */
-#define WM8915_CP_DISCH                         0x8000  /* CP_DISCH */
-#define WM8915_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
-#define WM8915_CP_DISCH_SHIFT                       15  /* CP_DISCH */
-#define WM8915_CP_DISCH_WIDTH                        1  /* CP_DISCH */
-
-/*
- * R80 (0x50) - DC Servo (1)
- */
-#define WM8915_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
-#define WM8915_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
-#define WM8915_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
-#define WM8915_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
-#define WM8915_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
-
-/*
- * R81 (0x51) - DC Servo (2)
- */
-#define WM8915_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
-#define WM8915_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
-#define WM8915_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
-#define WM8915_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
-#define WM8915_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
-#define WM8915_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
-#define WM8915_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
-#define WM8915_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
-#define WM8915_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
-#define WM8915_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
-#define WM8915_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
-#define WM8915_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
-#define WM8915_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
-#define WM8915_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
-#define WM8915_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
-#define WM8915_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
-#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
-
-/*
- * R82 (0x52) - DC Servo (3)
- */
-#define WM8915_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
-#define WM8915_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
-#define WM8915_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
-#define WM8915_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
-
-/*
- * R84 (0x54) - DC Servo (5)
- */
-#define WM8915_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
-#define WM8915_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
-#define WM8915_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
-#define WM8915_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
-
-/*
- * R85 (0x55) - DC Servo (6)
- */
-#define WM8915_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
-
-/*
- * R86 (0x56) - DC Servo (7)
- */
-#define WM8915_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
-#define WM8915_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
-#define WM8915_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
-
-/*
- * R87 (0x57) - DC Servo Readback 0
- */
-#define WM8915_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
-#define WM8915_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
-#define WM8915_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
-#define WM8915_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
-#define WM8915_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
-
-/*
- * R96 (0x60) - Analogue HP (1)
- */
-#define WM8915_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
-#define WM8915_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
-#define WM8915_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
-#define WM8915_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
-#define WM8915_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
-#define WM8915_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
-#define WM8915_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
-
-/*
- * R97 (0x61) - Analogue HP (2)
- */
-#define WM8915_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
-#define WM8915_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
-#define WM8915_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
-#define WM8915_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
-#define WM8915_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
-#define WM8915_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
-#define WM8915_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
-
-/*
- * R256 (0x100) - Chip Revision
- */
-#define WM8915_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
-#define WM8915_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
-#define WM8915_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
-
-/*
- * R257 (0x101) - Control Interface (1)
- */
-#define WM8915_AUTO_INC                         0x0004  /* AUTO_INC */
-#define WM8915_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
-#define WM8915_AUTO_INC_SHIFT                        2  /* AUTO_INC */
-#define WM8915_AUTO_INC_WIDTH                        1  /* AUTO_INC */
-
-/*
- * R272 (0x110) - Write Sequencer Ctrl (1)
- */
-#define WM8915_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
-#define WM8915_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
-#define WM8915_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
-#define WM8915_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
-#define WM8915_WSEQ_START                       0x0100  /* WSEQ_START */
-#define WM8915_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
-#define WM8915_WSEQ_START_SHIFT                      8  /* WSEQ_START */
-#define WM8915_WSEQ_START_WIDTH                      1  /* WSEQ_START */
-#define WM8915_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
-#define WM8915_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
-#define WM8915_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
-
-/*
- * R273 (0x111) - Write Sequencer Ctrl (2)
- */
-#define WM8915_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
-#define WM8915_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
-#define WM8915_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
-#define WM8915_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
-#define WM8915_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
-
-/*
- * R512 (0x200) - AIF Clocking (1)
- */
-#define WM8915_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
-#define WM8915_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
-#define WM8915_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
-#define WM8915_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
-#define WM8915_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
-#define WM8915_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
-
-/*
- * R513 (0x201) - AIF Clocking (2)
- */
-#define WM8915_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
-#define WM8915_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
-#define WM8915_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
-#define WM8915_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
-
-/*
- * R520 (0x208) - Clocking (1)
- */
-#define WM8915_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
-#define WM8915_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
-#define WM8915_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
-#define WM8915_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
-#define WM8915_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
-#define WM8915_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
-#define WM8915_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
-
-/*
- * R521 (0x209) - Clocking (2)
- */
-#define WM8915_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
-#define WM8915_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
-#define WM8915_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
-#define WM8915_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
-#define WM8915_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
-#define WM8915_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
-#define WM8915_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
-#define WM8915_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
-#define WM8915_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
-
-/*
- * R528 (0x210) - AIF Rate
- */
-#define WM8915_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
-#define WM8915_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
-
-/*
- * R544 (0x220) - FLL Control (1)
- */
-#define WM8915_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
-#define WM8915_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
-#define WM8915_FLL_ENA                          0x0001  /* FLL_ENA */
-#define WM8915_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
-#define WM8915_FLL_ENA_SHIFT                         0  /* FLL_ENA */
-#define WM8915_FLL_ENA_WIDTH                         1  /* FLL_ENA */
-
-/*
- * R545 (0x221) - FLL Control (2)
- */
-#define WM8915_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
-#define WM8915_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
-#define WM8915_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
-#define WM8915_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
-
-/*
- * R546 (0x222) - FLL Control (3)
- */
-#define WM8915_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
-#define WM8915_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
-#define WM8915_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
-
-/*
- * R547 (0x223) - FLL Control (4)
- */
-#define WM8915_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
-#define WM8915_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
-#define WM8915_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
-#define WM8915_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
-#define WM8915_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
-#define WM8915_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
-
-/*
- * R548 (0x224) - FLL Control (5)
- */
-#define WM8915_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
-#define WM8915_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
-#define WM8915_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
-#define WM8915_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
-#define WM8915_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
-#define WM8915_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
-#define WM8915_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
-#define WM8915_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
-#define WM8915_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
-
-/*
- * R549 (0x225) - FLL Control (6)
- */
-#define WM8915_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
-#define WM8915_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
-#define WM8915_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
-
-/*
- * R550 (0x226) - FLL EFS 1
- */
-#define WM8915_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
-#define WM8915_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
-#define WM8915_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
-
-/*
- * R551 (0x227) - FLL EFS 2
- */
-#define WM8915_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
-#define WM8915_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
-#define WM8915_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
-
-/*
- * R768 (0x300) - AIF1 Control
- */
-#define WM8915_AIF1_TRI                         0x0004  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
-#define WM8915_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
-#define WM8915_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
-#define WM8915_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
-#define WM8915_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
-
-/*
- * R769 (0x301) - AIF1 BCLK
- */
-#define WM8915_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
-#define WM8915_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
-#define WM8915_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
-#define WM8915_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
-#define WM8915_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
-#define WM8915_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
-
-/*
- * R770 (0x302) - AIF1 TX LRCLK(1)
- */
-#define WM8915_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
-#define WM8915_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
-#define WM8915_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
-
-/*
- * R771 (0x303) - AIF1 TX LRCLK(2)
- */
-#define WM8915_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
-#define WM8915_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
-#define WM8915_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
-#define WM8915_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
-#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
-
-/*
- * R772 (0x304) - AIF1 RX LRCLK(1)
- */
-#define WM8915_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
-#define WM8915_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
-#define WM8915_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
-
-/*
- * R773 (0x305) - AIF1 RX LRCLK(2)
- */
-#define WM8915_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
-#define WM8915_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
-#define WM8915_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
-#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
-
-/*
- * R774 (0x306) - AIF1TX Data Configuration (1)
- */
-#define WM8915_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
-#define WM8915_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
-
-/*
- * R775 (0x307) - AIF1TX Data Configuration (2)
- */
-#define WM8915_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
-#define WM8915_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
-
-/*
- * R776 (0x308) - AIF1RX Data Configuration
- */
-#define WM8915_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
-#define WM8915_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
-
-/*
- * R777 (0x309) - AIF1TX Channel 0 Configuration
- */
-#define WM8915_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
-#define WM8915_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R778 (0x30A) - AIF1TX Channel 1 Configuration
- */
-#define WM8915_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
-#define WM8915_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R779 (0x30B) - AIF1TX Channel 2 Configuration
- */
-#define WM8915_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
-#define WM8915_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
-
-/*
- * R780 (0x30C) - AIF1TX Channel 3 Configuration
- */
-#define WM8915_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
-#define WM8915_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
-
-/*
- * R781 (0x30D) - AIF1TX Channel 4 Configuration
- */
-#define WM8915_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
-#define WM8915_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
-
-/*
- * R782 (0x30E) - AIF1TX Channel 5 Configuration
- */
-#define WM8915_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
-#define WM8915_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
-
-/*
- * R783 (0x30F) - AIF1RX Channel 0 Configuration
- */
-#define WM8915_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
-#define WM8915_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R784 (0x310) - AIF1RX Channel 1 Configuration
- */
-#define WM8915_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
-#define WM8915_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R785 (0x311) - AIF1RX Channel 2 Configuration
- */
-#define WM8915_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
-#define WM8915_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
-
-/*
- * R786 (0x312) - AIF1RX Channel 3 Configuration
- */
-#define WM8915_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
-#define WM8915_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
-
-/*
- * R787 (0x313) - AIF1RX Channel 4 Configuration
- */
-#define WM8915_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
-#define WM8915_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
-
-/*
- * R788 (0x314) - AIF1RX Channel 5 Configuration
- */
-#define WM8915_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
-#define WM8915_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
-
-/*
- * R789 (0x315) - AIF1RX Mono Configuration
- */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
-#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
-
-/*
- * R794 (0x31A) - AIF1TX Test
- */
-#define WM8915_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
-#define WM8915_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
-
-/*
- * R800 (0x320) - AIF2 Control
- */
-#define WM8915_AIF2_TRI                         0x0004  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
-#define WM8915_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
-#define WM8915_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
-#define WM8915_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
-#define WM8915_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
-
-/*
- * R801 (0x321) - AIF2 BCLK
- */
-#define WM8915_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
-#define WM8915_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
-#define WM8915_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
-#define WM8915_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
-#define WM8915_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
-#define WM8915_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
-
-/*
- * R802 (0x322) - AIF2 TX LRCLK(1)
- */
-#define WM8915_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
-#define WM8915_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
-#define WM8915_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
-
-/*
- * R803 (0x323) - AIF2 TX LRCLK(2)
- */
-#define WM8915_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
-#define WM8915_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
-#define WM8915_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
-#define WM8915_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
-#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
-
-/*
- * R804 (0x324) - AIF2 RX LRCLK(1)
- */
-#define WM8915_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
-#define WM8915_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
-#define WM8915_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
-
-/*
- * R805 (0x325) - AIF2 RX LRCLK(2)
- */
-#define WM8915_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
-#define WM8915_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
-#define WM8915_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
-#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
-
-/*
- * R806 (0x326) - AIF2TX Data Configuration (1)
- */
-#define WM8915_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
-#define WM8915_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
-
-/*
- * R807 (0x327) - AIF2TX Data Configuration (2)
- */
-#define WM8915_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
-#define WM8915_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
-
-/*
- * R808 (0x328) - AIF2RX Data Configuration
- */
-#define WM8915_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
-#define WM8915_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
-#define WM8915_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
-
-/*
- * R809 (0x329) - AIF2TX Channel 0 Configuration
- */
-#define WM8915_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
-#define WM8915_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R810 (0x32A) - AIF2TX Channel 1 Configuration
- */
-#define WM8915_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
-#define WM8915_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R811 (0x32B) - AIF2RX Channel 0 Configuration
- */
-#define WM8915_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
-#define WM8915_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
-
-/*
- * R812 (0x32C) - AIF2RX Channel 1 Configuration
- */
-#define WM8915_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
-#define WM8915_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
-
-/*
- * R813 (0x32D) - AIF2RX Mono Configuration
- */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
-#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
-
-/*
- * R815 (0x32F) - AIF2TX Test
- */
-#define WM8915_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
-#define WM8915_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
-
-/*
- * R1024 (0x400) - DSP1 TX Left Volume
- */
-#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
-#define WM8915_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
-#define WM8915_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
-#define WM8915_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
-
-/*
- * R1025 (0x401) - DSP1 TX Right Volume
- */
-#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
-#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
-#define WM8915_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
-#define WM8915_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
-#define WM8915_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
-
-/*
- * R1026 (0x402) - DSP1 RX Left Volume
- */
-#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
-#define WM8915_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
-#define WM8915_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
-#define WM8915_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
-
-/*
- * R1027 (0x403) - DSP1 RX Right Volume
- */
-#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
-#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
-#define WM8915_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
-#define WM8915_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
-#define WM8915_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
-
-/*
- * R1040 (0x410) - DSP1 TX Filters
- */
-#define WM8915_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
-#define WM8915_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
-#define WM8915_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
-#define WM8915_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
-#define WM8915_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
-#define WM8915_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
-#define WM8915_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
-#define WM8915_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
-#define WM8915_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
-
-/*
- * R1056 (0x420) - DSP1 RX Filters (1)
- */
-#define WM8915_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
-#define WM8915_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
-#define WM8915_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
-#define WM8915_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
-#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
-
-/*
- * R1057 (0x421) - DSP1 RX Filters (2)
- */
-#define WM8915_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
-#define WM8915_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
-#define WM8915_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
-
-/*
- * R1088 (0x440) - DSP1 DRC (1)
- */
-#define WM8915_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
-#define WM8915_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
-#define WM8915_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
-#define WM8915_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
-#define WM8915_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
-#define WM8915_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
-#define WM8915_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
-
-/*
- * R1089 (0x441) - DSP1 DRC (2)
- */
-#define WM8915_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
-#define WM8915_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
-#define WM8915_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
-#define WM8915_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
-
-/*
- * R1090 (0x442) - DSP1 DRC (3)
- */
-#define WM8915_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
-#define WM8915_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
-#define WM8915_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
-#define WM8915_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
-#define WM8915_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
-#define WM8915_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
-#define WM8915_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
-
-/*
- * R1091 (0x443) - DSP1 DRC (4)
- */
-#define WM8915_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
-
-/*
- * R1092 (0x444) - DSP1 DRC (5)
- */
-#define WM8915_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
-
-/*
- * R1152 (0x480) - DSP1 RX EQ Gains (1)
- */
-#define WM8915_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
-#define WM8915_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
-
-/*
- * R1153 (0x481) - DSP1 RX EQ Gains (2)
- */
-#define WM8915_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
-
-/*
- * R1154 (0x482) - DSP1 RX EQ Band 1 A
- */
-#define WM8915_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
-
-/*
- * R1155 (0x483) - DSP1 RX EQ Band 1 B
- */
-#define WM8915_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
-
-/*
- * R1156 (0x484) - DSP1 RX EQ Band 1 PG
- */
-#define WM8915_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
-
-/*
- * R1157 (0x485) - DSP1 RX EQ Band 2 A
- */
-#define WM8915_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
-
-/*
- * R1158 (0x486) - DSP1 RX EQ Band 2 B
- */
-#define WM8915_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
-
-/*
- * R1159 (0x487) - DSP1 RX EQ Band 2 C
- */
-#define WM8915_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
-
-/*
- * R1160 (0x488) - DSP1 RX EQ Band 2 PG
- */
-#define WM8915_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
-
-/*
- * R1161 (0x489) - DSP1 RX EQ Band 3 A
- */
-#define WM8915_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
-
-/*
- * R1162 (0x48A) - DSP1 RX EQ Band 3 B
- */
-#define WM8915_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
-
-/*
- * R1163 (0x48B) - DSP1 RX EQ Band 3 C
- */
-#define WM8915_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
-
-/*
- * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
- */
-#define WM8915_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
-
-/*
- * R1165 (0x48D) - DSP1 RX EQ Band 4 A
- */
-#define WM8915_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
-
-/*
- * R1166 (0x48E) - DSP1 RX EQ Band 4 B
- */
-#define WM8915_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
-
-/*
- * R1167 (0x48F) - DSP1 RX EQ Band 4 C
- */
-#define WM8915_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
-
-/*
- * R1168 (0x490) - DSP1 RX EQ Band 4 PG
- */
-#define WM8915_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
-
-/*
- * R1169 (0x491) - DSP1 RX EQ Band 5 A
- */
-#define WM8915_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
-
-/*
- * R1170 (0x492) - DSP1 RX EQ Band 5 B
- */
-#define WM8915_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
-
-/*
- * R1171 (0x493) - DSP1 RX EQ Band 5 PG
- */
-#define WM8915_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
-
-/*
- * R1280 (0x500) - DSP2 TX Left Volume
- */
-#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
-#define WM8915_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
-#define WM8915_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
-#define WM8915_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
-
-/*
- * R1281 (0x501) - DSP2 TX Right Volume
- */
-#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
-#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
-#define WM8915_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
-#define WM8915_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
-#define WM8915_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
-
-/*
- * R1282 (0x502) - DSP2 RX Left Volume
- */
-#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
-#define WM8915_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
-#define WM8915_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
-#define WM8915_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
-
-/*
- * R1283 (0x503) - DSP2 RX Right Volume
- */
-#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
-#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
-#define WM8915_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
-#define WM8915_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
-#define WM8915_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
-
-/*
- * R1296 (0x510) - DSP2 TX Filters
- */
-#define WM8915_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
-#define WM8915_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
-#define WM8915_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
-#define WM8915_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
-#define WM8915_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
-#define WM8915_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
-#define WM8915_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
-#define WM8915_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
-#define WM8915_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
-
-/*
- * R1312 (0x520) - DSP2 RX Filters (1)
- */
-#define WM8915_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
-#define WM8915_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
-#define WM8915_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
-#define WM8915_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
-#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
-
-/*
- * R1313 (0x521) - DSP2 RX Filters (2)
- */
-#define WM8915_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
-#define WM8915_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
-#define WM8915_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
-
-/*
- * R1344 (0x540) - DSP2 DRC (1)
- */
-#define WM8915_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
-#define WM8915_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
-#define WM8915_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
-#define WM8915_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
-#define WM8915_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
-#define WM8915_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
-#define WM8915_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
-#define WM8915_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
-#define WM8915_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
-
-/*
- * R1345 (0x541) - DSP2 DRC (2)
- */
-#define WM8915_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
-#define WM8915_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
-#define WM8915_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
-#define WM8915_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
-#define WM8915_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
-
-/*
- * R1346 (0x542) - DSP2 DRC (3)
- */
-#define WM8915_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
-#define WM8915_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
-#define WM8915_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
-#define WM8915_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
-#define WM8915_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
-#define WM8915_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
-#define WM8915_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
-#define WM8915_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
-
-/*
- * R1347 (0x543) - DSP2 DRC (4)
- */
-#define WM8915_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
-#define WM8915_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
-
-/*
- * R1348 (0x544) - DSP2 DRC (5)
- */
-#define WM8915_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
-#define WM8915_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
-#define WM8915_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
-
-/*
- * R1408 (0x580) - DSP2 RX EQ Gains (1)
- */
-#define WM8915_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
-#define WM8915_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
-#define WM8915_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
-
-/*
- * R1409 (0x581) - DSP2 RX EQ Gains (2)
- */
-#define WM8915_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
-
-/*
- * R1410 (0x582) - DSP2 RX EQ Band 1 A
- */
-#define WM8915_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
-
-/*
- * R1411 (0x583) - DSP2 RX EQ Band 1 B
- */
-#define WM8915_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
-
-/*
- * R1412 (0x584) - DSP2 RX EQ Band 1 PG
- */
-#define WM8915_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
-
-/*
- * R1413 (0x585) - DSP2 RX EQ Band 2 A
- */
-#define WM8915_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
-
-/*
- * R1414 (0x586) - DSP2 RX EQ Band 2 B
- */
-#define WM8915_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
-
-/*
- * R1415 (0x587) - DSP2 RX EQ Band 2 C
- */
-#define WM8915_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
-
-/*
- * R1416 (0x588) - DSP2 RX EQ Band 2 PG
- */
-#define WM8915_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
-
-/*
- * R1417 (0x589) - DSP2 RX EQ Band 3 A
- */
-#define WM8915_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
-
-/*
- * R1418 (0x58A) - DSP2 RX EQ Band 3 B
- */
-#define WM8915_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
-
-/*
- * R1419 (0x58B) - DSP2 RX EQ Band 3 C
- */
-#define WM8915_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
-
-/*
- * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
- */
-#define WM8915_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
-
-/*
- * R1421 (0x58D) - DSP2 RX EQ Band 4 A
- */
-#define WM8915_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
-
-/*
- * R1422 (0x58E) - DSP2 RX EQ Band 4 B
- */
-#define WM8915_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
-
-/*
- * R1423 (0x58F) - DSP2 RX EQ Band 4 C
- */
-#define WM8915_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
-
-/*
- * R1424 (0x590) - DSP2 RX EQ Band 4 PG
- */
-#define WM8915_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
-
-/*
- * R1425 (0x591) - DSP2 RX EQ Band 5 A
- */
-#define WM8915_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
-
-/*
- * R1426 (0x592) - DSP2 RX EQ Band 5 B
- */
-#define WM8915_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
-
-/*
- * R1427 (0x593) - DSP2 RX EQ Band 5 PG
- */
-#define WM8915_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
-#define WM8915_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
-
-/*
- * R1536 (0x600) - DAC1 Mixer Volumes
- */
-#define WM8915_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
-#define WM8915_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
-#define WM8915_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
-#define WM8915_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
-
-/*
- * R1537 (0x601) - DAC1 Left Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
-#define WM8915_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
-#define WM8915_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
-#define WM8915_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
-
-/*
- * R1538 (0x602) - DAC1 Right Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
-#define WM8915_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
-#define WM8915_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
-#define WM8915_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
-
-/*
- * R1539 (0x603) - DAC2 Mixer Volumes
- */
-#define WM8915_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
-#define WM8915_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
-#define WM8915_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
-#define WM8915_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
-
-/*
- * R1540 (0x604) - DAC2 Left Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
-#define WM8915_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
-#define WM8915_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
-#define WM8915_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
-
-/*
- * R1541 (0x605) - DAC2 Right Mixer Routing
- */
-#define WM8915_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
-#define WM8915_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
-#define WM8915_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
-#define WM8915_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
-
-/*
- * R1542 (0x606) - DSP1 TX Left Mixer Routing
- */
-#define WM8915_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
-#define WM8915_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
-#define WM8915_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
-
-/*
- * R1543 (0x607) - DSP1 TX Right Mixer Routing
- */
-#define WM8915_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
-#define WM8915_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
-#define WM8915_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
-
-/*
- * R1544 (0x608) - DSP2 TX Left Mixer Routing
- */
-#define WM8915_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
-#define WM8915_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
-#define WM8915_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
-
-/*
- * R1545 (0x609) - DSP2 TX Right Mixer Routing
- */
-#define WM8915_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
-#define WM8915_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
-#define WM8915_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
-
-/*
- * R1546 (0x60A) - DSP TX Mixer Select
- */
-#define WM8915_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
-#define WM8915_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
-
-/*
- * R1552 (0x610) - DAC Softmute
- */
-#define WM8915_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
-#define WM8915_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
-#define WM8915_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
-
-/*
- * R1568 (0x620) - Oversampling
- */
-#define WM8915_SPK_OSR128                       0x0008  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
-#define WM8915_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
-#define WM8915_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
-#define WM8915_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
-#define WM8915_ADC_OSR128                       0x0002  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
-#define WM8915_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
-#define WM8915_DAC_OSR128                       0x0001  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
-#define WM8915_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
-
-/*
- * R1569 (0x621) - Sidetone
- */
-#define WM8915_ST_LPF                           0x1000  /* ST_LPF */
-#define WM8915_ST_LPF_MASK                      0x1000  /* ST_LPF */
-#define WM8915_ST_LPF_SHIFT                         12  /* ST_LPF */
-#define WM8915_ST_LPF_WIDTH                          1  /* ST_LPF */
-#define WM8915_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
-#define WM8915_ST_HPF                           0x0040  /* ST_HPF */
-#define WM8915_ST_HPF_MASK                      0x0040  /* ST_HPF */
-#define WM8915_ST_HPF_SHIFT                          6  /* ST_HPF */
-#define WM8915_ST_HPF_WIDTH                          1  /* ST_HPF */
-#define WM8915_STR_SEL                          0x0002  /* STR_SEL */
-#define WM8915_STR_SEL_MASK                     0x0002  /* STR_SEL */
-#define WM8915_STR_SEL_SHIFT                         1  /* STR_SEL */
-#define WM8915_STR_SEL_WIDTH                         1  /* STR_SEL */
-#define WM8915_STL_SEL                          0x0001  /* STL_SEL */
-#define WM8915_STL_SEL_MASK                     0x0001  /* STL_SEL */
-#define WM8915_STL_SEL_SHIFT                         0  /* STL_SEL */
-#define WM8915_STL_SEL_WIDTH                         1  /* STL_SEL */
-
-/*
- * R1792 (0x700) - GPIO 1
- */
-#define WM8915_GP1_DIR                          0x8000  /* GP1_DIR */
-#define WM8915_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
-#define WM8915_GP1_DIR_SHIFT                        15  /* GP1_DIR */
-#define WM8915_GP1_DIR_WIDTH                         1  /* GP1_DIR */
-#define WM8915_GP1_PU                           0x4000  /* GP1_PU */
-#define WM8915_GP1_PU_MASK                      0x4000  /* GP1_PU */
-#define WM8915_GP1_PU_SHIFT                         14  /* GP1_PU */
-#define WM8915_GP1_PU_WIDTH                          1  /* GP1_PU */
-#define WM8915_GP1_PD                           0x2000  /* GP1_PD */
-#define WM8915_GP1_PD_MASK                      0x2000  /* GP1_PD */
-#define WM8915_GP1_PD_SHIFT                         13  /* GP1_PD */
-#define WM8915_GP1_PD_WIDTH                          1  /* GP1_PD */
-#define WM8915_GP1_POL                          0x0400  /* GP1_POL */
-#define WM8915_GP1_POL_MASK                     0x0400  /* GP1_POL */
-#define WM8915_GP1_POL_SHIFT                        10  /* GP1_POL */
-#define WM8915_GP1_POL_WIDTH                         1  /* GP1_POL */
-#define WM8915_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
-#define WM8915_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
-#define WM8915_GP1_DB                           0x0100  /* GP1_DB */
-#define WM8915_GP1_DB_MASK                      0x0100  /* GP1_DB */
-#define WM8915_GP1_DB_SHIFT                          8  /* GP1_DB */
-#define WM8915_GP1_DB_WIDTH                          1  /* GP1_DB */
-#define WM8915_GP1_LVL                          0x0040  /* GP1_LVL */
-#define WM8915_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
-#define WM8915_GP1_LVL_SHIFT                         6  /* GP1_LVL */
-#define WM8915_GP1_LVL_WIDTH                         1  /* GP1_LVL */
-#define WM8915_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
-#define WM8915_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
-#define WM8915_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
-
-/*
- * R1793 (0x701) - GPIO 2
- */
-#define WM8915_GP2_DIR                          0x8000  /* GP2_DIR */
-#define WM8915_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
-#define WM8915_GP2_DIR_SHIFT                        15  /* GP2_DIR */
-#define WM8915_GP2_DIR_WIDTH                         1  /* GP2_DIR */
-#define WM8915_GP2_PU                           0x4000  /* GP2_PU */
-#define WM8915_GP2_PU_MASK                      0x4000  /* GP2_PU */
-#define WM8915_GP2_PU_SHIFT                         14  /* GP2_PU */
-#define WM8915_GP2_PU_WIDTH                          1  /* GP2_PU */
-#define WM8915_GP2_PD                           0x2000  /* GP2_PD */
-#define WM8915_GP2_PD_MASK                      0x2000  /* GP2_PD */
-#define WM8915_GP2_PD_SHIFT                         13  /* GP2_PD */
-#define WM8915_GP2_PD_WIDTH                          1  /* GP2_PD */
-#define WM8915_GP2_POL                          0x0400  /* GP2_POL */
-#define WM8915_GP2_POL_MASK                     0x0400  /* GP2_POL */
-#define WM8915_GP2_POL_SHIFT                        10  /* GP2_POL */
-#define WM8915_GP2_POL_WIDTH                         1  /* GP2_POL */
-#define WM8915_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
-#define WM8915_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
-#define WM8915_GP2_DB                           0x0100  /* GP2_DB */
-#define WM8915_GP2_DB_MASK                      0x0100  /* GP2_DB */
-#define WM8915_GP2_DB_SHIFT                          8  /* GP2_DB */
-#define WM8915_GP2_DB_WIDTH                          1  /* GP2_DB */
-#define WM8915_GP2_LVL                          0x0040  /* GP2_LVL */
-#define WM8915_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
-#define WM8915_GP2_LVL_SHIFT                         6  /* GP2_LVL */
-#define WM8915_GP2_LVL_WIDTH                         1  /* GP2_LVL */
-#define WM8915_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
-#define WM8915_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
-#define WM8915_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
-
-/*
- * R1794 (0x702) - GPIO 3
- */
-#define WM8915_GP3_DIR                          0x8000  /* GP3_DIR */
-#define WM8915_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
-#define WM8915_GP3_DIR_SHIFT                        15  /* GP3_DIR */
-#define WM8915_GP3_DIR_WIDTH                         1  /* GP3_DIR */
-#define WM8915_GP3_PU                           0x4000  /* GP3_PU */
-#define WM8915_GP3_PU_MASK                      0x4000  /* GP3_PU */
-#define WM8915_GP3_PU_SHIFT                         14  /* GP3_PU */
-#define WM8915_GP3_PU_WIDTH                          1  /* GP3_PU */
-#define WM8915_GP3_PD                           0x2000  /* GP3_PD */
-#define WM8915_GP3_PD_MASK                      0x2000  /* GP3_PD */
-#define WM8915_GP3_PD_SHIFT                         13  /* GP3_PD */
-#define WM8915_GP3_PD_WIDTH                          1  /* GP3_PD */
-#define WM8915_GP3_POL                          0x0400  /* GP3_POL */
-#define WM8915_GP3_POL_MASK                     0x0400  /* GP3_POL */
-#define WM8915_GP3_POL_SHIFT                        10  /* GP3_POL */
-#define WM8915_GP3_POL_WIDTH                         1  /* GP3_POL */
-#define WM8915_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
-#define WM8915_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
-#define WM8915_GP3_DB                           0x0100  /* GP3_DB */
-#define WM8915_GP3_DB_MASK                      0x0100  /* GP3_DB */
-#define WM8915_GP3_DB_SHIFT                          8  /* GP3_DB */
-#define WM8915_GP3_DB_WIDTH                          1  /* GP3_DB */
-#define WM8915_GP3_LVL                          0x0040  /* GP3_LVL */
-#define WM8915_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
-#define WM8915_GP3_LVL_SHIFT                         6  /* GP3_LVL */
-#define WM8915_GP3_LVL_WIDTH                         1  /* GP3_LVL */
-#define WM8915_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
-#define WM8915_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
-#define WM8915_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
-
-/*
- * R1795 (0x703) - GPIO 4
- */
-#define WM8915_GP4_DIR                          0x8000  /* GP4_DIR */
-#define WM8915_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
-#define WM8915_GP4_DIR_SHIFT                        15  /* GP4_DIR */
-#define WM8915_GP4_DIR_WIDTH                         1  /* GP4_DIR */
-#define WM8915_GP4_PU                           0x4000  /* GP4_PU */
-#define WM8915_GP4_PU_MASK                      0x4000  /* GP4_PU */
-#define WM8915_GP4_PU_SHIFT                         14  /* GP4_PU */
-#define WM8915_GP4_PU_WIDTH                          1  /* GP4_PU */
-#define WM8915_GP4_PD                           0x2000  /* GP4_PD */
-#define WM8915_GP4_PD_MASK                      0x2000  /* GP4_PD */
-#define WM8915_GP4_PD_SHIFT                         13  /* GP4_PD */
-#define WM8915_GP4_PD_WIDTH                          1  /* GP4_PD */
-#define WM8915_GP4_POL                          0x0400  /* GP4_POL */
-#define WM8915_GP4_POL_MASK                     0x0400  /* GP4_POL */
-#define WM8915_GP4_POL_SHIFT                        10  /* GP4_POL */
-#define WM8915_GP4_POL_WIDTH                         1  /* GP4_POL */
-#define WM8915_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
-#define WM8915_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
-#define WM8915_GP4_DB                           0x0100  /* GP4_DB */
-#define WM8915_GP4_DB_MASK                      0x0100  /* GP4_DB */
-#define WM8915_GP4_DB_SHIFT                          8  /* GP4_DB */
-#define WM8915_GP4_DB_WIDTH                          1  /* GP4_DB */
-#define WM8915_GP4_LVL                          0x0040  /* GP4_LVL */
-#define WM8915_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
-#define WM8915_GP4_LVL_SHIFT                         6  /* GP4_LVL */
-#define WM8915_GP4_LVL_WIDTH                         1  /* GP4_LVL */
-#define WM8915_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
-#define WM8915_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
-#define WM8915_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
-
-/*
- * R1796 (0x704) - GPIO 5
- */
-#define WM8915_GP5_DIR                          0x8000  /* GP5_DIR */
-#define WM8915_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
-#define WM8915_GP5_DIR_SHIFT                        15  /* GP5_DIR */
-#define WM8915_GP5_DIR_WIDTH                         1  /* GP5_DIR */
-#define WM8915_GP5_PU                           0x4000  /* GP5_PU */
-#define WM8915_GP5_PU_MASK                      0x4000  /* GP5_PU */
-#define WM8915_GP5_PU_SHIFT                         14  /* GP5_PU */
-#define WM8915_GP5_PU_WIDTH                          1  /* GP5_PU */
-#define WM8915_GP5_PD                           0x2000  /* GP5_PD */
-#define WM8915_GP5_PD_MASK                      0x2000  /* GP5_PD */
-#define WM8915_GP5_PD_SHIFT                         13  /* GP5_PD */
-#define WM8915_GP5_PD_WIDTH                          1  /* GP5_PD */
-#define WM8915_GP5_POL                          0x0400  /* GP5_POL */
-#define WM8915_GP5_POL_MASK                     0x0400  /* GP5_POL */
-#define WM8915_GP5_POL_SHIFT                        10  /* GP5_POL */
-#define WM8915_GP5_POL_WIDTH                         1  /* GP5_POL */
-#define WM8915_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
-#define WM8915_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
-#define WM8915_GP5_DB                           0x0100  /* GP5_DB */
-#define WM8915_GP5_DB_MASK                      0x0100  /* GP5_DB */
-#define WM8915_GP5_DB_SHIFT                          8  /* GP5_DB */
-#define WM8915_GP5_DB_WIDTH                          1  /* GP5_DB */
-#define WM8915_GP5_LVL                          0x0040  /* GP5_LVL */
-#define WM8915_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
-#define WM8915_GP5_LVL_SHIFT                         6  /* GP5_LVL */
-#define WM8915_GP5_LVL_WIDTH                         1  /* GP5_LVL */
-#define WM8915_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
-#define WM8915_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
-#define WM8915_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
-
-/*
- * R1824 (0x720) - Pull Control (1)
- */
-#define WM8915_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
-#define WM8915_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
-#define WM8915_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
-#define WM8915_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
-#define WM8915_MCLK2_PU                         0x0200  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
-#define WM8915_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
-#define WM8915_MCLK2_PD                         0x0100  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
-#define WM8915_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
-#define WM8915_MCLK1_PU                         0x0080  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
-#define WM8915_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
-#define WM8915_MCLK1_PD                         0x0040  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
-#define WM8915_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
-#define WM8915_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
-#define WM8915_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
-#define WM8915_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
-#define WM8915_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
-#define WM8915_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
-#define WM8915_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
-#define WM8915_BCLK1_PU                         0x0002  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
-#define WM8915_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
-#define WM8915_BCLK1_PD                         0x0001  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
-#define WM8915_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
-
-/*
- * R1825 (0x721) - Pull Control (2)
- */
-#define WM8915_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
-#define WM8915_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
-#define WM8915_ADDR_PD                          0x0040  /* ADDR_PD */
-#define WM8915_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
-#define WM8915_ADDR_PD_SHIFT                         6  /* ADDR_PD */
-#define WM8915_ADDR_PD_WIDTH                         1  /* ADDR_PD */
-#define WM8915_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
-#define WM8915_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
-#define WM8915_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
-#define WM8915_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
-#define WM8915_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
-#define WM8915_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
-#define WM8915_BCLK2_PU                         0x0002  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
-#define WM8915_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
-#define WM8915_BCLK2_PD                         0x0001  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
-#define WM8915_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
-
-/*
- * R1840 (0x730) - Interrupt Status 1
- */
-#define WM8915_GP5_EINT                         0x0010  /* GP5_EINT */
-#define WM8915_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
-#define WM8915_GP5_EINT_SHIFT                        4  /* GP5_EINT */
-#define WM8915_GP5_EINT_WIDTH                        1  /* GP5_EINT */
-#define WM8915_GP4_EINT                         0x0008  /* GP4_EINT */
-#define WM8915_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
-#define WM8915_GP4_EINT_SHIFT                        3  /* GP4_EINT */
-#define WM8915_GP4_EINT_WIDTH                        1  /* GP4_EINT */
-#define WM8915_GP3_EINT                         0x0004  /* GP3_EINT */
-#define WM8915_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
-#define WM8915_GP3_EINT_SHIFT                        2  /* GP3_EINT */
-#define WM8915_GP3_EINT_WIDTH                        1  /* GP3_EINT */
-#define WM8915_GP2_EINT                         0x0002  /* GP2_EINT */
-#define WM8915_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
-#define WM8915_GP2_EINT_SHIFT                        1  /* GP2_EINT */
-#define WM8915_GP2_EINT_WIDTH                        1  /* GP2_EINT */
-#define WM8915_GP1_EINT                         0x0001  /* GP1_EINT */
-#define WM8915_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
-#define WM8915_GP1_EINT_SHIFT                        0  /* GP1_EINT */
-#define WM8915_GP1_EINT_WIDTH                        1  /* GP1_EINT */
-
-/*
- * R1841 (0x731) - Interrupt Status 2
- */
-#define WM8915_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
-#define WM8915_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
-#define WM8915_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
-#define WM8915_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
-#define WM8915_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
-#define WM8915_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
-#define WM8915_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
-#define WM8915_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
-#define WM8915_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
-#define WM8915_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
-#define WM8915_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
-#define WM8915_MICD_EINT                        0x0001  /* MICD_EINT */
-#define WM8915_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
-#define WM8915_MICD_EINT_SHIFT                       0  /* MICD_EINT */
-#define WM8915_MICD_EINT_WIDTH                       1  /* MICD_EINT */
-
-/*
- * R1842 (0x732) - Interrupt Raw Status 2
- */
-#define WM8915_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
-#define WM8915_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
-#define WM8915_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
-#define WM8915_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
-#define WM8915_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
-#define WM8915_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
-#define WM8915_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
-#define WM8915_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
-#define WM8915_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
-
-/*
- * R1848 (0x738) - Interrupt Status 1 Mask
- */
-#define WM8915_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
-#define WM8915_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
-#define WM8915_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
-#define WM8915_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
-#define WM8915_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
-#define WM8915_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
-#define WM8915_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
-#define WM8915_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
-#define WM8915_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
-#define WM8915_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
-
-/*
- * R1849 (0x739) - Interrupt Status 2 Mask
- */
-#define WM8915_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
-#define WM8915_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
-#define WM8915_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
-#define WM8915_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
-#define WM8915_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
-#define WM8915_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
-
-/*
- * R1856 (0x740) - Interrupt Control
- */
-#define WM8915_IM_IRQ                           0x0001  /* IM_IRQ */
-#define WM8915_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
-#define WM8915_IM_IRQ_SHIFT                          0  /* IM_IRQ */
-#define WM8915_IM_IRQ_WIDTH                          1  /* IM_IRQ */
-
-/*
- * R2048 (0x800) - Left PDM Speaker
- */
-#define WM8915_SPKL_ENA                         0x0010  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
-#define WM8915_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
-#define WM8915_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
-#define WM8915_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
-#define WM8915_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
-#define WM8915_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
-#define WM8915_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
-
-/*
- * R2049 (0x801) - Right PDM Speaker
- */
-#define WM8915_SPKR_ENA                         0x0010  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
-#define WM8915_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
-#define WM8915_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
-#define WM8915_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
-#define WM8915_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
-#define WM8915_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
-#define WM8915_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
-
-/*
- * R2050 (0x802) - PDM Speaker Mute Sequence
- */
-#define WM8915_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
-#define WM8915_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
-#define WM8915_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
-#define WM8915_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
-
-/*
- * R2051 (0x803) - PDM Speaker Volume
- */
-#define WM8915_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
-#define WM8915_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
-#define WM8915_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
-#define WM8915_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
-
-#endif
index 09e680a..b393f9f 100644 (file)
@@ -2981,6 +2981,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                        wm8994->hubs.dcs_readback_mode = 1;
                        break;
                }
+               break;
 
        case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
new file mode 100644 (file)
index 0000000..ab8e9d1
--- /dev/null
@@ -0,0 +1,2994 @@
+/*
+ * wm8996.c - WM8996 audio codec interface
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8996.h>
+#include "wm8996.h"
+
+#define WM8996_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8996_NUM_SUPPLIES 4
+static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
+       "DBVDD",
+       "AVDD1",
+       "AVDD2",
+       "CPVDD",
+};
+
+struct wm8996_priv {
+       struct snd_soc_codec *codec;
+
+       int ldo1ena;
+
+       int sysclk;
+       int sysclk_src;
+
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       struct completion fll_lock;
+
+       u16 dcs_pending;
+       struct completion dcs_done;
+
+       u16 hpout_ena;
+       u16 hpout_pending;
+
+       struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
+
+       struct wm8996_pdata pdata;
+
+       int rx_rate[WM8996_AIFS];
+       int bclk_rate[WM8996_AIFS];
+
+       /* Platform dependant ReTune mobile configuration */
+       int num_retune_mobile_texts;
+       const char **retune_mobile_texts;
+       int retune_mobile_cfg[2];
+       struct soc_enum retune_mobile_enum;
+
+       struct snd_soc_jack *jack;
+       bool detecting;
+       bool jack_mic;
+       wm8996_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8996_REGULATOR_EVENT(n) \
+static int wm8996_regulator_event_##n(struct notifier_block *nb, \
+                                   unsigned long event, void *data)    \
+{ \
+       struct wm8996_priv *wm8996 = container_of(nb, struct wm8996_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8996->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8996_REGULATOR_EVENT(0)
+WM8996_REGULATOR_EVENT(1)
+WM8996_REGULATOR_EVENT(2)
+WM8996_REGULATOR_EVENT(3)
+
+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 const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *sidetone_hpf_text[] = {
+       "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 6, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+       "HiFi", "Custom", "Voice"
+};
+
+static const struct soc_enum dsp1tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const struct soc_enum dsp2tx_hpf_mode =
+       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+       "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum dsp1tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static const struct soc_enum dsp2tx_hpf_cutoff =
+       SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+       int base, best, best_val, save, i, cfg, iface;
+
+       if (!wm8996->num_retune_mobile_texts)
+               return;
+
+       switch (block) {
+       case 0:
+               base = WM8996_DSP1_RX_EQ_GAINS_1;
+               if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+                   WM8996_DSP1RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       case 1:
+               base = WM8996_DSP1_RX_EQ_GAINS_2;
+               if (snd_soc_read(codec, WM8996_POWER_MANAGEMENT_8) &
+                   WM8996_DSP2RX_SRC)
+                       iface = 1;
+               else
+                       iface = 0;
+               break;
+       default:
+               return;
+       }
+
+       /* Find the version of the currently selected configuration
+        * with the nearest sample rate. */
+       cfg = wm8996->retune_mobile_cfg[block];
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                          wm8996->retune_mobile_texts[cfg]) == 0 &&
+                   abs(pdata->retune_mobile_cfgs[i].rate
+                       - wm8996->rx_rate[iface]) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->retune_mobile_cfgs[i].rate
+                                      - wm8996->rx_rate[iface]);
+               }
+       }
+
+       dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+               block,
+               pdata->retune_mobile_cfgs[best].name,
+               pdata->retune_mobile_cfgs[best].rate,
+               wm8996->rx_rate[iface]);
+
+       /* The EQ will be disabled while reconfiguring it, remember the
+        * current configuration. 
+        */
+       save = snd_soc_read(codec, base);
+       save &= WM8996_DSP1RX_EQ_ENA;
+
+       for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+               snd_soc_update_bits(codec, base + i, 0xffff,
+                                   pdata->retune_mobile_cfgs[best].regs[i]);
+
+       snd_soc_update_bits(codec, base, WM8996_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8996_get_retune_mobile_block(const char *name)
+{
+       if (strcmp(name, "DSP1 EQ Mode") == 0)
+               return 0;
+       if (strcmp(name, "DSP2 EQ Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static int wm8996_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+       int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+       int value = ucontrol->value.integer.value[0];
+
+       if (block < 0)
+               return block;
+
+       if (value >= pdata->num_retune_mobile_cfgs)
+               return -EINVAL;
+
+       wm8996->retune_mobile_cfg[block] = value;
+
+       wm8996_set_retune_mobile(codec, block);
+
+       return 0;
+}
+
+static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+
+       ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block];
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8996_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8996_LEFT_LINE_INPUT_VOLUME,
+                WM8996_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8996_LEFT_LINE_INPUT_VOLUME,
+            WM8996_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8996_DAC1_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8996_DAC2_MIXER_VOLUMES,
+              0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8996_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8996_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8996_DSP1_TX_LEFT_VOLUME,
+                WM8996_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8996_DSP2_TX_LEFT_VOLUME,
+                WM8996_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8996_DSP1_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8996_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8996_DSP2_TX_FILTERS,
+          13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8996_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8996_DSP1_RX_LEFT_VOLUME,
+                WM8996_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8996_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8996_DSP2_RX_LEFT_VOLUME,
+                WM8996_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8996_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8996_DAC1_LEFT_VOLUME,
+                WM8996_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8996_DAC1_LEFT_VOLUME,
+            WM8996_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8996_DAC2_LEFT_VOLUME,
+                WM8996_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8996_DAC2_LEFT_VOLUME,
+            WM8996_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8996_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8996_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8996_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8996_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8996_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8996_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8996_DAC1_HPOUT1_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8996_DAC2_HPOUT2_VOLUME, 0, 4,
+              8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8996_OUTPUT1_LEFT_VOLUME,
+                WM8996_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8996_OUTPUT1_LEFT_VOLUME,
+            WM8996_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8996_OUTPUT2_LEFT_VOLUME,
+                WM8996_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8996_OUTPUT2_LEFT_VOLUME,
+            WM8996_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8996_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+              spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8996_LEFT_PDM_SPEAKER,
+            WM8996_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8996_LEFT_PDM_SPEAKER,
+            WM8996_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8996_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8996_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8996_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8996_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+              eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+              eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(5);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+
+       /* Record which outputs we enabled */
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               wm8996->hpout_pending &= ~w->shift;
+               break;
+       case SND_SOC_DAPM_PRE_PMU:
+               wm8996->hpout_pending |= w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+{
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+       unsigned long timeout = 200;
+
+       snd_soc_write(codec, WM8996_DC_SERVO_2, mask);
+
+       /* Use the interrupt if possible */
+       do {
+               if (i2c->irq) {
+                       timeout = wait_for_completion_timeout(&wm8996->dcs_done,
+                                                             msecs_to_jiffies(200));
+                       if (timeout == 0)
+                               dev_err(codec->dev, "DC servo timed out\n");
+
+               } else {
+                       msleep(1);
+                       if (--i) {
+                               timeout = 0;
+                               break;
+                       }
+               }
+
+               ret = snd_soc_read(codec, WM8996_DC_SERVO_2);
+               dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+       } while (ret & mask);
+
+       if (timeout == 0)
+               dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+       else
+               dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
+                               enum snd_soc_dapm_type event, int subseq)
+{
+       struct snd_soc_codec *codec = container_of(dapm,
+                                                  struct snd_soc_codec, dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       u16 val, mask;
+
+       /* Complete any pending DC servo starts */
+       if (wm8996->dcs_pending) {
+               dev_dbg(codec->dev, "Starting DC servo for %x\n",
+                       wm8996->dcs_pending);
+
+               /* Trigger a startup sequence */
+               wait_for_dc_servo(codec, wm8996->dcs_pending
+                                        << WM8996_DCS_TRIG_STARTUP_0_SHIFT);
+
+               wm8996->dcs_pending = 0;
+       }
+
+       if (wm8996->hpout_pending != wm8996->hpout_ena) {
+               dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+                       wm8996->hpout_ena, wm8996->hpout_pending);
+
+               val = 0;
+               mask = 0;
+               if (wm8996->hpout_pending & HPOUT1L) {
+                       val |= WM8996_HPOUT1L_RMV_SHORT;
+                       mask |= WM8996_HPOUT1L_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT1L_RMV_SHORT |
+                               WM8996_HPOUT1L_OUTP |
+                               WM8996_HPOUT1L_DLY;
+               }
+
+               if (wm8996->hpout_pending & HPOUT1R) {
+                       val |= WM8996_HPOUT1R_RMV_SHORT;
+                       mask |= WM8996_HPOUT1R_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT1R_RMV_SHORT |
+                               WM8996_HPOUT1R_OUTP |
+                               WM8996_HPOUT1R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_1, mask, val);
+
+               val = 0;
+               mask = 0;
+               if (wm8996->hpout_pending & HPOUT2L) {
+                       val |= WM8996_HPOUT2L_RMV_SHORT;
+                       mask |= WM8996_HPOUT2L_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT2L_RMV_SHORT |
+                               WM8996_HPOUT2L_OUTP |
+                               WM8996_HPOUT2L_DLY;
+               }
+
+               if (wm8996->hpout_pending & HPOUT2R) {
+                       val |= WM8996_HPOUT2R_RMV_SHORT;
+                       mask |= WM8996_HPOUT2R_RMV_SHORT;
+               } else {
+                       mask |= WM8996_HPOUT2R_RMV_SHORT |
+                               WM8996_HPOUT2R_OUTP |
+                               WM8996_HPOUT2R_DLY;
+               }
+
+               snd_soc_update_bits(codec, WM8996_ANALOGUE_HP_2, mask, val);
+
+               wm8996->hpout_ena = wm8996->hpout_pending;
+       }
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+                    struct snd_kcontrol *kcontrol, int event)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               wm8996->dcs_pending |= 1 << w->shift;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const char *sidetone_text[] = {
+       "IN1", "IN2",
+};
+
+static const struct soc_enum left_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+       SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static const struct soc_enum right_sidetone_enum =
+       SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+       SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const struct soc_enum spkl_enum =
+       SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+       SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static const struct soc_enum spkr_enum =
+       SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+       SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+       "AIF1", "AIF2"
+};
+
+static const struct soc_enum dsp1rx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+       SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+        "AIF2", "AIF1"
+};
+
+static const struct soc_enum dsp2rx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+       SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+       "DSP2", "DSP1", "AIF1"
+};
+
+static const struct soc_enum aif2tx_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+       SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+       "ADC", "DMIC1", "DMIC2"
+};
+
+static const struct soc_enum in1_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+       SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static const struct soc_enum in2_enum =
+       SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+       SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC2_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8996_DAC1_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8996_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP1_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8996_DSP2_TX_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8996_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
+                     SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8996_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8996_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8996_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8996_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+
+SND_SOC_DAPM_PGA("IN1L", WM8996_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R", WM8996_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2L", WM8996_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2R", WM8996_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8996_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8996_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8996_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8996_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8996_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8996_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8996_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8996_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8996_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8996_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8996_POWER_MANAGEMENT_5, 11, 0,
+                  dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8996_POWER_MANAGEMENT_5, 10, 0,
+                  dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8996_POWER_MANAGEMENT_5, 9, 0,
+                  dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8996_POWER_MANAGEMENT_5, 8, 0,
+                  dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+                  dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8996_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8996_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8996_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8996_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+                   WM8996_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+                   WM8996_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+                   WM8996_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+                   WM8996_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
+                   WM8996_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
+                   WM8996_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
+                   WM8996_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
+                   WM8996_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
+                   WM8996_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
+                   WM8996_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
+                    WM8996_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
+                    WM8996_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
+                    WM8996_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
+                    WM8996_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
+                    WM8996_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
+                    WM8996_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8996_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8996_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8996_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8996_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8996_DC_SERVO_1, 2, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8996_ANALOGUE_HP_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8996_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8996_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8996_DC_SERVO_1, 3, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8996_ANALOGUE_HP_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8996_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8996_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8996_DC_SERVO_1, 0, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8996_ANALOGUE_HP_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8996_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8996_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8996_DC_SERVO_1, 1, 0, dcs_start,
+                  SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8996_ANALOGUE_HP_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+                  rmv_short_event,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8996_dapm_routes[] = {
+       { "AIFCLK", NULL, "SYSCLK" },
+       { "SYSDSPCLK", NULL, "SYSCLK" },
+       { "Charge Pump", NULL, "SYSCLK" },
+
+       { "MICB1", NULL, "LDO2" },
+       { "MICB2", NULL, "LDO2" },
+
+       { "IN1L PGA", NULL, "IN2LN" },
+       { "IN1L PGA", NULL, "IN2LP" },
+       { "IN1L PGA", NULL, "IN1LN" },
+       { "IN1L PGA", NULL, "IN1LP" },
+
+       { "IN1R PGA", NULL, "IN2RN" },
+       { "IN1R PGA", NULL, "IN2RP" },
+       { "IN1R PGA", NULL, "IN1RN" },
+       { "IN1R PGA", NULL, "IN1RP" },
+
+       { "ADCL", NULL, "IN1L PGA" },
+
+       { "ADCR", NULL, "IN1R PGA" },
+
+       { "DMIC1L", NULL, "DMIC1DAT" },
+       { "DMIC1R", NULL, "DMIC1DAT" },
+       { "DMIC2L", NULL, "DMIC2DAT" },
+       { "DMIC2R", NULL, "DMIC2DAT" },
+
+       { "DMIC2L", NULL, "DMIC2" },
+       { "DMIC2R", NULL, "DMIC2" },
+       { "DMIC1L", NULL, "DMIC1" },
+       { "DMIC1R", NULL, "DMIC1" },
+
+       { "IN1L Mux", "ADC", "ADCL" },
+       { "IN1L Mux", "DMIC1", "DMIC1L" },
+       { "IN1L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN1R Mux", "ADC", "ADCR" },
+       { "IN1R Mux", "DMIC1", "DMIC1R" },
+       { "IN1R Mux", "DMIC2", "DMIC2R" },
+
+       { "IN2L Mux", "ADC", "ADCL" },
+       { "IN2L Mux", "DMIC1", "DMIC1L" },
+       { "IN2L Mux", "DMIC2", "DMIC2L" },
+
+       { "IN2R Mux", "ADC", "ADCR" },
+       { "IN2R Mux", "DMIC1", "DMIC1R" },
+       { "IN2R Mux", "DMIC2", "DMIC2R" },
+
+       { "Left Sidetone", "IN1", "IN1L Mux" },
+       { "Left Sidetone", "IN2", "IN2L Mux" },
+
+       { "Right Sidetone", "IN1", "IN1R Mux" },
+       { "Right Sidetone", "IN2", "IN2R Mux" },
+
+       { "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+       { "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+       { "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+       { "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+       { "AIF1TX0", NULL, "DSP1TXL" },
+       { "AIF1TX1", NULL, "DSP1TXR" },
+       { "AIF1TX2", NULL, "DSP2TXL" },
+       { "AIF1TX3", NULL, "DSP2TXR" },
+       { "AIF1TX4", NULL, "AIF2RX0" },
+       { "AIF1TX5", NULL, "AIF2RX1" },
+
+       { "AIF1RX0", NULL, "AIFCLK" },
+       { "AIF1RX1", NULL, "AIFCLK" },
+       { "AIF1RX2", NULL, "AIFCLK" },
+       { "AIF1RX3", NULL, "AIFCLK" },
+       { "AIF1RX4", NULL, "AIFCLK" },
+       { "AIF1RX5", NULL, "AIFCLK" },
+
+       { "AIF2RX0", NULL, "AIFCLK" },
+       { "AIF2RX1", NULL, "AIFCLK" },
+
+       { "DSP1RXL", NULL, "SYSDSPCLK" },
+       { "DSP1RXR", NULL, "SYSDSPCLK" },
+       { "DSP2RXL", NULL, "SYSDSPCLK" },
+       { "DSP2RXR", NULL, "SYSDSPCLK" },
+       { "DSP1TXL", NULL, "SYSDSPCLK" },
+       { "DSP1TXR", NULL, "SYSDSPCLK" },
+       { "DSP2TXL", NULL, "SYSDSPCLK" },
+       { "DSP2TXR", NULL, "SYSDSPCLK" },
+
+       { "AIF1RXA", NULL, "AIF1RX0" },
+       { "AIF1RXA", NULL, "AIF1RX1" },
+       { "AIF1RXB", NULL, "AIF1RX2" },
+       { "AIF1RXB", NULL, "AIF1RX3" },
+       { "AIF1RXC", NULL, "AIF1RX4" },
+       { "AIF1RXC", NULL, "AIF1RX5" },
+
+       { "AIF2RX", NULL, "AIF2RX0" },
+       { "AIF2RX", NULL, "AIF2RX1" },
+
+       { "AIF2TX", "DSP2", "DSP2TX" },
+       { "AIF2TX", "DSP1", "DSP1RX" },
+       { "AIF2TX", "AIF1", "AIF1RXC" },
+
+       { "DSP1RXL", NULL, "DSP1RX" },
+       { "DSP1RXR", NULL, "DSP1RX" },
+       { "DSP2RXL", NULL, "DSP2RX" },
+       { "DSP2RXR", NULL, "DSP2RX" },
+
+       { "DSP2TX", NULL, "DSP2TXL" },
+       { "DSP2TX", NULL, "DSP2TXR" },
+
+       { "DSP1RX", "AIF1", "AIF1RXA" },
+       { "DSP1RX", "AIF2", "AIF2RX" },
+
+       { "DSP2RX", "AIF1", "AIF1RXB" },
+       { "DSP2RX", "AIF2", "AIF2RX" },
+
+       { "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+       { "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+       { "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC2L", NULL, "DAC2L Mixer" },
+       { "DAC2R", NULL, "DAC2R Mixer" },
+
+       { "HPOUT2L PGA", NULL, "Charge Pump" },
+       { "HPOUT2L PGA", NULL, "DAC2L" },
+       { "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+       { "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+       { "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
+       { "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+
+       { "HPOUT2R PGA", NULL, "Charge Pump" },
+       { "HPOUT2R PGA", NULL, "DAC2R" },
+       { "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+       { "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+       { "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
+       { "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+
+       { "HPOUT1L PGA", NULL, "Charge Pump" },
+       { "HPOUT1L PGA", NULL, "DAC1L" },
+       { "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+       { "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+       { "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
+       { "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+
+       { "HPOUT1R PGA", NULL, "Charge Pump" },
+       { "HPOUT1R PGA", NULL, "DAC1R" },
+       { "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+       { "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+       { "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
+       { "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+
+       { "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+       { "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+       { "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+       { "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+       { "SPKL", "DAC1L", "DAC1L" },
+       { "SPKL", "DAC1R", "DAC1R" },
+       { "SPKL", "DAC2L", "DAC2L" },
+       { "SPKL", "DAC2R", "DAC2R" },
+
+       { "SPKR", "DAC1L", "DAC1L" },
+       { "SPKR", "DAC1R", "DAC1R" },
+       { "SPKR", "DAC2L", "DAC2L" },
+       { "SPKR", "DAC2R", "DAC2R" },
+
+       { "SPKL PGA", NULL, "SPKL" },
+       { "SPKR PGA", NULL, "SPKR" },
+
+       { "SPKDAT", NULL, "SPKL PGA" },
+       { "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static int wm8996_readable_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       /* Due to the sparseness of the register map the compiler
+        * output from an explicit switch statement ends up being much
+        * more efficient than a table.
+        */
+       switch (reg) {
+       case WM8996_SOFTWARE_RESET:
+       case WM8996_POWER_MANAGEMENT_1:
+       case WM8996_POWER_MANAGEMENT_2:
+       case WM8996_POWER_MANAGEMENT_3:
+       case WM8996_POWER_MANAGEMENT_4:
+       case WM8996_POWER_MANAGEMENT_5:
+       case WM8996_POWER_MANAGEMENT_6:
+       case WM8996_POWER_MANAGEMENT_7:
+       case WM8996_POWER_MANAGEMENT_8:
+       case WM8996_LEFT_LINE_INPUT_VOLUME:
+       case WM8996_RIGHT_LINE_INPUT_VOLUME:
+       case WM8996_LINE_INPUT_CONTROL:
+       case WM8996_DAC1_HPOUT1_VOLUME:
+       case WM8996_DAC2_HPOUT2_VOLUME:
+       case WM8996_DAC1_LEFT_VOLUME:
+       case WM8996_DAC1_RIGHT_VOLUME:
+       case WM8996_DAC2_LEFT_VOLUME:
+       case WM8996_DAC2_RIGHT_VOLUME:
+       case WM8996_OUTPUT1_LEFT_VOLUME:
+       case WM8996_OUTPUT1_RIGHT_VOLUME:
+       case WM8996_OUTPUT2_LEFT_VOLUME:
+       case WM8996_OUTPUT2_RIGHT_VOLUME:
+       case WM8996_MICBIAS_1:
+       case WM8996_MICBIAS_2:
+       case WM8996_LDO_1:
+       case WM8996_LDO_2:
+       case WM8996_ACCESSORY_DETECT_MODE_1:
+       case WM8996_ACCESSORY_DETECT_MODE_2:
+       case WM8996_HEADPHONE_DETECT_1:
+       case WM8996_HEADPHONE_DETECT_2:
+       case WM8996_MIC_DETECT_1:
+       case WM8996_MIC_DETECT_2:
+       case WM8996_MIC_DETECT_3:
+       case WM8996_CHARGE_PUMP_1:
+       case WM8996_CHARGE_PUMP_2:
+       case WM8996_DC_SERVO_1:
+       case WM8996_DC_SERVO_2:
+       case WM8996_DC_SERVO_3:
+       case WM8996_DC_SERVO_5:
+       case WM8996_DC_SERVO_6:
+       case WM8996_DC_SERVO_7:
+       case WM8996_DC_SERVO_READBACK_0:
+       case WM8996_ANALOGUE_HP_1:
+       case WM8996_ANALOGUE_HP_2:
+       case WM8996_CHIP_REVISION:
+       case WM8996_CONTROL_INTERFACE_1:
+       case WM8996_WRITE_SEQUENCER_CTRL_1:
+       case WM8996_WRITE_SEQUENCER_CTRL_2:
+       case WM8996_AIF_CLOCKING_1:
+       case WM8996_AIF_CLOCKING_2:
+       case WM8996_CLOCKING_1:
+       case WM8996_CLOCKING_2:
+       case WM8996_AIF_RATE:
+       case WM8996_FLL_CONTROL_1:
+       case WM8996_FLL_CONTROL_2:
+       case WM8996_FLL_CONTROL_3:
+       case WM8996_FLL_CONTROL_4:
+       case WM8996_FLL_CONTROL_5:
+       case WM8996_FLL_CONTROL_6:
+       case WM8996_FLL_EFS_1:
+       case WM8996_FLL_EFS_2:
+       case WM8996_AIF1_CONTROL:
+       case WM8996_AIF1_BCLK:
+       case WM8996_AIF1_TX_LRCLK_1:
+       case WM8996_AIF1_TX_LRCLK_2:
+       case WM8996_AIF1_RX_LRCLK_1:
+       case WM8996_AIF1_RX_LRCLK_2:
+       case WM8996_AIF1TX_DATA_CONFIGURATION_1:
+       case WM8996_AIF1TX_DATA_CONFIGURATION_2:
+       case WM8996_AIF1RX_DATA_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_2_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_3_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_4_CONFIGURATION:
+       case WM8996_AIF1TX_CHANNEL_5_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_2_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_3_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_4_CONFIGURATION:
+       case WM8996_AIF1RX_CHANNEL_5_CONFIGURATION:
+       case WM8996_AIF1RX_MONO_CONFIGURATION:
+       case WM8996_AIF1TX_TEST:
+       case WM8996_AIF2_CONTROL:
+       case WM8996_AIF2_BCLK:
+       case WM8996_AIF2_TX_LRCLK_1:
+       case WM8996_AIF2_TX_LRCLK_2:
+       case WM8996_AIF2_RX_LRCLK_1:
+       case WM8996_AIF2_RX_LRCLK_2:
+       case WM8996_AIF2TX_DATA_CONFIGURATION_1:
+       case WM8996_AIF2TX_DATA_CONFIGURATION_2:
+       case WM8996_AIF2RX_DATA_CONFIGURATION:
+       case WM8996_AIF2TX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF2TX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF2RX_CHANNEL_0_CONFIGURATION:
+       case WM8996_AIF2RX_CHANNEL_1_CONFIGURATION:
+       case WM8996_AIF2RX_MONO_CONFIGURATION:
+       case WM8996_AIF2TX_TEST:
+       case WM8996_DSP1_TX_LEFT_VOLUME:
+       case WM8996_DSP1_TX_RIGHT_VOLUME:
+       case WM8996_DSP1_RX_LEFT_VOLUME:
+       case WM8996_DSP1_RX_RIGHT_VOLUME:
+       case WM8996_DSP1_TX_FILTERS:
+       case WM8996_DSP1_RX_FILTERS_1:
+       case WM8996_DSP1_RX_FILTERS_2:
+       case WM8996_DSP1_DRC_1:
+       case WM8996_DSP1_DRC_2:
+       case WM8996_DSP1_DRC_3:
+       case WM8996_DSP1_DRC_4:
+       case WM8996_DSP1_DRC_5:
+       case WM8996_DSP1_RX_EQ_GAINS_1:
+       case WM8996_DSP1_RX_EQ_GAINS_2:
+       case WM8996_DSP1_RX_EQ_BAND_1_A:
+       case WM8996_DSP1_RX_EQ_BAND_1_B:
+       case WM8996_DSP1_RX_EQ_BAND_1_PG:
+       case WM8996_DSP1_RX_EQ_BAND_2_A:
+       case WM8996_DSP1_RX_EQ_BAND_2_B:
+       case WM8996_DSP1_RX_EQ_BAND_2_C:
+       case WM8996_DSP1_RX_EQ_BAND_2_PG:
+       case WM8996_DSP1_RX_EQ_BAND_3_A:
+       case WM8996_DSP1_RX_EQ_BAND_3_B:
+       case WM8996_DSP1_RX_EQ_BAND_3_C:
+       case WM8996_DSP1_RX_EQ_BAND_3_PG:
+       case WM8996_DSP1_RX_EQ_BAND_4_A:
+       case WM8996_DSP1_RX_EQ_BAND_4_B:
+       case WM8996_DSP1_RX_EQ_BAND_4_C:
+       case WM8996_DSP1_RX_EQ_BAND_4_PG:
+       case WM8996_DSP1_RX_EQ_BAND_5_A:
+       case WM8996_DSP1_RX_EQ_BAND_5_B:
+       case WM8996_DSP1_RX_EQ_BAND_5_PG:
+       case WM8996_DSP2_TX_LEFT_VOLUME:
+       case WM8996_DSP2_TX_RIGHT_VOLUME:
+       case WM8996_DSP2_RX_LEFT_VOLUME:
+       case WM8996_DSP2_RX_RIGHT_VOLUME:
+       case WM8996_DSP2_TX_FILTERS:
+       case WM8996_DSP2_RX_FILTERS_1:
+       case WM8996_DSP2_RX_FILTERS_2:
+       case WM8996_DSP2_DRC_1:
+       case WM8996_DSP2_DRC_2:
+       case WM8996_DSP2_DRC_3:
+       case WM8996_DSP2_DRC_4:
+       case WM8996_DSP2_DRC_5:
+       case WM8996_DSP2_RX_EQ_GAINS_1:
+       case WM8996_DSP2_RX_EQ_GAINS_2:
+       case WM8996_DSP2_RX_EQ_BAND_1_A:
+       case WM8996_DSP2_RX_EQ_BAND_1_B:
+       case WM8996_DSP2_RX_EQ_BAND_1_PG:
+       case WM8996_DSP2_RX_EQ_BAND_2_A:
+       case WM8996_DSP2_RX_EQ_BAND_2_B:
+       case WM8996_DSP2_RX_EQ_BAND_2_C:
+       case WM8996_DSP2_RX_EQ_BAND_2_PG:
+       case WM8996_DSP2_RX_EQ_BAND_3_A:
+       case WM8996_DSP2_RX_EQ_BAND_3_B:
+       case WM8996_DSP2_RX_EQ_BAND_3_C:
+       case WM8996_DSP2_RX_EQ_BAND_3_PG:
+       case WM8996_DSP2_RX_EQ_BAND_4_A:
+       case WM8996_DSP2_RX_EQ_BAND_4_B:
+       case WM8996_DSP2_RX_EQ_BAND_4_C:
+       case WM8996_DSP2_RX_EQ_BAND_4_PG:
+       case WM8996_DSP2_RX_EQ_BAND_5_A:
+       case WM8996_DSP2_RX_EQ_BAND_5_B:
+       case WM8996_DSP2_RX_EQ_BAND_5_PG:
+       case WM8996_DAC1_MIXER_VOLUMES:
+       case WM8996_DAC1_LEFT_MIXER_ROUTING:
+       case WM8996_DAC1_RIGHT_MIXER_ROUTING:
+       case WM8996_DAC2_MIXER_VOLUMES:
+       case WM8996_DAC2_LEFT_MIXER_ROUTING:
+       case WM8996_DAC2_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP1_TX_LEFT_MIXER_ROUTING:
+       case WM8996_DSP1_TX_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP2_TX_LEFT_MIXER_ROUTING:
+       case WM8996_DSP2_TX_RIGHT_MIXER_ROUTING:
+       case WM8996_DSP_TX_MIXER_SELECT:
+       case WM8996_DAC_SOFTMUTE:
+       case WM8996_OVERSAMPLING:
+       case WM8996_SIDETONE:
+       case WM8996_GPIO_1:
+       case WM8996_GPIO_2:
+       case WM8996_GPIO_3:
+       case WM8996_GPIO_4:
+       case WM8996_GPIO_5:
+       case WM8996_PULL_CONTROL_1:
+       case WM8996_PULL_CONTROL_2:
+       case WM8996_INTERRUPT_STATUS_1:
+       case WM8996_INTERRUPT_STATUS_2:
+       case WM8996_INTERRUPT_RAW_STATUS_2:
+       case WM8996_INTERRUPT_STATUS_1_MASK:
+       case WM8996_INTERRUPT_STATUS_2_MASK:
+       case WM8996_INTERRUPT_CONTROL:
+       case WM8996_LEFT_PDM_SPEAKER:
+       case WM8996_RIGHT_PDM_SPEAKER:
+       case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
+       case WM8996_PDM_SPEAKER_VOLUME:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8996_volatile_register(struct snd_soc_codec *codec,
+                                   unsigned int reg)
+{
+       switch (reg) {
+       case WM8996_SOFTWARE_RESET:
+       case WM8996_CHIP_REVISION:
+       case WM8996_LDO_1:
+       case WM8996_LDO_2:
+       case WM8996_INTERRUPT_STATUS_1:
+       case WM8996_INTERRUPT_STATUS_2:
+       case WM8996_INTERRUPT_RAW_STATUS_2:
+       case WM8996_DC_SERVO_READBACK_0:
+       case WM8996_DC_SERVO_2:
+       case WM8996_DC_SERVO_6:
+       case WM8996_DC_SERVO_7:
+       case WM8996_FLL_CONTROL_6:
+       case WM8996_MIC_DETECT_3:
+       case WM8996_HEADPHONE_DETECT_1:
+       case WM8996_HEADPHONE_DETECT_2:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int wm8996_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8996_SOFTWARE_RESET, 0x8915);
+}
+
+static const int bclk_divs[] = {
+       1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static void wm8996_update_bclk(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int aif, best, cur_val, bclk_rate, bclk_reg, i;
+
+       /* Don't bother if we're in a low frequency idle mode that
+        * can't support audio.
+        */
+       if (wm8996->sysclk < 64000)
+               return;
+
+       for (aif = 0; aif < WM8996_AIFS; aif++) {
+               switch (aif) {
+               case 0:
+                       bclk_reg = WM8996_AIF1_BCLK;
+                       break;
+               case 1:
+                       bclk_reg = WM8996_AIF2_BCLK;
+                       break;
+               }
+
+               bclk_rate = wm8996->bclk_rate[aif];
+
+               /* Pick a divisor for BCLK as close as we can get to ideal */
+               best = 0;
+               for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+                       cur_val = (wm8996->sysclk / bclk_divs[i]) - bclk_rate;
+                       if (cur_val < 0) /* BCLK table is sorted */
+                               break;
+                       best = i;
+               }
+               bclk_rate = wm8996->sysclk / bclk_divs[best];
+               dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+                       bclk_divs[best], bclk_rate);
+
+               snd_soc_update_bits(codec, bclk_reg,
+                                   WM8996_AIF1_BCLK_DIV_MASK, best);
+       }
+}
+
+static int wm8996_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+                       snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+                                           WM8996_BG_ENA, WM8996_BG_ENA);
+                       msleep(2);
+               }
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies),
+                                                   wm8996->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       if (wm8996->pdata.ldo_ena >= 0) {
+                               gpio_set_value_cansleep(wm8996->pdata.ldo_ena,
+                                                       1);
+                               msleep(5);
+                       }
+
+                       codec->cache_only = false;
+                       snd_soc_cache_sync(codec);
+               }
+
+               snd_soc_update_bits(codec, WM8996_POWER_MANAGEMENT_1,
+                                   WM8996_BG_ENA, 0);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               codec->cache_only = true;
+               if (wm8996->pdata.ldo_ena >= 0)
+                       gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
+               regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies),
+                                      wm8996->supplies);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int aifctrl = 0;
+       int bclk = 0;
+       int lrclk_tx = 0;
+       int lrclk_rx = 0;
+       int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+       switch (dai->id) {
+       case 0:
+               aifctrl_reg = WM8996_AIF1_CONTROL;
+               bclk_reg = WM8996_AIF1_BCLK;
+               lrclk_tx_reg = WM8996_AIF1_TX_LRCLK_2;
+               lrclk_rx_reg = WM8996_AIF1_RX_LRCLK_2;
+               break;
+       case 1:
+               aifctrl_reg = WM8996_AIF2_CONTROL;
+               bclk_reg = WM8996_AIF2_BCLK;
+               lrclk_tx_reg = WM8996_AIF2_TX_LRCLK_2;
+               lrclk_rx_reg = WM8996_AIF2_RX_LRCLK_2;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bclk |= WM8996_AIF1_BCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bclk |= WM8996_AIF1_BCLK_INV;
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_INV;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_INV;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               bclk |= WM8996_AIF1_BCLK_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               bclk |= WM8996_AIF1_BCLK_MSTR;
+               lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
+               lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               aifctrl |= 1;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aifctrl |= 2;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aifctrl |= 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, aifctrl_reg, WM8996_AIF1_FMT_MASK, aifctrl);
+       snd_soc_update_bits(codec, bclk_reg,
+                           WM8996_AIF1_BCLK_INV | WM8996_AIF1_BCLK_MSTR,
+                           bclk);
+       snd_soc_update_bits(codec, lrclk_tx_reg,
+                           WM8996_AIF1TX_LRCLK_INV |
+                           WM8996_AIF1TX_LRCLK_MSTR,
+                           lrclk_tx);
+       snd_soc_update_bits(codec, lrclk_rx_reg,
+                           WM8996_AIF1RX_LRCLK_INV |
+                           WM8996_AIF1RX_LRCLK_MSTR,
+                           lrclk_rx);
+
+       return 0;
+}
+
+static const int dsp_divs[] = {
+       48000, 32000, 16000, 8000
+};
+
+static int wm8996_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int bits, i, bclk_rate;
+       int aifdata = 0;
+       int lrclk = 0;
+       int dsp = 0;
+       int aifdata_reg, lrclk_reg, dsp_shift;
+
+       switch (dai->id) {
+       case 0:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8996_GPIO_1)) & WM8996_GP1_FN_MASK) {
+                       aifdata_reg = WM8996_AIF1RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8996_AIF1_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8996_AIF1TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8996_AIF1_TX_LRCLK_1;
+               }
+               dsp_shift = 0;
+               break;
+       case 1:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+                   (snd_soc_read(codec, WM8996_GPIO_2)) & WM8996_GP2_FN_MASK) {
+                       aifdata_reg = WM8996_AIF2RX_DATA_CONFIGURATION;
+                       lrclk_reg = WM8996_AIF2_RX_LRCLK_1;
+               } else {
+                       aifdata_reg = WM8996_AIF2TX_DATA_CONFIGURATION_1;
+                       lrclk_reg = WM8996_AIF2_TX_LRCLK_1;
+               }
+               dsp_shift = WM8996_DSP2_DIV_SHIFT;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       bclk_rate = snd_soc_params_to_bclk(params);
+       if (bclk_rate < 0) {
+               dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+               return bclk_rate;
+       }
+
+       wm8996->bclk_rate[dai->id] = bclk_rate;
+       wm8996->rx_rate[dai->id] = params_rate(params);
+
+       /* Needs looking at for TDM */
+       bits = snd_pcm_format_width(params_format(params));
+       if (bits < 0)
+               return bits;
+       aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits;
+
+       for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+               if (dsp_divs[i] == params_rate(params))
+                       break;
+       }
+       if (i == ARRAY_SIZE(dsp_divs)) {
+               dev_err(codec->dev, "Unsupported sample rate %dHz\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+       dsp |= i << dsp_shift;
+
+       wm8996_update_bclk(codec);
+
+       lrclk = bclk_rate / params_rate(params);
+       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+               lrclk, bclk_rate / lrclk);
+
+       snd_soc_update_bits(codec, aifdata_reg,
+                           WM8996_AIF1TX_WL_MASK |
+                           WM8996_AIF1TX_SLOT_LEN_MASK,
+                           aifdata);
+       snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
+                           lrclk);
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
+                           WM8996_DSP1_DIV_SHIFT << dsp_shift, dsp);
+
+       return 0;
+}
+
+static int wm8996_set_sysclk(struct snd_soc_dai *dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int lfclk = 0;
+       int ratediv = 0;
+       int src;
+       int old;
+
+       if (freq == wm8996->sysclk && clk_id == wm8996->sysclk_src)
+               return 0;
+
+       /* Disable SYSCLK while we reconfigure */
+       old = snd_soc_read(codec, WM8996_AIF_CLOCKING_1) & WM8996_SYSCLK_ENA;
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_ENA, 0);
+
+       switch (clk_id) {
+       case WM8996_SYSCLK_MCLK1:
+               wm8996->sysclk = freq;
+               src = 0;
+               break;
+       case WM8996_SYSCLK_MCLK2:
+               wm8996->sysclk = freq;
+               src = 1;
+               break;
+       case WM8996_SYSCLK_FLL:
+               wm8996->sysclk = freq;
+               src = 2;
+               break;
+       default:
+               dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       switch (wm8996->sysclk) {
+       case 6144000:
+               snd_soc_update_bits(codec, WM8996_AIF_RATE,
+                                   WM8996_SYSCLK_RATE, 0);
+               break;
+       case 24576000:
+               ratediv = WM8996_SYSCLK_DIV;
+       case 12288000:
+               snd_soc_update_bits(codec, WM8996_AIF_RATE,
+                                   WM8996_SYSCLK_RATE, WM8996_SYSCLK_RATE);
+               break;
+       case 32000:
+       case 32768:
+               lfclk = WM8996_LFCLK_ENA;
+               break;
+       default:
+               dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+                        wm8996->sysclk);
+               return -EINVAL;
+       }
+
+       wm8996_update_bclk(codec);
+
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_SRC_MASK | WM8996_SYSCLK_DIV_MASK,
+                           src << WM8996_SYSCLK_SRC_SHIFT | ratediv);
+       snd_soc_update_bits(codec, WM8996_CLOCKING_1, WM8996_LFCLK_ENA, lfclk);
+       snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_1,
+                           WM8996_SYSCLK_ENA, old);
+
+       wm8996->sysclk_src = clk_id;
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_refclk_div;
+       u16 fll_loop_gain;
+       u16 fll_ref_freq;
+       u16 n;
+       u16 theta;
+       u16 lambda;
+};
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       unsigned int target;
+       unsigned int div;
+       unsigned int fratio, gcd_fll;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_refclk_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_refclk_div++;
+
+               if (div > 8) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       if (Fref >= 3000000)
+               fll_div->fll_loop_gain = 5;
+       else
+               fll_div->fll_loop_gain = 0;
+
+       if (Fref >= 48000)
+               fll_div->fll_ref_freq = 0;
+       else
+               fll_div->fll_ref_freq = 1;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 2;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("FLL Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       fratio = fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       fll_div->n = target / (fratio * Fref);
+
+       if (target % Fref == 0) {
+               fll_div->theta = 0;
+               fll_div->lambda = 0;
+       } else {
+               gcd_fll = gcd(target, fratio * Fref);
+
+               fll_div->theta = (target - (fll_div->n * fratio * Fref))
+                       / gcd_fll;
+               fll_div->lambda = (fratio * Fref) / gcd_fll;
+       }
+
+       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+                fll_div->n, fll_div->theta, fll_div->lambda);
+       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_refclk_div);
+
+       return 0;
+}
+
+static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct _fll_div fll_div;
+       unsigned long timeout;
+       int ret, reg;
+
+       /* Any change? */
+       if (source == wm8996->fll_src && Fref == wm8996->fll_fref &&
+           Fout == wm8996->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8996->fll_fref = 0;
+               wm8996->fll_fout = 0;
+
+               snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+                                   WM8996_FLL_ENA, 0);
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       switch (source) {
+       case WM8996_FLL_MCLK1:
+               reg = 0;
+               break;
+       case WM8996_FLL_MCLK2:
+               reg = 1;
+               break;
+       case WM8996_FLL_DACLRCLK1:
+               reg = 2;
+               break;
+       case WM8996_FLL_BCLK1:
+               reg = 3;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+               return -EINVAL;
+       }
+
+       reg |= fll_div.fll_refclk_div << WM8996_FLL_REFCLK_DIV_SHIFT;
+       reg |= fll_div.fll_ref_freq << WM8996_FLL_REF_FREQ_SHIFT;
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_5,
+                           WM8996_FLL_REFCLK_DIV_MASK | WM8996_FLL_REF_FREQ |
+                           WM8996_FLL_REFCLK_SRC_MASK, reg);
+
+       reg = 0;
+       if (fll_div.theta || fll_div.lambda)
+               reg |= WM8996_FLL_EFS_ENA | (3 << WM8996_FLL_LFSR_SEL_SHIFT);
+       else
+               reg |= 1 << WM8996_FLL_LFSR_SEL_SHIFT;
+       snd_soc_write(codec, WM8996_FLL_EFS_2, reg);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_2,
+                           WM8996_FLL_OUTDIV_MASK |
+                           WM8996_FLL_FRATIO_MASK,
+                           (fll_div.fll_outdiv << WM8996_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_fratio));
+
+       snd_soc_write(codec, WM8996_FLL_CONTROL_3, fll_div.theta);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_4,
+                           WM8996_FLL_N_MASK | WM8996_FLL_LOOP_GAIN_MASK,
+                           (fll_div.n << WM8996_FLL_N_SHIFT) |
+                           fll_div.fll_loop_gain);
+
+       snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+
+       snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
+                           WM8996_FLL_ENA, WM8996_FLL_ENA);
+
+       /* The FLL supports live reconfiguration - kick that in case we were
+        * already enabled.
+        */
+       snd_soc_write(codec, WM8996_FLL_CONTROL_6, WM8996_FLL_SWITCH_CLK);
+
+       /* Wait for the FLL to lock, using the interrupt if possible */
+       if (Fref > 1000000)
+               timeout = usecs_to_jiffies(300);
+       else
+               timeout = msecs_to_jiffies(2);
+
+       /* Allow substantially longer if we've actually got the IRQ */
+       if (i2c->irq)
+               timeout *= 1000;
+
+       ret = wait_for_completion_timeout(&wm8996->fll_lock, timeout);
+
+       if (ret == 0 && i2c->irq) {
+               dev_err(codec->dev, "Timed out waiting for FLL\n");
+               ret = -ETIMEDOUT;
+       } else {
+               ret = 0;
+       }
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8996->fll_fref = Fref;
+       wm8996->fll_fout = Fout;
+       wm8996->fll_src = source;
+
+       return ret;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8996_priv *gpio_to_wm8996(struct gpio_chip *chip)
+{
+       return container_of(chip, struct wm8996_priv, gpio_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);
+}
+
+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);
+}
+
+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;
+       int ret;
+
+       ret = snd_soc_read(codec, WM8996_GPIO_1 + offset);
+       if (ret < 0)
+               return ret;
+
+       return (ret & 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));
+}
+
+static struct gpio_chip wm8996_template_chip = {
+       .label                  = "wm8996",
+       .owner                  = THIS_MODULE,
+       .direction_output       = wm8996_gpio_direction_out,
+       .set                    = wm8996_gpio_set,
+       .direction_input        = wm8996_gpio_direction_in,
+       .get                    = wm8996_gpio_get,
+       .can_sleep              = 1,
+};
+
+static void wm8996_init_gpio(struct snd_soc_codec *codec)
+{
+       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;
+
+       if (wm8996->pdata.gpio_base)
+               wm8996->gpio_chip.base = wm8996->pdata.gpio_base;
+       else
+               wm8996->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&wm8996->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8996_free_gpio(struct snd_soc_codec *codec)
+{
+       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);
+}
+#else
+static void wm8996_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8996_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+/**
+ * wm8996_detect - Enable default WM8996 jack detection
+ *
+ * The WM8996 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8996_polarity_fn polarity_cb)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+
+       wm8996->jack = jack;
+       wm8996->detecting = true;
+       wm8996->polarity_cb = polarity_cb;
+
+       if (wm8996->polarity_cb)
+               wm8996->polarity_cb(codec, 0);
+
+       /* Clear discarge to avoid noise during detection */
+       snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+                           WM8996_MICB1_DISCH, 0);
+       snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+                           WM8996_MICB2_DISCH, 0);
+
+       /* LDO2 powers the microphones, SYSCLK clocks detection */
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+
+       /* We start off just enabling microphone detection - even a
+        * plain headphone will trigger detection.
+        */
+       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                           WM8996_MICD_ENA, WM8996_MICD_ENA);
+
+       /* Slowest detection rate, gives debounce for initial detection */
+       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                           WM8996_MICD_RATE_MASK,
+                           WM8996_MICD_RATE_MASK);
+
+       /* Enable interrupts and we're off */
+       snd_soc_update_bits(codec, WM8996_INTERRUPT_STATUS_2_MASK,
+                           WM8996_IM_MICD_EINT, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8996_detect);
+
+static void wm8996_micd(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int val, reg;
+
+       val = snd_soc_read(codec, WM8996_MIC_DETECT_3);
+
+       dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+       if (!(val & WM8996_MICD_VALID)) {
+               dev_warn(codec->dev, "Microphone detection state invalid\n");
+               return;
+       }
+
+       /* No accessory, reset everything and report removal */
+       if (!(val & WM8996_MICD_STS)) {
+               dev_dbg(codec->dev, "Jack removal detected\n");
+               wm8996->jack_mic = false;
+               wm8996->detecting = true;
+               snd_soc_jack_report(wm8996->jack, 0,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                                   WM8996_MICD_RATE_MASK,
+                                   WM8996_MICD_RATE_MASK);
+               return;
+       }
+
+       /* If the measurement is very high we've got a microphone but
+        * do a little debounce to account for mechanical issues.
+        */
+       if (val & 0x400) {
+               dev_dbg(codec->dev, "Microphone detected\n");
+               snd_soc_jack_report(wm8996->jack, SND_JACK_HEADSET,
+                                   SND_JACK_HEADSET | SND_JACK_BTN_0);
+               wm8996->jack_mic = true;
+               wm8996->detecting = false;
+
+               /* 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);
+       }
+
+       /* If we detected a lower impedence during initial startup
+        * then we probably have the wrong polarity, flip it.  Don't
+        * do this for the lowest impedences to speed up detection of
+        * plain headphones.
+        */
+       if (wm8996->detecting && (val & 0x3f0)) {
+               reg = snd_soc_read(codec, WM8996_ACCESSORY_DETECT_MODE_2);
+               reg ^= WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+                       WM8996_MICD_BIAS_SRC;
+               snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
+                                   WM8996_HPOUT1FB_SRC | WM8996_MICD_SRC |
+                                   WM8996_MICD_BIAS_SRC, reg);
+
+               if (wm8996->polarity_cb)
+                       wm8996->polarity_cb(codec,
+                                           (reg & WM8996_MICD_SRC) != 0);
+
+               dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+                       (reg & WM8996_MICD_SRC) != 0);
+
+               return;
+       }
+
+       /* Don't distinguish between buttons, just report any low
+        * impedence as BTN_0.
+        */
+       if (val & 0x3fc) {
+               if (wm8996->jack_mic) {
+                       dev_dbg(codec->dev, "Mic button detected\n");
+                       snd_soc_jack_report(wm8996->jack,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0,
+                                           SND_JACK_HEADSET | SND_JACK_BTN_0);
+               } else {
+                       dev_dbg(codec->dev, "Headphone detected\n");
+                       snd_soc_jack_report(wm8996->jack,
+                                           SND_JACK_HEADPHONE,
+                                           SND_JACK_HEADSET |
+                                           SND_JACK_BTN_0);
+
+                       /* Increase the detection rate a bit for
+                        * responsiveness.
+                        */
+                       snd_soc_update_bits(codec, WM8996_MIC_DETECT_1,
+                                           WM8996_MICD_RATE_MASK,
+                                           7 << WM8996_MICD_RATE_SHIFT);
+
+                       wm8996->detecting = false;
+               }
+       }
+}
+
+static irqreturn_t wm8996_irq(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       int irq_val;
+
+       irq_val = snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2);
+       if (irq_val < 0) {
+               dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+                       irq_val);
+               return IRQ_NONE;
+       }
+       irq_val &= ~snd_soc_read(codec, WM8996_INTERRUPT_STATUS_2_MASK);
+
+       snd_soc_write(codec, WM8996_INTERRUPT_STATUS_2, irq_val);
+
+       if (irq_val & (WM8996_DCS_DONE_01_EINT | WM8996_DCS_DONE_23_EINT)) {
+               dev_dbg(codec->dev, "DC servo IRQ\n");
+               complete(&wm8996->dcs_done);
+       }
+
+       if (irq_val & WM8996_FIFOS_ERR_EINT)
+               dev_err(codec->dev, "Digital core FIFO error\n");
+
+       if (irq_val & WM8996_FLL_LOCK_EINT) {
+               dev_dbg(codec->dev, "FLL locked\n");
+               complete(&wm8996->fll_lock);
+       }
+
+       if (irq_val & WM8996_MICD_EINT)
+               wm8996_micd(codec);
+
+       if (irq_val)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static irqreturn_t wm8996_edge_irq(int irq, void *data)
+{
+       irqreturn_t ret = IRQ_NONE;
+       irqreturn_t val;
+
+       do {
+               val = wm8996_irq(irq, data);
+               if (val != IRQ_NONE)
+                       ret = val;
+       } while (val != IRQ_NONE);
+
+       return ret;
+}
+
+static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct wm8996_pdata *pdata = &wm8996->pdata;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("DSP1 EQ Mode",
+                            wm8996->retune_mobile_enum,
+                            wm8996_get_retune_mobile_enum,
+                            wm8996_put_retune_mobile_enum),
+               SOC_ENUM_EXT("DSP2 EQ Mode",
+                            wm8996->retune_mobile_enum,
+                            wm8996_get_retune_mobile_enum,
+                            wm8996_put_retune_mobile_enum),
+       };
+       int ret, i, j;
+       const char **t;
+
+       /* We need an array of texts for the enum API but the number
+        * of texts is likely to be less than the number of
+        * configurations due to the sample rate dependency of the
+        * configurations. */
+       wm8996->num_retune_mobile_texts = 0;
+       wm8996->retune_mobile_texts = NULL;
+       for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+               for (j = 0; j < wm8996->num_retune_mobile_texts; j++) {
+                       if (strcmp(pdata->retune_mobile_cfgs[i].name,
+                                  wm8996->retune_mobile_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != wm8996->num_retune_mobile_texts)
+                       continue;
+
+               /* Expand the array... */
+               t = krealloc(wm8996->retune_mobile_texts,
+                            sizeof(char *) * 
+                            (wm8996->num_retune_mobile_texts + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* ...store the new entry... */
+               t[wm8996->num_retune_mobile_texts] = 
+                       pdata->retune_mobile_cfgs[i].name;
+
+               /* ...and remember the new version. */
+               wm8996->num_retune_mobile_texts++;
+               wm8996->retune_mobile_texts = t;
+       }
+
+       dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+               wm8996->num_retune_mobile_texts);
+
+       wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts;
+       wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev,
+                       "Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static int wm8996_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int i, irq_flags;
+
+       wm8996->codec = codec;
+
+       init_completion(&wm8996->dcs_done);
+       init_completion(&wm8996->fll_lock);
+
+       dapm->idle_bias_off = true;
+       dapm->bias_level = SND_SOC_BIAS_OFF;
+
+       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];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8996->supplies),
+                                wm8996->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
+       wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
+       wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
+       wm8996->disable_nb[3].notifier_call = wm8996_regulator_event_3;
+
+       /* 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,
+                                                 &wm8996->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       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_get;
+       }
+
+       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;
+
+       /* Apply platform data settings */
+       snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL,
+                           WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK,
+                           wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT |
+                           wm8996->pdata.inr_mode);
+
+       for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) {
+               if (!wm8996->pdata.gpio_default[i])
+                       continue;
+
+               snd_soc_write(codec, WM8996_GPIO_1 + i,
+                             wm8996->pdata.gpio_default[i] & 0xffff);
+       }
+
+       if (wm8996->pdata.spkmute_seq)
+               snd_soc_update_bits(codec, WM8996_PDM_SPEAKER_MUTE_SEQUENCE,
+                                   WM8996_SPK_MUTE_ENDIAN |
+                                   WM8996_SPK_MUTE_SEQ1_MASK,
+                                   wm8996->pdata.spkmute_seq);
+
+       snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2,
+                           WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC |
+                           WM8996_MICD_SRC, wm8996->pdata.micdet_def);
+
+       /* Latch volume update bits */
+       snd_soc_update_bits(codec, WM8996_LEFT_LINE_INPUT_VOLUME,
+                           WM8996_IN1_VU, WM8996_IN1_VU);
+       snd_soc_update_bits(codec, WM8996_RIGHT_LINE_INPUT_VOLUME,
+                           WM8996_IN1_VU, WM8996_IN1_VU);
+
+       snd_soc_update_bits(codec, WM8996_DAC1_LEFT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_DAC1_RIGHT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_DAC2_LEFT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+       snd_soc_update_bits(codec, WM8996_DAC2_RIGHT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8996_OUTPUT1_LEFT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT1_RIGHT_VOLUME,
+                           WM8996_DAC1_VU, WM8996_DAC1_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT2_LEFT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+       snd_soc_update_bits(codec, WM8996_OUTPUT2_RIGHT_VOLUME,
+                           WM8996_DAC2_VU, WM8996_DAC2_VU);
+
+       snd_soc_update_bits(codec, WM8996_DSP1_TX_LEFT_VOLUME,
+                           WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP1_TX_RIGHT_VOLUME,
+                           WM8996_DSP1TX_VU, WM8996_DSP1TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_TX_LEFT_VOLUME,
+                           WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_TX_RIGHT_VOLUME,
+                           WM8996_DSP2TX_VU, WM8996_DSP2TX_VU);
+
+       snd_soc_update_bits(codec, WM8996_DSP1_RX_LEFT_VOLUME,
+                           WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP1_RX_RIGHT_VOLUME,
+                           WM8996_DSP1RX_VU, WM8996_DSP1RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_RX_LEFT_VOLUME,
+                           WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+       snd_soc_update_bits(codec, WM8996_DSP2_RX_RIGHT_VOLUME,
+                           WM8996_DSP2RX_VU, WM8996_DSP2RX_VU);
+
+       /* No support currently for the underclocked TDM modes and
+        * pick a default TDM layout with each channel pair working with
+        * slots 0 and 1. */
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_2_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN2_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN2_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_3_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN3_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_4_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN4_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_5_CONFIGURATION,
+                           WM8996_AIF1RX_CHAN5_SLOTS_MASK |
+                           WM8996_AIF1RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF2RX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF2RX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF2RX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF2RX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_2_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN2_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_3_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN3_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_4_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN4_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_5_CONFIGURATION,
+                           WM8996_AIF1TX_CHAN5_SLOTS_MASK |
+                           WM8996_AIF1TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+       snd_soc_update_bits(codec, WM8996_AIF2TX_CHANNEL_0_CONFIGURATION,
+                           WM8996_AIF2TX_CHAN0_SLOTS_MASK |
+                           WM8996_AIF2TX_CHAN0_START_SLOT_MASK,
+                           1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+       snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION,
+                           WM8996_AIF2TX_CHAN1_SLOTS_MASK |
+                           WM8996_AIF2TX_CHAN1_START_SLOT_MASK,
+                           1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+       if (wm8996->pdata.num_retune_mobile_cfgs)
+               wm8996_retune_mobile_pdata(codec);
+       else
+               snd_soc_add_controls(codec, wm8996_eq_controls,
+                                    ARRAY_SIZE(wm8996_eq_controls));
+
+       /* If the TX LRCLK pins are not in LRCLK mode configure the
+        * AIFs to source their clocks from the RX LRCLKs.
+        */
+       if ((snd_soc_read(codec, WM8996_GPIO_1)))
+               snd_soc_update_bits(codec, WM8996_AIF1_TX_LRCLK_2,
+                                   WM8996_AIF1TX_LRCLK_MODE,
+                                   WM8996_AIF1TX_LRCLK_MODE);
+
+       if ((snd_soc_read(codec, WM8996_GPIO_2)))
+               snd_soc_update_bits(codec, WM8996_AIF2_TX_LRCLK_2,
+                                   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;
+               else
+                       irq_flags = IRQF_TRIGGER_LOW;
+
+               irq_flags |= IRQF_ONESHOT;
+
+               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+                       ret = request_threaded_irq(i2c->irq, NULL,
+                                                  wm8996_edge_irq,
+                                                  irq_flags, "wm8996", codec);
+               else
+                       ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq,
+                                                  irq_flags, "wm8996", codec);
+
+               if (ret == 0) {
+                       /* Unmask the interrupt */
+                       snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+                                           WM8996_IM_IRQ, 0);
+
+                       /* Enable error reporting and DC servo status */
+                       snd_soc_update_bits(codec,
+                                           WM8996_INTERRUPT_STATUS_2_MASK,
+                                           WM8996_IM_DCS_DONE_23_EINT |
+                                           WM8996_IM_DCS_DONE_01_EINT |
+                                           WM8996_IM_FLL_LOCK_EINT |
+                                           WM8996_IM_FIFOS_ERR_EINT,
+                                           0);
+               } else {
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
+                               ret);
+               }
+       }
+
+       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_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+err:
+       return ret;
+}
+
+static int wm8996_remove(struct snd_soc_codec *codec)
+{
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = to_i2c_client(codec->dev);
+       int i;
+
+       snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL,
+                           WM8996_IM_IRQ, WM8996_IM_IRQ);
+
+       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]);
+       regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
+
+       return 0;
+}
+
+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,
+       .num_dapm_widgets = ARRAY_SIZE(wm8996_dapm_widgets),
+       .dapm_routes = wm8996_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8996_dapm_routes),
+       .set_pll = wm8996_set_fll,
+};
+
+#define WM8996_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define WM8996_FORMATS (SNDRV_PCM_FMTBIT_S8 | 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 wm8996_dai_ops = {
+       .set_fmt = wm8996_set_fmt,
+       .hw_params = wm8996_hw_params,
+       .set_sysclk = wm8996_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8996_dai[] = {
+       {
+               .name = "wm8996-aif1",
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rates = WM8996_RATES,
+                       .formats = WM8996_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 6,
+                        .rates = WM8996_RATES,
+                        .formats = WM8996_FORMATS,
+                },
+               .ops = &wm8996_dai_ops,
+       },
+       {
+               .name = "wm8996-aif2",
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8996_RATES,
+                       .formats = WM8996_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8996_RATES,
+                        .formats = WM8996_FORMATS,
+                },
+               .ops = &wm8996_dai_ops,
+       },
+};
+
+static __devinit int wm8996_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8996_priv *wm8996;
+       int ret;
+
+       wm8996 = kzalloc(sizeof(struct wm8996_priv), GFP_KERNEL);
+       if (wm8996 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8996);
+
+       if (dev_get_platdata(&i2c->dev))
+               memcpy(&wm8996->pdata, dev_get_platdata(&i2c->dev),
+                      sizeof(wm8996->pdata));
+
+       if (wm8996->pdata.ldo_ena > 0) {
+               ret = gpio_request_one(wm8996->pdata.ldo_ena,
+                                      GPIOF_OUT_INIT_LOW, "WM8996 ENA");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+                               wm8996->pdata.ldo_ena, ret);
+                       goto err;
+               }
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8996, wm8996_dai,
+                                    ARRAY_SIZE(wm8996_dai));
+       if (ret < 0)
+               goto err_gpio;
+
+       return ret;
+
+err_gpio:
+       if (wm8996->pdata.ldo_ena > 0)
+               gpio_free(wm8996->pdata.ldo_ena);
+err:
+       kfree(wm8996);
+
+       return ret;
+}
+
+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)
+               gpio_free(wm8996->pdata.ldo_ena);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8996_i2c_id[] = {
+       { "wm8996", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id);
+
+static struct i2c_driver wm8996_i2c_driver = {
+       .driver = {
+               .name = "wm8996",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8996_i2c_probe,
+       .remove =   __devexit_p(wm8996_i2c_remove),
+       .id_table = wm8996_i2c_id,
+};
+
+static int __init wm8996_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&wm8996_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8996 I2C driver: %d\n",
+                      ret);
+       }
+
+       return ret;
+}
+module_init(wm8996_modinit);
+
+static void __exit wm8996_exit(void)
+{
+       i2c_del_driver(&wm8996_i2c_driver);
+}
+module_exit(wm8996_exit);
+
+MODULE_DESCRIPTION("ASoC WM8996 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8996.h b/sound/soc/codecs/wm8996.h
new file mode 100644 (file)
index 0000000..0fde643
--- /dev/null
@@ -0,0 +1,3717 @@
+/*
+ * wm8996.h - WM8996 audio codec interface
+ *
+ * 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 _WM8996_H
+#define _WM8996_H
+
+#define WM8996_SYSCLK_MCLK1 1
+#define WM8996_SYSCLK_MCLK2 2
+#define WM8996_SYSCLK_FLL   3
+
+#define WM8996_FLL_MCLK1      1
+#define WM8996_FLL_MCLK2      2
+#define WM8996_FLL_DACLRCLK1  3
+#define WM8996_FLL_BCLK1      4
+
+typedef void (*wm8996_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+
+int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                 wm8996_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8996_SOFTWARE_RESET                   0x00
+#define WM8996_POWER_MANAGEMENT_1               0x01
+#define WM8996_POWER_MANAGEMENT_2               0x02
+#define WM8996_POWER_MANAGEMENT_3               0x03
+#define WM8996_POWER_MANAGEMENT_4               0x04
+#define WM8996_POWER_MANAGEMENT_5               0x05
+#define WM8996_POWER_MANAGEMENT_6               0x06
+#define WM8996_POWER_MANAGEMENT_7               0x07
+#define WM8996_POWER_MANAGEMENT_8               0x08
+#define WM8996_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8996_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8996_LINE_INPUT_CONTROL               0x12
+#define WM8996_DAC1_HPOUT1_VOLUME               0x15
+#define WM8996_DAC2_HPOUT2_VOLUME               0x16
+#define WM8996_DAC1_LEFT_VOLUME                 0x18
+#define WM8996_DAC1_RIGHT_VOLUME                0x19
+#define WM8996_DAC2_LEFT_VOLUME                 0x1A
+#define WM8996_DAC2_RIGHT_VOLUME                0x1B
+#define WM8996_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8996_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8996_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8996_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8996_MICBIAS_1                        0x20
+#define WM8996_MICBIAS_2                        0x21
+#define WM8996_LDO_1                            0x28
+#define WM8996_LDO_2                            0x29
+#define WM8996_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8996_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8996_HEADPHONE_DETECT_1               0x34
+#define WM8996_HEADPHONE_DETECT_2               0x35
+#define WM8996_MIC_DETECT_1                     0x38
+#define WM8996_MIC_DETECT_2                     0x39
+#define WM8996_MIC_DETECT_3                     0x3A
+#define WM8996_CHARGE_PUMP_1                    0x40
+#define WM8996_CHARGE_PUMP_2                    0x41
+#define WM8996_DC_SERVO_1                       0x50
+#define WM8996_DC_SERVO_2                       0x51
+#define WM8996_DC_SERVO_3                       0x52
+#define WM8996_DC_SERVO_5                       0x54
+#define WM8996_DC_SERVO_6                       0x55
+#define WM8996_DC_SERVO_7                       0x56
+#define WM8996_DC_SERVO_READBACK_0              0x57
+#define WM8996_ANALOGUE_HP_1                    0x60
+#define WM8996_ANALOGUE_HP_2                    0x61
+#define WM8996_CHIP_REVISION                    0x100
+#define WM8996_CONTROL_INTERFACE_1              0x101
+#define WM8996_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8996_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8996_AIF_CLOCKING_1                   0x200
+#define WM8996_AIF_CLOCKING_2                   0x201
+#define WM8996_CLOCKING_1                       0x208
+#define WM8996_CLOCKING_2                       0x209
+#define WM8996_AIF_RATE                         0x210
+#define WM8996_FLL_CONTROL_1                    0x220
+#define WM8996_FLL_CONTROL_2                    0x221
+#define WM8996_FLL_CONTROL_3                    0x222
+#define WM8996_FLL_CONTROL_4                    0x223
+#define WM8996_FLL_CONTROL_5                    0x224
+#define WM8996_FLL_CONTROL_6                    0x225
+#define WM8996_FLL_EFS_1                        0x226
+#define WM8996_FLL_EFS_2                        0x227
+#define WM8996_AIF1_CONTROL                     0x300
+#define WM8996_AIF1_BCLK                        0x301
+#define WM8996_AIF1_TX_LRCLK_1                  0x302
+#define WM8996_AIF1_TX_LRCLK_2                  0x303
+#define WM8996_AIF1_RX_LRCLK_1                  0x304
+#define WM8996_AIF1_RX_LRCLK_2                  0x305
+#define WM8996_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8996_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8996_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8996_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8996_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8996_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8996_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8996_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8996_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8996_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8996_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8996_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8996_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8996_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8996_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8996_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8996_AIF1TX_TEST                      0x31A
+#define WM8996_AIF2_CONTROL                     0x320
+#define WM8996_AIF2_BCLK                        0x321
+#define WM8996_AIF2_TX_LRCLK_1                  0x322
+#define WM8996_AIF2_TX_LRCLK_2                  0x323
+#define WM8996_AIF2_RX_LRCLK_1                  0x324
+#define WM8996_AIF2_RX_LRCLK_2                  0x325
+#define WM8996_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8996_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8996_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8996_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8996_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8996_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8996_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8996_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8996_AIF2TX_TEST                      0x32F
+#define WM8996_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8996_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8996_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8996_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8996_DSP1_TX_FILTERS                  0x410
+#define WM8996_DSP1_RX_FILTERS_1                0x420
+#define WM8996_DSP1_RX_FILTERS_2                0x421
+#define WM8996_DSP1_DRC_1                       0x440
+#define WM8996_DSP1_DRC_2                       0x441
+#define WM8996_DSP1_DRC_3                       0x442
+#define WM8996_DSP1_DRC_4                       0x443
+#define WM8996_DSP1_DRC_5                       0x444
+#define WM8996_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8996_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8996_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8996_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8996_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8996_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8996_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8996_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8996_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8996_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8996_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8996_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8996_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8996_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8996_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8996_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8996_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8996_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8996_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8996_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8996_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8996_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8996_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8996_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8996_DSP2_TX_FILTERS                  0x510
+#define WM8996_DSP2_RX_FILTERS_1                0x520
+#define WM8996_DSP2_RX_FILTERS_2                0x521
+#define WM8996_DSP2_DRC_1                       0x540
+#define WM8996_DSP2_DRC_2                       0x541
+#define WM8996_DSP2_DRC_3                       0x542
+#define WM8996_DSP2_DRC_4                       0x543
+#define WM8996_DSP2_DRC_5                       0x544
+#define WM8996_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8996_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8996_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8996_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8996_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8996_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8996_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8996_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8996_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8996_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8996_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8996_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8996_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8996_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8996_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8996_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8996_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8996_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8996_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8996_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8996_DAC1_MIXER_VOLUMES               0x600
+#define WM8996_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8996_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8996_DAC2_MIXER_VOLUMES               0x603
+#define WM8996_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8996_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8996_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8996_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8996_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8996_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8996_DSP_TX_MIXER_SELECT              0x60A
+#define WM8996_DAC_SOFTMUTE                     0x610
+#define WM8996_OVERSAMPLING                     0x620
+#define WM8996_SIDETONE                         0x621
+#define WM8996_GPIO_1                           0x700
+#define WM8996_GPIO_2                           0x701
+#define WM8996_GPIO_3                           0x702
+#define WM8996_GPIO_4                           0x703
+#define WM8996_GPIO_5                           0x704
+#define WM8996_PULL_CONTROL_1                   0x720
+#define WM8996_PULL_CONTROL_2                   0x721
+#define WM8996_INTERRUPT_STATUS_1               0x730
+#define WM8996_INTERRUPT_STATUS_2               0x731
+#define WM8996_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8996_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8996_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8996_INTERRUPT_CONTROL                0x740
+#define WM8996_LEFT_PDM_SPEAKER                 0x800
+#define WM8996_RIGHT_PDM_SPEAKER                0x801
+#define WM8996_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8996_PDM_SPEAKER_VOLUME               0x803
+#define WM8996_WRITE_SEQUENCER_0                0x3000
+#define WM8996_WRITE_SEQUENCER_1                0x3001
+#define WM8996_WRITE_SEQUENCER_2                0x3002
+#define WM8996_WRITE_SEQUENCER_3                0x3003
+#define WM8996_WRITE_SEQUENCER_4                0x3004
+#define WM8996_WRITE_SEQUENCER_5                0x3005
+#define WM8996_WRITE_SEQUENCER_6                0x3006
+#define WM8996_WRITE_SEQUENCER_7                0x3007
+#define WM8996_WRITE_SEQUENCER_8                0x3008
+#define WM8996_WRITE_SEQUENCER_9                0x3009
+#define WM8996_WRITE_SEQUENCER_10               0x300A
+#define WM8996_WRITE_SEQUENCER_11               0x300B
+#define WM8996_WRITE_SEQUENCER_12               0x300C
+#define WM8996_WRITE_SEQUENCER_13               0x300D
+#define WM8996_WRITE_SEQUENCER_14               0x300E
+#define WM8996_WRITE_SEQUENCER_15               0x300F
+#define WM8996_WRITE_SEQUENCER_16               0x3010
+#define WM8996_WRITE_SEQUENCER_17               0x3011
+#define WM8996_WRITE_SEQUENCER_18               0x3012
+#define WM8996_WRITE_SEQUENCER_19               0x3013
+#define WM8996_WRITE_SEQUENCER_20               0x3014
+#define WM8996_WRITE_SEQUENCER_21               0x3015
+#define WM8996_WRITE_SEQUENCER_22               0x3016
+#define WM8996_WRITE_SEQUENCER_23               0x3017
+#define WM8996_WRITE_SEQUENCER_24               0x3018
+#define WM8996_WRITE_SEQUENCER_25               0x3019
+#define WM8996_WRITE_SEQUENCER_26               0x301A
+#define WM8996_WRITE_SEQUENCER_27               0x301B
+#define WM8996_WRITE_SEQUENCER_28               0x301C
+#define WM8996_WRITE_SEQUENCER_29               0x301D
+#define WM8996_WRITE_SEQUENCER_30               0x301E
+#define WM8996_WRITE_SEQUENCER_31               0x301F
+#define WM8996_WRITE_SEQUENCER_32               0x3020
+#define WM8996_WRITE_SEQUENCER_33               0x3021
+#define WM8996_WRITE_SEQUENCER_34               0x3022
+#define WM8996_WRITE_SEQUENCER_35               0x3023
+#define WM8996_WRITE_SEQUENCER_36               0x3024
+#define WM8996_WRITE_SEQUENCER_37               0x3025
+#define WM8996_WRITE_SEQUENCER_38               0x3026
+#define WM8996_WRITE_SEQUENCER_39               0x3027
+#define WM8996_WRITE_SEQUENCER_40               0x3028
+#define WM8996_WRITE_SEQUENCER_41               0x3029
+#define WM8996_WRITE_SEQUENCER_42               0x302A
+#define WM8996_WRITE_SEQUENCER_43               0x302B
+#define WM8996_WRITE_SEQUENCER_44               0x302C
+#define WM8996_WRITE_SEQUENCER_45               0x302D
+#define WM8996_WRITE_SEQUENCER_46               0x302E
+#define WM8996_WRITE_SEQUENCER_47               0x302F
+#define WM8996_WRITE_SEQUENCER_48               0x3030
+#define WM8996_WRITE_SEQUENCER_49               0x3031
+#define WM8996_WRITE_SEQUENCER_50               0x3032
+#define WM8996_WRITE_SEQUENCER_51               0x3033
+#define WM8996_WRITE_SEQUENCER_52               0x3034
+#define WM8996_WRITE_SEQUENCER_53               0x3035
+#define WM8996_WRITE_SEQUENCER_54               0x3036
+#define WM8996_WRITE_SEQUENCER_55               0x3037
+#define WM8996_WRITE_SEQUENCER_56               0x3038
+#define WM8996_WRITE_SEQUENCER_57               0x3039
+#define WM8996_WRITE_SEQUENCER_58               0x303A
+#define WM8996_WRITE_SEQUENCER_59               0x303B
+#define WM8996_WRITE_SEQUENCER_60               0x303C
+#define WM8996_WRITE_SEQUENCER_61               0x303D
+#define WM8996_WRITE_SEQUENCER_62               0x303E
+#define WM8996_WRITE_SEQUENCER_63               0x303F
+#define WM8996_WRITE_SEQUENCER_64               0x3040
+#define WM8996_WRITE_SEQUENCER_65               0x3041
+#define WM8996_WRITE_SEQUENCER_66               0x3042
+#define WM8996_WRITE_SEQUENCER_67               0x3043
+#define WM8996_WRITE_SEQUENCER_68               0x3044
+#define WM8996_WRITE_SEQUENCER_69               0x3045
+#define WM8996_WRITE_SEQUENCER_70               0x3046
+#define WM8996_WRITE_SEQUENCER_71               0x3047
+#define WM8996_WRITE_SEQUENCER_72               0x3048
+#define WM8996_WRITE_SEQUENCER_73               0x3049
+#define WM8996_WRITE_SEQUENCER_74               0x304A
+#define WM8996_WRITE_SEQUENCER_75               0x304B
+#define WM8996_WRITE_SEQUENCER_76               0x304C
+#define WM8996_WRITE_SEQUENCER_77               0x304D
+#define WM8996_WRITE_SEQUENCER_78               0x304E
+#define WM8996_WRITE_SEQUENCER_79               0x304F
+#define WM8996_WRITE_SEQUENCER_80               0x3050
+#define WM8996_WRITE_SEQUENCER_81               0x3051
+#define WM8996_WRITE_SEQUENCER_82               0x3052
+#define WM8996_WRITE_SEQUENCER_83               0x3053
+#define WM8996_WRITE_SEQUENCER_84               0x3054
+#define WM8996_WRITE_SEQUENCER_85               0x3055
+#define WM8996_WRITE_SEQUENCER_86               0x3056
+#define WM8996_WRITE_SEQUENCER_87               0x3057
+#define WM8996_WRITE_SEQUENCER_88               0x3058
+#define WM8996_WRITE_SEQUENCER_89               0x3059
+#define WM8996_WRITE_SEQUENCER_90               0x305A
+#define WM8996_WRITE_SEQUENCER_91               0x305B
+#define WM8996_WRITE_SEQUENCER_92               0x305C
+#define WM8996_WRITE_SEQUENCER_93               0x305D
+#define WM8996_WRITE_SEQUENCER_94               0x305E
+#define WM8996_WRITE_SEQUENCER_95               0x305F
+#define WM8996_WRITE_SEQUENCER_96               0x3060
+#define WM8996_WRITE_SEQUENCER_97               0x3061
+#define WM8996_WRITE_SEQUENCER_98               0x3062
+#define WM8996_WRITE_SEQUENCER_99               0x3063
+#define WM8996_WRITE_SEQUENCER_100              0x3064
+#define WM8996_WRITE_SEQUENCER_101              0x3065
+#define WM8996_WRITE_SEQUENCER_102              0x3066
+#define WM8996_WRITE_SEQUENCER_103              0x3067
+#define WM8996_WRITE_SEQUENCER_104              0x3068
+#define WM8996_WRITE_SEQUENCER_105              0x3069
+#define WM8996_WRITE_SEQUENCER_106              0x306A
+#define WM8996_WRITE_SEQUENCER_107              0x306B
+#define WM8996_WRITE_SEQUENCER_108              0x306C
+#define WM8996_WRITE_SEQUENCER_109              0x306D
+#define WM8996_WRITE_SEQUENCER_110              0x306E
+#define WM8996_WRITE_SEQUENCER_111              0x306F
+#define WM8996_WRITE_SEQUENCER_112              0x3070
+#define WM8996_WRITE_SEQUENCER_113              0x3071
+#define WM8996_WRITE_SEQUENCER_114              0x3072
+#define WM8996_WRITE_SEQUENCER_115              0x3073
+#define WM8996_WRITE_SEQUENCER_116              0x3074
+#define WM8996_WRITE_SEQUENCER_117              0x3075
+#define WM8996_WRITE_SEQUENCER_118              0x3076
+#define WM8996_WRITE_SEQUENCER_119              0x3077
+#define WM8996_WRITE_SEQUENCER_120              0x3078
+#define WM8996_WRITE_SEQUENCER_121              0x3079
+#define WM8996_WRITE_SEQUENCER_122              0x307A
+#define WM8996_WRITE_SEQUENCER_123              0x307B
+#define WM8996_WRITE_SEQUENCER_124              0x307C
+#define WM8996_WRITE_SEQUENCER_125              0x307D
+#define WM8996_WRITE_SEQUENCER_126              0x307E
+#define WM8996_WRITE_SEQUENCER_127              0x307F
+#define WM8996_WRITE_SEQUENCER_128              0x3080
+#define WM8996_WRITE_SEQUENCER_129              0x3081
+#define WM8996_WRITE_SEQUENCER_130              0x3082
+#define WM8996_WRITE_SEQUENCER_131              0x3083
+#define WM8996_WRITE_SEQUENCER_132              0x3084
+#define WM8996_WRITE_SEQUENCER_133              0x3085
+#define WM8996_WRITE_SEQUENCER_134              0x3086
+#define WM8996_WRITE_SEQUENCER_135              0x3087
+#define WM8996_WRITE_SEQUENCER_136              0x3088
+#define WM8996_WRITE_SEQUENCER_137              0x3089
+#define WM8996_WRITE_SEQUENCER_138              0x308A
+#define WM8996_WRITE_SEQUENCER_139              0x308B
+#define WM8996_WRITE_SEQUENCER_140              0x308C
+#define WM8996_WRITE_SEQUENCER_141              0x308D
+#define WM8996_WRITE_SEQUENCER_142              0x308E
+#define WM8996_WRITE_SEQUENCER_143              0x308F
+#define WM8996_WRITE_SEQUENCER_144              0x3090
+#define WM8996_WRITE_SEQUENCER_145              0x3091
+#define WM8996_WRITE_SEQUENCER_146              0x3092
+#define WM8996_WRITE_SEQUENCER_147              0x3093
+#define WM8996_WRITE_SEQUENCER_148              0x3094
+#define WM8996_WRITE_SEQUENCER_149              0x3095
+#define WM8996_WRITE_SEQUENCER_150              0x3096
+#define WM8996_WRITE_SEQUENCER_151              0x3097
+#define WM8996_WRITE_SEQUENCER_152              0x3098
+#define WM8996_WRITE_SEQUENCER_153              0x3099
+#define WM8996_WRITE_SEQUENCER_154              0x309A
+#define WM8996_WRITE_SEQUENCER_155              0x309B
+#define WM8996_WRITE_SEQUENCER_156              0x309C
+#define WM8996_WRITE_SEQUENCER_157              0x309D
+#define WM8996_WRITE_SEQUENCER_158              0x309E
+#define WM8996_WRITE_SEQUENCER_159              0x309F
+#define WM8996_WRITE_SEQUENCER_160              0x30A0
+#define WM8996_WRITE_SEQUENCER_161              0x30A1
+#define WM8996_WRITE_SEQUENCER_162              0x30A2
+#define WM8996_WRITE_SEQUENCER_163              0x30A3
+#define WM8996_WRITE_SEQUENCER_164              0x30A4
+#define WM8996_WRITE_SEQUENCER_165              0x30A5
+#define WM8996_WRITE_SEQUENCER_166              0x30A6
+#define WM8996_WRITE_SEQUENCER_167              0x30A7
+#define WM8996_WRITE_SEQUENCER_168              0x30A8
+#define WM8996_WRITE_SEQUENCER_169              0x30A9
+#define WM8996_WRITE_SEQUENCER_170              0x30AA
+#define WM8996_WRITE_SEQUENCER_171              0x30AB
+#define WM8996_WRITE_SEQUENCER_172              0x30AC
+#define WM8996_WRITE_SEQUENCER_173              0x30AD
+#define WM8996_WRITE_SEQUENCER_174              0x30AE
+#define WM8996_WRITE_SEQUENCER_175              0x30AF
+#define WM8996_WRITE_SEQUENCER_176              0x30B0
+#define WM8996_WRITE_SEQUENCER_177              0x30B1
+#define WM8996_WRITE_SEQUENCER_178              0x30B2
+#define WM8996_WRITE_SEQUENCER_179              0x30B3
+#define WM8996_WRITE_SEQUENCER_180              0x30B4
+#define WM8996_WRITE_SEQUENCER_181              0x30B5
+#define WM8996_WRITE_SEQUENCER_182              0x30B6
+#define WM8996_WRITE_SEQUENCER_183              0x30B7
+#define WM8996_WRITE_SEQUENCER_184              0x30B8
+#define WM8996_WRITE_SEQUENCER_185              0x30B9
+#define WM8996_WRITE_SEQUENCER_186              0x30BA
+#define WM8996_WRITE_SEQUENCER_187              0x30BB
+#define WM8996_WRITE_SEQUENCER_188              0x30BC
+#define WM8996_WRITE_SEQUENCER_189              0x30BD
+#define WM8996_WRITE_SEQUENCER_190              0x30BE
+#define WM8996_WRITE_SEQUENCER_191              0x30BF
+#define WM8996_WRITE_SEQUENCER_192              0x30C0
+#define WM8996_WRITE_SEQUENCER_193              0x30C1
+#define WM8996_WRITE_SEQUENCER_194              0x30C2
+#define WM8996_WRITE_SEQUENCER_195              0x30C3
+#define WM8996_WRITE_SEQUENCER_196              0x30C4
+#define WM8996_WRITE_SEQUENCER_197              0x30C5
+#define WM8996_WRITE_SEQUENCER_198              0x30C6
+#define WM8996_WRITE_SEQUENCER_199              0x30C7
+#define WM8996_WRITE_SEQUENCER_200              0x30C8
+#define WM8996_WRITE_SEQUENCER_201              0x30C9
+#define WM8996_WRITE_SEQUENCER_202              0x30CA
+#define WM8996_WRITE_SEQUENCER_203              0x30CB
+#define WM8996_WRITE_SEQUENCER_204              0x30CC
+#define WM8996_WRITE_SEQUENCER_205              0x30CD
+#define WM8996_WRITE_SEQUENCER_206              0x30CE
+#define WM8996_WRITE_SEQUENCER_207              0x30CF
+#define WM8996_WRITE_SEQUENCER_208              0x30D0
+#define WM8996_WRITE_SEQUENCER_209              0x30D1
+#define WM8996_WRITE_SEQUENCER_210              0x30D2
+#define WM8996_WRITE_SEQUENCER_211              0x30D3
+#define WM8996_WRITE_SEQUENCER_212              0x30D4
+#define WM8996_WRITE_SEQUENCER_213              0x30D5
+#define WM8996_WRITE_SEQUENCER_214              0x30D6
+#define WM8996_WRITE_SEQUENCER_215              0x30D7
+#define WM8996_WRITE_SEQUENCER_216              0x30D8
+#define WM8996_WRITE_SEQUENCER_217              0x30D9
+#define WM8996_WRITE_SEQUENCER_218              0x30DA
+#define WM8996_WRITE_SEQUENCER_219              0x30DB
+#define WM8996_WRITE_SEQUENCER_220              0x30DC
+#define WM8996_WRITE_SEQUENCER_221              0x30DD
+#define WM8996_WRITE_SEQUENCER_222              0x30DE
+#define WM8996_WRITE_SEQUENCER_223              0x30DF
+#define WM8996_WRITE_SEQUENCER_224              0x30E0
+#define WM8996_WRITE_SEQUENCER_225              0x30E1
+#define WM8996_WRITE_SEQUENCER_226              0x30E2
+#define WM8996_WRITE_SEQUENCER_227              0x30E3
+#define WM8996_WRITE_SEQUENCER_228              0x30E4
+#define WM8996_WRITE_SEQUENCER_229              0x30E5
+#define WM8996_WRITE_SEQUENCER_230              0x30E6
+#define WM8996_WRITE_SEQUENCER_231              0x30E7
+#define WM8996_WRITE_SEQUENCER_232              0x30E8
+#define WM8996_WRITE_SEQUENCER_233              0x30E9
+#define WM8996_WRITE_SEQUENCER_234              0x30EA
+#define WM8996_WRITE_SEQUENCER_235              0x30EB
+#define WM8996_WRITE_SEQUENCER_236              0x30EC
+#define WM8996_WRITE_SEQUENCER_237              0x30ED
+#define WM8996_WRITE_SEQUENCER_238              0x30EE
+#define WM8996_WRITE_SEQUENCER_239              0x30EF
+#define WM8996_WRITE_SEQUENCER_240              0x30F0
+#define WM8996_WRITE_SEQUENCER_241              0x30F1
+#define WM8996_WRITE_SEQUENCER_242              0x30F2
+#define WM8996_WRITE_SEQUENCER_243              0x30F3
+#define WM8996_WRITE_SEQUENCER_244              0x30F4
+#define WM8996_WRITE_SEQUENCER_245              0x30F5
+#define WM8996_WRITE_SEQUENCER_246              0x30F6
+#define WM8996_WRITE_SEQUENCER_247              0x30F7
+#define WM8996_WRITE_SEQUENCER_248              0x30F8
+#define WM8996_WRITE_SEQUENCER_249              0x30F9
+#define WM8996_WRITE_SEQUENCER_250              0x30FA
+#define WM8996_WRITE_SEQUENCER_251              0x30FB
+#define WM8996_WRITE_SEQUENCER_252              0x30FC
+#define WM8996_WRITE_SEQUENCER_253              0x30FD
+#define WM8996_WRITE_SEQUENCER_254              0x30FE
+#define WM8996_WRITE_SEQUENCER_255              0x30FF
+#define WM8996_WRITE_SEQUENCER_256              0x3100
+#define WM8996_WRITE_SEQUENCER_257              0x3101
+#define WM8996_WRITE_SEQUENCER_258              0x3102
+#define WM8996_WRITE_SEQUENCER_259              0x3103
+#define WM8996_WRITE_SEQUENCER_260              0x3104
+#define WM8996_WRITE_SEQUENCER_261              0x3105
+#define WM8996_WRITE_SEQUENCER_262              0x3106
+#define WM8996_WRITE_SEQUENCER_263              0x3107
+#define WM8996_WRITE_SEQUENCER_264              0x3108
+#define WM8996_WRITE_SEQUENCER_265              0x3109
+#define WM8996_WRITE_SEQUENCER_266              0x310A
+#define WM8996_WRITE_SEQUENCER_267              0x310B
+#define WM8996_WRITE_SEQUENCER_268              0x310C
+#define WM8996_WRITE_SEQUENCER_269              0x310D
+#define WM8996_WRITE_SEQUENCER_270              0x310E
+#define WM8996_WRITE_SEQUENCER_271              0x310F
+#define WM8996_WRITE_SEQUENCER_272              0x3110
+#define WM8996_WRITE_SEQUENCER_273              0x3111
+#define WM8996_WRITE_SEQUENCER_274              0x3112
+#define WM8996_WRITE_SEQUENCER_275              0x3113
+#define WM8996_WRITE_SEQUENCER_276              0x3114
+#define WM8996_WRITE_SEQUENCER_277              0x3115
+#define WM8996_WRITE_SEQUENCER_278              0x3116
+#define WM8996_WRITE_SEQUENCER_279              0x3117
+#define WM8996_WRITE_SEQUENCER_280              0x3118
+#define WM8996_WRITE_SEQUENCER_281              0x3119
+#define WM8996_WRITE_SEQUENCER_282              0x311A
+#define WM8996_WRITE_SEQUENCER_283              0x311B
+#define WM8996_WRITE_SEQUENCER_284              0x311C
+#define WM8996_WRITE_SEQUENCER_285              0x311D
+#define WM8996_WRITE_SEQUENCER_286              0x311E
+#define WM8996_WRITE_SEQUENCER_287              0x311F
+#define WM8996_WRITE_SEQUENCER_288              0x3120
+#define WM8996_WRITE_SEQUENCER_289              0x3121
+#define WM8996_WRITE_SEQUENCER_290              0x3122
+#define WM8996_WRITE_SEQUENCER_291              0x3123
+#define WM8996_WRITE_SEQUENCER_292              0x3124
+#define WM8996_WRITE_SEQUENCER_293              0x3125
+#define WM8996_WRITE_SEQUENCER_294              0x3126
+#define WM8996_WRITE_SEQUENCER_295              0x3127
+#define WM8996_WRITE_SEQUENCER_296              0x3128
+#define WM8996_WRITE_SEQUENCER_297              0x3129
+#define WM8996_WRITE_SEQUENCER_298              0x312A
+#define WM8996_WRITE_SEQUENCER_299              0x312B
+#define WM8996_WRITE_SEQUENCER_300              0x312C
+#define WM8996_WRITE_SEQUENCER_301              0x312D
+#define WM8996_WRITE_SEQUENCER_302              0x312E
+#define WM8996_WRITE_SEQUENCER_303              0x312F
+#define WM8996_WRITE_SEQUENCER_304              0x3130
+#define WM8996_WRITE_SEQUENCER_305              0x3131
+#define WM8996_WRITE_SEQUENCER_306              0x3132
+#define WM8996_WRITE_SEQUENCER_307              0x3133
+#define WM8996_WRITE_SEQUENCER_308              0x3134
+#define WM8996_WRITE_SEQUENCER_309              0x3135
+#define WM8996_WRITE_SEQUENCER_310              0x3136
+#define WM8996_WRITE_SEQUENCER_311              0x3137
+#define WM8996_WRITE_SEQUENCER_312              0x3138
+#define WM8996_WRITE_SEQUENCER_313              0x3139
+#define WM8996_WRITE_SEQUENCER_314              0x313A
+#define WM8996_WRITE_SEQUENCER_315              0x313B
+#define WM8996_WRITE_SEQUENCER_316              0x313C
+#define WM8996_WRITE_SEQUENCER_317              0x313D
+#define WM8996_WRITE_SEQUENCER_318              0x313E
+#define WM8996_WRITE_SEQUENCER_319              0x313F
+#define WM8996_WRITE_SEQUENCER_320              0x3140
+#define WM8996_WRITE_SEQUENCER_321              0x3141
+#define WM8996_WRITE_SEQUENCER_322              0x3142
+#define WM8996_WRITE_SEQUENCER_323              0x3143
+#define WM8996_WRITE_SEQUENCER_324              0x3144
+#define WM8996_WRITE_SEQUENCER_325              0x3145
+#define WM8996_WRITE_SEQUENCER_326              0x3146
+#define WM8996_WRITE_SEQUENCER_327              0x3147
+#define WM8996_WRITE_SEQUENCER_328              0x3148
+#define WM8996_WRITE_SEQUENCER_329              0x3149
+#define WM8996_WRITE_SEQUENCER_330              0x314A
+#define WM8996_WRITE_SEQUENCER_331              0x314B
+#define WM8996_WRITE_SEQUENCER_332              0x314C
+#define WM8996_WRITE_SEQUENCER_333              0x314D
+#define WM8996_WRITE_SEQUENCER_334              0x314E
+#define WM8996_WRITE_SEQUENCER_335              0x314F
+#define WM8996_WRITE_SEQUENCER_336              0x3150
+#define WM8996_WRITE_SEQUENCER_337              0x3151
+#define WM8996_WRITE_SEQUENCER_338              0x3152
+#define WM8996_WRITE_SEQUENCER_339              0x3153
+#define WM8996_WRITE_SEQUENCER_340              0x3154
+#define WM8996_WRITE_SEQUENCER_341              0x3155
+#define WM8996_WRITE_SEQUENCER_342              0x3156
+#define WM8996_WRITE_SEQUENCER_343              0x3157
+#define WM8996_WRITE_SEQUENCER_344              0x3158
+#define WM8996_WRITE_SEQUENCER_345              0x3159
+#define WM8996_WRITE_SEQUENCER_346              0x315A
+#define WM8996_WRITE_SEQUENCER_347              0x315B
+#define WM8996_WRITE_SEQUENCER_348              0x315C
+#define WM8996_WRITE_SEQUENCER_349              0x315D
+#define WM8996_WRITE_SEQUENCER_350              0x315E
+#define WM8996_WRITE_SEQUENCER_351              0x315F
+#define WM8996_WRITE_SEQUENCER_352              0x3160
+#define WM8996_WRITE_SEQUENCER_353              0x3161
+#define WM8996_WRITE_SEQUENCER_354              0x3162
+#define WM8996_WRITE_SEQUENCER_355              0x3163
+#define WM8996_WRITE_SEQUENCER_356              0x3164
+#define WM8996_WRITE_SEQUENCER_357              0x3165
+#define WM8996_WRITE_SEQUENCER_358              0x3166
+#define WM8996_WRITE_SEQUENCER_359              0x3167
+#define WM8996_WRITE_SEQUENCER_360              0x3168
+#define WM8996_WRITE_SEQUENCER_361              0x3169
+#define WM8996_WRITE_SEQUENCER_362              0x316A
+#define WM8996_WRITE_SEQUENCER_363              0x316B
+#define WM8996_WRITE_SEQUENCER_364              0x316C
+#define WM8996_WRITE_SEQUENCER_365              0x316D
+#define WM8996_WRITE_SEQUENCER_366              0x316E
+#define WM8996_WRITE_SEQUENCER_367              0x316F
+#define WM8996_WRITE_SEQUENCER_368              0x3170
+#define WM8996_WRITE_SEQUENCER_369              0x3171
+#define WM8996_WRITE_SEQUENCER_370              0x3172
+#define WM8996_WRITE_SEQUENCER_371              0x3173
+#define WM8996_WRITE_SEQUENCER_372              0x3174
+#define WM8996_WRITE_SEQUENCER_373              0x3175
+#define WM8996_WRITE_SEQUENCER_374              0x3176
+#define WM8996_WRITE_SEQUENCER_375              0x3177
+#define WM8996_WRITE_SEQUENCER_376              0x3178
+#define WM8996_WRITE_SEQUENCER_377              0x3179
+#define WM8996_WRITE_SEQUENCER_378              0x317A
+#define WM8996_WRITE_SEQUENCER_379              0x317B
+#define WM8996_WRITE_SEQUENCER_380              0x317C
+#define WM8996_WRITE_SEQUENCER_381              0x317D
+#define WM8996_WRITE_SEQUENCER_382              0x317E
+#define WM8996_WRITE_SEQUENCER_383              0x317F
+#define WM8996_WRITE_SEQUENCER_384              0x3180
+#define WM8996_WRITE_SEQUENCER_385              0x3181
+#define WM8996_WRITE_SEQUENCER_386              0x3182
+#define WM8996_WRITE_SEQUENCER_387              0x3183
+#define WM8996_WRITE_SEQUENCER_388              0x3184
+#define WM8996_WRITE_SEQUENCER_389              0x3185
+#define WM8996_WRITE_SEQUENCER_390              0x3186
+#define WM8996_WRITE_SEQUENCER_391              0x3187
+#define WM8996_WRITE_SEQUENCER_392              0x3188
+#define WM8996_WRITE_SEQUENCER_393              0x3189
+#define WM8996_WRITE_SEQUENCER_394              0x318A
+#define WM8996_WRITE_SEQUENCER_395              0x318B
+#define WM8996_WRITE_SEQUENCER_396              0x318C
+#define WM8996_WRITE_SEQUENCER_397              0x318D
+#define WM8996_WRITE_SEQUENCER_398              0x318E
+#define WM8996_WRITE_SEQUENCER_399              0x318F
+#define WM8996_WRITE_SEQUENCER_400              0x3190
+#define WM8996_WRITE_SEQUENCER_401              0x3191
+#define WM8996_WRITE_SEQUENCER_402              0x3192
+#define WM8996_WRITE_SEQUENCER_403              0x3193
+#define WM8996_WRITE_SEQUENCER_404              0x3194
+#define WM8996_WRITE_SEQUENCER_405              0x3195
+#define WM8996_WRITE_SEQUENCER_406              0x3196
+#define WM8996_WRITE_SEQUENCER_407              0x3197
+#define WM8996_WRITE_SEQUENCER_408              0x3198
+#define WM8996_WRITE_SEQUENCER_409              0x3199
+#define WM8996_WRITE_SEQUENCER_410              0x319A
+#define WM8996_WRITE_SEQUENCER_411              0x319B
+#define WM8996_WRITE_SEQUENCER_412              0x319C
+#define WM8996_WRITE_SEQUENCER_413              0x319D
+#define WM8996_WRITE_SEQUENCER_414              0x319E
+#define WM8996_WRITE_SEQUENCER_415              0x319F
+#define WM8996_WRITE_SEQUENCER_416              0x31A0
+#define WM8996_WRITE_SEQUENCER_417              0x31A1
+#define WM8996_WRITE_SEQUENCER_418              0x31A2
+#define WM8996_WRITE_SEQUENCER_419              0x31A3
+#define WM8996_WRITE_SEQUENCER_420              0x31A4
+#define WM8996_WRITE_SEQUENCER_421              0x31A5
+#define WM8996_WRITE_SEQUENCER_422              0x31A6
+#define WM8996_WRITE_SEQUENCER_423              0x31A7
+#define WM8996_WRITE_SEQUENCER_424              0x31A8
+#define WM8996_WRITE_SEQUENCER_425              0x31A9
+#define WM8996_WRITE_SEQUENCER_426              0x31AA
+#define WM8996_WRITE_SEQUENCER_427              0x31AB
+#define WM8996_WRITE_SEQUENCER_428              0x31AC
+#define WM8996_WRITE_SEQUENCER_429              0x31AD
+#define WM8996_WRITE_SEQUENCER_430              0x31AE
+#define WM8996_WRITE_SEQUENCER_431              0x31AF
+#define WM8996_WRITE_SEQUENCER_432              0x31B0
+#define WM8996_WRITE_SEQUENCER_433              0x31B1
+#define WM8996_WRITE_SEQUENCER_434              0x31B2
+#define WM8996_WRITE_SEQUENCER_435              0x31B3
+#define WM8996_WRITE_SEQUENCER_436              0x31B4
+#define WM8996_WRITE_SEQUENCER_437              0x31B5
+#define WM8996_WRITE_SEQUENCER_438              0x31B6
+#define WM8996_WRITE_SEQUENCER_439              0x31B7
+#define WM8996_WRITE_SEQUENCER_440              0x31B8
+#define WM8996_WRITE_SEQUENCER_441              0x31B9
+#define WM8996_WRITE_SEQUENCER_442              0x31BA
+#define WM8996_WRITE_SEQUENCER_443              0x31BB
+#define WM8996_WRITE_SEQUENCER_444              0x31BC
+#define WM8996_WRITE_SEQUENCER_445              0x31BD
+#define WM8996_WRITE_SEQUENCER_446              0x31BE
+#define WM8996_WRITE_SEQUENCER_447              0x31BF
+#define WM8996_WRITE_SEQUENCER_448              0x31C0
+#define WM8996_WRITE_SEQUENCER_449              0x31C1
+#define WM8996_WRITE_SEQUENCER_450              0x31C2
+#define WM8996_WRITE_SEQUENCER_451              0x31C3
+#define WM8996_WRITE_SEQUENCER_452              0x31C4
+#define WM8996_WRITE_SEQUENCER_453              0x31C5
+#define WM8996_WRITE_SEQUENCER_454              0x31C6
+#define WM8996_WRITE_SEQUENCER_455              0x31C7
+#define WM8996_WRITE_SEQUENCER_456              0x31C8
+#define WM8996_WRITE_SEQUENCER_457              0x31C9
+#define WM8996_WRITE_SEQUENCER_458              0x31CA
+#define WM8996_WRITE_SEQUENCER_459              0x31CB
+#define WM8996_WRITE_SEQUENCER_460              0x31CC
+#define WM8996_WRITE_SEQUENCER_461              0x31CD
+#define WM8996_WRITE_SEQUENCER_462              0x31CE
+#define WM8996_WRITE_SEQUENCER_463              0x31CF
+#define WM8996_WRITE_SEQUENCER_464              0x31D0
+#define WM8996_WRITE_SEQUENCER_465              0x31D1
+#define WM8996_WRITE_SEQUENCER_466              0x31D2
+#define WM8996_WRITE_SEQUENCER_467              0x31D3
+#define WM8996_WRITE_SEQUENCER_468              0x31D4
+#define WM8996_WRITE_SEQUENCER_469              0x31D5
+#define WM8996_WRITE_SEQUENCER_470              0x31D6
+#define WM8996_WRITE_SEQUENCER_471              0x31D7
+#define WM8996_WRITE_SEQUENCER_472              0x31D8
+#define WM8996_WRITE_SEQUENCER_473              0x31D9
+#define WM8996_WRITE_SEQUENCER_474              0x31DA
+#define WM8996_WRITE_SEQUENCER_475              0x31DB
+#define WM8996_WRITE_SEQUENCER_476              0x31DC
+#define WM8996_WRITE_SEQUENCER_477              0x31DD
+#define WM8996_WRITE_SEQUENCER_478              0x31DE
+#define WM8996_WRITE_SEQUENCER_479              0x31DF
+#define WM8996_WRITE_SEQUENCER_480              0x31E0
+#define WM8996_WRITE_SEQUENCER_481              0x31E1
+#define WM8996_WRITE_SEQUENCER_482              0x31E2
+#define WM8996_WRITE_SEQUENCER_483              0x31E3
+#define WM8996_WRITE_SEQUENCER_484              0x31E4
+#define WM8996_WRITE_SEQUENCER_485              0x31E5
+#define WM8996_WRITE_SEQUENCER_486              0x31E6
+#define WM8996_WRITE_SEQUENCER_487              0x31E7
+#define WM8996_WRITE_SEQUENCER_488              0x31E8
+#define WM8996_WRITE_SEQUENCER_489              0x31E9
+#define WM8996_WRITE_SEQUENCER_490              0x31EA
+#define WM8996_WRITE_SEQUENCER_491              0x31EB
+#define WM8996_WRITE_SEQUENCER_492              0x31EC
+#define WM8996_WRITE_SEQUENCER_493              0x31ED
+#define WM8996_WRITE_SEQUENCER_494              0x31EE
+#define WM8996_WRITE_SEQUENCER_495              0x31EF
+#define WM8996_WRITE_SEQUENCER_496              0x31F0
+#define WM8996_WRITE_SEQUENCER_497              0x31F1
+#define WM8996_WRITE_SEQUENCER_498              0x31F2
+#define WM8996_WRITE_SEQUENCER_499              0x31F3
+#define WM8996_WRITE_SEQUENCER_500              0x31F4
+#define WM8996_WRITE_SEQUENCER_501              0x31F5
+#define WM8996_WRITE_SEQUENCER_502              0x31F6
+#define WM8996_WRITE_SEQUENCER_503              0x31F7
+#define WM8996_WRITE_SEQUENCER_504              0x31F8
+#define WM8996_WRITE_SEQUENCER_505              0x31F9
+#define WM8996_WRITE_SEQUENCER_506              0x31FA
+#define WM8996_WRITE_SEQUENCER_507              0x31FB
+#define WM8996_WRITE_SEQUENCER_508              0x31FC
+#define WM8996_WRITE_SEQUENCER_509              0x31FD
+#define WM8996_WRITE_SEQUENCER_510              0x31FE
+#define WM8996_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8996_REGISTER_COUNT                   706
+#define WM8996_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8996_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8996_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8996_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8996_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8996_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8996_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8996_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8996_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8996_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8996_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8996_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8996_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8996_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8996_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8996_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8996_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8996_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8996_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8996_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8996_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8996_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8996_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8996_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8996_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8996_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8996_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8996_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8996_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8996_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8996_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8996_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8996_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8996_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8996_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8996_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8996_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8996_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8996_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8996_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8996_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8996_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8996_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8996_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8996_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8996_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8996_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8996_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8996_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8996_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8996_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8996_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8996_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8996_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8996_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8996_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8996_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8996_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8996_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8996_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8996_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8996_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8996_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8996_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8996_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8996_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8996_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8996_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8996_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8996_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8996_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8996_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8996_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8996_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8996_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8996_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8996_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8996_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8996_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8996_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8996_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8996_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8996_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8996_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8996_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8996_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8996_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8996_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8996_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8996_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8996_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8996_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8996_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8996_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8996_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8996_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8996_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8996_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8996_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8996_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8996_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8996_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8996_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8996_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8996_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8996_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8996_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8996_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8996_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8996_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8996_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8996_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8996_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8996_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8996_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8996_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8996_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8996_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8996_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8996_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8996_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8996_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8996_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8996_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8996_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8996_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8996_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8996_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8996_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8996_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8996_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8996_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8996_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8996_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8996_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8996_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8996_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8996_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8996_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8996_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8996_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8996_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8996_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8996_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8996_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8996_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8996_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8996_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8996_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8996_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8996_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8996_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8996_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8996_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8996_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8996_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8996_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8996_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8996_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8996_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8996_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8996_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8996_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8996_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8996_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8996_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8996_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8996_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8996_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8996_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8996_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8996_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8996_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8996_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8996_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8996_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8996_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8996_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8996_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8996_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8996_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8996_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8996_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8996_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8996_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8996_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8996_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8996_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8996_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8996_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8996_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8996_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8996_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8996_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8996_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8996_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8996_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8996_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8996_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8996_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8996_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8996_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8996_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8996_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8996_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8996_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8996_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8996_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8996_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8996_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8996_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8996_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8996_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8996_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8996_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8996_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8996_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8996_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8996_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8996_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8996_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8996_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8996_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8996_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8996_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8996_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8996_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8996_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8996_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8996_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8996_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8996_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8996_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8996_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8996_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8996_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8996_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8996_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8996_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8996_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8996_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8996_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8996_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8996_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8996_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8996_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8996_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8996_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8996_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8996_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8996_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8996_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8996_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8996_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8996_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8996_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8996_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8996_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8996_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8996_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8996_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8996_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8996_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8996_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8996_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8996_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8996_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8996_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8996_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8996_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8996_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8996_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8996_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8996_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8996_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8996_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8996_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8996_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8996_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8996_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8996_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8996_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8996_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8996_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8996_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8996_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8996_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8996_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8996_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8996_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8996_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8996_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8996_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8996_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8996_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8996_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8996_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8996_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8996_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8996_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8996_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8996_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8996_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8996_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8996_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8996_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8996_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8996_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8996_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8996_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8996_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8996_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8996_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8996_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8996_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8996_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8996_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8996_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8996_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8996_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8996_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8996_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8996_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8996_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8996_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8996_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8996_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8996_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8996_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8996_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8996_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8996_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8996_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8996_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8996_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8996_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8996_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8996_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8996_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8996_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8996_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8996_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8996_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8996_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8996_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8996_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8996_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8996_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8996_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8996_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8996_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8996_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8996_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8996_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8996_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8996_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8996_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8996_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8996_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8996_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8996_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8996_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8996_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8996_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8996_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8996_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8996_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8996_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8996_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8996_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8996_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8996_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8996_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8996_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8996_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8996_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8996_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8996_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8996_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8996_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8996_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8996_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8996_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8996_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8996_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8996_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8996_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8996_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8996_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8996_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8996_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8996_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8996_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8996_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8996_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8996_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8996_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8996_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8996_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8996_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8996_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8996_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8996_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8996_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8996_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8996_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8996_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8996_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8996_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8996_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8996_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8996_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8996_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8996_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8996_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8996_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8996_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8996_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8996_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8996_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8996_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8996_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8996_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8996_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8996_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8996_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8996_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8996_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8996_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8996_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8996_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8996_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8996_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8996_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8996_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8996_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8996_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8996_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8996_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8996_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8996_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8996_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8996_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8996_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8996_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8996_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8996_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8996_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8996_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8996_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8996_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8996_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8996_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8996_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8996_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8996_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8996_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8996_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8996_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8996_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8996_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8996_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8996_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8996_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8996_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8996_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8996_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8996_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8996_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8996_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8996_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8996_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8996_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8996_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8996_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8996_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8996_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8996_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8996_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8996_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8996_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8996_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8996_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8996_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8996_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8996_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8996_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8996_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8996_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8996_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8996_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8996_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8996_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8996_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8996_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8996_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8996_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8996_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8996_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8996_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8996_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8996_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8996_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8996_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8996_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8996_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8996_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8996_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8996_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8996_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8996_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8996_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8996_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8996_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8996_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8996_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8996_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8996_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8996_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8996_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8996_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8996_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8996_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8996_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8996_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8996_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8996_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8996_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8996_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8996_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8996_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8996_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8996_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8996_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8996_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8996_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8996_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8996_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8996_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8996_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8996_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8996_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8996_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8996_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8996_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8996_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8996_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8996_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8996_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8996_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8996_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8996_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8996_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8996_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8996_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8996_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8996_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8996_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8996_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8996_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8996_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8996_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8996_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8996_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8996_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8996_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8996_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8996_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8996_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8996_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8996_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8996_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8996_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8996_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8996_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8996_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8996_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8996_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8996_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8996_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8996_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8996_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8996_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8996_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8996_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8996_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8996_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8996_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8996_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8996_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8996_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8996_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8996_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8996_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8996_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8996_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8996_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8996_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8996_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8996_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8996_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8996_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8996_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8996_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8996_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8996_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8996_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8996_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8996_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8996_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8996_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8996_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8996_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8996_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8996_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8996_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8996_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8996_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8996_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8996_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8996_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8996_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8996_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8996_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8996_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8996_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8996_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8996_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8996_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8996_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8996_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8996_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8996_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8996_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8996_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8996_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8996_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8996_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8996_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8996_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8996_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8996_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8996_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8996_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8996_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8996_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8996_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8996_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8996_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8996_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8996_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8996_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8996_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8996_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8996_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8996_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8996_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8996_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8996_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8996_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8996_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8996_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8996_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8996_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8996_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8996_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8996_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8996_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8996_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8996_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8996_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8996_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8996_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8996_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8996_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8996_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8996_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8996_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8996_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8996_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8996_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8996_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8996_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8996_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8996_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8996_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8996_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8996_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8996_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8996_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8996_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8996_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8996_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8996_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8996_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8996_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8996_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8996_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8996_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8996_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8996_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8996_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8996_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8996_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8996_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8996_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8996_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8996_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8996_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8996_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8996_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8996_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8996_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8996_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8996_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8996_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8996_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8996_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8996_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8996_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8996_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8996_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8996_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8996_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8996_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8996_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8996_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8996_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8996_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8996_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8996_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8996_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8996_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8996_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8996_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8996_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8996_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8996_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8996_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8996_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8996_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8996_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8996_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8996_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8996_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8996_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8996_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8996_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8996_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8996_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8996_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8996_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8996_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8996_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8996_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8996_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8996_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8996_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8996_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8996_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8996_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8996_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8996_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8996_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8996_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8996_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8996_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8996_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8996_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8996_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8996_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8996_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8996_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8996_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8996_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8996_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8996_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8996_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8996_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8996_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8996_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8996_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8996_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8996_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8996_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8996_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8996_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8996_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8996_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8996_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8996_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8996_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8996_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8996_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8996_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8996_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8996_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8996_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8996_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8996_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8996_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8996_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8996_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8996_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8996_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8996_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8996_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8996_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8996_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8996_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8996_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8996_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8996_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8996_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8996_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8996_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8996_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8996_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif
index 4cc2d56..e763c54 100644 (file)
@@ -440,9 +440,8 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
                snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
 
-               /* Smallest supported update interval */
                snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
-                                   WM8993_DCS_TIMER_PERIOD_01_MASK, 1);
+                                   WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
                calibrate_dc_servo(codec);
 
index 83d213b..62e292f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -402,6 +402,6 @@ static void __exit n810_soc_exit(void)
 module_init(n810_soc_init);
 module_exit(n810_soc_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("ALSA SoC Nokia N810");
 MODULE_LICENSE("GPL");
index 07b7723..ebcc2d4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -780,6 +780,6 @@ static void __exit snd_omap_mcbsp_exit(void)
 }
 module_exit(snd_omap_mcbsp_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");
index 9a7dedd..65cde9d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
index b2f5751..9b5c88a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -436,6 +436,6 @@ static void __exit snd_omap_pcm_exit(void)
 }
 module_exit(snd_omap_pcm_exit);
 
-MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
index a0ed1db..f95fe30 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008 Nokia Corporation
  *
- * Contact: Jarkko Nikula <jhnikula@gmail.com>
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
  *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  * This program is free software; you can redistribute it and/or
index 0aae998..893300a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
- *          Jarkko Nikula <jhnikula@gmail.com>
+ *          Jarkko Nikula <jarkko.nikula@bitmer.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 54b0e4b..b99091f 100644 (file)
@@ -183,7 +183,7 @@ config SND_SOC_SPEYSIDE
        tristate "Audio support for Wolfson Speyside"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
        select SND_SAMSUNG_I2S
-       select SND_SOC_WM8915
+       select SND_SOC_WM8996
        select SND_SOC_WM9081
 
 config SND_SOC_SPEYSIDE_WM8962
index 9eb3b12..8509d3c 100644 (file)
@@ -1,5 +1,6 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := dma.o
+snd-soc-idma-objs := idma.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
 snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-ac97-objs := ac97.o
@@ -16,6 +17,7 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
 obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
 obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
 obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
+obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
 
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
new file mode 100644 (file)
index 0000000..ebde074
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * sound/soc/samsung/idma.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * I2S0's Internal DMA driver
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "i2s.h"
+#include "idma.h"
+#include "dma.h"
+#include "i2s-regs.h"
+
+#define ST_RUNNING             (1<<0)
+#define ST_OPENED              (1<<1)
+
+static const struct snd_pcm_hardware idma_hardware = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                   SNDRV_PCM_INFO_MMAP |
+                   SNDRV_PCM_INFO_MMAP_VALID |
+                   SNDRV_PCM_INFO_PAUSE |
+                   SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                   SNDRV_PCM_FMTBIT_U16_LE |
+                   SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_U24_LE |
+                   SNDRV_PCM_FMTBIT_U8 |
+                   SNDRV_PCM_FMTBIT_S8,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = MAX_IDMA_BUFFER,
+       .period_bytes_min = 128,
+       .period_bytes_max = MAX_IDMA_PERIOD,
+       .periods_min = 1,
+       .periods_max = 2,
+};
+
+struct idma_ctrl {
+       spinlock_t      lock;
+       int             state;
+       dma_addr_t      start;
+       dma_addr_t      pos;
+       dma_addr_t      end;
+       dma_addr_t      period;
+       dma_addr_t      periodsz;
+       void            *token;
+       void            (*cb)(void *dt, int bytes_xfer);
+};
+
+static struct idma_info {
+       spinlock_t      lock;
+       void             __iomem  *regs;
+       dma_addr_t      lp_tx_addr;
+} idma;
+
+static void idma_getpos(dma_addr_t *src)
+{
+       *src = idma.lp_tx_addr +
+               (readl(idma.regs + I2STRNCNT) & 0xffffff) * 4;
+}
+
+static int idma_enqueue(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       u32 val;
+
+       spin_lock(&prtd->lock);
+       prtd->token = (void *) substream;
+       spin_unlock(&prtd->lock);
+
+       /* Internal DMA Level0 Interrupt Address */
+       val = idma.lp_tx_addr + prtd->periodsz;
+       writel(val, idma.regs + I2SLVL0ADDR);
+
+       /* Start address0 of I2S internal DMA operation. */
+       val = idma.lp_tx_addr;
+       writel(val, idma.regs + I2SSTR0);
+
+       /*
+        * Transfer block size for I2S internal DMA.
+        * Should decide transfer size before start dma operation
+        */
+       val = readl(idma.regs + I2SSIZE);
+       val &= ~(I2SSIZE_TRNMSK << I2SSIZE_SHIFT);
+       val |= (((runtime->dma_bytes >> 2) &
+                       I2SSIZE_TRNMSK) << I2SSIZE_SHIFT);
+       writel(val, idma.regs + I2SSIZE);
+
+       val = readl(idma.regs + I2SAHB);
+       val |= AHB_INTENLVL0;
+       writel(val, idma.regs + I2SAHB);
+
+       return 0;
+}
+
+static void idma_setcallbk(struct snd_pcm_substream *substream,
+                               void (*cb)(void *, int))
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       spin_lock(&prtd->lock);
+       prtd->cb = cb;
+       spin_unlock(&prtd->lock);
+}
+
+static void idma_control(int op)
+{
+       u32 val = readl(idma.regs + I2SAHB);
+
+       spin_lock(&idma.lock);
+
+       switch (op) {
+       case LPAM_DMA_START:
+               val |= (AHB_INTENLVL0 | AHB_DMAEN);
+               break;
+       case LPAM_DMA_STOP:
+               val &= ~(AHB_INTENLVL0 | AHB_DMAEN);
+               break;
+       default:
+               spin_unlock(&idma.lock);
+               return;
+       }
+
+       writel(val, idma.regs + I2SAHB);
+       spin_unlock(&idma.lock);
+}
+
+static void idma_done(void *id, int bytes_xfer)
+{
+       struct snd_pcm_substream *substream = id;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       if (prtd && (prtd->state & ST_RUNNING))
+               snd_pcm_period_elapsed(substream);
+}
+
+static int idma_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       u32 mod = readl(idma.regs + I2SMOD);
+       u32 ahb = readl(idma.regs + I2SAHB);
+
+       ahb |= (AHB_DMARLD | AHB_INTMASK);
+       mod |= MOD_TXS_IDMA;
+       writel(ahb, idma.regs + I2SAHB);
+       writel(mod, idma.regs + I2SMOD);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       runtime->dma_bytes = params_buffer_bytes(params);
+
+       prtd->start = prtd->pos = runtime->dma_addr;
+       prtd->period = params_periods(params);
+       prtd->periodsz = params_period_bytes(params);
+       prtd->end = runtime->dma_addr + runtime->dma_bytes;
+
+       idma_setcallbk(substream, idma_done);
+
+       return 0;
+}
+
+static int idma_hw_free(struct snd_pcm_substream *substream)
+{
+       snd_pcm_set_runtime_buffer(substream, NULL);
+
+       return 0;
+}
+
+static int idma_prepare(struct snd_pcm_substream *substream)
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+
+       prtd->pos = prtd->start;
+
+       /* flush the DMA channel */
+       idma_control(LPAM_DMA_STOP);
+       idma_enqueue(substream);
+
+       return 0;
+}
+
+static int idma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct idma_ctrl *prtd = substream->runtime->private_data;
+       int ret = 0;
+
+       spin_lock(&prtd->lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               prtd->state |= ST_RUNNING;
+               idma_control(LPAM_DMA_START);
+               break;
+
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               prtd->state &= ~ST_RUNNING;
+               idma_control(LPAM_DMA_STOP);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       spin_unlock(&prtd->lock);
+
+       return ret;
+}
+
+static snd_pcm_uframes_t
+       idma_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = runtime->private_data;
+       dma_addr_t src;
+       unsigned long res;
+
+       spin_lock(&prtd->lock);
+
+       idma_getpos(&src);
+       res = src - prtd->start;
+
+       spin_unlock(&prtd->lock);
+
+       return bytes_to_frames(substream->runtime, res);
+}
+
+static int idma_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long size, offset;
+       int ret;
+
+       /* From snd_pcm_lib_mmap_iomem */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       vma->vm_flags |= VM_IO;
+       size = vma->vm_end - vma->vm_start;
+       offset = vma->vm_pgoff << PAGE_SHIFT;
+       ret = io_remap_pfn_range(vma, vma->vm_start,
+                       (runtime->dma_addr + offset) >> PAGE_SHIFT,
+                       size, vma->vm_page_prot);
+
+       return ret;
+}
+
+static irqreturn_t iis_irq(int irqno, void *dev_id)
+{
+       struct idma_ctrl *prtd = (struct idma_ctrl *)dev_id;
+       u32 iiscon, iisahb, val, addr;
+
+       iisahb  = readl(idma.regs + I2SAHB);
+       iiscon  = readl(idma.regs + I2SCON);
+
+       val = (iisahb & AHB_LVL0INT) ? AHB_CLRLVL0INT : 0;
+
+       if (val) {
+               iisahb |= val;
+               writel(iisahb, idma.regs + I2SAHB);
+
+               addr = readl(idma.regs + I2SLVL0ADDR) - idma.lp_tx_addr;
+               addr += prtd->periodsz;
+               addr %= (prtd->end - prtd->start);
+               addr += idma.lp_tx_addr;
+
+               writel(addr, idma.regs + I2SLVL0ADDR);
+
+               if (prtd->cb)
+                       prtd->cb(prtd->token, prtd->period);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int idma_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd;
+       int ret;
+
+       snd_soc_set_runtime_hwparams(substream, &idma_hardware);
+
+       prtd = kzalloc(sizeof(struct idma_ctrl), GFP_KERNEL);
+       if (prtd == NULL)
+               return -ENOMEM;
+
+       ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
+       if (ret < 0) {
+               pr_err("fail to claim i2s irq , ret = %d\n", ret);
+               kfree(prtd);
+               return ret;
+       }
+
+       spin_lock_init(&prtd->lock);
+
+       runtime->private_data = prtd;
+
+       return 0;
+}
+
+static int idma_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct idma_ctrl *prtd = runtime->private_data;
+
+       free_irq(IRQ_I2S0, prtd);
+
+       if (!prtd)
+               pr_err("idma_close called with prtd == NULL\n");
+
+       kfree(prtd);
+
+       return 0;
+}
+
+static struct snd_pcm_ops idma_ops = {
+       .open           = idma_open,
+       .close          = idma_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .trigger        = idma_trigger,
+       .pointer        = idma_pointer,
+       .mmap           = idma_mmap,
+       .hw_params      = idma_hw_params,
+       .hw_free        = idma_hw_free,
+       .prepare        = idma_prepare,
+};
+
+static void idma_free(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+
+       substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       if (!substream)
+               return;
+
+       buf = &substream->dma_buffer;
+       if (!buf->area)
+               return;
+
+       iounmap(buf->area);
+
+       buf->area = NULL;
+       buf->addr = 0;
+}
+
+static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
+{
+       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+       struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+       buf->dev.dev = pcm->card->dev;
+       buf->private_data = NULL;
+
+       /* Assign PCM buffer pointers */
+       buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+       buf->addr = idma.lp_tx_addr;
+       buf->bytes = idma_hardware.buffer_bytes_max;
+       buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes);
+
+       return 0;
+}
+
+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;
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &idma_mask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+       if (dai->driver->playback.channels_min)
+               ret = preallocate_idma_buffer(pcm,
+                               SNDRV_PCM_STREAM_PLAYBACK);
+
+       return ret;
+}
+
+void idma_reg_addr_init(void *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 = {
+       .ops = &idma_ops,
+       .pcm_new = idma_new,
+       .pcm_free = idma_free,
+};
+
+static int __devinit asoc_idma_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
+}
+
+static int __devexit asoc_idma_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_idma_driver = {
+       .driver = {
+               .name = "samsung-idma",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_idma_platform_probe,
+       .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_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
+MODULE_DESCRIPTION("Samsung ASoC IDMA Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/idma.h b/sound/soc/samsung/idma.h
new file mode 100644 (file)
index 0000000..4827321
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * sound/soc/samsung/idma.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 __SND_SOC_SAMSUNG_IDMA_H_
+#define __SND_SOC_SAMSUNG_IDMA_H_
+
+extern void idma_reg_addr_init(void *regs, dma_addr_t addr);
+
+/* dma_state */
+#define LPAM_DMA_STOP  0
+#define LPAM_DMA_START 1
+
+#define MAX_IDMA_PERIOD (128 * 1024)
+#define MAX_IDMA_BUFFER (160 * 1024)
+
+#endif /* __SND_SOC_SAMSUNG_IDMA_H_ */
index 3b53ad5..14eb6ea 100644 (file)
@@ -131,7 +131,7 @@ static struct snd_soc_dai_link jive_dai = {
        .cpu_dai_name   = "s3c2412-i2s",
        .codec_dai_name = "wm8750-hifi",
        .platform_name  = "samsung-audio",
-       .codec_name     = "wm8750-codec.0-0x1a",
+       .codec_name     = "wm8750-codec.0-001a",
        .init           = jive_wm8750_init,
        .ops            = &jive_ops,
 };
index d6dee4d..590e927 100644 (file)
 #include <sound/jack.h>
 #include <linux/gpio.h>
 
-#include "../codecs/wm8915.h"
+#include "../codecs/wm8996.h"
 #include "../codecs/wm9081.h"
 
-#define WM8915_HPSEL_GPIO 214
+#define WM8996_HPSEL_GPIO 214
 
 static int speyside_set_bias_level(struct snd_soc_card *card,
                                   struct snd_soc_dapm_context *dapm,
@@ -31,12 +31,12 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
 
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2,
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8996_SYSCLK_MCLK2,
                                             32768, SND_SOC_CLOCK_IN);
                if (ret < 0)
                        return ret;
 
-               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2,
+               ret = snd_soc_dai_set_pll(codec_dai, WM8996_FLL_MCLK2,
                                          0, 0, 0);
                if (ret < 0) {
                        pr_err("Failed to stop FLL\n");
@@ -65,7 +65,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
        case SND_SOC_BIAS_PREPARE:
                if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
                        ret = snd_soc_dai_set_pll(codec_dai, 0,
-                                                 WM8915_FLL_MCLK2,
+                                                 WM8996_FLL_MCLK2,
                                                  32768, 48000 * 256);
                        if (ret < 0) {
                                pr_err("Failed to start FLL\n");
@@ -73,7 +73,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
                        }
 
                        ret = snd_soc_dai_set_sysclk(codec_dai,
-                                                    WM8915_SYSCLK_FLL,
+                                                    WM8996_SYSCLK_FLL,
                                                     48000 * 256,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0)
@@ -149,26 +149,26 @@ static void speyside_set_polarity(struct snd_soc_codec *codec,
                                  int polarity)
 {
        speyside_jack_polarity = !polarity;
-       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+       gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
        /* Re-run DAPM to make sure we're using the correct mic bias */
        snd_soc_dapm_sync(&codec->dapm);
 }
 
-static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
+static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->codec_dai;
        struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0);
+       ret = snd_soc_dai_set_sysclk(dai, WM8996_SYSCLK_MCLK2, 32768, 0);
        if (ret < 0)
                return ret;
 
-       ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+       ret = gpio_request(WM8996_HPSEL_GPIO, "HP_SEL");
        if (ret != 0)
                pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
-       gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+       gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
 
        ret = snd_soc_jack_new(codec, "Headset",
                               SND_JACK_HEADSET | SND_JACK_BTN_0,
@@ -182,7 +182,7 @@ static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                return ret;
 
-       wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+       wm8996_detect(codec, &speyside_headset, speyside_set_polarity);
 
        return 0;
 }
@@ -205,16 +205,16 @@ static struct snd_soc_dai_link speyside_dai[] = {
                .name = "CPU",
                .stream_name = "CPU",
                .cpu_dai_name = "samsung-i2s.0",
-               .codec_dai_name = "wm8915-aif1",
+               .codec_dai_name = "wm8996-aif1",
                .platform_name = "samsung-audio",
-               .codec_name = "wm8915.1-001a",
-               .init = speyside_wm8915_init,
+               .codec_name = "wm8996.1-001a",
+               .init = speyside_wm8996_init,
                .ops = &speyside_ops,
        },
        {
                .name = "Baseband",
                .stream_name = "Baseband",
-               .cpu_dai_name = "wm8915-aif2",
+               .cpu_dai_name = "wm8996-aif2",
                .codec_dai_name = "wm1250-ev1",
                .codec_name = "wm1250-ev1.1-0027",
                .ops = &speyside_ops,
index 8ac42bf..0b9eb5f 100644 (file)
@@ -37,7 +37,7 @@ static int speyside_wm8962_set_bias_level(struct snd_soc_card *card,
                                                     44100 * 256,
                                                     SND_SOC_CLOCK_IN);
                        if (ret < 0) {
-                               pr_err("Failed to set SYSCLK: %d\n");
+                               pr_err("Failed to set SYSCLK: %d\n", ret);
                                return ret;
                        }
                }
index ff86e5e..c7cfd96 100644 (file)
@@ -309,9 +309,14 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 
 static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
-       struct snd_pcm_substream *substream = pcm->streams[stream].substream;
-       struct snd_dma_buffer *buf = &substream->dma_buffer;
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+
+       substream = pcm->streams[stream].substream;
+       if (!substream)
+               return;
 
+       buf = &substream->dma_buffer;
        if (!buf->area)
                return;
 
index a42e9ac..661373c 100644 (file)
@@ -56,6 +56,7 @@
 #define GPIO_HP_MUTE    BIT(1)
 #define GPIO_INT_MIC_EN BIT(2)
 #define GPIO_EXT_MIC_EN BIT(3)
+#define GPIO_HP_DET     BIT(4)
 
 struct tegra_wm8903 {
        struct tegra_asoc_utils_data util_data;
@@ -304,6 +305,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
                snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack,
                                        1,
                                        &tegra_wm8903_hp_jack_gpio);
+               machine->gpio_requested |= GPIO_HP_DET;
        }
 
        snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
@@ -429,10 +431,10 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
        struct tegra_wm8903_platform_data *pdata = machine->pdata;
 
-       snd_soc_unregister_card(card);
-
-       tegra_asoc_utils_fini(&machine->util_data);
-
+       if (machine->gpio_requested & GPIO_HP_DET)
+               snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
+                                       1,
+                                       &tegra_wm8903_hp_jack_gpio);
        if (machine->gpio_requested & GPIO_EXT_MIC_EN)
                gpio_free(pdata->gpio_ext_mic_en);
        if (machine->gpio_requested & GPIO_INT_MIC_EN)
@@ -441,6 +443,11 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
                gpio_free(pdata->gpio_hp_mute);
        if (machine->gpio_requested & GPIO_SPKR_EN)
                gpio_free(pdata->gpio_spkr_en);
+       machine->gpio_requested = 0;
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
 
        kfree(machine);
 
index d0d493c..aa52b3e 100644 (file)
@@ -614,6 +614,7 @@ static void read_completed(struct urb *urb)
        struct snd_usb_caiaqdev *dev;
        struct urb *out;
        int frame, len, send_it = 0, outframe = 0;
+       size_t offset = 0;
 
        if (urb->status || !info)
                return;
@@ -634,7 +635,8 @@ static void read_completed(struct urb *urb)
                len = urb->iso_frame_desc[outframe].actual_length;
                out->iso_frame_desc[outframe].length = len;
                out->iso_frame_desc[outframe].actual_length = 0;
-               out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame;
+               out->iso_frame_desc[outframe].offset = offset;
+               offset += len;
 
                if (len > 0) {
                        spin_lock(&dev->spinlock);
@@ -650,7 +652,7 @@ static void read_completed(struct urb *urb)
        }
 
        if (send_it) {
-               out->number_of_packets = FRAMES_PER_URB;
+               out->number_of_packets = outframe;
                out->transfer_flags = URB_ISO_ASAP;
                usb_submit_urb(out, GFP_ATOMIC);
        }
index 4432ef7..a213813 100644 (file)
@@ -30,7 +30,7 @@ static unsigned short keycode_ak1[] =  { KEY_C, KEY_B, KEY_A };
 static unsigned short keycode_rk2[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
                                         KEY_5, KEY_6, KEY_7 };
 static unsigned short keycode_rk3[] =  { KEY_1, KEY_2, KEY_3, KEY_4,
-                                        KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 };
+                                        KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 };
 
 static unsigned short keycode_kore[] = {
        KEY_FN_F1,      /* "menu"               */
index 7c0d21e..7d46e48 100644 (file)
@@ -352,7 +352,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        continue;
                }
                if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
-                   ((protocol == UAC_VERSION_2) && (fmt->bLength != 6))) {
+                   ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
                        snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
index c22fa76..c04d7c7 100644 (file)
@@ -1191,6 +1191,11 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
 
        if (state->mixer->protocol == UAC_VERSION_1) {
                csize = hdr->bControlSize;
+               if (!csize) {
+                       snd_printdd(KERN_ERR "usbaudio: unit %u: "
+                                   "invalid bControlSize == 0\n", unitid);
+                       return -EINVAL;
+               }
                channels = (hdr->bLength - 7) / csize - 1;
                bmaControls = hdr->bmaControls;
        } else {
@@ -1934,15 +1939,13 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        struct mixer_build state;
        int err;
        const struct usbmix_ctl_map *map;
-       struct usb_host_interface *hostif;
        void *p;
 
-       hostif = mixer->chip->ctrl_intf;
        memset(&state, 0, sizeof(state));
        state.chip = mixer->chip;
        state.mixer = mixer;
-       state.buffer = hostif->extra;
-       state.buflen = hostif->extralen;
+       state.buffer = mixer->hostif->extra;
+       state.buflen = mixer->hostif->extralen;
 
        /* check the mapping table */
        for (map = usbmix_ctl_maps; map->id; map++) {
@@ -1955,7 +1958,8 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
        }
 
        p = NULL;
-       while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
+       while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen,
+                                           p, UAC_OUTPUT_TERMINAL)) != NULL) {
                if (mixer->protocol == UAC_VERSION_1) {
                        struct uac1_output_terminal_descriptor *desc = p;
 
@@ -2162,17 +2166,15 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
 /* create the handler for the optional status interrupt endpoint */
 static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
 {
-       struct usb_host_interface *hostif;
        struct usb_endpoint_descriptor *ep;
        void *transfer_buffer;
        int buffer_length;
        unsigned int epnum;
 
-       hostif = mixer->chip->ctrl_intf;
        /* we need one interrupt input endpoint */
-       if (get_iface_desc(hostif)->bNumEndpoints < 1)
+       if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)
                return 0;
-       ep = get_endpoint(hostif, 0);
+       ep = get_endpoint(mixer->hostif, 0);
        if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
                return 0;
 
@@ -2202,7 +2204,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
        };
        struct usb_mixer_interface *mixer;
        struct snd_info_entry *entry;
-       struct usb_host_interface *host_iface;
        int err;
 
        strcpy(chip->card->mixername, "USB Mixer");
@@ -2219,8 +2220,8 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
                return -ENOMEM;
        }
 
-       host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
-       switch (get_iface_desc(host_iface)->bInterfaceProtocol) {
+       mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
+       switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
        case UAC_VERSION_1:
        default:
                mixer->protocol = UAC_VERSION_1;
index ae1a14d..81b2d8a 100644 (file)
@@ -3,6 +3,7 @@
 
 struct usb_mixer_interface {
        struct snd_usb_audio *chip;
+       struct usb_host_interface *hostif;
        struct list_head list;
        unsigned int ignore_ctl_error;
        struct urb *urb;
index dba0b7f..a42e3ef 100644 (file)
@@ -1707,6 +1707,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x0582, 0x0130),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "BOSS", */
+               /* .product_name = "MICRO BR-80", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
@@ -2417,6 +2451,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        .idProduct = 0x1020,
 },
 
+/* KeithMcMillen Stringport */
+{
+       USB_DEVICE(0x1f38, 0x0001),
+       .bInterfaceClass = USB_CLASS_AUDIO,
+},
+
 /* Miditech devices */
 {
        USB_DEVICE(0x4752, 0x0011),
index 77762c9..81e07d8 100644 (file)
@@ -426,7 +426,7 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
  */
 static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
 {
-       int err, reg;
+       int err  = 0, reg;
        int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
 
        for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
index 56d62d3..3b8f7b8 100644 (file)
@@ -181,9 +181,9 @@ strip-libs = $(filter-out -l%,$(1))
 
 $(OUTPUT)python/perf.so: $(PYRF_OBJS)
        $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
-         --quiet build_ext \
-         --build-lib='$(OUTPUT)python' \
-         --build-temp='$(OUTPUT)python/temp'
+         --quiet build_ext; \
+       mkdir -p $(OUTPUT)python && \
+       cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
 #
 # No Perl scripts right now:
 #
@@ -509,9 +509,13 @@ else
 
   PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
-  python-clean := $(PYTHON_WORD) util/setup.py clean \
-    --build-lib='$(OUTPUT)python' \
-    --build-temp='$(OUTPUT)python/temp'
+  # python extension build directories
+  PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
+  PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
+  PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
+  export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
+
+  python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
 
   ifdef NO_LIBPYTHON
     $(call disable-python)
@@ -868,6 +872,9 @@ install: all
        $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
        $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
 
+install-python_ext:
+       $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
+
 install-doc:
        $(MAKE) -C Documentation install
 
@@ -895,7 +902,7 @@ quick-install-html:
 ### Cleaning rules
 
 clean:
-       $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
+       $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
        $(RM) $(ALL_PROGRAMS) perf
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
        $(MAKE) -C Documentation/ clean
index 9ac05aa..899080a 100644 (file)
@@ -942,10 +942,10 @@ static const char *record_args[] = {
        "-f",
        "-m", "1024",
        "-c", "1",
-       "-e", "lock:lock_acquire:r",
-       "-e", "lock:lock_acquired:r",
-       "-e", "lock:lock_contended:r",
-       "-e", "lock:lock_release:r",
+       "-e", "lock:lock_acquire",
+       "-e", "lock:lock_acquired",
+       "-e", "lock:lock_contended",
+       "-e", "lock:lock_release",
 };
 
 static int __cmd_record(int argc, const char **argv)
index 5f2a5c7..710ae3d 100644 (file)
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used,
 {
        int ret = 0;
 
-       if (str)
-               ret = parse_line_range_desc(str, &params.line_range);
-       INIT_LIST_HEAD(&params.line_range.line_list);
+       if (!str)
+               return 0;
+
+       if (params.show_lines) {
+               pr_warning("Warning: more than one --line options are"
+                          " detected. Only the first one is valid.\n");
+               return 0;
+       }
+
        params.show_lines = true;
+       ret = parse_line_range_desc(str, &params.line_range);
+       INIT_LIST_HEAD(&params.line_range.line_list);
 
        return ret;
 }
index 80dc5b7..f6426b4 100644 (file)
@@ -30,8 +30,6 @@
 #include <sched.h>
 #include <sys/mman.h>
 
-#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
-
 enum write_mode_t {
        WRITE_FORCE,
        WRITE_APPEND
@@ -438,7 +436,6 @@ static void mmap_read_all(void)
 
 static int __cmd_record(int argc, const char **argv)
 {
-       int i;
        struct stat st;
        int flags;
        int err;
@@ -682,7 +679,6 @@ static int __cmd_record(int argc, const char **argv)
 
        for (;;) {
                int hits = samples;
-               int thread;
 
                mmap_read_all();
 
@@ -693,19 +689,8 @@ static int __cmd_record(int argc, const char **argv)
                        waking++;
                }
 
-               if (done) {
-                       for (i = 0; i < evsel_list->cpus->nr; i++) {
-                               struct perf_evsel *pos;
-
-                               list_for_each_entry(pos, &evsel_list->entries, node) {
-                                       for (thread = 0;
-                                               thread < evsel_list->threads->nr;
-                                               thread++)
-                                               ioctl(FD(pos, i, thread),
-                                                       PERF_EVENT_IOC_DISABLE);
-                               }
-                       }
-               }
+               if (done)
+                       perf_evlist__disable(evsel_list);
        }
 
        if (quiet || signr == SIGUSR1)
index f854efd..d7ff277 100644 (file)
@@ -162,23 +162,22 @@ static int perf_session__setup_sample_type(struct perf_session *self)
 {
        if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
-                       fprintf(stderr, "selected --sort parent, but no"
-                                       " callchain data. Did you call"
-                                       " perf record without -g?\n");
+                       ui__warning("Selected --sort parent, but no "
+                                   "callchain data. Did you call "
+                                   "'perf record' without -g?\n");
                        return -EINVAL;
                }
                if (symbol_conf.use_callchain) {
-                       fprintf(stderr, "selected -g but no callchain data."
-                                       " Did you call perf record without"
-                                       " -g?\n");
+                       ui__warning("Selected -g but no callchain data. Did "
+                                   "you call 'perf record' without -g?\n");
                        return -1;
                }
        } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
                   !symbol_conf.use_callchain) {
                        symbol_conf.use_callchain = true;
                        if (callchain_register_param(&callchain_param) < 0) {
-                               fprintf(stderr, "Can't register callchain"
-                                               " params\n");
+                               ui__warning("Can't register callchain "
+                                           "params.\n");
                                return -EINVAL;
                        }
        }
index dcfe887..5177964 100644 (file)
@@ -1637,23 +1637,29 @@ static struct perf_event_ops event_ops = {
        .ordered_samples        = true,
 };
 
-static int read_events(void)
+static void read_events(bool destroy, struct perf_session **psession)
 {
        int err = -EINVAL;
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
                                                         0, false, &event_ops);
        if (session == NULL)
-               return -ENOMEM;
+               die("No Memory");
 
        if (perf_session__has_traces(session, "record -R")) {
                err = perf_session__process_events(session, &event_ops);
+               if (err)
+                       die("Failed to process events, error %d", err);
+
                nr_events      = session->hists.stats.nr_events[0];
                nr_lost_events = session->hists.stats.total_lost;
                nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
        }
 
-       perf_session__delete(session);
-       return err;
+       if (destroy)
+               perf_session__delete(session);
+
+       if (psession)
+               *psession = session;
 }
 
 static void print_bad_events(void)
@@ -1689,9 +1695,10 @@ static void print_bad_events(void)
 static void __cmd_lat(void)
 {
        struct rb_node *next;
+       struct perf_session *session;
 
        setup_pager();
-       read_events();
+       read_events(false, &session);
        sort_lat();
 
        printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1717,6 +1724,7 @@ static void __cmd_lat(void)
        print_bad_events();
        printf("\n");
 
+       perf_session__delete(session);
 }
 
 static struct trace_sched_handler map_ops  = {
@@ -1731,7 +1739,7 @@ static void __cmd_map(void)
        max_cpu = sysconf(_SC_NPROCESSORS_CONF);
 
        setup_pager();
-       read_events();
+       read_events(true, NULL);
        print_bad_events();
 }
 
@@ -1744,7 +1752,7 @@ static void __cmd_replay(void)
 
        test_calibrations();
 
-       read_events();
+       read_events(true, NULL);
 
        printf("nr_run_events:        %ld\n", nr_run_events);
        printf("nr_sleep_events:      %ld\n", nr_sleep_events);
@@ -1769,7 +1777,7 @@ static void __cmd_replay(void)
 
 
 static const char * const sched_usage[] = {
-       "perf sched [<options>] {record|latency|map|replay|trace}",
+       "perf sched [<options>] {record|latency|map|replay|script}",
        NULL
 };
 
index e02d78c..fe02903 100644 (file)
@@ -399,7 +399,6 @@ static int perf_config_global(void)
 int perf_config(config_fn_t fn, void *data)
 {
        int ret = 0, found = 0;
-       char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
@@ -414,19 +413,32 @@ int perf_config(config_fn_t fn, void *data)
        home = getenv("HOME");
        if (perf_config_global() && home) {
                char *user_config = strdup(mkpath("%s/.perfconfig", home));
-               if (!access(user_config, R_OK)) {
-                       ret += perf_config_from_file(fn, user_config, data);
-                       found += 1;
+               struct stat st;
+
+               if (user_config == NULL) {
+                       warning("Not enough memory to process %s/.perfconfig, "
+                               "ignoring it.", home);
+                       goto out;
                }
-               free(user_config);
-       }
 
-       repo_config = perf_pathdup("config");
-       if (!access(repo_config, R_OK)) {
-               ret += perf_config_from_file(fn, repo_config, data);
+               if (stat(user_config, &st) < 0)
+                       goto out_free;
+
+               if (st.st_uid && (st.st_uid != geteuid())) {
+                       warning("File %s not owned by current user or root, "
+                               "ignoring it.", user_config);
+                       goto out_free;
+               }
+
+               if (!st.st_size)
+                       goto out_free;
+
+               ret += perf_config_from_file(fn, user_config, data);
                found += 1;
+out_free:
+               free(user_config);
        }
-       free(repo_config);
+out:
        if (found == 0)
                return -1;
        return ret;
index fddf40f..ee51e9b 100644 (file)
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
        return *lineno ?: -ENOENT;
 }
 
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
+
+/**
+ * cu_walk_functions_at - Walk on function DIEs at given address
+ * @cu_die: A CU DIE
+ * @addr: An address
+ * @callback: A callback which called with found DIEs
+ * @data: A user data
+ *
+ * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
+ * should be subprogram or inlined-subroutines.
+ */
+int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                   int (*callback)(Dwarf_Die *, void *), void *data)
+{
+       Dwarf_Die die_mem;
+       Dwarf_Die *sc_die;
+       int ret = -ENOENT;
+
+       /* Inlined function could be recursive. Trace it until fail */
+       for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
+            sc_die != NULL;
+            sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
+                                    &die_mem)) {
+               ret = callback(sc_die, data);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+
+}
+
 /**
  * die_compare_name - Compare diename and tname
  * @dw_die: a DIE
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
        return 0;
 }
 
+/* Get attribute and translate it as a sdata */
+static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
+                             Dwarf_Sword *result)
+{
+       Dwarf_Attribute attr;
+
+       if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formsdata(&attr, result) != 0)
+               return -ENOENT;
+
+       return 0;
+}
+
 /**
  * die_is_signed_type - Check whether a type DIE is signed or not
  * @tp_die: a DIE of a type
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
        return 0;
 }
 
+/* Get the call file index number in CU DIE */
+static int die_get_call_fileno(Dwarf_Die *in_die)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/* Get the declared file index number in CU DIE */
+static int die_get_decl_fileno(Dwarf_Die *pdie)
+{
+       Dwarf_Sword idx;
+
+       if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+}
+
+/**
+ * die_get_call_file - Get callsite file name of inlined function instance
+ * @in_die: a DIE of an inlined function instance
+ *
+ * Get call-site file name of @in_die. This means from which file the inline
+ * function is called.
+ */
+const char *die_get_call_file(Dwarf_Die *in_die)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Files *files;
+       int idx;
+
+       idx = die_get_call_fileno(in_die);
+       if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
+           dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
+               return NULL;
+
+       return dwarf_filesrc(files, idx, NULL, NULL);
+}
+
+
 /**
  * die_find_child - Generic DIE search function in DIE tree
  * @rt_die: a root DIE
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
        return die_mem;
 }
 
+struct __instance_walk_param {
+       void    *addr;
+       int     (*callback)(Dwarf_Die *, void *);
+       void    *data;
+       int     retval;
+};
+
+static int __die_walk_instances_cb(Dwarf_Die *inst, void *data)
+{
+       struct __instance_walk_param *iwp = data;
+       Dwarf_Attribute attr_mem;
+       Dwarf_Die origin_mem;
+       Dwarf_Attribute *attr;
+       Dwarf_Die *origin;
+       int tmp;
+
+       attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem);
+       if (attr == NULL)
+               return DIE_FIND_CB_CONTINUE;
+
+       origin = dwarf_formref_die(attr, &origin_mem);
+       if (origin == NULL || origin->addr != iwp->addr)
+               return DIE_FIND_CB_CONTINUE;
+
+       /* Ignore redundant instances */
+       if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) {
+               dwarf_decl_line(origin, &tmp);
+               if (die_get_call_lineno(inst) == tmp) {
+                       tmp = die_get_decl_fileno(origin);
+                       if (die_get_call_fileno(inst) == tmp)
+                               return DIE_FIND_CB_CONTINUE;
+               }
+       }
+
+       iwp->retval = iwp->callback(inst, iwp->data);
+
+       return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE;
+}
+
+/**
+ * die_walk_instances - Walk on instances of given DIE
+ * @or_die: an abstract original DIE
+ * @callback: a callback function which is called with instance DIE
+ * @data: user data
+ *
+ * Walk on the instances of give @in_die. @in_die must be an inlined function
+ * declartion. This returns the return value of @callback if it returns
+ * non-zero value, or -ENOENT if there is no instance.
+ */
+int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *),
+                      void *data)
+{
+       Dwarf_Die cu_die;
+       Dwarf_Die die_mem;
+       struct __instance_walk_param iwp = {
+               .addr = or_die->addr,
+               .callback = callback,
+               .data = data,
+               .retval = -ENOENT,
+       };
+
+       if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL)
+               return -ENOENT;
+
+       die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem);
+
+       return iwp.retval;
+}
+
 /* Line walker internal parameters */
 struct __line_walk_param {
-       const char *fname;
+       bool recursive;
        line_walk_callback_t callback;
        void *data;
        int retval;
@@ -385,39 +544,56 @@ struct __line_walk_param {
 static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
 {
        struct __line_walk_param *lw = data;
-       Dwarf_Addr addr;
+       Dwarf_Addr addr = 0;
+       const char *fname;
        int lineno;
 
        if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+               fname = die_get_call_file(in_die);
                lineno = die_get_call_lineno(in_die);
-               if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
-                       lw->retval = lw->callback(lw->fname, lineno, addr,
-                                                 lw->data);
+               if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
                        if (lw->retval != 0)
                                return DIE_FIND_CB_END;
                }
        }
-       return DIE_FIND_CB_SIBLING;
+       if (!lw->recursive)
+               /* Don't need to search recursively */
+               return DIE_FIND_CB_SIBLING;
+
+       if (addr) {
+               fname = dwarf_decl_file(in_die);
+               if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
+                       lw->retval = lw->callback(fname, lineno, addr, lw->data);
+                       if (lw->retval != 0)
+                               return DIE_FIND_CB_END;
+               }
+       }
+
+       /* Continue to search nested inlined function call-sites */
+       return DIE_FIND_CB_CONTINUE;
 }
 
 /* Walk on lines of blocks included in given DIE */
-static int __die_walk_funclines(Dwarf_Die *sp_die,
+static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
                                line_walk_callback_t callback, void *data)
 {
        struct __line_walk_param lw = {
+               .recursive = recursive,
                .callback = callback,
                .data = data,
                .retval = 0,
        };
        Dwarf_Die die_mem;
        Dwarf_Addr addr;
+       const char *fname;
        int lineno;
 
        /* Handle function declaration line */
-       lw.fname = dwarf_decl_file(sp_die);
-       if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+       fname = dwarf_decl_file(sp_die);
+       if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
            dwarf_entrypc(sp_die, &addr) == 0) {
-               lw.retval = callback(lw.fname, lineno, addr, data);
+               lw.retval = callback(fname, lineno, addr, data);
                if (lw.retval != 0)
                        goto done;
        }
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 {
        struct __line_walk_param *lw = data;
 
-       lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data);
+       lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
        if (lw->retval != 0)
                return DWARF_CB_ABORT;
 
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
 
 /**
  * die_walk_lines - Walk on lines inside given DIE
- * @rt_die: a root DIE (CU or subprogram)
+ * @rt_die: a root DIE (CU, subprogram or inlined_subroutine)
  * @callback: callback routine
  * @data: user data
  *
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
        size_t nlines, i;
 
        /* Get the CU die */
-       if (dwarf_tag(rt_die) == DW_TAG_subprogram)
+       if (dwarf_tag(rt_die) != DW_TAG_compile_unit)
                cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
        else
                cu_die = rt_die;
        if (!cu_die) {
-               pr_debug2("Failed to get CU from subprogram\n");
+               pr_debug2("Failed to get CU from given DIE.\n");
                return -EINVAL;
        }
 
@@ -509,7 +685,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
         * subroutines. We have to check functions list or given function.
         */
        if (rt_die != cu_die)
-               ret = __die_walk_funclines(rt_die, callback, data);
+               /*
+                * Don't need walk functions recursively, because nested
+                * inlined functions don't have lines of the specified DIE.
+                */
+               ret = __die_walk_funclines(rt_die, false, callback, data);
        else {
                struct __line_walk_param param = {
                        .callback = callback,
index bc3b211..6ce1717 100644 (file)
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
 extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
                            const char **fname, int *lineno);
 
+/* Walk on funcitons at given address */
+extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
+                       int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Compare diename and tname */
 extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
 
 /* Get callsite line number of inline-function instance */
 extern int die_get_call_lineno(Dwarf_Die *in_die);
 
+/* Get callsite file name of inlined function instance */
+extern const char *die_get_call_file(Dwarf_Die *in_die);
+
 /* Get type die */
 extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
 
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
 extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
                                      Dwarf_Die *die_mem);
 
+/* Walk on the instances of given DIE */
+extern int die_walk_instances(Dwarf_Die *in_die,
+                             int (*callback)(Dwarf_Die *, void *), void *data);
+
 /* Walker on lines (Note: line number will not be sorted) */
 typedef int (* line_walk_callback_t) (const char *fname, int lineno,
                                      Dwarf_Addr addr, void *data);
index b021ea9..e03e7bc 100644 (file)
@@ -91,6 +91,19 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
        return 0;
 }
 
+void perf_evlist__disable(struct perf_evlist *evlist)
+{
+       int cpu, thread;
+       struct perf_evsel *pos;
+
+       for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+               list_for_each_entry(pos, &evlist->entries, node) {
+                       for (thread = 0; thread < evlist->threads->nr; thread++)
+                               ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
+               }
+       }
+}
+
 int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
        int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
index b2b8623..ce85ae9 100644 (file)
@@ -53,6 +53,8 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
 void perf_evlist__munmap(struct perf_evlist *evlist);
 
+void perf_evlist__disable(struct perf_evlist *evlist);
+
 static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
                                         struct cpu_map *cpus,
                                         struct thread_map *threads)
index cb2959a..b6c1ad1 100644 (file)
@@ -189,8 +189,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms)
 {
        const size_t size = PATH_MAX;
-       char *realname, *filename = malloc(size),
-            *linkname = malloc(size), *targetname;
+       char *realname, *filename = zalloc(size),
+            *linkname = zalloc(size), *targetname;
        int len, err = -1;
 
        if (is_kallsyms) {
@@ -254,8 +254,8 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
 {
        const size_t size = PATH_MAX;
-       char *filename = malloc(size),
-            *linkname = malloc(size);
+       char *filename = zalloc(size),
+            *linkname = zalloc(size);
        int err = -1;
 
        if (filename == NULL || linkname == NULL)
@@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
                        return -1;
 
                bev.header = old_bev.header;
-               bev.pid    = 0;
+
+               /*
+                * As the pid is the missing value, we need to fill
+                * it properly. The header.misc value give us nice hint.
+                */
+               bev.pid = HOST_KERNEL_ID;
+               if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
+                   bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
+                       bev.pid = DEFAULT_GUEST_KERNEL_ID;
+
                memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
                __event_process_build_id(&bev, filename, session);
 
index b82d54f..1c7bfa5 100644 (file)
@@ -1820,11 +1820,15 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
                ret = -ENOMEM;
                goto error;
        }
-       tev->point.module = strdup(module);
-       if (tev->point.module == NULL) {
-               ret = -ENOMEM;
-               goto error;
+
+       if (module) {
+               tev->point.module = strdup(module);
+               if (tev->point.module == NULL) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
        }
+
        tev->point.offset = pev->point.offset;
        tev->point.retprobe = pev->point.retprobe;
        tev->nargs = pev->nargs;
index 3e44a3e..555fc38 100644 (file)
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
        return ret;
 }
 
-/* Find a variable in a subprogram die */
-static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Find a variable in a scope DIE */
+static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die vr_die, *scopes;
+       Dwarf_Die vr_die;
        char buf[32], *ptr;
-       int ret, nscopes;
+       int ret = 0;
 
        if (!is_c_varname(pf->pvar->var)) {
                /* Copy raw parameters */
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (pf->tvar->name == NULL)
                return -ENOMEM;
 
-       pr_debug("Searching '%s' variable in context.\n",
-                pf->pvar->var);
+       pr_debug("Searching '%s' variable in context.\n", pf->pvar->var);
        /* Search child die for local variables and parameters. */
-       if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
-               ret = convert_variable(&vr_die, pf);
-       else {
-               /* Search upper class */
-               nscopes = dwarf_getscopes_die(sp_die, &scopes);
-               while (nscopes-- > 1) {
-                       pr_debug("Searching variables in %s\n",
-                                dwarf_diename(&scopes[nscopes]));
-                       /* We should check this scope, so give dummy address */
-                       if (die_find_variable_at(&scopes[nscopes],
-                                                pf->pvar->var, 0,
-                                                &vr_die)) {
-                               ret = convert_variable(&vr_die, pf);
-                               goto found;
-                       }
-               }
-               if (scopes)
-                       free(scopes);
-               ret = -ENOENT;
+       if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
+               /* Search again in global variables */
+               if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
+                       ret = -ENOENT;
        }
-found:
+       if (ret == 0)
+               ret = convert_variable(&vr_die, pf);
+
        if (ret < 0)
                pr_warning("Failed to find '%s' in this function.\n",
                           pf->pvar->var);
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
        return 0;
 }
 
-/* Call probe_finder callback with real subprogram DIE */
-static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Call probe_finder callback with scope DIE */
+static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
-       Dwarf_Die die_mem;
        Dwarf_Attribute fb_attr;
        size_t nops;
        int ret;
 
-       /* If no real subprogram, find a real one */
-       if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-               sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
-               if (!sp_die) {
+       if (!sc_die) {
+               pr_err("Caller must pass a scope DIE. Program error.\n");
+               return -EINVAL;
+       }
+
+       /* If not a real subprogram, find a real one */
+       if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
+               if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
                        pr_warning("Failed to find probe point in any "
                                   "functions.\n");
                        return -ENOENT;
                }
-       }
+       } else
+               memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
 
-       /* Get the frame base attribute/ops */
-       dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
+       /* Get the frame base attribute/ops from subprogram */
+       dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
        ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
        if (ret <= 0 || nops == 0) {
                pf->fb_ops = NULL;
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
 
        /* Call finder's callback handler */
-       ret = pf->callback(sp_die, pf);
+       ret = pf->callback(sc_die, pf);
 
        /* *pf->fb_ops will be cached in libdw. Don't free it. */
        pf->fb_ops = NULL;
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        return ret;
 }
 
+struct find_scope_param {
+       const char *function;
+       const char *file;
+       int line;
+       int diff;
+       Dwarf_Die *die_mem;
+       bool found;
+};
+
+static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
+{
+       struct find_scope_param *fsp = data;
+       const char *file;
+       int lno;
+
+       /* Skip if declared file name does not match */
+       if (fsp->file) {
+               file = dwarf_decl_file(fn_die);
+               if (!file || strcmp(fsp->file, file) != 0)
+                       return 0;
+       }
+       /* If the function name is given, that's what user expects */
+       if (fsp->function) {
+               if (die_compare_name(fn_die, fsp->function)) {
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+                       return 1;
+               }
+       } else {
+               /* With the line number, find the nearest declared DIE */
+               dwarf_decl_line(fn_die, &lno);
+               if (lno < fsp->line && fsp->diff > fsp->line - lno) {
+                       /* Keep a candidate and continue */
+                       fsp->diff = fsp->line - lno;
+                       memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
+                       fsp->found = true;
+               }
+       }
+       return 0;
+}
+
+/* Find an appropriate scope fits to given conditions */
+static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
+{
+       struct find_scope_param fsp = {
+               .function = pf->pev->point.function,
+               .file = pf->fname,
+               .line = pf->lno,
+               .diff = INT_MAX,
+               .die_mem = die_mem,
+               .found = false,
+       };
+
+       cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
+
+       return fsp.found ? die_mem : NULL;
+}
+
 static int probe_point_line_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
                return 0;
 
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /* Continue if no error, because the line will be in inline function */
        return ret < 0 ? ret : 0;
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
                                   Dwarf_Addr addr, void *data)
 {
        struct probe_finder *pf = data;
+       Dwarf_Die *sc_die, die_mem;
        int ret;
 
        if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
        pr_debug("Probe line found: line:%d addr:0x%llx\n",
                 lineno, (unsigned long long)addr);
        pf->addr = addr;
-       ret = call_probe_finder(NULL, pf);
+       pf->lno = lineno;
+       sc_die = find_best_scope(pf, &die_mem);
+       if (!sc_die) {
+               pr_warning("Failed to find scope of probe point.\n");
+               return -ENOENT;
+       }
+
+       ret = call_probe_finder(sc_die, pf);
 
        /*
         * Continue if no error, because the lazy pattern will match
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
-/* Callback parameter with return value */
-struct dwarf_callback_param {
-       void *data;
-       int retval;
-};
-
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
-       struct probe_finder *pf = param->data;
+       struct probe_finder *pf = data;
        struct perf_probe_point *pp = &pf->pev->point;
        Dwarf_Addr addr;
+       int ret;
 
        if (pp->lazy_line)
-               param->retval = find_probe_point_lazy(in_die, pf);
+               ret = find_probe_point_lazy(in_die, pf);
        else {
                /* Get probe address */
                if (dwarf_entrypc(in_die, &addr) != 0) {
                        pr_warning("Failed to get entry address of %s.\n",
                                   dwarf_diename(in_die));
-                       param->retval = -ENOENT;
-                       return DWARF_CB_ABORT;
+                       return -ENOENT;
                }
                pf->addr = addr;
                pf->addr += pp->offset;
                pr_debug("found inline addr: 0x%jx\n",
                         (uintmax_t)pf->addr);
 
-               param->retval = call_probe_finder(in_die, pf);
-               if (param->retval < 0)
-                       return DWARF_CB_ABORT;
+               ret = call_probe_finder(in_die, pf);
        }
 
-       return DWARF_CB_OK;
+       return ret;
 }
 
+/* Callback parameter with return value for libdw */
+struct dwarf_callback_param {
+       void *data;
+       int retval;
+};
+
 /* Search function from function name */
 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
                }
-       } else {
-               struct dwarf_callback_param _param = {.data = (void *)pf,
-                                                     .retval = 0};
+       } else
                /* Inlined function: search instances */
-               dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
-                                           &_param);
-               param->retval = _param.retval;
-       }
+               param->retval = die_walk_instances(sp_die,
+                                       probe_point_inline_cb, (void *)pf);
 
        return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
 }
@@ -1060,7 +1116,7 @@ found:
 }
 
 /* Add a found probe point into trace event list */
-static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct trace_event_finder *tf =
                        container_of(pf, struct trace_event_finder, pf);
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        tev = &tf->tevs[tf->ntevs++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &tev->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &tev->point);
        if (ret < 0)
                return ret;
 
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
        for (i = 0; i < pf->pev->nargs; i++) {
                pf->pvar = &pf->pev->args[i];
                pf->tvar = &tev->args[i];
-               ret = find_variable(sp_die, pf);
+               /* Variable should be found from scope DIE */
+               ret = find_variable(sc_die, pf);
                if (ret != 0)
                        return ret;
        }
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 }
 
 /* Add a found vars into available variables list */
-static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
 {
        struct available_var_finder *af =
                        container_of(pf, struct available_var_finder, pf);
        struct variable_list *vl;
-       Dwarf_Die die_mem, *scopes = NULL;
-       int ret, nscopes;
+       Dwarf_Die die_mem;
+       int ret;
 
        /* Check number of tevs */
        if (af->nvls == af->max_vls) {
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        }
        vl = &af->vls[af->nvls++];
 
-       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
-                                    &vl->point);
+       /* Trace point should be converted from subprogram DIE */
+       ret = convert_to_trace_point(&pf->sp_die, pf->addr,
+                                    pf->pev->point.retprobe, &vl->point);
        if (ret < 0)
                return ret;
 
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
        if (vl->vars == NULL)
                return -ENOMEM;
        af->child = true;
-       die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+       die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
 
        /* Find external variables */
        if (!af->externs)
                goto out;
        /* Don't need to search child DIE for externs. */
        af->child = false;
-       nscopes = dwarf_getscopes_die(sp_die, &scopes);
-       while (nscopes-- > 1)
-               die_find_child(&scopes[nscopes], collect_variables_cb,
-                              (void *)af, &die_mem);
-       if (scopes)
-               free(scopes);
+       die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem);
 
 out:
        if (strlist__empty(vl->vars)) {
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
 {
-       struct dwarf_callback_param *param = data;
+       find_line_range_by_line(in_die, data);
 
-       param->retval = find_line_range_by_line(in_die, param->data);
-       return DWARF_CB_ABORT;  /* No need to find other instances */
+       /*
+        * We have to check all instances of inlined function, because
+        * some execution paths can be optimized out depends on the
+        * function argument of instances
+        */
+       return 0;
 }
 
 /* Search function from function name */
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
                pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
                lr->start = lf->lno_s;
                lr->end = lf->lno_e;
-               if (dwarf_func_inline(sp_die)) {
-                       struct dwarf_callback_param _param;
-                       _param.data = (void *)lf;
-                       _param.retval = 0;
-                       dwarf_func_inline_instances(sp_die,
-                                                   line_range_inline_cb,
-                                                   &_param);
-                       param->retval = _param.retval;
-               } else
+               if (dwarf_func_inline(sp_die))
+                       param->retval = die_walk_instances(sp_die,
+                                               line_range_inline_cb, lf);
+               else
                        param->retval = find_line_range_by_line(sp_die, lf);
                return DWARF_CB_ABORT;
        }
index c478b42..1132c8f 100644 (file)
@@ -57,7 +57,7 @@ struct probe_finder {
        struct perf_probe_event *pev;           /* Target probe event */
 
        /* Callback when a probe point is found */
-       int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
+       int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
 
        /* For function searching */
        int                     lno;            /* Line number */
index 8e0b5a3..cbc8f21 100644 (file)
@@ -187,14 +187,117 @@ static PyTypeObject pyrf_throttle_event__type = {
        .tp_repr        = (reprfunc)pyrf_throttle_event__repr,
 };
 
+static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
+
+static PyMemberDef pyrf_lost_event__members[] = {
+       sample_members
+       member_def(lost_event, id, T_ULONGLONG, "event id"),
+       member_def(lost_event, lost, T_ULONGLONG, "number of lost events"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent)
+{
+       PyObject *ret;
+       char *s;
+
+       if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", "
+                        "lost: %#" PRIx64 " }",
+                    pevent->event.lost.id, pevent->event.lost.lost) < 0) {
+               ret = PyErr_NoMemory();
+       } else {
+               ret = PyString_FromString(s);
+               free(s);
+       }
+       return ret;
+}
+
+static PyTypeObject pyrf_lost_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.lost_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_lost_event__doc,
+       .tp_members     = pyrf_lost_event__members,
+       .tp_repr        = (reprfunc)pyrf_lost_event__repr,
+};
+
+static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
+
+static PyMemberDef pyrf_read_event__members[] = {
+       sample_members
+       member_def(read_event, pid, T_UINT, "event pid"),
+       member_def(read_event, tid, T_UINT, "event tid"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
+{
+       return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
+                                  pevent->event.read.pid,
+                                  pevent->event.read.tid);
+       /*
+        * FIXME: return the array of read values,
+        * making this method useful ;-)
+        */
+}
+
+static PyTypeObject pyrf_read_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.read_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_read_event__doc,
+       .tp_members     = pyrf_read_event__members,
+       .tp_repr        = (reprfunc)pyrf_read_event__repr,
+};
+
+static char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
+
+static PyMemberDef pyrf_sample_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent)
+{
+       PyObject *ret;
+       char *s;
+
+       if (asprintf(&s, "{ type: sample }") < 0) {
+               ret = PyErr_NoMemory();
+       } else {
+               ret = PyString_FromString(s);
+               free(s);
+       }
+       return ret;
+}
+
+static PyTypeObject pyrf_sample_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.sample_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_sample_event__doc,
+       .tp_members     = pyrf_sample_event__members,
+       .tp_repr        = (reprfunc)pyrf_sample_event__repr,
+};
+
 static int pyrf_event__setup_types(void)
 {
        int err;
        pyrf_mmap_event__type.tp_new =
        pyrf_task_event__type.tp_new =
        pyrf_comm_event__type.tp_new =
+       pyrf_lost_event__type.tp_new =
+       pyrf_read_event__type.tp_new =
+       pyrf_sample_event__type.tp_new =
        pyrf_throttle_event__type.tp_new = PyType_GenericNew;
        err = PyType_Ready(&pyrf_mmap_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_lost_event__type);
        if (err < 0)
                goto out;
        err = PyType_Ready(&pyrf_task_event__type);
@@ -206,20 +309,26 @@ static int pyrf_event__setup_types(void)
        err = PyType_Ready(&pyrf_throttle_event__type);
        if (err < 0)
                goto out;
+       err = PyType_Ready(&pyrf_read_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_sample_event__type);
+       if (err < 0)
+               goto out;
 out:
        return err;
 }
 
 static PyTypeObject *pyrf_event__type[] = {
        [PERF_RECORD_MMAP]       = &pyrf_mmap_event__type,
-       [PERF_RECORD_LOST]       = &pyrf_mmap_event__type,
+       [PERF_RECORD_LOST]       = &pyrf_lost_event__type,
        [PERF_RECORD_COMM]       = &pyrf_comm_event__type,
        [PERF_RECORD_EXIT]       = &pyrf_task_event__type,
        [PERF_RECORD_THROTTLE]   = &pyrf_throttle_event__type,
        [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
        [PERF_RECORD_FORK]       = &pyrf_task_event__type,
-       [PERF_RECORD_READ]       = &pyrf_mmap_event__type,
-       [PERF_RECORD_SAMPLE]     = &pyrf_mmap_event__type,
+       [PERF_RECORD_READ]       = &pyrf_read_event__type,
+       [PERF_RECORD_SAMPLE]     = &pyrf_sample_event__type,
 };
 
 static PyObject *pyrf_event__new(union perf_event *event)
index bbc982f..95d3700 100644 (file)
@@ -3,9 +3,27 @@
 from distutils.core import setup, Extension
 from os import getenv
 
+from distutils.command.build_ext   import build_ext   as _build_ext
+from distutils.command.install_lib import install_lib as _install_lib
+
+class build_ext(_build_ext):
+    def finalize_options(self):
+        _build_ext.finalize_options(self)
+        self.build_lib  = build_lib
+        self.build_temp = build_tmp
+
+class install_lib(_install_lib):
+    def finalize_options(self):
+        _install_lib.finalize_options(self)
+        self.build_dir = build_lib
+
+
 cflags = ['-fno-strict-aliasing', '-Wno-write-strings']
 cflags += getenv('CFLAGS', '').split()
 
+build_lib = getenv('PYTHON_EXTBUILD_LIB')
+build_tmp = getenv('PYTHON_EXTBUILD_TMP')
+
 perf = Extension('perf',
                  sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
                             'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
@@ -21,4 +39,5 @@ setup(name='perf',
       author_email='acme@redhat.com',
       license='GPLv2',
       url='http://perf.wiki.kernel.org',
-      ext_modules=[perf])
+      ext_modules=[perf],
+      cmdclass={'build_ext': build_ext, 'install_lib': install_lib})
index eec1963..469c026 100644 (file)
@@ -1504,6 +1504,17 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        dso->adjust_symbols = 0;
 
        if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
+               struct stat st;
+
+               if (lstat(dso->name, &st) < 0)
+                       return -1;
+
+               if (st.st_uid && (st.st_uid != geteuid())) {
+                       pr_warning("File %s not owned by current user or root, "
+                               "ignoring it.\n", dso->name);
+                       return -1;
+               }
+
                ret = dso__load_perf_map(dso, map, filter);
                dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
                                              SYMTAB__NOT_FOUND;
@@ -2170,27 +2181,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
        return ret;
 }
 
-struct dso *dso__new_kernel(const char *name)
+static struct dso*
+dso__kernel_findnew(struct machine *machine, const char *name,
+                   const char *short_name, int dso_type)
 {
-       struct dso *dso = dso__new(name ?: "[kernel.kallsyms]");
-
-       if (dso != NULL) {
-               dso__set_short_name(dso, "[kernel]");
-               dso->kernel = DSO_TYPE_KERNEL;
-       }
-
-       return dso;
-}
+       /*
+        * The kernel dso could be created by build_id processing.
+        */
+       struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
 
-static struct dso *dso__new_guest_kernel(struct machine *machine,
-                                       const char *name)
-{
-       char bf[PATH_MAX];
-       struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf,
-                                                             sizeof(bf)));
+       /*
+        * We need to run this in all cases, since during the build_id
+        * processing we had no idea this was the kernel dso.
+        */
        if (dso != NULL) {
-               dso__set_short_name(dso, "[guest.kernel]");
-               dso->kernel = DSO_TYPE_GUEST_KERNEL;
+               dso__set_short_name(dso, short_name);
+               dso->kernel = dso_type;
        }
 
        return dso;
@@ -2208,24 +2214,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
                dso->has_build_id = true;
 }
 
-static struct dso *machine__create_kernel(struct machine *machine)
+static struct dso *machine__get_kernel(struct machine *machine)
 {
        const char *vmlinux_name = NULL;
        struct dso *kernel;
 
        if (machine__is_host(machine)) {
                vmlinux_name = symbol_conf.vmlinux_name;
-               kernel = dso__new_kernel(vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = "[kernel.kallsyms]";
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[kernel]",
+                                            DSO_TYPE_KERNEL);
        } else {
+               char bf[PATH_MAX];
+
                if (machine__is_default_guest(machine))
                        vmlinux_name = symbol_conf.default_guest_vmlinux_name;
-               kernel = dso__new_guest_kernel(machine, vmlinux_name);
+               if (!vmlinux_name)
+                       vmlinux_name = machine__mmap_name(machine, bf,
+                                                         sizeof(bf));
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[guest.kernel]",
+                                            DSO_TYPE_GUEST_KERNEL);
        }
 
-       if (kernel != NULL) {
+       if (kernel != NULL && (!kernel->has_build_id))
                dso__read_running_kernel_build_id(kernel, machine);
-               dsos__add(&machine->kernel_dsos, kernel);
-       }
+
        return kernel;
 }
 
@@ -2329,7 +2347,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
 
 int machine__create_kernel_maps(struct machine *machine)
 {
-       struct dso *kernel = machine__create_kernel(machine);
+       struct dso *kernel = machine__get_kernel(machine);
 
        if (kernel == NULL ||
            __machine__create_kernel_maps(machine, kernel) < 0)
index 325ee36..4f377d9 100644 (file)
@@ -155,7 +155,6 @@ struct dso {
 };
 
 struct dso *dso__new(const char *name);
-struct dso *dso__new_kernel(const char *name);
 void dso__delete(struct dso *dso);
 
 int dso__name_len(const struct dso *dso);
index 5a06538..88403cf 100644 (file)
@@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top)
                },
        };
 
-       ui_helpline__push("Press <- or ESC to exit");
        return perf_top_browser__run(&browser);
 }